From 99b822cc2f1331d4f3fbefb58619c410c82615a0 Mon Sep 17 00:00:00 2001 From: lilong Date: Fri, 31 May 2024 10:51:35 +0800 Subject: [PATCH 01/69] =?UTF-8?q?feat:(REQ-2509)=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E9=89=B4=E6=9D=83=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=8A=8A=E9=89=B4?= =?UTF-8?q?=E6=9D=83=E5=92=8C=E6=9F=A5=E8=AF=A2=E8=8F=9C=E5=8D=95=E5=88=86?= =?UTF-8?q?=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/model/req/IdentityAuthReq.java | 27 +- .../client/model/res/SaasPermissionRes.java | 6 + .../model/roleuser/dto/SaasRoleUserV2DTO.java | 39 +++ .../req/ListRoleUserRelationParam.java | 60 ++++ .../config/exception/BizResultCode.java | 4 +- .../server/controller/PrivateController.java | 23 ++ .../service/PermissionCacheService.java | 131 ++++++++ .../ProductPermissionCacheService.java | 68 ++++ .../service/RolePermissionCacheService.java | 84 +++++ .../axzo/tyr/server/service/RoleService.java | 16 + .../server/service/TyrSaasAuthService.java | 8 + .../impl/PermissionCacheServiceImpl.java | 124 +++++++- .../impl/PermissionQueryServiceImpl.java | 10 +- .../ProductPermissionCacheServiceImpl.java | 106 +++++++ .../impl/RolePermissionCacheServiceImpl.java | 106 +++++++ .../server/service/impl/RoleServiceImpl.java | 68 +++- .../server/service/impl/RoleUserService.java | 1 + .../impl/SaasRoleUserRelationServiceImpl.java | 38 ++- .../service/impl/TyrSaasAuthServiceImpl.java | 292 +++++++++++++++--- 19 files changed, 1159 insertions(+), 52 deletions(-) create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductPermissionCacheService.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/RolePermissionCacheService.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductPermissionCacheServiceImpl.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RolePermissionCacheServiceImpl.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/IdentityAuthReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/IdentityAuthReq.java index 099f3495..396e5c4f 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/IdentityAuthReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/IdentityAuthReq.java @@ -1,9 +1,8 @@ package cn.axzo.tyr.client.model.req; import cn.axzo.framework.auth.domain.TerminalInfo; -import cn.axzo.tyr.client.common.enums.WorkspaceJoinType; -import cn.axzo.tyr.client.model.enums.FeatureType; import cn.axzo.tyr.client.model.enums.IdentityType; +import cn.axzo.tyr.client.model.res.IdentityAuthRes; import cn.hutool.core.collection.CollectionUtil; import lombok.AllArgsConstructor; import lombok.Builder; @@ -13,18 +12,11 @@ import lombok.NoArgsConstructor; import javax.validation.Valid; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; -import static cn.axzo.tyr.client.common.enums.WorkspaceJoinType.ENT_GROUP; -import static cn.axzo.tyr.client.common.enums.WorkspaceJoinType.ENT_TEAM; -import static cn.axzo.tyr.client.common.enums.WorkspaceJoinType.PROJ_GROUP; -import static cn.axzo.tyr.client.common.enums.WorkspaceJoinType.PROJ_TEAM; - /** * @author tanjie@axzo.cn * @date 2023/10/13 15:23 @@ -73,6 +65,23 @@ public class IdentityAuthReq { @Builder.Default private boolean useCache = true; + public IdentityAuthRes toEmpty() { + IdentityAuthRes result = new IdentityAuthRes(); + result.setIdentity(this.getIdentityId()); + result.setIdentityType(this.getIdentityType()); + result.setPersonId(this.getPersonId()); + + List permissions = this.getWorkspaceOusPairs().stream() + .map(workspaceOuPair -> IdentityAuthRes.WorkspacePermission.builder() + .workspaceId(workspaceOuPair.getWorkspaceId()) + .ouId(workspaceOuPair.getOuId()) + .build()) + .collect(Collectors.toList()); + result.setPermissions(permissions); + + return result; + } + public void distinctOUWorkspacePair() { if (CollectionUtil.isEmpty(this.workspaceOusPairs)) { return; diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasPermissionRes.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasPermissionRes.java index 5e007685..2cf6fc65 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasPermissionRes.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasPermissionRes.java @@ -17,4 +17,10 @@ public class SaasPermissionRes { * 资源编码-权限码 */ private String featureCode; + + /** + * 资源所属端 + */ + private String terminal; + } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/dto/SaasRoleUserV2DTO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/dto/SaasRoleUserV2DTO.java index bb63b56a..f548e0d8 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/dto/SaasRoleUserV2DTO.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/dto/SaasRoleUserV2DTO.java @@ -1,10 +1,13 @@ package cn.axzo.tyr.client.model.roleuser.dto; +import cn.axzo.tyr.client.model.res.SaasPermissionRes; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.util.List; + @Data @Builder @AllArgsConstructor @@ -18,6 +21,8 @@ public class SaasRoleUserV2DTO { private SaasRoleUser saasRoleUser; + private SaasRole saasRole; + @Data @Builder @NoArgsConstructor @@ -34,4 +39,38 @@ public class SaasRoleUserV2DTO { */ private String realName; } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class SaasRole { + private Long id; + + /** + * 角色名称 + */ + private String name; + + /** + * 角色类型: + * cn.axzo.tyr.client.common.enums.RoleTypeEnum + */ + private String roleType; + + private Long workspaceId; + + private Long ownerOuId; + + /** + * 产品单位类型 + * 1:总包 2:建设单位 3:监理单位 4:劳务分包 5:专业分包 6:OMS通用 7:企业通用 8:企业内班组 9:项目内班组 + */ + private Integer productUnitType; + + /** + * 角色权限 + */ + private List saasPermissions; + } } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/req/ListRoleUserRelationParam.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/req/ListRoleUserRelationParam.java index 2138726a..7bc6c4e5 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/req/ListRoleUserRelationParam.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/req/ListRoleUserRelationParam.java @@ -2,7 +2,9 @@ package cn.axzo.tyr.client.model.roleuser.req; import cn.axzo.foundation.dao.support.wrapper.CriteriaField; import cn.axzo.foundation.dao.support.wrapper.Operator; +import cn.axzo.tyr.client.model.enums.IdentityType; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; @@ -20,4 +22,62 @@ public class ListRoleUserRelationParam { @CriteriaField(ignore = true) private Boolean needUsers; + + /** + * 自然人Id + */ + @CriteriaField(field = "naturalPersonId", operator = Operator.EQ) + private Long personId; + + /** + * 身份Id + */ + @CriteriaField(field = "identityId", operator = Operator.EQ) + private Long identityId; + + /** + * 身份类型 1:工人 2:从业人员 3:班组长 4:运营人员 5:政务人员 + */ + @CriteriaField(field = "identityType", operator = Operator.EQ) + private IdentityType identityType; + + /** + * workspaceId和ouId配对查询 + * 例如:((workspaceId = ## and ouId = ##) or (workspaceId = ## and ouId = ##)) + */ + @CriteriaField(ignore = true) + private List workspaceOuPairs; + + @CriteriaField(ignore = true) + private Boolean needRole; + + /** + * 从saas_feature中查询权限点 + */ + @CriteriaField(ignore = true) + private Boolean needRolePermissionOld; + + /** + * 根据权限点id过滤 + */ + @CriteriaField(ignore = true) + private List featureIds; + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class WorkspaceOuPair { + + /** + * 租户id + */ + private Long workspaceId; + + /** + * 单位id + */ + private Long ouId; + } + } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/config/exception/BizResultCode.java b/tyr-server/src/main/java/cn/axzo/tyr/server/config/exception/BizResultCode.java index 128d9c1f..07316d28 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/config/exception/BizResultCode.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/config/exception/BizResultCode.java @@ -9,7 +9,9 @@ import lombok.Getter; public enum BizResultCode implements IResultCode { CANT_DELETE_ROLE_GROUP("100001", "不能删除角色分组,当前角色分组下有子角色分组"), - ROLE_GROUP_NOT_FOUND("100002", "角色分组不存在"); + ROLE_GROUP_NOT_FOUND("100002", "角色分组不存在"), + REDIS_ROLE_NOT_NULL("100003", "角色id不能为空"), + REDIS_PRODUCT_NOT_NULL("100004", "产品id不能为空"); private String errorCode; private String errorMessage; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java index 56c96e1b..bce3f4ea 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java @@ -17,6 +17,8 @@ import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import cn.axzo.tyr.server.repository.entity.SaasRole; import cn.axzo.tyr.server.repository.entity.SaasRoleGroup; import cn.axzo.tyr.server.repository.entity.SaasRoleGroupRelation; +import cn.axzo.tyr.server.service.ProductPermissionCacheService; +import cn.axzo.tyr.server.service.RolePermissionCacheService; import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasCommonDictService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; @@ -67,6 +69,11 @@ public class PrivateController { private SaasFeatureResourceDao saasFeatureResourceDao; @Autowired private SaasFeatureResourceCacheService saasFeatureResourceCacheService; + @Autowired + private RolePermissionCacheService rolePermissionCacheService; + @Autowired + private ProductPermissionCacheService productPermissionCacheService; + /** @@ -251,6 +258,22 @@ public class PrivateController { }); } + @PostMapping("/api/private/productPermission/add") + public Object addProductPermission(@Validated @RequestBody ProductPermissionCacheService.StoreProductPermissionParam request) { + productPermissionCacheService.store(request); + return "ok"; + } + + @PostMapping("/api/private/productPermission/get") + public Object getProductPermission(@Validated @RequestBody ProductPermissionCacheService.ListProductPermissionParam request) { + return productPermissionCacheService.list(request); + } + + @PostMapping("/api/private/productPermission/has") + public Object hasProductIds(@Validated @RequestBody ProductPermissionCacheService.HasProductPermissionParam request) { + return productPermissionCacheService.hasProductIds(request); + } + @Data @Builder @NoArgsConstructor diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/PermissionCacheService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/PermissionCacheService.java index bb401d7c..f1608317 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/PermissionCacheService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/PermissionCacheService.java @@ -2,6 +2,13 @@ package cn.axzo.tyr.server.service; import cn.axzo.tyr.client.model.res.IdentityAuthRes; import cn.axzo.tyr.server.model.PermissionCacheKey; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Set; /** * 授权缓存服务 @@ -23,4 +30,128 @@ public interface PermissionCacheService { /** 标记缓存暂时不可用 - 等缓存全部失效 **/ void markTempDisable(PermissionCacheKey key); + + /** + * 缓存权限码跟角色的信息,采用set数据结构 + * redisKey:featureCode + * redisValue: roleId + * @param param + */ + void cachePermissionRole(CachePermissionRoleParam param); + + /** + * 根据权限码查询对应的角色信息 + * @param param + * @return + */ + List listPermissionRole(ListPermissionRoleParam param); + + /** + * 缓存权限码跟产品和单位类型的信息,采用set数据结构 + * redisKey: featureCode + * redisValue: 产品信息 + * @param param + */ + void cachePermissionProduct(CachePermissionProductParam param); + + /** + * 根据权限码查询对应的产品信息 + * 一个权限点对应的产品数据比较少,一般10多个,所以没有聚合返回,方便排查哪些权限点已经在redis中,不用从数据库中查询 + * @param param + * @return + */ + List listPermissionProduct(ListPermissionProductParam param); + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class HasPermissionRoleParam { + + private List featureCodes; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ListPermissionRoleParam { + + private List featureCodes; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class CachePermissionRoleParam { + + private List permissionRoles; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class PermissionRole { + /** + * 权限码 + */ + private String featureCode; + + /** + * 角色id + */ + private List roleIds; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ListPermissionProductParam { + + private List featureCodes; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class CachePermissionProductParam { + + private List permissionProducts; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class PermissionProduct { + /** + * 权限码 + */ + private String featureCode; + + /** + * 产品信息 + */ + private List products; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class Product { + /** + * 产品id + */ + private Long productId; + + /** + * 单位类型 + */ + private Integer ouType; + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductPermissionCacheService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductPermissionCacheService.java new file mode 100644 index 00000000..bdad9d38 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductPermissionCacheService.java @@ -0,0 +1,68 @@ +package cn.axzo.tyr.server.service; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +public interface ProductPermissionCacheService { + + List list(ListProductPermissionParam param); + + void store(StoreProductPermissionParam param); + + + List hasProductIds(HasProductPermissionParam param); + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class HasProductPermissionParam { + private List productIds; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class StoreProductPermissionParam { + private List productPermissions; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ProductPermission { + private Long productId; + + private List permissions; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ListProductPermissionParam { + private List productIds; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class PermissionDTO { + + /** + * 产品关联的字典 Code 原值 + */ + private String dictCode; + + private Long featureId; + + private String featureCode; + } +} \ No newline at end of file diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/RolePermissionCacheService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RolePermissionCacheService.java new file mode 100644 index 00000000..e974b1a5 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RolePermissionCacheService.java @@ -0,0 +1,84 @@ +package cn.axzo.tyr.server.service; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Set; + +public interface RolePermissionCacheService { + + + List list(ListRolePermissionParam param); + + /** + * redisKey:roleId + * redisValue:permission + * @param param + */ + void store(StoreRolePermissionParam param); + + List hasRoleIds(HasRolePermissionParam param); + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class HasRolePermissionParam { + private List roleIds; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class StoreRolePermissionParam { + private List rolePermissions; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class RolePermission { + private Long roleId; + + private List permissions; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ListRolePermissionParam { + private List roleIds; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class RolePermissionDTO { + private Long roleId; + + private List permissions; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class PermissionDTO { + + private Long featureId; + + private String featureCode; + + /** + * 资源所属端 + */ + private String terminal; + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java index eecce09f..02a51e13 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java @@ -159,6 +159,9 @@ public interface RoleService extends IService { @CriteriaField(field = "id", operator = Operator.NE) private Long idNE; + /** + * 权限点从saas_feature_resource表查询 + */ @CriteriaField(ignore = true) private Boolean needPermission; @@ -167,6 +170,19 @@ public interface RoleService extends IService { @CriteriaField(ignore = true) private Boolean needRoleUser; + + /** + * 当前非oms和政务端的权限存储在saas_feature + * 权限点从saas_feature表查询 + */ + @CriteriaField(ignore = true) + private Boolean needPermissionOld; + + /** + * 根据权限点id过滤 + */ + @CriteriaField(ignore = true) + private List featureIds; } @SuperBuilder diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/TyrSaasAuthService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/TyrSaasAuthService.java index 69137c8b..e08de57c 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/TyrSaasAuthService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/TyrSaasAuthService.java @@ -8,6 +8,7 @@ import cn.axzo.tyr.client.model.req.ListIdentityFromPermissionReq; import cn.axzo.tyr.client.model.req.ListPermissionFromFeatureReq; import cn.axzo.tyr.client.model.req.ListPermissionFromIdentityReq; import cn.axzo.tyr.client.model.req.ListPermissionFromRoleGroupReq; +import cn.axzo.tyr.client.model.req.PermissionCheckReq; import cn.axzo.tyr.client.model.req.WorkspacePermissionIdentityReq; import cn.axzo.tyr.client.model.res.IdentityAuthRes; import cn.axzo.tyr.client.model.res.ListIdentityFromPermissionResp; @@ -51,4 +52,11 @@ public interface TyrSaasAuthService { * @return */ List listAuthByResourceAndRoleGroup(ListPermissionFromRoleGroupReq listPermissionFromRoleGroupReq); + + /** + * 接口鉴权 + * @param req + * @return + */ + boolean authPermission(PermissionCheckReq req); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionCacheServiceImpl.java index 43eb6d75..10f2fe8c 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionCacheServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionCacheServiceImpl.java @@ -1,20 +1,32 @@ package cn.axzo.tyr.server.service.impl; +import cn.axzo.pokonyan.config.redis.RedisClient; import cn.axzo.pokonyan.config.redis.RedisUtil; import cn.axzo.tyr.client.model.res.IdentityAuthRes; import cn.axzo.tyr.server.model.PermissionCacheKey; import cn.axzo.tyr.server.service.PermissionCacheService; import cn.hutool.core.util.BooleanUtil; import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.serializer.SerializerFeature; +import com.google.common.collect.Streams; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.core.RedisOperations; +import org.springframework.data.redis.core.SessionCallback; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import java.util.Collections; +import java.util.List; import java.util.Objects; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; /** * 授权缓存服务实现 @@ -35,7 +47,10 @@ public class PermissionCacheServiceImpl implements PermissionCacheService { /** 授权缓存过期时间 **/ @Value("${axzo.cache.auth.expire:30}") private Long expireInMinutes; - + @Autowired + protected StringRedisTemplate redisTemplate; + private static final String PERMISSION_ROLE_KEY = "permission:role:%s"; + private static final String PERMISSION_PRODUCT_KEY = "permission:product:%s"; @Override public boolean cacheDisable(PermissionCacheKey key) { @@ -95,4 +110,111 @@ public class PermissionCacheServiceImpl implements PermissionCacheService { log.error("mark permission refresh error", ex); } } + + @Override + public void cachePermissionRole(CachePermissionRoleParam param) { + redisTemplate.executePipelined(new SessionCallback() { + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + + for (PermissionRole permissionRole : param.getPermissionRoles()) { + String redisKey = getKey(PERMISSION_ROLE_KEY, permissionRole.getFeatureCode()); + + String[] redisValues = permissionRole.getRoleIds().stream().toArray(String[]::new); + + RedisClient.SetOps.sAdd(redisKey, redisValues); + redisTemplate.expire(redisKey, 4, TimeUnit.DAYS); + log.info("succeed to store permission role: redisKey:{} value:{}", redisKey, redisValues); + } + return null; + } + }); + } + + @Override + public List listPermissionRole(ListPermissionRoleParam param) { + if (CollectionUtils.isEmpty(param.getFeatureCodes())) { + return Collections.emptyList(); + } + + List redisValues = redisTemplate.executePipelined(new SessionCallback() { + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + + for (String featureCode : param.getFeatureCodes()) { + String redisKey = getKey(PERMISSION_ROLE_KEY, featureCode); + operations.opsForSet().members(redisKey); + } + return null; + } + }); + + return Streams.zip(param.getFeatureCodes().stream(), + redisValues.stream(), + (featureCode, redisValue) -> { + PermissionRole permissionProduct = PermissionRole.builder() + .featureCode(featureCode) + .roleIds(JSONArray.parseArray(JSONArray.toJSONString(redisValue), Long.class)) + .build(); + return permissionProduct; + }) + .collect(Collectors.toList()); + } + + @Override + public void cachePermissionProduct(CachePermissionProductParam param) { + redisTemplate.executePipelined(new SessionCallback() { + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + + for (PermissionProduct permissionProduct : param.getPermissionProducts()) { + String redisKey = getKey(PERMISSION_PRODUCT_KEY, permissionProduct.getFeatureCode()); + + String[] redisValues = permissionProduct.getProducts().stream() + .map(JSONObject::toJSONString) + .toArray(String[]::new); + + RedisClient.SetOps.sAdd(redisKey, redisValues); + redisTemplate.expire(redisKey, 4, TimeUnit.DAYS); + log.info("succeed to store permission product: redisKey:{} value:{}", redisKey, redisValues); + } + return null; + } + }); + } + + @Override + public List listPermissionProduct(ListPermissionProductParam param) { + if (CollectionUtils.isEmpty(param.getFeatureCodes())) { + return Collections.emptyList(); + } + + + List redisValues = redisTemplate.executePipelined(new SessionCallback() { + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + + for (String featureCode : param.getFeatureCodes()) { + String redisKey = getKey(PERMISSION_PRODUCT_KEY, featureCode); + operations.opsForSet().members(redisKey); + } + return null; + } + }); + + return Streams.zip(param.getFeatureCodes().stream(), + redisValues.stream(), + (featureCode, redisValue) -> { + PermissionProduct permissionProduct = PermissionProduct.builder() + .featureCode(featureCode) + .products(JSONArray.parseArray(JSONArray.toJSONString(redisValue), Product.class)) + .build(); + return permissionProduct; + }) + .collect(Collectors.toList()); + } + + private String getKey(String pref, Object... params) { + return String.format(pref, params); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java index 5a3a3942..cb8f14dd 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java @@ -50,6 +50,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Service; import java.util.ArrayList; @@ -74,6 +76,7 @@ import java.util.stream.Collectors; @Slf4j @Service @RequiredArgsConstructor +@RefreshScope public class PermissionQueryServiceImpl implements PermissionQueryService { private final SaasFeatureResourceService featureResourceService; @@ -84,6 +87,8 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { private final ProductModuleDao productModuleDao; private final ProductFeatureRelationService productFeatureRelationService; + @Value("${use.old.auth:true}") + private boolean USE_OLD_AUTH; @Override public List getNavTree(NavTreeReq req) { //构造参数 @@ -130,7 +135,10 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { //这里暂时硬编码-非OMS端鉴权请求 直接转老接口处理 if (!StrUtil.equals("NT_OMS_WEB" ,req.getTerminal()) && !Objects.equals(TerminalInfo.NT_PC_GA_GENERAL, req.getTerminal())) { - return hasPermissionV2(req); + if (USE_OLD_AUTH) { + return hasPermissionV2(req); + } + return saasAuthService.authPermission(req); } //权限编码转ID List resourcePermissions = featureResourceService.permissionQuery( diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductPermissionCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductPermissionCacheServiceImpl.java new file mode 100644 index 00000000..4989fda3 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductPermissionCacheServiceImpl.java @@ -0,0 +1,106 @@ +package cn.axzo.tyr.server.service.impl; + +import cn.axzo.foundation.exception.Axssert; +import cn.axzo.pokonyan.config.redis.RedisClient; +import cn.axzo.tyr.server.service.ProductPermissionCacheService; +import cn.hutool.core.lang.Pair; +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Streams; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.core.RedisOperations; +import org.springframework.data.redis.core.SessionCallback; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static cn.axzo.tyr.server.config.exception.BizResultCode.REDIS_PRODUCT_NOT_NULL; + +@Slf4j +@Service +public class ProductPermissionCacheServiceImpl implements ProductPermissionCacheService { + + private static final String PRODUCT_PERMISSION_KEY = "product:permission:%s"; + + @Autowired + protected StringRedisTemplate redisTemplate; + + @Override + public List list(ListProductPermissionParam param) { + if (CollectionUtils.isEmpty(param.getProductIds())) { + return Collections.emptyList(); + } + + Set redisKeys = param.getProductIds().stream() + .map(this::getKey) + .collect(Collectors.toSet()); + + Set redisValues = redisTemplate.opsForSet().union(redisKeys); + + return redisValues.stream() + .filter(StringUtils::isNotBlank) + .map(value -> JSONObject.parseObject(value, PermissionDTO.class)) + .collect(Collectors.toList()); + } + + @Override + public void store(StoreProductPermissionParam param) { + + Axssert.check(param.getProductPermissions().stream().allMatch(e -> Objects.nonNull(e.getProductId())), REDIS_PRODUCT_NOT_NULL); + + redisTemplate.executePipelined(new SessionCallback() { + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + + for (ProductPermission productPermission : param.getProductPermissions()) { + String redisKey = getKey(productPermission.getProductId()); + + String[] redisValues = productPermission.getPermissions().stream() + .map(JSONObject::toJSONString) + .toArray(String[]::new); + + RedisClient.SetOps.sAdd(redisKey, redisValues); + redisTemplate.expire(redisKey, 4, TimeUnit.DAYS); + log.info("succeed to store product permission: redisKey:{} value:{}", redisKey, redisValues); + } + return null; + } + }); + } + + @Override + public List hasProductIds(HasProductPermissionParam param) { + List redisValues = redisTemplate.executePipelined(new SessionCallback() { + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + + for (Long productId : param.getProductIds()) { + String redisKey = getKey(productId); + operations.hasKey(redisKey); + } + return null; + } + }); + + return Streams.zip(param.getProductIds().stream(), + redisValues.stream(), + (productId, redisValue) -> Pair.of(productId, redisValue)) + .filter(e -> BooleanUtils.isTrue((Boolean) e.getValue())) + .map(Pair::getKey) + .collect(Collectors.toList()); + } + + private String getKey(Object... params) { + return String.format(PRODUCT_PERMISSION_KEY, params); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RolePermissionCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RolePermissionCacheServiceImpl.java new file mode 100644 index 00000000..455175da --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RolePermissionCacheServiceImpl.java @@ -0,0 +1,106 @@ +package cn.axzo.tyr.server.service.impl; + +import cn.axzo.foundation.exception.Axssert; +import cn.axzo.pokonyan.config.redis.RedisClient; +import cn.axzo.tyr.server.service.RolePermissionCacheService; +import cn.hutool.core.lang.Pair; +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Streams; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.RedisOperations; +import org.springframework.data.redis.core.SessionCallback; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static cn.axzo.tyr.server.config.exception.BizResultCode.REDIS_ROLE_NOT_NULL; + +@Slf4j +@Service +public class RolePermissionCacheServiceImpl implements RolePermissionCacheService { + + private static final String ROLE_PERMISSION_KEY = "role:permission:%s"; + + @Autowired + protected StringRedisTemplate redisTemplate; + + @Override + public List list(ListRolePermissionParam param) { + if (CollectionUtils.isEmpty(param.getRoleIds())) { + return Collections.emptyList(); + } + + Set redisKeys = param.getRoleIds().stream() + .map(this::getKey) + .collect(Collectors.toSet()); + + // 聚合是因为角色的权限点有重复,网络io压力大 + Set redisValues = redisTemplate.opsForSet().union(redisKeys); + return redisValues.stream() + .filter(StringUtils::isNotBlank) + .map(value -> JSONObject.parseObject(value, PermissionDTO.class)) + .collect(Collectors.toList()); + } + + @Override + public void store(StoreRolePermissionParam param) { + + Axssert.check(param.getRolePermissions().stream().allMatch(e -> Objects.nonNull(e.getRoleId())), REDIS_ROLE_NOT_NULL); + + redisTemplate.executePipelined((RedisCallback) connection -> { + + connection.openPipeline(); + + for (RolePermission rolePermission : param.getRolePermissions()) { + String redisKey = getKey(rolePermission.getRoleId()); + + String[] redisValues = rolePermission.getPermissions().stream() + .map(JSONObject::toJSONString) + .toArray(String[]::new); + + RedisClient.SetOps.sAdd(redisKey, redisValues); + redisTemplate.expire(redisKey, 4, TimeUnit.DAYS); + log.info("succeed to store role permission: redisKey:{} value:{}", redisKey, redisValues); + } + return null; + }); + } + + @Override + public List hasRoleIds(HasRolePermissionParam param) { + List redisValues = redisTemplate.executePipelined(new SessionCallback() { + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + + for (Long roleId : param.getRoleIds()) { + String redisKey = getKey(roleId); + operations.hasKey(redisKey); + } + return null; + } + }); + + return Streams.zip(param.getRoleIds().stream(), + redisValues.stream(), + (roleId, redisValue) -> Pair.of(roleId, redisValue)) + .filter(e -> BooleanUtils.isTrue((Boolean) e.getValue())) + .map(Pair::getKey) + .collect(Collectors.toList()); + } + + private String getKey(Object... params) { + return String.format(ROLE_PERMISSION_KEY, params); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java index 12900c2e..5c8ec51a 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java @@ -1182,11 +1182,13 @@ public class RoleServiceImpl extends ServiceImpl Map> saasPermissions = listRolePermissions(param, page.getRecords()); + Map> saasPermissionsOld = listRolePermissionsOld(param, page.getRecords()); + Map> saasRoleUsers = listSaasRoleUser(param, page.getRecords()); return PageConverter.toResp(page, (record) -> from(record, saasRoleGroups, - saasPermissions, + BooleanUtils.isTrue(param.getNeedPermissionOld()) ? saasPermissionsOld : saasPermissions, saasRoleUsers)); } @@ -1410,4 +1412,68 @@ public class RoleServiceImpl extends ServiceImpl .map(e -> Pair.of(e.getRoleId(), e.getSaasRoleUser())) .collect(Collectors.groupingBy(Pair::getKey, Collectors.mapping(Pair::getValue, Collectors.toList()))); } + + /** + * 待所有端的权限点都迁移到saas_feature_resource后就删除 + * @param param + * @param saasRoles + * @return + */ + private Map> listRolePermissionsOld(PageSaasRoleParam param, + List saasRoles) { + if (CollectionUtils.isEmpty(saasRoles) || BooleanUtils.isNotTrue(param.getNeedPermissionOld())) { + return Collections.emptyMap(); + } + + List saasPgroupRoleRelations = saasPgroupRoleRelationDao.findByRoleIds(Lists.transform(saasRoles, SaasRole::getId)); + + if (CollectionUtils.isEmpty(saasPgroupRoleRelations)) { + return Collections.emptyMap(); + } + + List saasPgroupPermissionRelations = saasPgroupPermissionRelationDao.lambdaQuery() + .in(SaasPgroupPermissionRelation::getGroupId, Lists.transform(saasPgroupRoleRelations, SaasPgroupRoleRelation::getGroupId)) + .in(CollectionUtils.isNotEmpty(param.getFeatureIds()), SaasPgroupPermissionRelation::getFeatureId, param.getFeatureIds()) + .eq(SaasPgroupPermissionRelation::getIsDelete, TableIsDeleteEnum.NORMAL.value) + .list(); + if (CollectionUtils.isEmpty(saasPgroupPermissionRelations)) { + return Collections.emptyMap(); + } + + List featureIds = Lists.transform(saasPgroupPermissionRelations, SaasPgroupPermissionRelation::getFeatureId); + + Map resourcePermissions = saasFeatureDao.listByIds(featureIds).stream() + .map(e -> SaasPermissionRes.builder() + .id(e.getId()) + .featureCode(e.getFeatureCode()) + .terminal(e.getTerminal()) + .build()) + .collect(Collectors.toMap(SaasPermissionRes::getId, Function.identity())); + + Map> pgroupPermissions = saasPgroupPermissionRelations.stream() + .collect(Collectors.groupingBy(SaasPgroupPermissionRelation::getGroupId, + Collectors.mapping(SaasPgroupPermissionRelation::getFeatureId, Collectors.toList()))); + + return saasPgroupRoleRelations.stream() + .map(e -> { + List permissionIds = pgroupPermissions.get(e.getGroupId()); + if (CollectionUtils.isEmpty(permissionIds)) { + return null; + } + + return permissionIds.stream() + .map(permissionId -> { + SaasPermissionRes saasPermissionRes = resourcePermissions.get(permissionId); + return SaasPermissionWrapper.from(e, saasPermissionRes); + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + }) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.groupingBy(SaasPermissionWrapper::getRoleId, + Collectors.mapping(e -> SaasPermissionRes.builder().id(e.getId()).featureCode(e.getFeatureCode()).build(), + Collectors.toList()))); + } + } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleUserService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleUserService.java index c6a5197d..3600e255 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleUserService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleUserService.java @@ -19,6 +19,7 @@ import cn.axzo.tyr.client.model.roleuser.req.AutoOwnRoleUserReq; import cn.axzo.tyr.client.model.roleuser.req.CreateSuperAdminRoleParam; import cn.axzo.tyr.client.model.roleuser.req.GantOrUnGantaWorkerLeaderRoleReq; import cn.axzo.tyr.client.model.roleuser.req.GetUserAutoOwnRoleReq; +import cn.axzo.tyr.client.model.roleuser.req.GetUserFeatureResourceIdsReq; import cn.axzo.tyr.client.model.roleuser.req.RoleUserReq; import cn.axzo.tyr.client.model.roleuser.req.SuperAdminParam; import cn.axzo.tyr.client.model.roleuser.req.WorkerManagerRoleUserReq; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleUserRelationServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleUserRelationServiceImpl.java index 885f7bbd..4065282c 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleUserRelationServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleUserRelationServiceImpl.java @@ -19,6 +19,7 @@ import cn.axzo.tyr.server.repository.dao.SaasRoleUserRelationDao; import cn.axzo.tyr.server.repository.entity.SaasRole; import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation; import cn.axzo.tyr.server.repository.mapper.SaasRoleUserRelationMapper; +import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasRoleUserRelationService; import cn.axzo.tyr.server.util.RpcInternalUtil; import cn.hutool.core.bean.BeanUtil; @@ -61,6 +62,8 @@ public class SaasRoleUserRelationServiceImpl extends ServiceImpl list(RoleUserParam param) { @@ -141,11 +144,13 @@ public class SaasRoleUserRelationServiceImpl extends ServiceImpl saasRoleUsers = listSaasRoleUser(param, page.getRecords()); - return PageConverter.toResp(page, (record) -> from(record, saasRoleUsers)); + Map saasRoles = listSaasRole(param, page.getRecords()); + + return PageConverter.toResp(page, (record) -> from(record, saasRoleUsers, saasRoles)); } private Map listSaasRoleUser(PageRoleUserRelationParam param, - List saasRoleUserRelations) { + List saasRoleUserRelations) { if (CollectionUtils.isEmpty(saasRoleUserRelations) || BooleanUtils.isNotTrue(param.getNeedUsers())) { return Collections.emptyMap(); } @@ -182,11 +187,38 @@ public class SaasRoleUserRelationServiceImpl extends ServiceImpl saasRoleUsers) { + Map saasRoleUsers, + Map saasRoles) { return SaasRoleUserV2DTO.builder() .roleId(saasRoleUserRelation.getRoleId()) .saasRoleUser(saasRoleUsers.get(saasRoleUserRelation.getNaturalPersonId())) + .saasRole(saasRoles.get(saasRoleUserRelation.getRoleId())) .build(); } + + private Map listSaasRole(PageRoleUserRelationParam param, + List saasRoleUserRelations) { + if (CollectionUtils.isEmpty(saasRoleUserRelations) || BooleanUtils.isNotTrue(param.getNeedRole())) { + return Collections.emptyMap(); + } + + List roleIds = saasRoleUserRelations.stream() + .map(SaasRoleUserRelation::getRoleId) + .distinct() + .collect(Collectors.toList()); + + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .roleIds(roleIds) + .needPermissionOld(param.getNeedRolePermissionOld()) + .featureIds(param.getFeatureIds()) + .build(); + return roleService.list(listSaasRoleParam).stream() + .map(e -> { + SaasRoleUserV2DTO.SaasRole saasRole = SaasRoleUserV2DTO.SaasRole.builder().build(); + BeanUtils.copyProperties(e, saasRole); + return saasRole; + }) + .collect(Collectors.toMap(SaasRoleUserV2DTO.SaasRole::getId, Function.identity())); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java index fccbda58..c2203589 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java @@ -1,9 +1,8 @@ package cn.axzo.tyr.server.service.impl; import cn.axzo.basics.common.BeanMapper; +import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum; import cn.axzo.framework.domain.ServiceException; -import cn.axzo.framework.domain.web.result.ApiResult; -import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.pokonyan.util.TraceSupplier; import cn.axzo.thrones.client.saas.ServicePkgClient; import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct; @@ -15,40 +14,61 @@ import cn.axzo.tyr.client.model.enums.IdentityType; import cn.axzo.tyr.client.model.permission.PermissionPointListQueryRequest; import cn.axzo.tyr.client.model.permission.PermissionPointTreeNode; import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO; -import cn.axzo.tyr.client.model.req.*; +import cn.axzo.tyr.client.model.req.CheckIdentityPermissionReq; +import cn.axzo.tyr.client.model.req.IdentityAuthReq; +import cn.axzo.tyr.client.model.req.ListIdentityFromPermissionReq; +import cn.axzo.tyr.client.model.req.ListPermissionFromFeatureReq; +import cn.axzo.tyr.client.model.req.ListPermissionFromIdentityReq; +import cn.axzo.tyr.client.model.req.ListPermissionFromRoleGroupReq; +import cn.axzo.tyr.client.model.req.OUWorkspacePair; +import cn.axzo.tyr.client.model.req.PermissionCheckReq; +import cn.axzo.tyr.client.model.req.QueryPermissionByIdsReq; +import cn.axzo.tyr.client.model.req.QuerySaasRoleReq; +import cn.axzo.tyr.client.model.req.WorkspacePermissionIdentityReq; import cn.axzo.tyr.client.model.res.IdentityAuthRes; import cn.axzo.tyr.client.model.res.ListIdentityFromPermissionResp; import cn.axzo.tyr.client.model.res.ListPermissionFromRoleGroupResp; import cn.axzo.tyr.client.model.res.QueryIdentityByPermissionResp; -import cn.axzo.tyr.client.model.res.SimpleFeatureInfo; +import cn.axzo.tyr.client.model.res.SaasPermissionRes; +import cn.axzo.tyr.client.model.res.SaasRoleRes; import cn.axzo.tyr.client.model.res.SimplePermissionPointResp; +import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO; +import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam; import cn.axzo.tyr.client.model.vo.SaasPermissionGroupVO; -import cn.axzo.tyr.client.model.roleuser.dto.SuperAminInfoResp; -import cn.axzo.tyr.client.model.roleuser.req.SuperAdminParam; import cn.axzo.tyr.client.model.vo.SaasRoleVO; import cn.axzo.tyr.server.model.FilterRoleAuth; import cn.axzo.tyr.server.model.PermissionCacheKey; -import cn.axzo.tyr.server.repository.entity.*; +import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; +import cn.axzo.tyr.server.repository.dao.SaasProductModuleFeatureRelationDao; +import cn.axzo.tyr.server.repository.entity.ProductFeatureInfo; +import cn.axzo.tyr.server.repository.entity.ProductFeatureQuery; +import cn.axzo.tyr.server.repository.entity.RolePermission; +import cn.axzo.tyr.server.repository.entity.SaasFeature; +import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; +import cn.axzo.tyr.server.repository.entity.SaasRole; +import cn.axzo.tyr.server.repository.entity.SaasRoleGroup; +import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation; +import cn.axzo.tyr.server.repository.entity.SaasRoleWithUser; import cn.axzo.tyr.server.repository.mapper.TyrSaasAuthMapper; import cn.axzo.tyr.server.service.PermissionCacheService; import cn.axzo.tyr.server.service.PermissionPointService; import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasRoleGroupService; +import cn.axzo.tyr.server.service.SaasRoleUserRelationService; import cn.axzo.tyr.server.service.TyrSaasAuthService; import cn.axzo.tyr.server.util.KeyUtil; import cn.axzo.tyr.server.utils.RpcExternalUtil; -import cn.axzo.tyr.server.utils.RpcInternalUtil; import cn.azxo.framework.common.model.CommonResponse; import cn.azxo.framework.common.utils.LogUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.StopWatch; import cn.hutool.core.lang.Pair; -import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.BooleanUtil; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -59,16 +79,26 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; -import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.stream.Collectors; import static cn.axzo.tyr.server.util.RpcInternalUtil.checkAndGetData; +import static cn.axzo.tyr.server.util.RpcInternalUtil.rpcListProcessor; /** * @author tanjie@axzo.cn @@ -94,7 +124,9 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { private final PermissionCacheService permissionCacheService; private final SaasRoleGroupService roleGroupService; - + private final SaasRoleUserRelationService saasRoleUserRelationService; + private final SaasFeatureDao saasFeatureDao; + private final SaasProductModuleFeatureRelationDao saasProductModuleFeatureRelationDao; /** * 通过身份查询人员权限 @@ -317,7 +349,10 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { private IdentityAuthRes findIdentityAuth(IdentityAuthReq identityAuthReq) { //用户角色关系 List saasRoleUserRelations = listRoleUserRelations(identityAuthReq); - + if (CollectionUtils.isEmpty(saasRoleUserRelations)) { + log.warn("no user role relations found"); + return identityAuthReq.toEmpty(); + } Set realWorkspaceId = saasRoleUserRelations.stream().map(SaasRoleUserRelation::getWorkspaceId).collect(Collectors.toSet()); //工作台对应产品 key = workspaceId @@ -363,7 +398,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return resultPermission; } - Set roles = ouwRoleInfo.getRoles(); + Set roles = ouwRoleInfo.getRoles(); if (CollectionUtil.isEmpty(roles)) { log.warn("no roles for ou:{} workspace:{}", ouwRoleInfo.getOuId(), ouwRoleInfo.getWorkspaceId()); return resultPermission; @@ -404,17 +439,17 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { Set allMatchedProductFeatureIds = new HashSet<>(); Set allAuthPermissionIds = new HashSet<>(); //聚合实际授权的权限:角色权限和产品权限交集 - for (SaasRoleVO role : userRoleInfoMap.getRoles()) { + for (SaasRoleRes role : userRoleInfoMap.getRoles()) { //跳过超管和管理员 if (RoleTypeEnum.SUPER_ADMIN.getValue().equals(role.getRoleType()) || RoleTypeEnum.ADMIN.getValue().equals(role.getRoleType())) { continue; } log.info("build permission for role:{}", role.getId()); - Set rolePermissionIds = role.getMatchFeature(userRoleInfoMap.getWorkspaceId(), userRoleInfoMap.ouId) - .stream() + + Set rolePermissionIds = role.getSaasPermissions().stream() .filter(Objects::nonNull) - .map(PermissionPointTreeNode::getPermissionPointId) + .map(SaasPermissionRes::getId) .collect(Collectors.toSet()); //角色标签类型匹配产品标签类型 Set productPermissionIds = productFeatures.stream() @@ -446,9 +481,8 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { private Pair> buildAdminPermission(OUWRoleInfo userRoleInfoMap, List productFeatures) { Boolean superAdmin = false; //超管和管理员角色 - List adminRoles = userRoleInfoMap.getRoles().stream() - .filter(r -> RoleTypeEnum.SUPER_ADMIN.getValue().equals(r.getRoleType()) - || RoleTypeEnum.ADMIN.getValue().equals(r.getRoleType())) + List adminRoles = userRoleInfoMap.getRoles().stream() + .filter(r -> RoleTypeEnum.isAdmin(r.getRoleType())) .collect(Collectors.toList()); if (CollectionUtil.isEmpty(adminRoles)) { log.info("no admin roles"); @@ -459,7 +493,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { //聚合超管和管理员的权限点: 直接取角色标签和产品标签相匹配的权限点 Set permissionIds = new HashSet<>(); - for (SaasRoleVO adminRole : adminRoles) { + for (SaasRoleRes adminRole : adminRoles) { //超管:查询工作台对应产品,获取权限点, ( 权限点通过单位类型过滤) if (RoleTypeEnum.SUPER_ADMIN.getValue().equals(adminRole.getRoleType())) { superAdmin = true; @@ -485,14 +519,10 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { private List listRolesWithPermission(List roleUserRelations, IdentityAuthReq identityAuthReq) { //拼装参数 - Set realWorkspaceIds = new HashSet<>(); - Set realOuIds = new HashSet<>(); Set roleIds = new HashSet<>(); //按ow分组角色ID: workspaceId-ouId --> roleIds Map> owRoleIdMap = new HashMap<>(); for (SaasRoleUserRelation relation : roleUserRelations) { - realWorkspaceIds.add(relation.getWorkspaceId()); - realOuIds.add(relation.getOuId()); roleIds.add(relation.getRoleId()); String key = KeyUtil.buildKeyBySeparator(relation.getWorkspaceId(), relation.getOuId()); Set owRoleIds = owRoleIdMap.getOrDefault(key, new HashSet<>()); @@ -500,13 +530,12 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { owRoleIdMap.put(key, owRoleIds); } //获取角色和关联权限信息 - List roles = roleService.query(QuerySaasRoleReq.builder() - //角色ID - .ids(new ArrayList<>(roleIds)) - .workspaceId(new ArrayList<>(realWorkspaceIds)) - .ouId(new ArrayList<>(realOuIds)) - .includePermissionGroup(true) - .build()); + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .roleIds(Lists.newArrayList(roleIds)) + .needPermissionOld(true) + .build(); + Map saasRoleRes = roleService.list(listSaasRoleParam).stream() + .collect(Collectors.toMap(SaasRoleRes::getId, Function.identity())); //按ow组装拥有的角色 List owRoleMap = new ArrayList<>(); @@ -521,8 +550,8 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { log.info("no roles found for ow:{}", key); owRoleInfo.setRoles(Collections.emptySet()); } else { - owRoleInfo.setRoles(roles.stream() - .filter(r -> owRoleIds.contains(r.getId())) + owRoleInfo.setRoles(owRoleIds.stream() + .map(saasRoleRes::get) .collect(Collectors.toSet())); } owRoleMap.add(owRoleInfo); @@ -888,7 +917,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { Integer workspaceType; Long ouId; WorkspaceJoinType workspaceJoinType; - Set roles = new HashSet<>(); + Set roles = new HashSet<>(); } @@ -1006,4 +1035,195 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return new ArrayList<>(distinctMap.values()); } + + /** + * 判断用户是否有指定权限码的权限 + * 1、查询用户的角色id、租户的产品id(db) + * 2、根据权限点找对应的产品、单位类型(redis) + * 3、租户开通的产品是否在权限点对应的产品,不满足条件直接返回false + * 4、查询是否有免授权的权限点 + * 4、有管理员角色:租户的产品要在权限点的产品里、单位类型要是管理员角色的单位类型,满足条件则返回true + * 6、根据权限点找对应的角色(redis) + * 7、有非管理员角色: + * @param req + * @return + */ + public boolean authPermission(PermissionCheckReq req) { + // saas_feature表会被废弃,所以直接查询,没提供统一的查询 + List saasFeatures = saasFeatureDao.lambdaQuery() + .in(SaasFeature::getFeatureCode, req.getFeatureCodes()) + .eq(SaasFeature::getIsDelete, TableIsDeleteEnum.NORMAL.value) + .list(); + if (CollectionUtils.isEmpty(saasFeatures)) { + log.info("featureCode not found:{}", req.getFeatureCodes()); + return false; + } + + //用户角色关系,以及对应角色的权限点 + List saasRoleUserRelations = listRoleUserRelations(req, saasFeatures); + if (CollectionUtils.isEmpty(saasRoleUserRelations)) { + return false; + } + + // 查询租户开通的所有产品 + Set productIds = listProducts(req); + if (CollectionUtils.isEmpty(productIds)) { + log.info("product not found:{}", req.getWorkspaceId()); + return false; + } + + // 查询产品开通的这些权限点的信息 + List permissionProducts = listPermissionProduct(saasFeatures, productIds); + if (CollectionUtils.isEmpty(productIds)) { + log.info("permission product not found:{}", req.getWorkspaceId()); + return false; + } + + // 是否有免授权的权限码,且在租户开通了这个产品 + boolean matchedNoNeedAuthFeature = matchNoAuthFeature(saasFeatures, permissionProducts); + if (BooleanUtil.isTrue(matchedNoNeedAuthFeature)) { + log.info("has no need auth feature:{}", req.getWorkspaceId()); + return true; + } + + // 是否有管理员角色,且租户开通了管理员角色的单位类型对应的产品权限码 + boolean matchedAdminRole = matchAdminRole(saasRoleUserRelations, permissionProducts); + if (BooleanUtil.isTrue(matchedAdminRole)) { + log.info("admin role has permission:{}", req.getWorkspaceId()); + return true; + } + + return matchNormalRole(saasRoleUserRelations, permissionProducts); + } + + private boolean matchNormalRole(List saasRoleUserRelations, + List permissionProducts) { + List normalRoles = saasRoleUserRelations.stream() + .filter(e -> !RoleTypeEnum.isAdmin(e.getSaasRole().getRoleType())) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(normalRoles)) { + return false; + } + + // 权限点对应角色的单位类型要与权限点对应产品的单位类型一致才能算有权限 + Map permissionProductMap = permissionProducts.stream() + .collect(Collectors.toMap(SaasProductModuleFeatureRelation::getFeatureId, Function.identity())); + + for (SaasRoleUserV2DTO permissionRole : normalRoles) { + Set ouTypesOfProduct = permissionRole.getSaasRole().getSaasPermissions().stream() + .map(permissionProductMap::get) + .filter(Objects::nonNull) + .map(SaasProductModuleFeatureRelation::getDictCode) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(ouTypesOfProduct)) { + continue; + } + + if (ouTypesOfProduct.contains(String.valueOf(permissionRole.getSaasRole().getProductUnitType()))) { + return true; + } + } + + return false; + } + + /** + * 租户开通的产品是否有不需要鉴权的权限码 + * @param saasFeatures + * @param permissionProducts + * @return + */ + private boolean matchNoAuthFeature(List saasFeatures, + List permissionProducts) { + + Set noNeedAuthFeatureIds = saasFeatures.stream() + .filter(e -> Objects.equals(e.getDelegatedType(), DelegatedType.NO_NEED.getCode())) + .map(SaasFeature::getId) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(noNeedAuthFeatureIds)) { + log.info("not found no need auth featureCode"); + return false; + } + + return permissionProducts.stream() + .anyMatch(e -> noNeedAuthFeatureIds.contains(e.getFeatureId())); + } + + /** + * 匹配管理员角色是否有权限点的权限 + * @param saasRoleUserRelations + * @param permissionProducts + * @return + */ + private boolean matchAdminRole(List saasRoleUserRelations, + List permissionProducts) { + + List adminRoles = saasRoleUserRelations.stream() + .filter(e -> RoleTypeEnum.isAdmin(e.getSaasRole().getRoleType())) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(adminRoles)) { + return false; + } + + Set ouTypes = permissionProducts.stream() + .map(SaasProductModuleFeatureRelation::getDictCode) + .collect(Collectors.toSet()); + + return adminRoles.stream() + .anyMatch(adminRole -> ouTypes.contains(String.valueOf(adminRole.getSaasRole().getProductUnitType()))); + } + + private List listPermissionProduct(List saasFeatures, + Set productIds) { + + return saasProductModuleFeatureRelationDao.lambdaQuery() + .in(SaasProductModuleFeatureRelation::getProductModuleId, productIds) + .in(SaasProductModuleFeatureRelation::getFeatureId, Lists.transform(saasFeatures, SaasFeature::getId)) + .eq(SaasProductModuleFeatureRelation::getIsDelete, TableIsDeleteEnum.NORMAL.value) + .list(); + } + + private List listRoleUserRelations(PermissionCheckReq identityAuthReq, + List saasFeatures) { + + List workspaceOuPairs = Lists.newArrayList( + ListRoleUserRelationParam.WorkspaceOuPair.builder() + .workspaceId(identityAuthReq.getWorkspaceId()) + .ouId(identityAuthReq.getOuId()) + .build() + ); + ListRoleUserRelationParam listRoleUserRelationParam = ListRoleUserRelationParam.builder() + .personId(identityAuthReq.getPersonId()) + .workspaceOuPairs(Lists.newArrayList(workspaceOuPairs)) + .needRole(true) + .needRolePermissionOld(true) + .featureIds(Lists.transform(saasFeatures, SaasFeature::getId)) + .build(); + return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream() + .filter(e -> e.getSaasRole() != null) + // 角色没有需要鉴权的权限点,也需要过滤 + .filter(e -> !CollectionUtils.isEmpty(e.getSaasRole().getSaasPermissions())) + .collect(Collectors.toList()); + } + + public Set listProducts(PermissionCheckReq req) { + + List servicePkgDetailRes = rpcListProcessor(() -> servicePkgClient.getServicePkgDetailBySpaceId(Sets.newHashSet(req.getWorkspaceId())), + "查询租户的产品", req.getWorkspaceId()).getData(); + + if (CollectionUtil.isEmpty(servicePkgDetailRes)) { + return Collections.emptySet(); + } + + return servicePkgDetailRes.stream() + .map(ServicePkgDetailRes::getProducts) + .filter(CollectionUtil::isNotEmpty) + .flatMap(Collection::stream) + .map(ServicePkgProduct::getProductId) + .collect(Collectors.toSet()); + } } From d61723aaddd38db9e19af3db1972aa0bf3acb144 Mon Sep 17 00:00:00 2001 From: lilong Date: Fri, 31 May 2024 17:20:33 +0800 Subject: [PATCH 02/69] =?UTF-8?q?feat:(REQ-2509)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E7=94=A8=E6=88=B7=E5=85=B3=E7=B3=BB=E6=94=AF?= =?UTF-8?q?=E6=8C=81pair=E9=85=8D=E5=AF=B9=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/SaasRoleUserRelationServiceImpl.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleUserRelationServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleUserRelationServiceImpl.java index 4065282c..d429eb0d 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleUserRelationServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleUserRelationServiceImpl.java @@ -140,6 +140,17 @@ public class SaasRoleUserRelationServiceImpl extends ServiceImpl wrapper = QueryWrapperHelper.fromBean(param, SaasRoleUserRelation.class); wrapper.eq("is_delete", 0); + if (!CollectionUtils.isEmpty(param.getWorkspaceOuPairs())) { + wrapper.and(j -> { + for (ListRoleUserRelationParam.WorkspaceOuPair workspaceOuPair : param.getWorkspaceOuPairs()) { + j.or(k -> { + k.eq(Objects.nonNull(workspaceOuPair.getOuId()), "ou_id", workspaceOuPair.getOuId()); + k.eq(Objects.nonNull(workspaceOuPair.getWorkspaceId()), "workspace_id", workspaceOuPair.getWorkspaceId()); + }); + } + }); + } + IPage page = this.page(PageConverter.toMybatis(param, SaasRoleUserRelation.class), wrapper); Map saasRoleUsers = listSaasRoleUser(param, page.getRecords()); From f0ea5340e40d99e5cae89e4bddeb41b9683ffe03 Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 4 Jun 2024 14:00:01 +0800 Subject: [PATCH 03/69] =?UTF-8?q?feat:(REQ-2524)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E9=89=B4=E6=9D=83=E8=8F=9C=E5=8D=95=E7=9A=84=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=EF=BC=8C=E8=A7=92=E8=89=B2=E6=B2=A1=E6=9C=89=E6=9D=83=E9=99=90?= =?UTF-8?q?=EF=BC=8C=E6=8A=9BNPE=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/PrivateController.java | 11 +++- .../service/impl/TyrSaasAuthServiceImpl.java | 12 ++-- .../impl/TyrSaasAuthServiceImplTest.java | 62 +++++++++++++++++++ .../mysql/TyrSaasAuthServiceImplTest.sql | 2 + .../src/test/resources/mysql/schema.sql | 36 ++++++++++- 5 files changed, 114 insertions(+), 9 deletions(-) create mode 100644 tyr-server/src/test/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImplTest.java create mode 100644 tyr-server/src/test/resources/mysql/TyrSaasAuthServiceImplTest.sql diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java index bce3f4ea..0682bbb1 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java @@ -1,10 +1,9 @@ package cn.axzo.tyr.server.controller; import cn.axzo.basics.common.util.TreeUtil; -import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.model.req.CommonDictQueryReq; -import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; +import cn.axzo.tyr.client.model.req.PermissionCheckReq; import cn.axzo.tyr.client.model.req.QuerySaasRoleGroupReq; import cn.axzo.tyr.client.model.res.CommonDictResp; import cn.axzo.tyr.client.model.res.FeatureResourceDTO; @@ -23,6 +22,7 @@ import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasCommonDictService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; import cn.axzo.tyr.server.service.SaasRoleGroupService; +import cn.axzo.tyr.server.service.TyrSaasAuthService; import cn.axzo.tyr.server.service.impl.SaasFeatureResourceCacheService; import com.google.common.collect.Lists; import lombok.AllArgsConstructor; @@ -73,6 +73,8 @@ public class PrivateController { private RolePermissionCacheService rolePermissionCacheService; @Autowired private ProductPermissionCacheService productPermissionCacheService; + @Autowired + private TyrSaasAuthService tyrSaasAuthService; @@ -274,6 +276,11 @@ public class PrivateController { return productPermissionCacheService.hasProductIds(request); } + @PostMapping("/api/private/permission/auth") + public Object authPermission(@Validated @RequestBody PermissionCheckReq request) { + return tyrSaasAuthService.authPermission(request); + } + @Data @Builder @NoArgsConstructor diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java index c2203589..7e3cfe4f 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java @@ -75,6 +75,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.cloud.context.config.annotation.RefreshScope; @@ -447,10 +448,12 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } log.info("build permission for role:{}", role.getId()); - Set rolePermissionIds = role.getSaasPermissions().stream() - .filter(Objects::nonNull) - .map(SaasPermissionRes::getId) - .collect(Collectors.toSet()); + Set rolePermissionIds = Optional.ofNullable(role.getSaasPermissions()) + .map(e -> e.stream() + .filter(Objects::nonNull) + .map(SaasPermissionRes::getId) + .collect(Collectors.toSet())) + .orElseGet(Sets::newHashSet); //角色标签类型匹配产品标签类型 Set productPermissionIds = productFeatures.stream() .filter(productFeatureRelationVO -> Objects.equals(productFeatureRelationVO.getDictCode(), String.valueOf(role.getProductUnitType()))) @@ -1053,6 +1056,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { List saasFeatures = saasFeatureDao.lambdaQuery() .in(SaasFeature::getFeatureCode, req.getFeatureCodes()) .eq(SaasFeature::getIsDelete, TableIsDeleteEnum.NORMAL.value) + .eq(StringUtils.isNotBlank(req.getTerminal()), SaasFeature::getTerminal, req.getTerminal()) .list(); if (CollectionUtils.isEmpty(saasFeatures)) { log.info("featureCode not found:{}", req.getFeatureCodes()); diff --git a/tyr-server/src/test/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImplTest.java b/tyr-server/src/test/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImplTest.java new file mode 100644 index 00000000..e34f11c6 --- /dev/null +++ b/tyr-server/src/test/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImplTest.java @@ -0,0 +1,62 @@ +package cn.axzo.tyr.server.service.impl; + +import cn.axzo.tyr.base.BaseTest; +import cn.axzo.tyr.base.MysqlDataLoader; +import cn.axzo.tyr.client.model.req.PermissionCheckReq; +import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; +import cn.axzo.tyr.server.repository.dao.SaasRoleDao; +import cn.axzo.tyr.server.repository.entity.SaasFeature; +import cn.axzo.tyr.server.service.TyrSaasAuthService; +import org.assertj.core.util.Lists; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import static org.junit.jupiter.api.Assertions.*; + +class TyrSaasAuthServiceImplTest extends BaseTest { + + @Autowired + private MysqlDataLoader mysqlDataLoader; + @Autowired + private TyrSaasAuthService tyrSaasAuthService; + @Autowired + private SaasFeatureDao saasFeatureDao; + + @BeforeEach + @Override + public void setup() { + super.setup(); + mysqlDataLoader.loadFromClassName(getClass().getSimpleName()); + } + + @Test + void authPermission() { + + saasFeatureDao.save(SaasFeature.builder() + .featureCode("CMS_001") + .terminal("CMS") + .build()); + + PermissionCheckReq permissionCheckReq = PermissionCheckReq.builder() + .ouId(5708L) + .workspaceId(300L) + .personId(42642L) + .featureCodes(Lists.newArrayList("dfff")) + .build(); + boolean result = tyrSaasAuthService.authPermission(permissionCheckReq); + Assertions.assertFalse(result); + + result = tyrSaasAuthService.authPermission(PermissionCheckReq.builder() + .ouId(5708L) + .workspaceId(300L) + .personId(42642L) + .featureCodes(Lists.newArrayList("CMS_001")) + .terminal("sdf") + .build()); + Assertions.assertFalse(result); + + + } +} \ No newline at end of file diff --git a/tyr-server/src/test/resources/mysql/TyrSaasAuthServiceImplTest.sql b/tyr-server/src/test/resources/mysql/TyrSaasAuthServiceImplTest.sql new file mode 100644 index 00000000..7dc4afae --- /dev/null +++ b/tyr-server/src/test/resources/mysql/TyrSaasAuthServiceImplTest.sql @@ -0,0 +1,2 @@ +### DEFAULT + diff --git a/tyr-server/src/test/resources/mysql/schema.sql b/tyr-server/src/test/resources/mysql/schema.sql index b872955f..1e875627 100644 --- a/tyr-server/src/test/resources/mysql/schema.sql +++ b/tyr-server/src/test/resources/mysql/schema.sql @@ -107,7 +107,37 @@ CREATE TABLE `saas_role` ( KEY `ou_workspace_idx` (`owner_ou_id`,`workspace_id`,`is_delete`) ) ENGINE=InnoDB AUTO_INCREMENT=102623 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='saas-角色'; +CREATE TABLE `saas_feature_resource` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增主键ID', + `feature_code` varchar(64) NOT NULL DEFAULT '' COMMENT '资源编码-权限码', + `feature_name` varchar(64) NOT NULL DEFAULT '' COMMENT '资源名称', + `feature_type` tinyint NOT NULL DEFAULT '0' COMMENT '资源类型1-菜单 2-页面 3-应用入口 4-组件', + `terminal` varchar(32) NOT NULL DEFAULT '' COMMENT '资源所属端', + `component_type` tinyint NOT NULL DEFAULT '0' COMMENT '组件细分类型 1-跳转子页面 2-跳转公共组件 3-弹出窗口 4-下拉项 5-操作按钮 6-数据卡片 7-站外跳转', + `parent_id` bigint NOT NULL DEFAULT '0' COMMENT '上级资源ID', + `path` varchar(255) DEFAULT '0' COMMENT '资源ID层级路径, 逗号分隔', + `display_order` int NOT NULL DEFAULT '0' COMMENT '展示顺序', + `status` tinyint NOT NULL DEFAULT '1' COMMENT '资源状态 0-隐藏 1-展示', + `icon` varchar(255) NOT NULL DEFAULT '' COMMENT '资源图标', + `redirect_type` tinyint NOT NULL DEFAULT '0' COMMENT '跳转类型 1-站内跳转 2-站外跳转', + `link_url` varchar(255) NOT NULL DEFAULT '' COMMENT '资源跳转URI', + `link_type` tinyint NOT NULL DEFAULT '0' COMMENT '路由类型1-PC 2-小程序 3-原生', + `link_ext` varchar(255) NOT NULL DEFAULT '' COMMENT 'APP适配参数', + `app_item_id` int NOT NULL DEFAULT '0' COMMENT '小程序id', + `sync_version` int NOT NULL DEFAULT '0' COMMENT '资源同步版本', + -- `extra` json DEFAULT NULL COMMENT '扩展字段', + `extra` varchar(255) DEFAULT NULL COMMENT '扩展字段', + `auth_type` tinyint NOT NULL DEFAULT '1' COMMENT '授权类型0-全部角色 1-指定角色', + `sub_auth_type` tinyint NOT NULL DEFAULT '0' COMMENT '子级鉴权类型 0-不鉴权1-鉴权', + `create_at` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `create_by` bigint NOT NULL DEFAULT '0' COMMENT '创建人', + `update_by` bigint NOT NULL DEFAULT '0' COMMENT '更新人', + `is_delete` bigint NOT NULL DEFAULT '0' COMMENT '删除标识', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=459 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='功能资源表'; + alter table saas_feature_resource - add column `workspace_type` tinyint DEFAULT '0' COMMENT '1:企业工作台 2;项目工作台' after `path`, -add column `version` int DEFAULT '0' COMMENT '最低版本序列,主要支持版本灰度策略' after `workspace_type` -add column `uni_code` varchar(64) not null default '' comment '唯一编码,用于pre环境菜单同步' after `version`; \ No newline at end of file + add column `workspace_type` tinyint DEFAULT '0' COMMENT '1:企业工作台 2;项目工作台' after `path`; +alter table saas_feature_resource add column `version` int DEFAULT '0' COMMENT '最低版本序列,主要支持版本灰度策略' after `workspace_type`; +alter table saas_feature_resource add column `uni_code` varchar(64) not null default '' comment '唯一编码,用于pre环境菜单同步' after `version`; \ No newline at end of file From 36ef8d048ec021e7188ccc039bf7a05836a68e37 Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 4 Jun 2024 14:59:16 +0800 Subject: [PATCH 04/69] =?UTF-8?q?feat:(REQ-2524)=20=E6=9C=89saas=5Frole=5F?= =?UTF-8?q?user=5Frelation=E6=9C=89=E8=AE=B0=E5=BD=95=EF=BC=8C=E4=BD=86?= =?UTF-8?q?=E6=98=AF=E5=AF=B9=E5=BA=94=E7=9A=84saas=5Frole=E4=B8=8D?= =?UTF-8?q?=E5=AD=98=E5=9C=A8=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java index 7e3cfe4f..ef26c645 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java @@ -555,6 +555,8 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } else { owRoleInfo.setRoles(owRoleIds.stream() .map(saasRoleRes::get) + // 有saas_role_user_relation有记录,但是对应的saas_role不存在的情况 + .filter(Objects::nonNull) .collect(Collectors.toSet())); } owRoleMap.add(owRoleInfo); From d7b36fb515edfb353fab2c135858b93112f8f77e Mon Sep 17 00:00:00 2001 From: lilong Date: Wed, 12 Jun 2024 10:19:56 +0800 Subject: [PATCH 05/69] =?UTF-8?q?feat:(REQ-2524)=20=E5=9B=A0=E4=B8=BA?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=91=98=E8=A7=92=E8=89=B2=E4=B8=8D=E4=BC=9A?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=9D=83=E9=99=90=E7=82=B9=EF=BC=8C=E6=89=80?= =?UTF-8?q?=E4=BB=A5=E4=B8=8D=E8=83=BD=E6=8E=92=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/TyrSaasAuthServiceImpl.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java index ef26c645..4c22051d 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java @@ -1113,14 +1113,19 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } // 权限点对应角色的单位类型要与权限点对应产品的单位类型一致才能算有权限 - Map permissionProductMap = permissionProducts.stream() - .collect(Collectors.toMap(SaasProductModuleFeatureRelation::getFeatureId, Function.identity())); + Map> permissionProductMap = permissionProducts.stream() + .collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getFeatureId, + Collectors.mapping(SaasProductModuleFeatureRelation::getDictCode, Collectors.toList()))); for (SaasRoleUserV2DTO permissionRole : normalRoles) { + if (CollectionUtils.isEmpty(permissionRole.getSaasRole().getSaasPermissions())) { + continue; + } + Set ouTypesOfProduct = permissionRole.getSaasRole().getSaasPermissions().stream() - .map(permissionProductMap::get) + .map(e -> permissionProductMap.get(e.getId())) .filter(Objects::nonNull) - .map(SaasProductModuleFeatureRelation::getDictCode) + .flatMap(Collection::stream) .collect(Collectors.toSet()); if (CollectionUtils.isEmpty(ouTypesOfProduct)) { @@ -1211,8 +1216,6 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .build(); return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream() .filter(e -> e.getSaasRole() != null) - // 角色没有需要鉴权的权限点,也需要过滤 - .filter(e -> !CollectionUtils.isEmpty(e.getSaasRole().getSaasPermissions())) .collect(Collectors.toList()); } From 7fd7e601c5c8f20613def330cc8d7cb5dd567782 Mon Sep 17 00:00:00 2001 From: lilong Date: Wed, 12 Jun 2024 18:34:10 +0800 Subject: [PATCH 06/69] =?UTF-8?q?feat:(REQ-2524)=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E9=89=B4=E6=9D=83=E7=89=88=E6=9C=AC=E7=9A=84?= =?UTF-8?q?=E6=97=A5=E5=BF=97=EF=BC=8C=E6=96=B9=E4=BE=BF=E6=8E=92=E6=9F=A5?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E7=94=9F=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/service/impl/PermissionQueryServiceImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java index cb8f14dd..7e90ffeb 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java @@ -136,8 +136,10 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { if (!StrUtil.equals("NT_OMS_WEB" ,req.getTerminal()) && !Objects.equals(TerminalInfo.NT_PC_GA_GENERAL, req.getTerminal())) { if (USE_OLD_AUTH) { + log.info("user old auth"); return hasPermissionV2(req); } + log.info("user new auth"); return saasAuthService.authPermission(req); } //权限编码转ID From f9e394f62bc0f1bc9e6783ade96575a23a795d05 Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 18 Jun 2024 16:44:24 +0800 Subject: [PATCH 07/69] =?UTF-8?q?feat:(REQ-2545)=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=B8=85=E6=B4=97saas=5Fpgroup=5Fpermission=5Frelation?= =?UTF-8?q?=E8=A1=A8=E7=9A=84featureType=EF=BC=8C=E6=96=B9=E4=BE=BF?= =?UTF-8?q?=E5=90=8E=E9=9D=A2=E5=BF=AB=E9=80=9F=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../req/PagePgroupPermissionRelationReq.java | 33 +++++ .../server/controller/PrivateController.java | 123 ++++++++++++++++++ .../entity/SaasFeatureResource.java | 2 + .../entity/SaasPgroupPermissionRelation.java | 21 +++ .../SaasPgroupPermissionRelationService.java | 7 +- ...asPgroupPermissionRelationServiceImpl.java | 26 ++-- 6 files changed, 202 insertions(+), 10 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PagePgroupPermissionRelationReq.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PagePgroupPermissionRelationReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PagePgroupPermissionRelationReq.java new file mode 100644 index 00000000..ffb9ab6d --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PagePgroupPermissionRelationReq.java @@ -0,0 +1,33 @@ +package cn.axzo.tyr.client.model.req; + +import cn.axzo.foundation.dao.support.wrapper.CriteriaField; +import cn.axzo.foundation.dao.support.wrapper.Operator; +import cn.axzo.foundation.page.IPageReq; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PagePgroupPermissionRelationReq implements IPageReq { + + @CriteriaField(ignore = true) + Integer page; + + @CriteriaField(ignore = true) + Integer pageSize; + + /** + * 排序:使用示例,createTime__DESC + */ + @CriteriaField(ignore = true) + List sort; + + @CriteriaField(field = "id", operator = Operator.IN) + private List ids; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java index 0682bbb1..0c324906 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java @@ -1,8 +1,10 @@ package cn.axzo.tyr.server.controller; import cn.axzo.basics.common.util.TreeUtil; +import cn.axzo.foundation.page.PageResp; import cn.axzo.tyr.client.model.req.CommonDictQueryReq; import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; +import cn.axzo.tyr.client.model.req.PagePgroupPermissionRelationReq; import cn.axzo.tyr.client.model.req.PermissionCheckReq; import cn.axzo.tyr.client.model.req.QuerySaasRoleGroupReq; import cn.axzo.tyr.client.model.res.CommonDictResp; @@ -10,9 +12,12 @@ import cn.axzo.tyr.client.model.res.FeatureResourceDTO; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; import cn.axzo.tyr.client.model.res.SaasRoleRes; import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO; +import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; import cn.axzo.tyr.server.repository.dao.SaasRoleGroupRelationDao; +import cn.axzo.tyr.server.repository.entity.SaasFeature; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; +import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation; import cn.axzo.tyr.server.repository.entity.SaasRole; import cn.axzo.tyr.server.repository.entity.SaasRoleGroup; import cn.axzo.tyr.server.repository.entity.SaasRoleGroupRelation; @@ -21,6 +26,7 @@ import cn.axzo.tyr.server.service.RolePermissionCacheService; import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasCommonDictService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService; import cn.axzo.tyr.server.service.SaasRoleGroupService; import cn.axzo.tyr.server.service.TyrSaasAuthService; import cn.axzo.tyr.server.service.impl.SaasFeatureResourceCacheService; @@ -50,6 +56,9 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE; + @Slf4j @RestController @RequiredArgsConstructor @@ -75,6 +84,10 @@ public class PrivateController { private ProductPermissionCacheService productPermissionCacheService; @Autowired private TyrSaasAuthService tyrSaasAuthService; + @Autowired + private SaasFeatureDao saasFeatureDao; + @Autowired + private SaasPgroupPermissionRelationService saasPgroupPermissionRelationService; @@ -281,6 +294,107 @@ public class PrivateController { return tyrSaasAuthService.authPermission(request); } + /** + * 刷新saas_pgroup_permission_relation表的featureType + * 1、type = 0的数据从saas_feature中查询 + * 2、type = 1的数据从saas_feature_resource中查询 + * @param request + * @return + */ + @PostMapping("/api/private/pGroupPermissionRelation/featureResource/refresh") + public Object reFreshFeature(@Validated @RequestBody RefreshPGroupPermissionFeatureParam request) { + + final Integer DEFAULT_PAGE_SIZE = 100; + Integer pageNumber = 1; + while (true) { + PagePgroupPermissionRelationReq req = PagePgroupPermissionRelationReq.builder() + .ids(request.getIds()) + .page(pageNumber++) + .pageSize(DEFAULT_PAGE_SIZE) + .build(); + + PageResp page = saasPgroupPermissionRelationService.page(req); + if (CollectionUtils.isNotEmpty(page.getData())) { + updateOldFeature(page.getData()); + + updateNewFeature(page.getData()); + } + + if (!page.hasNext()) { + break; + } + } + return "ok"; + } + + private void updateNewFeature(List saasPgroupPermissionRelations) { + List newFeatureRelations = saasPgroupPermissionRelations.stream() + .filter(e -> Objects.equals(e.getFeatureType(), NEW_FEATURE)) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(newFeatureRelations)) { + return; + } + + Map saasFeatureResourceMap = saasFeatureResourceDao.listByIds(Lists.transform(newFeatureRelations, SaasPgroupPermissionRelation::getFeatureId)) + .stream() + .collect(Collectors.toMap(SaasFeatureResource::getId, Function.identity())); + + List update = saasPgroupPermissionRelations.stream() + .map(e -> { + SaasFeatureResource saasFeatureResource = saasFeatureResourceMap.get(e.getFeatureId()); + if (saasFeatureResource == null) { + return null; + } + + SaasPgroupPermissionRelation saasPgroupPermissionRelation = new SaasPgroupPermissionRelation(); + saasPgroupPermissionRelation.setId(e.getId()); + saasPgroupPermissionRelation.setFeatureType(saasFeatureResource.getFeatureType()); + return saasPgroupPermissionRelation; + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (CollectionUtils.isEmpty(update)) { + return; + } + + saasPgroupPermissionRelationService.updateBatchById(update); + } + + private void updateOldFeature(List saasPgroupPermissionRelations) { + List oldFeatureRelations = saasPgroupPermissionRelations.stream() + .filter(e -> Objects.equals(e.getFeatureType(), OLD_FEATURE)) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(oldFeatureRelations)) { + return; + } + + Map saasFeatureMap = saasFeatureDao.listByIds(Lists.transform(oldFeatureRelations, SaasPgroupPermissionRelation::getFeatureId)) + .stream() + .collect(Collectors.toMap(SaasFeature::getId, Function.identity())); + + List update = saasPgroupPermissionRelations.stream() + .map(e -> { + SaasFeature saasFeature = saasFeatureMap.get(e.getFeatureId()); + if (saasFeature == null) { + return null; + } + + SaasPgroupPermissionRelation saasPgroupPermissionRelation = new SaasPgroupPermissionRelation(); + saasPgroupPermissionRelation.setId(e.getId()); + saasPgroupPermissionRelation.setFeatureType(saasFeature.getFeatureType()); + return saasPgroupPermissionRelation; + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (CollectionUtils.isEmpty(update)) { + return; + } + + saasPgroupPermissionRelationService.updateBatchById(update); + } + @Data @Builder @NoArgsConstructor @@ -292,4 +406,13 @@ public class PrivateController { @NotNull(message = "rootId不能为空") private Long rootId; } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class RefreshPGroupPermissionFeatureParam { + + private List ids; + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java index 910bffad..44abf59e 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java @@ -31,7 +31,9 @@ public class SaasFeatureResource extends BaseEntity { /** * 资源编码-权限码 + * 废弃,同步数据使用uniCode */ + @Deprecated private String featureCode; /** diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPgroupPermissionRelation.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPgroupPermissionRelation.java index 982d7452..6c689cc6 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPgroupPermissionRelation.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPgroupPermissionRelation.java @@ -1,7 +1,10 @@ package cn.axzo.tyr.server.repository.entity; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @@ -23,6 +26,9 @@ import java.util.Objects; @TableName("saas_pgroup_permission_relation") public class SaasPgroupPermissionRelation extends BaseEntity { + public static final Integer OLD_FEATURE = 0; + + public static final Integer NEW_FEATURE = 1; /** * 权限集id @@ -43,6 +49,21 @@ public class SaasPgroupPermissionRelation extends BaseEntity { void saveOrUpdate(List groupIds, List relations); - void deleteByFeatureIds(List featureIds); + PageResp page(PagePgroupPermissionRelationReq param); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPgroupPermissionRelationServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPgroupPermissionRelationServiceImpl.java index 9ad46caf..c8350d2e 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPgroupPermissionRelationServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPgroupPermissionRelationServiceImpl.java @@ -1,10 +1,17 @@ package cn.axzo.tyr.server.service.impl; import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum; +import cn.axzo.foundation.dao.support.converter.PageConverter; +import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper; +import cn.axzo.foundation.page.PageResp; +import cn.axzo.tyr.client.model.req.PagePgroupPermissionRelationReq; import cn.axzo.tyr.server.repository.dao.SaasPgroupPermissionRelationDao; import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation; +import cn.axzo.tyr.server.repository.mapper.SaasPgroupPermissionRelationMapper; import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService; -import cn.hutool.core.collection.CollectionUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; @@ -15,12 +22,15 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.function.Function; import java.util.stream.Collectors; @Slf4j @Service @RequiredArgsConstructor -public class SaasPgroupPermissionRelationServiceImpl implements SaasPgroupPermissionRelationService { +public class SaasPgroupPermissionRelationServiceImpl + extends ServiceImpl + implements SaasPgroupPermissionRelationService { private final SaasPgroupPermissionRelationDao saasPgroupPermissionRelationDao; @Override @@ -49,12 +59,12 @@ public class SaasPgroupPermissionRelationServiceImpl implements SaasPgroupPermis } @Override - @Transactional(rollbackFor = Exception.class) - public void deleteByFeatureIds(List featureIds) { - if (CollectionUtil.isEmpty(featureIds)) { - return; - } - saasPgroupPermissionRelationDao.removeByPermissionPointIds(featureIds); + public PageResp page(PagePgroupPermissionRelationReq param) { + QueryWrapper wrapper = QueryWrapperHelper.fromBean(param, SaasPgroupPermissionRelation.class); + wrapper.eq("is_delete", 0); + IPage page = this.page(PageConverter.toMybatis(param, SaasPgroupPermissionRelation.class), wrapper); + + return PageConverter.toResp(page, Function.identity()); } } From 5ee96d40032ca5bd2c387beefe553afd2643c855 Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 18 Jun 2024 18:12:14 +0800 Subject: [PATCH 08/69] =?UTF-8?q?feat:(REQ-2545)=20=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E9=85=8D=E7=BD=AE=E8=A7=92=E8=89=B2=E6=97=B6?= =?UTF-8?q?=EF=BC=8CpgroupPermissionRelation=E5=A2=9E=E5=8A=A0featureType?= =?UTF-8?q?=E5=92=8Ctype=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/tyr/client/model/req/FeatureRoleRelationReq.java | 5 +++++ .../cn/axzo/tyr/server/service/impl/RoleServiceImpl.java | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureRoleRelationReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureRoleRelationReq.java index 89109db0..ab463e31 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureRoleRelationReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureRoleRelationReq.java @@ -29,6 +29,11 @@ public class FeatureRoleRelationReq { /** 功能Id **/ private Long featureId; + /** + * 菜单资源的类型 + */ + private Integer featureType; + /** 应用的角色Id列表 **/ private List roleIds; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java index fb284ffc..56a53de7 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java @@ -112,6 +112,8 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; + /** * 角色 * @@ -1349,6 +1351,8 @@ public class RoleServiceImpl extends ServiceImpl relation.setFeatureId(item.getFeatureId()); relation.setGroupId(groupId); relation.setCreateBy(operatorId); + relation.setFeatureType(item.getFeatureType()); + relation.setType(NEW_FEATURE); insertRelation.add(relation); }); saasPgroupPermissionRelationDao.saveBatch(insertRelation); From b118e80ed1b218ca84b9f5adaa86c701d05ec03c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Wed, 19 Jun 2024 09:27:35 +0800 Subject: [PATCH 09/69] =?UTF-8?q?feat(REQ-2545):=20=E6=B4=97=E6=9D=83?= =?UTF-8?q?=E9=99=90=E8=B5=84=E6=BA=90=E5=85=B3=E7=B3=BB=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E3=80=81=E5=85=83=E7=B4=A0=E4=B8=8A=E6=8A=A5=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/enums/PageElementTypeEnum.java | 23 +++ .../axzo/tyr/client/feign/PageElementApi.java | 31 +++ .../client/model/req/GetPageElementReq.java | 34 ++++ .../model/req/PageElementReportReq.java | 66 +++++++ .../tyr/client/model/res/PageElementResp.java | 50 +++++ .../server/controller/PrivateController.java | 67 +++++++ .../permission/PageElementController.java | 37 ++++ .../repository/dao/SaasPageElementDao.java | 43 ++++ ...PageElementFeatureResourceRelationDao.java | 32 +++ .../repository/entity/SaasPageElement.java | 58 ++++++ ...aasPageElementFeatureResourceRelation.java | 54 +++++ ...eElementFeatureResourceRelationMapper.java | 9 + .../mapper/SaasPageElementMapper.java | 9 + .../service/SaasPageElementService.java | 30 +++ .../impl/SaasPageElementServiceImpl.java | 185 ++++++++++++++++++ 15 files changed, 728 insertions(+) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/PageElementTypeEnum.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/feign/PageElementApi.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetPageElementReq.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementReportReq.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementResp.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PageElementController.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementDao.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementFeatureResourceRelationDao.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElement.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElementFeatureResourceRelation.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasPageElementFeatureResourceRelationMapper.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasPageElementMapper.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementService.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/PageElementTypeEnum.java b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/PageElementTypeEnum.java new file mode 100644 index 00000000..d51b9070 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/PageElementTypeEnum.java @@ -0,0 +1,23 @@ +package cn.axzo.tyr.client.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/18 + */ +@Getter +@AllArgsConstructor +public enum PageElementTypeEnum { + + PAGE("PAGE", "页面"), + COMPONENT("COMPONENT", "组件"), + + ; + + private final String code; + + private final String desc; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PageElementApi.java b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PageElementApi.java new file mode 100644 index 00000000..00954597 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PageElementApi.java @@ -0,0 +1,31 @@ +package cn.axzo.tyr.client.feign; + +import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.tyr.client.model.req.GetPageElementReq; +import cn.axzo.tyr.client.model.req.PageElementReportReq; +import cn.axzo.tyr.client.model.res.PageElementResp; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import javax.validation.Valid; +import java.util.List; + +/** + * 页面及元素相关接口 + * + * @author likunpeng + * @version 1.0 + * @date 2024/6/18 + */ +@FeignClient(name = "tyr", url = "${axzo.service.tyr:http://tyr:8080}") +public interface PageElementApi { + + /** 页面及元素上报 **/ + @PostMapping("/api/pageElement/report") + ApiResult report(@RequestBody @Valid PageElementReportReq req); + + /** 查询页面资源 **/ + @PostMapping("/api/pageElement/getPageElement") + ApiResult> getPageElement(@RequestBody @Valid GetPageElementReq req); +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetPageElementReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetPageElementReq.java new file mode 100644 index 00000000..d7ef36f5 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetPageElementReq.java @@ -0,0 +1,34 @@ +package cn.axzo.tyr.client.model.req; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/14 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class GetPageElementReq { + + /** + * 页面的featureResourceId + */ + @NotNull(message = "页面的featureResourceId不能为空") + @Min(value = 1, message = "页面的featureResourceId有误") + private Long featureResourceId; + + /** + * 是否只查询组件已选择的元素 + */ + @Builder.Default + private Boolean querySelectedOnly = Boolean.FALSE; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementReportReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementReportReq.java new file mode 100644 index 00000000..591493e4 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementReportReq.java @@ -0,0 +1,66 @@ +package cn.axzo.tyr.client.model.req; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import java.util.List; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/14 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PageElementReportReq { + + /** + * 端 + */ + @NotBlank(message = "端信息不能为空") + private String terminal; + + /** + * 页面元素列表 + */ + @NotEmpty(message = "页面元素不能为空") + private List pageElements; + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class PageElement { + + /** + * 元素编码 + */ + private String code; + + /** + * 元素名称 + */ + private String name; + + /** + * 元素类型(PAGE:页面,COMPONENT:页面里的组件) + */ + private String type; + + /** + * 路由地址 + */ + private String linkUrl; + + /** + * 子元素(只包含一级) + */ + private List children; + } +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementResp.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementResp.java new file mode 100644 index 00000000..dbac024e --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementResp.java @@ -0,0 +1,50 @@ +package cn.axzo.tyr.client.model.res; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/14 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PageElementResp { + + /** + * 元素ID + */ + private Long id; + + /** + * 元素编码 + */ + private String code; + + /** + * 元素名称 + */ + private String name; + + /** + * 元素类型 + */ + private String type; + + /** + * 是否已勾选 + */ + private Boolean selected; + + /** + * 子元素(只包含一级) + */ + private List children; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java index 0c324906..c2a2f12c 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java @@ -1,6 +1,10 @@ package cn.axzo.tyr.server.controller; +import cn.axzo.basics.common.constant.enums.DeleteEnum; +import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum; import cn.axzo.basics.common.util.TreeUtil; +import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.foundation.page.PageResp; import cn.axzo.tyr.client.model.req.CommonDictQueryReq; import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; @@ -21,6 +25,8 @@ import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation; import cn.axzo.tyr.server.repository.entity.SaasRole; import cn.axzo.tyr.server.repository.entity.SaasRoleGroup; import cn.axzo.tyr.server.repository.entity.SaasRoleGroupRelation; +import cn.axzo.tyr.server.repository.dao.*; +import cn.axzo.tyr.server.repository.entity.*; import cn.axzo.tyr.server.service.ProductPermissionCacheService; import cn.axzo.tyr.server.service.RolePermissionCacheService; import cn.axzo.tyr.server.service.RoleService; @@ -30,6 +36,7 @@ import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService; import cn.axzo.tyr.server.service.SaasRoleGroupService; import cn.axzo.tyr.server.service.TyrSaasAuthService; import cn.axzo.tyr.server.service.impl.SaasFeatureResourceCacheService; +import com.alibaba.fastjson.JSON; import com.google.common.collect.Lists; import lombok.AllArgsConstructor; import lombok.Builder; @@ -88,6 +95,12 @@ public class PrivateController { private SaasFeatureDao saasFeatureDao; @Autowired private SaasPgroupPermissionRelationService saasPgroupPermissionRelationService; + @Autowired + private SaasRoleDao saasRoleDao; + @Autowired + private SaasPgroupRoleRelationDao saasPgroupRoleRelationDao; + @Autowired + private SaasPgroupPermissionRelationDao saasPgroupPermissionRelationDao; @@ -294,6 +307,48 @@ public class PrivateController { return tyrSaasAuthService.authPermission(request); } + @PostMapping("/api/private/pgroupPermissionRelation/refresh") + public ApiResult refreshPgroupPermissionRelation(@Validated @RequestBody RefreshPgroupPermissionRelationParam request) { + List workspaceTypes = Lists.newArrayList(3,6); + if (!workspaceTypes.contains(request.getWorkspaceType())) { + return ApiResult.err("非oms、政务的角色,不能清洗。"); + } + + Long startRoleId = 0L; + while (true) { + List saasRoles = saasRoleDao.lambdaQuery() + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) + .eq(SaasRole::getWorkspaceType, request.getWorkspaceType()) + .gt(BaseEntity::getId, startRoleId) + .orderByAsc(BaseEntity::getId) + .last("LIMIT " + request.getPageSize()) + .list(); + if (CollectionUtils.isEmpty(saasRoles)) { + return ApiResult.ok(); + } + processRole(saasRoles.stream().map(BaseEntity::getId).collect(Collectors.toList())); + + startRoleId = saasRoles.get(saasRoles.size() - 1).getId(); + } + } + + private void processRole(List roleIds) { + List saasPgroupRoleRelations = saasPgroupRoleRelationDao.findByRoleIds(roleIds); + if (CollectionUtils.isEmpty(saasPgroupRoleRelations)) { + log.info("refreshPgroupPermissionRelation roleIds:{} has no pgroup role relation", JSON.toJSONString(roleIds)); + return; + } + List groupIds = saasPgroupRoleRelations.stream().map(SaasPgroupRoleRelation::getGroupId).filter(Objects::nonNull).distinct().collect(Collectors.toList()); + if (CollectionUtils.isEmpty(groupIds)) { + return; + } + saasPgroupPermissionRelationDao.lambdaUpdate() + .eq(BaseEntity::getIsDelete, TableIsDeleteEnum.NORMAL.value) + .in(SaasPgroupPermissionRelation::getGroupId, groupIds) + .set(SaasPgroupPermissionRelation::getType, 1) + .update(); + } + /** * 刷新saas_pgroup_permission_relation表的featureType * 1、type = 0的数据从saas_feature中查询 @@ -407,6 +462,18 @@ public class PrivateController { private Long rootId; } + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class RefreshPgroupPermissionRelationParam { + + @NotNull(message = "workspaceType不能为空,(oms:6,政务:3)") + private Integer workspaceType; + @Builder.Default + private Integer pageSize = 10; + } + @Data @Builder @NoArgsConstructor diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PageElementController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PageElementController.java new file mode 100644 index 00000000..0cd5cec1 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PageElementController.java @@ -0,0 +1,37 @@ +package cn.axzo.tyr.server.controller.permission; + +import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.tyr.client.feign.PageElementApi; +import cn.axzo.tyr.client.model.req.GetPageElementReq; +import cn.axzo.tyr.client.model.req.PageElementReportReq; +import cn.axzo.tyr.client.model.res.PageElementResp; +import cn.axzo.tyr.server.service.SaasPageElementService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/18 + */ +@Slf4j +@RestController +@RequiredArgsConstructor +public class PageElementController implements PageElementApi { + + private final SaasPageElementService saasPageElementService; + + @Override + public ApiResult report(PageElementReportReq req) { + saasPageElementService.report(req); + return ApiResult.ok(); + } + + @Override + public ApiResult> getPageElement(GetPageElementReq req) { + return ApiResult.ok(saasPageElementService.getPageElement(req)); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementDao.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementDao.java new file mode 100644 index 00000000..347a2b09 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementDao.java @@ -0,0 +1,43 @@ +package cn.axzo.tyr.server.repository.dao; + +import cn.axzo.basics.common.constant.enums.DeleteEnum; +import cn.axzo.tyr.server.repository.entity.SaasPageElement; +import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; +import cn.axzo.tyr.server.repository.mapper.SaasPageElementMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Objects; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/18 + */ +@Repository +public class SaasPageElementDao extends ServiceImpl { + + public void deleteAllByTerminal(String terminal) { + lambdaUpdate() + .eq(SaasPageElement::getTerminal, terminal) + .set(SaasPageElement::getIsDelete, DeleteEnum.DELETE.getValue()) + .update(); + } + + public List listByCodes(List codes, String terminal) { + return lambdaQuery() + .eq(SaasPageElement::getTerminal, terminal) + .in(SaasPageElement::getCode, codes) + .list(); + } + + public List listByGroupCodesAndExcludeIds(List groupCodes, List excludeIds, String terminal) { + return lambdaQuery() + .eq(SaasPageElement::getTerminal, terminal) + .in(SaasPageElement::getGroupCode, groupCodes) + .notIn(CollectionUtils.isNotEmpty(excludeIds), SaasPageElement::getId, excludeIds) + .list(); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementFeatureResourceRelationDao.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementFeatureResourceRelationDao.java new file mode 100644 index 00000000..67131f9d --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementFeatureResourceRelationDao.java @@ -0,0 +1,32 @@ +package cn.axzo.tyr.server.repository.dao; + +import cn.axzo.basics.common.constant.enums.DeleteEnum; +import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; +import cn.axzo.tyr.server.repository.mapper.SaasPageElementFeatureResourceRelationMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/18 + */ +@Repository +public class SaasPageElementFeatureResourceRelationDao extends ServiceImpl { + + public List listByPageElementCode(String pageElementCode) { + return lambdaQuery() + .eq(SaasPageElementFeatureResourceRelation::getIsDelete, DeleteEnum.NORMAL.getValue()) + .eq(SaasPageElementFeatureResourceRelation::getPageElementCode, pageElementCode) + .list(); + } + public List listByFeatureUniCodeAndTerminal(String featureResourceUniCode, String terminal) { + return lambdaQuery() + .eq(SaasPageElementFeatureResourceRelation::getIsDelete, DeleteEnum.NORMAL.getValue()) + .eq(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode, featureResourceUniCode) + .eq(SaasPageElementFeatureResourceRelation::getTerminal, terminal) + .list(); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElement.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElement.java new file mode 100644 index 00000000..33eb98da --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElement.java @@ -0,0 +1,58 @@ +package cn.axzo.tyr.server.repository.entity; + +import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 页面元素表 + * + * @author likunpeng + * @version 1.0 + * @date 2024/6/18 + */ +@Getter +@Setter +@ToString +@Builder +@EqualsAndHashCode(callSuper = true) +@TableName("saas_page_element") +public class SaasPageElement extends BaseEntity { + + /** + * 元素的组编码 + */ + @TableField("group_code") + private String groupCode; + + /** + * 页面、元素编码 + */ + @TableField("code") + private String code; + + /** + * 页面、元素名称 + */ + @TableField("name") + private String name; + + /** + * 页面、元素类型(PAGE:页面,COMPONENT:组件) + */ + @TableField("type") + private String type; + + /** + * 页面路由地址 + */ + @TableField("link_url") + private String linkUr; + + /** + * 所属端 + */ + @TableField("terminal") + private String terminal; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElementFeatureResourceRelation.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElementFeatureResourceRelation.java new file mode 100644 index 00000000..42bfa043 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElementFeatureResourceRelation.java @@ -0,0 +1,54 @@ +package cn.axzo.tyr.server.repository.entity; + +import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +/** + * 页面元素与菜单组件关系表 + * + * @author likunpeng + * @version 1.0 + * @date 2024/6/18 + */ +@Getter +@Setter +@ToString +@EqualsAndHashCode(callSuper = true) +@TableName("saas_page_element_feature_resource_relation") +public class SaasPageElementFeatureResourceRelation extends BaseEntity { + + /** + * 页面元素code + */ + @TableField("page_element_code") + private String pageElementCode; + + /** + * 菜单组件code + */ + @TableField("feature_resource_uni_code") + private String featureResourceUniCode; + + /** + * 所属端 + */ + @TableField("terminal") + private String terminal; + + /** + * 创建人 + */ + @TableField("create_by") + private Long createBy; + + /** + * 更新人 + */ + @TableField("update_by") + private Long updateBy; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasPageElementFeatureResourceRelationMapper.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasPageElementFeatureResourceRelationMapper.java new file mode 100644 index 00000000..3d0597f8 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasPageElementFeatureResourceRelationMapper.java @@ -0,0 +1,9 @@ +package cn.axzo.tyr.server.repository.mapper; + +import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +public interface SaasPageElementFeatureResourceRelationMapper extends BaseMapper { + +} + diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasPageElementMapper.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasPageElementMapper.java new file mode 100644 index 00000000..1ca5d1b9 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasPageElementMapper.java @@ -0,0 +1,9 @@ +package cn.axzo.tyr.server.repository.mapper; + +import cn.axzo.tyr.server.repository.entity.SaasPageElement; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +public interface SaasPageElementMapper extends BaseMapper { + +} + diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementService.java new file mode 100644 index 00000000..11a180ad --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementService.java @@ -0,0 +1,30 @@ +package cn.axzo.tyr.server.service; + +import cn.axzo.tyr.client.model.req.GetPageElementReq; +import cn.axzo.tyr.client.model.req.PageElementReportReq; +import cn.axzo.tyr.client.model.res.PageElementResp; + +import java.util.List; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/18 + */ +public interface SaasPageElementService { + + /** + * 页面元素上报 + * + * @param request 上报元素列表 + */ + void report(PageElementReportReq request); + + /** + * 查询页面已配置的元素 + * + * @param request + * @return + */ + List getPageElement(GetPageElementReq request); +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java new file mode 100644 index 00000000..b13ad26c --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java @@ -0,0 +1,185 @@ +package cn.axzo.tyr.server.service.impl; + +import cn.axzo.basics.common.util.AssertUtil; +import cn.axzo.basics.common.util.StopWatchUtil; +import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; +import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.client.common.enums.PageElementTypeEnum; +import cn.axzo.tyr.client.model.req.GetPageElementReq; +import cn.axzo.tyr.client.model.req.PageElementReportReq; +import cn.axzo.tyr.client.model.res.PageElementResp; +import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; +import cn.axzo.tyr.server.repository.dao.SaasPageElementDao; +import cn.axzo.tyr.server.repository.dao.SaasPageElementFeatureResourceRelationDao; +import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; +import cn.axzo.tyr.server.repository.entity.SaasPageElement; +import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; +import cn.axzo.tyr.server.service.SaasPageElementService; +import com.google.common.collect.Lists; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/18 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class SaasPageElementServiceImpl implements SaasPageElementService { + + private final SaasPageElementDao saasPageElementDao; + private final SaasPageElementFeatureResourceRelationDao saasPageElementFeatureResourceRelationDao; + private final SaasFeatureResourceDao saasFeatureResourceDao; + + @Qualifier("asyncExecutor") + @Autowired + private ExecutorService asyncExecutor; + + @Override + @Transactional(rollbackFor = Exception.class) + public void report(PageElementReportReq request) { + StopWatchUtil watch = StopWatchUtil.createStarted("saasPageElement-report"); + watch.start("report"); + // 根据端删除所有的元素 + saasPageElementDao.deleteAllByTerminal(request.getTerminal()); + + List pageElements = processParam2Entities(request); + // 减少数据库的IO,分批写入 + Lists.partition(pageElements,500).forEach(saasPageElementDao::saveBatch); + + // 页面路由处理,如果绑定了saas_feature_resource,页面的路由更新到对应的字段,为性能考虑,异步处理 + CompletableFuture.runAsync(() -> processPageLinkUrl(request), asyncExecutor).whenComplete((t, ex) -> log.info("更新表saas_feature_resource的页面路由完成。")); + + watch.stop(); + log.info("saasPageElement-report cost:{} , ms:{}", watch.prettyPrint(), watch.getTotalTimeMillis()); + } + + @Override + public List getPageElement(GetPageElementReq request) { + SaasFeatureResource saasFeatureResource = saasFeatureResourceDao.lambdaQuery() + .eq(BaseEntity::getIsDelete,0) + .eq(SaasFeatureResource::getId, request.getFeatureResourceId()) + .one(); + AssertUtil.notNull(saasFeatureResource, "页面或组件信息不存在"); + + List relations = saasPageElementFeatureResourceRelationDao.listByFeatureUniCodeAndTerminal(saasFeatureResource.getUniCode(), saasFeatureResource.getTerminal()); + if (CollectionUtils.isEmpty(relations)) { + return Collections.emptyList(); + } + List selectedPageElements = saasPageElementDao.listByCodes(relations.stream().map(SaasPageElementFeatureResourceRelation::getPageElementCode).collect(Collectors.toList()), saasFeatureResource.getTerminal()); + if (CollectionUtils.isEmpty(selectedPageElements)) { + return Collections.emptyList(); + } + List selectedIds = selectedPageElements.stream().map(BaseEntity::getId).collect(Collectors.toList()); + + // 如果查询不仅仅是已勾选的,需要把已勾选的页面下未选择的组件也返回 + if (!Boolean.TRUE.equals(request.getQuerySelectedOnly())) { + List pageTypeCodes = selectedPageElements.stream().filter(e -> PageElementTypeEnum.PAGE.getCode().equals(e.getType())).map(SaasPageElement::getGroupCode).collect(Collectors.toList()); + List notSelectedComponents = saasPageElementDao.listByGroupCodesAndExcludeIds(pageTypeCodes, selectedIds, saasFeatureResource.getTerminal()); + if (CollectionUtils.isNotEmpty(notSelectedComponents)) { + selectedPageElements.addAll(notSelectedComponents); + } + } + return change2PageElementResp(selectedPageElements, selectedIds); + } + + private List processParam2Entities(PageElementReportReq request) { + List saasPageElements = Lists.newArrayList(); + + for (PageElementReportReq.PageElement pageElement : request.getPageElements()) { + saasPageElements.add(SaasPageElement.builder() + .terminal(request.getTerminal()) + .groupCode(pageElement.getCode()) + .code(pageElement.getCode()) + .type(pageElement.getType()) + .name(pageElement.getName()) + .linkUr(pageElement.getLinkUrl()) + .build()); + + if (CollectionUtils.isNotEmpty(pageElement.getChildren())) { + saasPageElements.addAll(pageElement.getChildren().stream().map(e -> SaasPageElement.builder() + .terminal(request.getTerminal()) + .groupCode(pageElement.getCode()) + .code(e.getCode()) + .type(e.getType()) + .name(e.getName()) + .build()).collect(Collectors.toList())); + } + } + return saasPageElements; + } + + private void processPageLinkUrl(PageElementReportReq request) { + for (PageElementReportReq.PageElement pageElement : request.getPageElements()) { + if (StringUtils.isBlank(pageElement.getLinkUrl())) { + continue; + } + List relations = saasPageElementFeatureResourceRelationDao.listByPageElementCode(pageElement.getCode()); + if (CollectionUtils.isEmpty(relations)) { + continue; + } + SaasFeatureResource saasFeatureResource = saasFeatureResourceDao.lambdaQuery() + .eq(SaasFeatureResource::getUniCode, relations.get(0).getFeatureResourceUniCode()) + .eq(SaasFeatureResource::getTerminal, request.getTerminal()) + .one(); + if (Objects.isNull(saasFeatureResource) + || !FeatureResourceType.PAGE.getCode().equals(saasFeatureResource.getFeatureType()) + || pageElement.getLinkUrl().equals(saasFeatureResource.getLinkUrl())) { + continue; + } + saasFeatureResourceDao.lambdaUpdate() + .eq(BaseEntity::getId, saasFeatureResource.getId()) + .set(SaasFeatureResource::getLinkUrl, pageElement.getLinkUrl()) + .update(); + } + } + + private List change2PageElementResp(List pageElements, List selectedIds) { + if (CollectionUtils.isEmpty(pageElements)) { + return Collections.emptyList(); + } + + List pageTypeElements = pageElements.stream().filter(e -> PageElementTypeEnum.PAGE.getCode().equals(e.getType())) + .map(e -> PageElementResp.builder() + .id(e.getId()) + .code(e.getCode()) + .name(e.getName()) + .type(e.getType()) + .selected(selectedIds.contains(e.getId())) + .children(Lists.newArrayList()) + .build()).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(pageTypeElements)) { + return Collections.emptyList(); + } + + Map pageTypeCodeMap = pageTypeElements.stream().collect(Collectors.toMap(PageElementResp::getCode, Function.identity(), (v1, v2) -> v1)); + pageElements.stream().filter(e -> PageElementTypeEnum.COMPONENT.getCode().equals(e.getType())).forEach(e -> { + PageElementResp pageTypeElement = pageTypeCodeMap.get(e.getGroupCode()); + if (Objects.nonNull(pageTypeElement)) { + pageTypeElement.getChildren().add(PageElementResp.builder() + .id(e.getId()) + .code(e.getCode()) + .name(e.getName()) + .type(e.getType()) + .selected(selectedIds.contains(e.getId())) + .build()); + } + }); + + return pageTypeElements; + } +} From 7f735f2b4feb8952de94823ff47bf5723c047418 Mon Sep 17 00:00:00 2001 From: lilong Date: Wed, 19 Jun 2024 09:50:24 +0800 Subject: [PATCH 10/69] =?UTF-8?q?feat:(REQ-2545)=20=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=9D=83=E9=99=90=E6=97=B6=E6=9F=A5=E8=AF=A2=E6=9D=83=E9=99=90?= =?UTF-8?q?=E6=A0=91=E6=A0=B9=E6=8D=AE=E5=BA=94=E7=94=A8=E8=8C=83=E5=9B=B4?= =?UTF-8?q?=E6=9D=A5=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/req/GetFeatureResourceTreeReq.java | 6 ++++++ .../dao/SaasFeatureResourceDao.java | 3 ++- .../entity/SaasFeatureResource.java | 5 +++++ .../impl/SaasFeatureResourceServiceImpl.java | 19 ++++++++++++++++++- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetFeatureResourceTreeReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetFeatureResourceTreeReq.java index c8a33df3..f6bd2a5b 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetFeatureResourceTreeReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetFeatureResourceTreeReq.java @@ -27,4 +27,10 @@ public class GetFeatureResourceTreeReq { /** feature类型列表 **/ private List featureTypes; + + /** + * 应用范围(原租户类型):1:企业租户 2;项目租户 + * 只有页面和应用会配置应用范围 + */ + private Long workspaceType; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java index 7004e8e4..a7124ff8 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java @@ -35,7 +35,8 @@ public class SaasFeatureResourceDao extends ServiceImpl { private static final long serialVersionUID = 1L; + /** + * 数据库默认的workspaceType + */ + public static final Long DEFAULT_WORKSPACE_TYPE = 0L; + /** * 资源编码-权限码 diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java index c55bd5ed..ae64c178 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java @@ -27,7 +27,6 @@ import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; import com.alibaba.nacos.common.utils.UuidUtils; -import com.google.common.collect.Lists; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; @@ -44,6 +43,8 @@ import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import static cn.axzo.tyr.server.repository.entity.SaasFeatureResource.DEFAULT_WORKSPACE_TYPE; + /** * 功能资源服务实现 * 功能资源树查询增加了redis缓存,在新增、修改该表时,记得清空缓存, @@ -119,6 +120,9 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic } List treeList = TreeUtil.buildTree(saasFeatureResources.stream() + // 因为非OMS端可能会根据应用范围来查询菜单资源,现在只有分组和页面有配置应用范围 + // 非分组和页面的菜单资源应该都能看到,所以只有有配置应用范围的菜单资源才进行过滤 + .filter(e -> filterWorkspaceType(req, e)) .map(this::featureResource2Node) .sorted(Comparator.comparing(FeatureResourceDTO::getDisplayOrder)) .collect(Collectors.toList())) @@ -136,6 +140,19 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic return resultNode; } + private boolean filterWorkspaceType(GetFeatureResourceTreeReq req, SaasFeatureResource e) { + if (Objects.isNull(req.getWorkspaceType())) { + return true; + } + + // 数据库默认值为0 + if (Objects.equals(e.getWorkspaceType(), DEFAULT_WORKSPACE_TYPE)) { + return true; + } + + return Objects.equals(e.getWorkspaceType(), req.getWorkspaceType()); + } + @Override public FeatureResourceTreeNode getTreeFeatureDescendant(Long featureId, Integer featureType) { List descendants = featureResourceDao.lambdaQuery() From 6b10eacdd70a477ac9fc269ea1cd94c284ad6d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Wed, 19 Jun 2024 11:47:21 +0800 Subject: [PATCH 11/69] =?UTF-8?q?feat(REQ-2545):=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E7=BB=91=E5=AE=9A=E5=85=83=E7=B4=A0=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/client/feign/PageElementApi.java | 5 ++ .../model/base/BaseFeatureResourceDO.java | 7 +- .../req/ModifyPageElementRelationDTO.java | 40 ++++++++++ .../client/model/res/FeatureResourceDTO.java | 5 ++ .../client/model/res/PageElementBasicDTO.java | 33 +++++++++ .../permission/PageElementController.java | 7 ++ ...PageElementFeatureResourceRelationDao.java | 12 ++- ...aasPageElementFeatureResourceRelation.java | 6 +- .../service/SaasPageElementService.java | 27 +++++++ .../impl/SaasFeatureResourceServiceImpl.java | 73 +++++++++++++++---- .../impl/SaasPageElementServiceImpl.java | 46 +++++++++++- 11 files changed, 239 insertions(+), 22 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ModifyPageElementRelationDTO.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementBasicDTO.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PageElementApi.java b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PageElementApi.java index 00954597..fd59bfd1 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PageElementApi.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PageElementApi.java @@ -2,6 +2,7 @@ package cn.axzo.tyr.client.feign; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.tyr.client.model.req.GetPageElementReq; +import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; import cn.axzo.tyr.client.model.req.PageElementReportReq; import cn.axzo.tyr.client.model.res.PageElementResp; import org.springframework.cloud.openfeign.FeignClient; @@ -28,4 +29,8 @@ public interface PageElementApi { /** 查询页面资源 **/ @PostMapping("/api/pageElement/getPageElement") ApiResult> getPageElement(@RequestBody @Valid GetPageElementReq req); + + /** 查询页面资源 **/ + @PostMapping("/api/pageElement/modifyPageElementRelation") + ApiResult modifyPageElementRelation(@RequestBody @Valid ModifyPageElementRelationDTO req); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/base/BaseFeatureResourceDO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/base/BaseFeatureResourceDO.java index f2a7e24b..ecbb2581 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/base/BaseFeatureResourceDO.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/base/BaseFeatureResourceDO.java @@ -5,6 +5,8 @@ import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; +import java.util.List; + @Data @SuperBuilder @NoArgsConstructor @@ -25,7 +27,7 @@ public class BaseFeatureResourceDO { private Integer featureType; /** 资源编码 **/ - private String featureCode; + private String uniCode; /** 状态 0-隐藏 1-显示 **/ private Integer status; @@ -38,4 +40,7 @@ public class BaseFeatureResourceDO { /** 组件类型 **/ private Integer componentType; + + /** 组件元素的code列表 */ + private List pageElementCodes; } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ModifyPageElementRelationDTO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ModifyPageElementRelationDTO.java new file mode 100644 index 00000000..17534857 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ModifyPageElementRelationDTO.java @@ -0,0 +1,40 @@ +package cn.axzo.tyr.client.model.req; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/19 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ModifyPageElementRelationDTO { + + /** + * 操作人ID + */ + private Long operatorId; + + /** + * 组件所属端 + */ + private String terminal; + + /** + * 组件code + */ + private String featureResourceUniCode; + + /** + * 页面元素编码列表 + */ + private List pageElementCodes; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourceDTO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourceDTO.java index ed67cc15..4a5a8539 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourceDTO.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourceDTO.java @@ -151,4 +151,9 @@ public class FeatureResourceDTO implements Serializable { * 唯一编码,用于pre环境菜单同步 */ private String uniCode; + + /** + * 页面元素对象 + */ + private PageElementBasicDTO pageElement; } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementBasicDTO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementBasicDTO.java new file mode 100644 index 00000000..20996806 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementBasicDTO.java @@ -0,0 +1,33 @@ +package cn.axzo.tyr.client.model.res; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/19 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PageElementBasicDTO { + + /** + * 页面、元素ID + */ + private Long id; + + /** + * 页面、元素编码 + */ + private String code; + + /** + * 页面、元素名称 + */ + private String name; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PageElementController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PageElementController.java index 0cd5cec1..0653502f 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PageElementController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PageElementController.java @@ -3,6 +3,7 @@ package cn.axzo.tyr.server.controller.permission; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.tyr.client.feign.PageElementApi; import cn.axzo.tyr.client.model.req.GetPageElementReq; +import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; import cn.axzo.tyr.client.model.req.PageElementReportReq; import cn.axzo.tyr.client.model.res.PageElementResp; import cn.axzo.tyr.server.service.SaasPageElementService; @@ -34,4 +35,10 @@ public class PageElementController implements PageElementApi { public ApiResult> getPageElement(GetPageElementReq req) { return ApiResult.ok(saasPageElementService.getPageElement(req)); } + + @Override + public ApiResult modifyPageElementRelation(ModifyPageElementRelationDTO req) { + saasPageElementService.modifyPageElementRelation(req); + return ApiResult.ok(); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementFeatureResourceRelationDao.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementFeatureResourceRelationDao.java index 67131f9d..105b8441 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementFeatureResourceRelationDao.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementFeatureResourceRelationDao.java @@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Repository; import java.util.List; +import java.util.Objects; /** * @author likunpeng @@ -22,11 +23,20 @@ public class SaasPageElementFeatureResourceRelationDao extends ServiceImpl listByFeatureUniCodeAndTerminal(String featureResourceUniCode, String terminal) { + public List listByUniCodeAndTerminal(String featureResourceUniCode, String terminal) { return lambdaQuery() .eq(SaasPageElementFeatureResourceRelation::getIsDelete, DeleteEnum.NORMAL.getValue()) .eq(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode, featureResourceUniCode) .eq(SaasPageElementFeatureResourceRelation::getTerminal, terminal) .list(); } + + public void deleteByTerminalAndUniCodes(String terminal, List featureResourceUniCodes, Long operatorId) { + lambdaUpdate() + .eq(SaasPageElementFeatureResourceRelation::getTerminal, terminal) + .in(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode, featureResourceUniCodes) + .set(SaasPageElementFeatureResourceRelation::getIsDelete, DeleteEnum.DELETE.getValue()) + .set(Objects.nonNull(operatorId), SaasPageElementFeatureResourceRelation::getUpdateBy, operatorId) + .update(); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElementFeatureResourceRelation.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElementFeatureResourceRelation.java index 42bfa043..26929c13 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElementFeatureResourceRelation.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElementFeatureResourceRelation.java @@ -3,10 +3,7 @@ package cn.axzo.tyr.server.repository.entity; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; +import lombok.*; /** * 页面元素与菜单组件关系表 @@ -18,6 +15,7 @@ import lombok.ToString; @Getter @Setter @ToString +@Builder @EqualsAndHashCode(callSuper = true) @TableName("saas_page_element_feature_resource_relation") public class SaasPageElementFeatureResourceRelation extends BaseEntity { diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementService.java index 11a180ad..13d35ef7 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementService.java @@ -1,8 +1,10 @@ package cn.axzo.tyr.server.service; import cn.axzo.tyr.client.model.req.GetPageElementReq; +import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; import cn.axzo.tyr.client.model.req.PageElementReportReq; import cn.axzo.tyr.client.model.res.PageElementResp; +import cn.axzo.tyr.server.repository.entity.SaasPageElement; import java.util.List; @@ -27,4 +29,29 @@ public interface SaasPageElementService { * @return */ List getPageElement(GetPageElementReq request); + + /** + * 通过组件code查询页面元素 + * + * @param terminal 组件所属端 + * @param featureResourceUniCode 组件code + * @return + */ + List getByTerminalAndUniCode(String terminal, String featureResourceUniCode); + + /** + * 新增页面组件与页面元素关系 + * + * @param modifyPageElementRelation 关系对象 + */ + void modifyPageElementRelation(ModifyPageElementRelationDTO modifyPageElementRelation); + + /** + * 通过组件code删除绑定关系 + * + * @param terminal 组件所属端 + * @param featureResourceUniCodes 组件code + * @param operatorId 操作人 + */ + void deleteRelationByTerminalAndUniCodes(String terminal, List featureResourceUniCodes, Long operatorId); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java index ae64c178..2c6dd3dd 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java @@ -11,16 +11,20 @@ import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.model.req.FeatureComponentSaveReq; import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; +import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; import cn.axzo.tyr.client.model.res.FeatureResourceDTO; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; +import cn.axzo.tyr.client.model.res.PageElementBasicDTO; import cn.axzo.tyr.server.common.util.Throws; import cn.axzo.tyr.server.model.ResourcePermission; import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO; import cn.axzo.tyr.server.model.convert.SaasFeatureResourceConvert; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; +import cn.axzo.tyr.server.repository.entity.SaasPageElement; import cn.axzo.tyr.server.service.SaasCommonDictService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import cn.axzo.tyr.server.service.SaasPageElementService; import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService; import cn.azxo.framework.common.utils.StringUtils; import cn.hutool.core.collection.CollectionUtil; @@ -66,6 +70,7 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic private final SaasCommonDictService saasCommonDictService; private final SaasPgroupPermissionRelationService pgroupPermissionRelationService; + private final SaasPageElementService saasPageElementService; @Override public List listNavByIds(List featureIds, List featureTypes) { @@ -167,7 +172,9 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic .map(SaasFeatureResourceConvert.INSTANCE::convert) .sorted(Comparator.comparing(FeatureResourceDTO::getDisplayOrder)) .collect(Collectors.toList())); - return treeList.get(0); + FeatureResourceTreeNode featureResourceTreeNode = treeList.get(0); + fillPageElement2PageFeatureResource(featureResourceTreeNode); + return featureResourceTreeNode; } @Override @@ -189,14 +196,22 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic baseResource.setDisplayOrder(maxOrderResource.getDisplayOrder() + 1); } // 生成唯一编码,用于pre菜单同步 - baseResource.setUniCode(UuidUtils.generateUuid()); + baseResource.setFeatureCode(req.getUniCode()); newResource(baseResource, parent == null ? "" : parent.getPath()); } else { //补充path SaasFeatureResource dbResource = featureResourceDao.getById(req.getId()); baseResource.setPath(dbResource.getPath()); + baseResource.setFeatureCode(req.getUniCode()); featureResourceDao.updateById(baseResource); } + // 保存组件与页面元素关系 + saasPageElementService.modifyPageElementRelation(ModifyPageElementRelationDTO.builder() + .operatorId(req.getOperatorId()) + .terminal(req.getTerminal()) + .featureResourceUniCode(req.getUniCode()) + .pageElementCodes(req.getPageElementCodes()) + .build()); if (CollectionUtil.isNotEmpty(req.getComponentSaveReqList())) { List components = req.getComponentSaveReqList(); @@ -245,11 +260,20 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic if (saasFeatureResource.getId() != null) { SaasFeatureResource dbResource = featureResourceDao.getById(saasFeatureResource.getId()); saasFeatureResource.setPath(dbResource.getPath()); + saasFeatureResource.setFeatureCode(featureComponentSaveReq.getUniCode()); featureResourceDao.updateById(saasFeatureResource); } else { saasFeatureResource.setCreateBy(operatorId); + saasFeatureResource.setFeatureCode(featureComponentSaveReq.getUniCode()); newResource(saasFeatureResource, parentPath); } + // 保存组件与页面元素关系 + saasPageElementService.modifyPageElementRelation(ModifyPageElementRelationDTO.builder() + .operatorId(operatorId) + .terminal(featureComponentSaveReq.getTerminal()) + .featureResourceUniCode(featureComponentSaveReq.getUniCode()) + .pageElementCodes(featureComponentSaveReq.getPageElementCodes()) + .build()); List children = featureComponentSaveReq.getChildren(); // 删除前端没带但数据库中有的组件。 @@ -280,21 +304,29 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic .eq(SaasFeatureResource::getParentId, resourceId) .list(); List updateChildIds = submitChildren.stream().map(FeatureComponentSaveReq::getId).filter(Objects::nonNull).collect(Collectors.toList()); - List updateChildCodes = submitChildren.stream().map(FeatureComponentSaveReq::getFeatureCode).collect(Collectors.toList()); + List updateChildCodes = submitChildren.stream().map(FeatureComponentSaveReq::getUniCode).collect(Collectors.toList()); List deleteChildren = existChild.stream() .filter(item -> (!updateChildIds.contains(item.getId()) && !updateChildCodes.contains(item.getFeatureCode()))) .collect(Collectors.toList()); // 前端没传但是数据库中有的,需要删除 if (!CollectionUtil.isEmpty(deleteChildren)) { for (SaasFeatureResource deleteChild : deleteChildren) { - // 删除自己及自己的子集组件 - featureResourceDao.lambdaUpdate() + // 查询数据库要删除的组件 + List deletedResources = featureResourceDao.lambdaQuery() .eq(BaseEntity::getIsDelete,0) .eq(SaasFeatureResource::getFeatureType, FeatureResourceType.COMPONENT.getCode()) .apply("FIND_IN_SET('" + deleteChild.getId() + "', path)") - .set(SaasFeatureResource::getUpdateBy, operatorId) - .set(BaseEntity::getIsDelete,1) - .update(); + .list(); + if (!CollectionUtil.isEmpty(deletedResources)) { + // 删除自己及自己的子集组件 + featureResourceDao.lambdaUpdate() + .in(BaseEntity::getId, deletedResources.stream().map(BaseEntity::getId).collect(Collectors.toList())) + .set(SaasFeatureResource::getUpdateBy, operatorId) + .set(BaseEntity::getIsDelete,1) + .update(); + // 删除组件与页面元素的绑定关系 + saasPageElementService.deleteRelationByTerminalAndUniCodes(deleteChild.getTerminal(), deletedResources.stream().map(SaasFeatureResource::getUniCode).collect(Collectors.toList()), operatorId); + } } } } @@ -445,15 +477,10 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic * @param featureResource */ void validFeatureCode(SaasFeatureResource featureResource) { - - if (Objects.equals(FeatureResourceType.COMPONENT.getCode(), featureResource.getFeatureType())) { - return; - } - - Assert.notNull(featureResource.getFeatureCode(), "权限码code不能为空"); + Assert.notNull(featureResource.getUniCode(), "权限码code不能为空"); SaasFeatureResource exist = featureResourceDao.lambdaQuery() .eq(SaasFeatureResource::getTerminal, featureResource.getTerminal()) - .eq(SaasFeatureResource::getFeatureCode, featureResource.getFeatureCode()) + .eq(SaasFeatureResource::getUniCode, featureResource.getUniCode()) .eq(BaseEntity::getIsDelete, 0) .one(); if (exist != null && !exist.getId().equals(featureResource.getId())) { @@ -509,4 +536,20 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic .in(CollectionUtil.isNotEmpty(featureIds), SaasFeatureResource::getId, featureIds) .list(); } + + private void fillPageElement2PageFeatureResource(FeatureResourceTreeNode featureResourceTreeNode) { + if (!FeatureResourceType.PAGE.getCode().equals(featureResourceTreeNode.getFeatureType())) { + return; + } + List saasPageElements = saasPageElementService.getByTerminalAndUniCode(featureResourceTreeNode.getTerminal(), featureResourceTreeNode.getUniCode()); + if (CollectionUtils.isEmpty(saasPageElements)) { + return; + } + SaasPageElement saasPageElement = saasPageElements.get(0); + featureResourceTreeNode.setPageElement(PageElementBasicDTO.builder() + .id(saasPageElement.getId()) + .code(saasPageElement.getCode()) + .name(saasPageElement.getName()) + .build()); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java index b13ad26c..60316cc7 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java @@ -6,6 +6,7 @@ import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.common.enums.PageElementTypeEnum; import cn.axzo.tyr.client.model.req.GetPageElementReq; +import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; import cn.axzo.tyr.client.model.req.PageElementReportReq; import cn.axzo.tyr.client.model.res.PageElementResp; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; @@ -15,6 +16,7 @@ import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import cn.axzo.tyr.server.repository.entity.SaasPageElement; import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; import cn.axzo.tyr.server.service.SaasPageElementService; +import cn.hutool.json.JSONUtil; import com.google.common.collect.Lists; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -76,7 +78,7 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { .one(); AssertUtil.notNull(saasFeatureResource, "页面或组件信息不存在"); - List relations = saasPageElementFeatureResourceRelationDao.listByFeatureUniCodeAndTerminal(saasFeatureResource.getUniCode(), saasFeatureResource.getTerminal()); + List relations = saasPageElementFeatureResourceRelationDao.listByUniCodeAndTerminal(saasFeatureResource.getUniCode(), saasFeatureResource.getTerminal()); if (CollectionUtils.isEmpty(relations)) { return Collections.emptyList(); } @@ -97,6 +99,48 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { return change2PageElementResp(selectedPageElements, selectedIds); } + @Override + public List getByTerminalAndUniCode(String terminal, String featureResourceUniCode) { + List relations = saasPageElementFeatureResourceRelationDao.listByUniCodeAndTerminal(featureResourceUniCode, terminal); + if (CollectionUtils.isEmpty(relations)) { + return Collections.emptyList(); + } + return saasPageElementDao.listByCodes(relations.stream().map(SaasPageElementFeatureResourceRelation::getPageElementCode).collect(Collectors.toList()), terminal); + } + + @Override + public void modifyPageElementRelation(ModifyPageElementRelationDTO modifyPageElementRelation) { + if (StringUtils.isBlank(modifyPageElementRelation.getTerminal()) + || StringUtils.isBlank(modifyPageElementRelation.getFeatureResourceUniCode())) { + log.warn("addPageElementRelation param error, param:{}", JSONUtil.toJsonStr(modifyPageElementRelation)); + return; + } + + // 删除组件已有的绑定关系 + saasPageElementFeatureResourceRelationDao.deleteByTerminalAndUniCodes(modifyPageElementRelation.getTerminal(), + Lists.newArrayList(modifyPageElementRelation.getFeatureResourceUniCode()), modifyPageElementRelation.getOperatorId()); + + // 保存新的绑定关系 + if (CollectionUtils.isNotEmpty(modifyPageElementRelation.getPageElementCodes())) { + List relations = modifyPageElementRelation.getPageElementCodes().stream().map(e -> SaasPageElementFeatureResourceRelation.builder() + .pageElementCode(e) + .featureResourceUniCode(modifyPageElementRelation.getFeatureResourceUniCode()) + .terminal(modifyPageElementRelation.getTerminal()) + .createBy(modifyPageElementRelation.getOperatorId()) + .build()).collect(Collectors.toList()); + saasPageElementFeatureResourceRelationDao.saveBatch(relations); + } + } + + @Override + public void deleteRelationByTerminalAndUniCodes(String terminal, List featureResourceUniCodes, Long operatorId) { + if (StringUtils.isBlank(terminal) || CollectionUtils.isEmpty(featureResourceUniCodes)) { + log.warn("deleteRelationByTerminalAndUniCode param error, terminal:{}, uniCodes:{}", terminal, featureResourceUniCodes); + return; + } + saasPageElementFeatureResourceRelationDao.deleteByTerminalAndUniCodes(terminal, featureResourceUniCodes, operatorId); + } + private List processParam2Entities(PageElementReportReq request) { List saasPageElements = Lists.newArrayList(); From 25c39c86bab35f17e147fd2c555d5d274718d116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Wed, 19 Jun 2024 15:22:02 +0800 Subject: [PATCH 12/69] =?UTF-8?q?feat(REQ-2545):=20=E5=88=86=E9=A1=B5?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E9=A1=B5=E9=9D=A2=E5=85=83=E7=B4=A0=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/client/feign/PageElementApi.java | 8 ++- .../client/model/req/PageQueryElementReq.java | 49 +++++++++++++++ .../tyr/client/model/res/PageElementResp.java | 10 ++++ .../permission/PageElementController.java | 7 +++ .../repository/dao/SaasPageElementDao.java | 3 +- ...PageElementFeatureResourceRelationDao.java | 3 +- .../service/SaasPageElementService.java | 10 ++++ .../impl/SaasPageElementServiceImpl.java | 59 ++++++++++++++++++- 8 files changed, 144 insertions(+), 5 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementReq.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PageElementApi.java b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PageElementApi.java index fd59bfd1..07166076 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PageElementApi.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PageElementApi.java @@ -1,9 +1,11 @@ package cn.axzo.tyr.client.feign; +import cn.axzo.framework.domain.web.result.ApiPageResult; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.tyr.client.model.req.GetPageElementReq; import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; import cn.axzo.tyr.client.model.req.PageElementReportReq; +import cn.axzo.tyr.client.model.req.PageQueryElementReq; import cn.axzo.tyr.client.model.res.PageElementResp; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; @@ -30,7 +32,11 @@ public interface PageElementApi { @PostMapping("/api/pageElement/getPageElement") ApiResult> getPageElement(@RequestBody @Valid GetPageElementReq req); - /** 查询页面资源 **/ + /** 编辑页面、页面组件的元素 **/ @PostMapping("/api/pageElement/modifyPageElementRelation") ApiResult modifyPageElementRelation(@RequestBody @Valid ModifyPageElementRelationDTO req); + + /** 分页查询页面资源 **/ + @PostMapping("/api/pageElement/page") + ApiPageResult page(@RequestBody @Valid PageQueryElementReq req); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementReq.java new file mode 100644 index 00000000..21706a88 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementReq.java @@ -0,0 +1,49 @@ +package cn.axzo.tyr.client.model.req; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import java.util.List; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/14 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PageQueryElementReq { + + /** + * 端 + */ + @NotBlank(message = "端不能为空") + private String terminal; + + /** + * 页面元素组件类型 + */ + private List elementTypes; + + /** + * 搜索条件 + */ + private String searchKey; + + /** + * 页码 + */ + @Builder.Default + private Long page = 1L; + + /** + * 每页大小 + */ + @Builder.Default + private Long pageSize = 100L; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementResp.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementResp.java index dbac024e..311b7c28 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementResp.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementResp.java @@ -23,6 +23,11 @@ public class PageElementResp { */ private Long id; + /** + * 元素的组编码 + */ + private String groupCode; + /** * 元素编码 */ @@ -38,6 +43,11 @@ public class PageElementResp { */ private String type; + /** + * 页面路由地址 + */ + private String linkUr; + /** * 是否已勾选 */ diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PageElementController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PageElementController.java index 0653502f..f708e574 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PageElementController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PageElementController.java @@ -1,10 +1,12 @@ package cn.axzo.tyr.server.controller.permission; +import cn.axzo.framework.domain.web.result.ApiPageResult; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.tyr.client.feign.PageElementApi; import cn.axzo.tyr.client.model.req.GetPageElementReq; import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; import cn.axzo.tyr.client.model.req.PageElementReportReq; +import cn.axzo.tyr.client.model.req.PageQueryElementReq; import cn.axzo.tyr.client.model.res.PageElementResp; import cn.axzo.tyr.server.service.SaasPageElementService; import lombok.RequiredArgsConstructor; @@ -41,4 +43,9 @@ public class PageElementController implements PageElementApi { saasPageElementService.modifyPageElementRelation(req); return ApiResult.ok(); } + + @Override + public ApiPageResult page(PageQueryElementReq req) { + return ApiPageResult.ok(saasPageElementService.page(req)); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementDao.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementDao.java index 347a2b09..cefcefed 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementDao.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementDao.java @@ -33,10 +33,11 @@ public class SaasPageElementDao extends ServiceImpl listByGroupCodesAndExcludeIds(List groupCodes, List excludeIds, String terminal) { + public List listByGroupCodesAndExcludeIds(List groupCodes, List excludeIds, String terminal, List types) { return lambdaQuery() .eq(SaasPageElement::getTerminal, terminal) .in(SaasPageElement::getGroupCode, groupCodes) + .in(CollectionUtils.isNotEmpty(types), SaasPageElement::getType, types) .notIn(CollectionUtils.isNotEmpty(excludeIds), SaasPageElement::getId, excludeIds) .list(); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementFeatureResourceRelationDao.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementFeatureResourceRelationDao.java index 105b8441..0036cdaa 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementFeatureResourceRelationDao.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementFeatureResourceRelationDao.java @@ -17,10 +17,11 @@ import java.util.Objects; @Repository public class SaasPageElementFeatureResourceRelationDao extends ServiceImpl { - public List listByPageElementCode(String pageElementCode) { + public List listByPageElementCode(String pageElementCode, String terminal) { return lambdaQuery() .eq(SaasPageElementFeatureResourceRelation::getIsDelete, DeleteEnum.NORMAL.getValue()) .eq(SaasPageElementFeatureResourceRelation::getPageElementCode, pageElementCode) + .eq(SaasPageElementFeatureResourceRelation::getTerminal, terminal) .list(); } public List listByUniCodeAndTerminal(String featureResourceUniCode, String terminal) { diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementService.java index 13d35ef7..02a2f6cf 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementService.java @@ -1,8 +1,10 @@ package cn.axzo.tyr.server.service; +import cn.axzo.framework.domain.page.PageResp; import cn.axzo.tyr.client.model.req.GetPageElementReq; import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; import cn.axzo.tyr.client.model.req.PageElementReportReq; +import cn.axzo.tyr.client.model.req.PageQueryElementReq; import cn.axzo.tyr.client.model.res.PageElementResp; import cn.axzo.tyr.server.repository.entity.SaasPageElement; @@ -54,4 +56,12 @@ public interface SaasPageElementService { * @param operatorId 操作人 */ void deleteRelationByTerminalAndUniCodes(String terminal, List featureResourceUniCodes, Long operatorId); + + /** + * 分页查询页面元素接口 + * + * @param request 查询条件 + * @return + */ + PageResp page(PageQueryElementReq request); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java index 60316cc7..6ae88c25 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java @@ -1,13 +1,16 @@ package cn.axzo.tyr.server.service.impl; +import cn.axzo.basics.common.BeanMapper; import cn.axzo.basics.common.util.AssertUtil; import cn.axzo.basics.common.util.StopWatchUtil; +import cn.axzo.framework.domain.page.PageResp; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.common.enums.PageElementTypeEnum; import cn.axzo.tyr.client.model.req.GetPageElementReq; import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; import cn.axzo.tyr.client.model.req.PageElementReportReq; +import cn.axzo.tyr.client.model.req.PageQueryElementReq; import cn.axzo.tyr.client.model.res.PageElementResp; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; import cn.axzo.tyr.server.repository.dao.SaasPageElementDao; @@ -17,7 +20,10 @@ import cn.axzo.tyr.server.repository.entity.SaasPageElement; import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; import cn.axzo.tyr.server.service.SaasPageElementService; import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; @@ -91,7 +97,7 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { // 如果查询不仅仅是已勾选的,需要把已勾选的页面下未选择的组件也返回 if (!Boolean.TRUE.equals(request.getQuerySelectedOnly())) { List pageTypeCodes = selectedPageElements.stream().filter(e -> PageElementTypeEnum.PAGE.getCode().equals(e.getType())).map(SaasPageElement::getGroupCode).collect(Collectors.toList()); - List notSelectedComponents = saasPageElementDao.listByGroupCodesAndExcludeIds(pageTypeCodes, selectedIds, saasFeatureResource.getTerminal()); + List notSelectedComponents = saasPageElementDao.listByGroupCodesAndExcludeIds(pageTypeCodes, selectedIds, saasFeatureResource.getTerminal(), null); if (CollectionUtils.isNotEmpty(notSelectedComponents)) { selectedPageElements.addAll(notSelectedComponents); } @@ -141,6 +147,20 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { saasPageElementFeatureResourceRelationDao.deleteByTerminalAndUniCodes(terminal, featureResourceUniCodes, operatorId); } + @Override + public PageResp page(PageQueryElementReq request) { + IPage page = saasPageElementDao.lambdaQuery() + .eq(SaasPageElement::getTerminal, request.getTerminal()) + .in(CollectionUtils.isNotEmpty(request.getElementTypes()), SaasPageElement::getType, request.getElementTypes()) + .and(StringUtils.isNotBlank(request.getSearchKey()), w -> w.eq(BaseEntity::getId, request.getSearchKey()) + .or().like(SaasPageElement::getName, request.getSearchKey()) + .or().like(SaasPageElement::getLinkUr, request.getSearchKey())) + .page(new Page<>(request.getPage(), request.getPageSize())); + List list = BeanMapper.copyList(page.getRecords(), PageElementResp.class); + addComponentElement2Page(request.getTerminal(), list); + return PageResp.list(page.getCurrent(), page.getSize(), page.getTotal(), list); + } + private List processParam2Entities(PageElementReportReq request) { List saasPageElements = Lists.newArrayList(); @@ -172,7 +192,7 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { if (StringUtils.isBlank(pageElement.getLinkUrl())) { continue; } - List relations = saasPageElementFeatureResourceRelationDao.listByPageElementCode(pageElement.getCode()); + List relations = saasPageElementFeatureResourceRelationDao.listByPageElementCode(pageElement.getCode(), request.getTerminal()); if (CollectionUtils.isEmpty(relations)) { continue; } @@ -226,4 +246,39 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { return pageTypeElements; } + + private void addComponentElement2Page(String terminal, List list) { + if (CollectionUtils.isEmpty(list)) { + return; + } + List pageTypeCodes = Lists.newArrayList(); + List excludeIds = Lists.newArrayList(); + Map pageTypeCodeMap = Maps.newHashMap(); + for (PageElementResp element : list) { + if (PageElementTypeEnum.PAGE.getCode().equals(element.getType())) { + pageTypeCodes.add(element.getGroupCode()); + pageTypeCodeMap.put(element.getCode(), element); + } + excludeIds.add(element.getId()); + element.setChildren(Lists.newArrayList()); + } + + List componentElements = saasPageElementDao.listByGroupCodesAndExcludeIds(pageTypeCodes, excludeIds, terminal, Lists.newArrayList(PageElementTypeEnum.COMPONENT.getCode())); + if (CollectionUtils.isEmpty(componentElements)) { + return; + } + + componentElements.forEach(e -> { + PageElementResp pageTypeElement = pageTypeCodeMap.get(e.getGroupCode()); + if (Objects.nonNull(pageTypeElement)) { + pageTypeElement.getChildren().add(PageElementResp.builder() + .id(e.getId()) + .groupCode(e.getGroupCode()) + .code(e.getCode()) + .name(e.getName()) + .type(e.getType()) + .build()); + } + }); + } } From 76dabbe3be6cee3101708dc9f3dcceec472635fa Mon Sep 17 00:00:00 2001 From: lilong Date: Wed, 19 Jun 2024 18:11:30 +0800 Subject: [PATCH 13/69] =?UTF-8?q?feat:(REQ-2545)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E6=9D=83=E9=99=90=E4=BF=A1=E6=81=AF=EF=BC=8C?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E6=97=B6=E5=A2=9E=E5=8A=A0type=E5=92=8Cfeatu?= =?UTF-8?q?reType?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/server/service/RoleService.java | 3 + .../SaasPgroupPermissionRelationService.java | 29 +++- .../service/impl/PermissionGroupImpl.java | 44 ++++-- .../server/service/impl/RoleServiceImpl.java | 140 ++++++++++-------- ...asPgroupPermissionRelationServiceImpl.java | 16 +- 5 files changed, 156 insertions(+), 76 deletions(-) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java index 49b060e1..c804fe92 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java @@ -25,6 +25,7 @@ import cn.axzo.tyr.client.model.vo.SaasRoleGroupCodeVO; import cn.axzo.tyr.client.model.vo.SaasRoleVO; import cn.axzo.tyr.client.model.vo.SaveOrUpdateRoleVO; import cn.axzo.tyr.server.model.RoleWithFeature; +import cn.axzo.tyr.server.repository.entity.SaasFeature; import cn.axzo.tyr.server.repository.entity.SaasRole; import cn.axzo.tyr.server.repository.entity.SaasRoleWithUser; import cn.axzo.tyr.server.service.impl.TyrSaasAuthServiceImpl; @@ -127,6 +128,8 @@ public interface RoleService extends IService { FeatureRoleRelationResp queryFeatureRoleRelation(Long featureId); + List validFeature(List featureIds); + @SuperBuilder @Data @NoArgsConstructor diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPgroupPermissionRelationService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPgroupPermissionRelationService.java index 2187852f..5c7e1abf 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPgroupPermissionRelationService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPgroupPermissionRelationService.java @@ -4,11 +4,38 @@ import cn.axzo.foundation.page.PageResp; import cn.axzo.tyr.client.model.req.PagePgroupPermissionRelationReq; import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation; import com.baomidou.mybatisplus.extension.service.IService; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; import java.util.List; public interface SaasPgroupPermissionRelationService extends IService { - void saveOrUpdate(List groupIds, List relations); + void saveOrUpdate(UpsertPermissionRelationParam param); PageResp page(PagePgroupPermissionRelationReq param); + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class UpsertPermissionRelationParam { + + /** + * 权限组id + */ + private List groupIds; + + /** + * 权限关系明细 + */ + private List relations; + + /** + * 同一个端更新只能是一个版本类型 + * 关联类型(0:saas_feature,1:saas_feature_resource) + */ + private Integer type; + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionGroupImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionGroupImpl.java index 39aa54fd..77cf8230 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionGroupImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionGroupImpl.java @@ -20,6 +20,7 @@ import cn.axzo.tyr.server.repository.dao.SaasPermissionGroupScopeDao; import cn.axzo.tyr.server.repository.dao.SaasPgroupPermissionRelationDao; import cn.axzo.tyr.server.repository.dao.SaasPgroupRoleRelationDao; import cn.axzo.tyr.server.repository.dao.SaasRoleDao; +import cn.axzo.tyr.server.repository.entity.SaasFeature; import cn.axzo.tyr.server.repository.entity.SaasPermissionGroup; import cn.axzo.tyr.server.repository.entity.SaasPermissionGroupScope; import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation; @@ -27,6 +28,7 @@ import cn.axzo.tyr.server.repository.entity.SaasPgroupRoleRelation; import cn.axzo.tyr.server.repository.entity.SaasRole; import cn.axzo.tyr.server.service.PermissionGroupService; import cn.axzo.tyr.server.service.PermissionPointService; +import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasPermissionGroupScopeService; import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService; import cn.hutool.core.collection.CollectionUtil; @@ -52,6 +54,8 @@ import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE; + /** * 权限集 * @@ -71,6 +75,7 @@ public class PermissionGroupImpl implements PermissionGroupService { private final SaasPgroupPermissionRelationService saasPgroupPermissionRelationService; private final SaasRoleDao saasRoleDao; private final SaasPermissionGroupScopeService saasPermissionGroupScopeService; + private final RoleService roleService; @Override public PageResp page(QuerySaasPermissionGroupReq req) { @@ -199,15 +204,36 @@ public class PermissionGroupImpl implements PermissionGroupService { @Transactional(rollbackFor = Exception.class) public void savePermissionPoints(SavePermissionGroupPPVO save) { SaasPermissionGroup saasPermissionGroup = getRequiredPermissionGroup(save.getId(), null); - List pgpRelations = Optional.ofNullable(save.getSelectedPPIds()).orElse(new ArrayList<>()).stream().map(ppId -> { - SaasPgroupPermissionRelation target = new SaasPgroupPermissionRelation(); - target.setGroupId(saasPermissionGroup.getId()); - target.setFeatureId(ppId); - target.setCreateBy(save.getOperatorId()); - target.setUpdateBy(save.getOperatorId()); - return target; - }).collect(Collectors.toList()); - saasPgroupPermissionRelationService.saveOrUpdate(Lists.newArrayList(saasPermissionGroup.getId()), pgpRelations); + List pgpRelations = resolvePermissionRelations(save, saasPermissionGroup); + + SaasPgroupPermissionRelationService.UpsertPermissionRelationParam upsertPermissionRelationParam = SaasPgroupPermissionRelationService.UpsertPermissionRelationParam.builder() + .groupIds(Lists.newArrayList(saasPermissionGroup.getId())) + .relations(pgpRelations) + .type(OLD_FEATURE) + .build(); + saasPgroupPermissionRelationService.saveOrUpdate(upsertPermissionRelationParam); + } + + private List resolvePermissionRelations(SavePermissionGroupPPVO param, + SaasPermissionGroup saasPermissionGroup) { + if (CollectionUtils.isEmpty(param.getSelectedPPIds())) { + return Lists.newArrayList(); + } + + Map saasFeatureTypeMap = roleService.validFeature(param.getSelectedPPIds()).stream() + .collect(Collectors.toMap(SaasFeature::getId, SaasFeature::getFeatureType)); + + return param.getSelectedPPIds().stream() + .map(ppId -> { + SaasPgroupPermissionRelation target = new SaasPgroupPermissionRelation(); + target.setGroupId(saasPermissionGroup.getId()); + target.setFeatureId(ppId); + target.setCreateBy(param.getOperatorId()); + target.setUpdateBy(param.getOperatorId()); + target.setFeatureType(saasFeatureTypeMap.get(ppId)); + target.setType(OLD_FEATURE); + return target; + }).collect(Collectors.toList()); } @Override diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java index 56a53de7..b1af4330 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java @@ -113,6 +113,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE; /** * 角色 @@ -342,9 +343,9 @@ public class RoleServiceImpl extends ServiceImpl SaasPermissionGroup saasPermissionGroup = validPermissionGroupCommon(saveOrUpdateRole); // TODO 旧的权限,待权限切完后就下掉 - validFeature(saveOrUpdateRole.getSelectedPPIds()); + List saasFeatures = validFeature(saveOrUpdateRole.getSelectedPPIds()); // 新的权限 - validPermission(saveOrUpdateRole.getPermissionIds()); + List saasFeatureResources = validPermission(saveOrUpdateRole.getPermissionIds()); saasRoleDao.saveOrUpdate(saasRole); // 新增或者保存分组和角色映射关系 @@ -368,72 +369,84 @@ public class RoleServiceImpl extends ServiceImpl if (Objects.isNull(saveOrUpdateRole.getId())) { saasPgroupRoleRelationDao.save(pgrr); } - if (CollectionUtils.isNotEmpty(saveOrUpdateRole.getSelectedPPIds()) - || CollectionUtils.isNotEmpty(saveOrUpdateRole.getPermissionIds())) { - List pids = Optional.ofNullable(saveOrUpdateRole.getSelectedPPIds()) - .orElseGet(() -> Lists.newArrayList(saveOrUpdateRole.getPermissionIds())); + // 还有CMP和CM使用旧的菜单资源树 + saveSaasFeaturePermission(saveOrUpdateRole, saasFeatures, saasPermissionGroup); - // 保存权限集和权限点映射关系 - List pgpRelations = pids.stream().map(ppId -> { - SaasPgroupPermissionRelation target = new SaasPgroupPermissionRelation(); - target.setGroupId(saasPermissionGroup.getId()); - target.setFeatureId(ppId); - target.setCreateBy(saveOrUpdateRole.getOperatorId()); - target.setUpdateBy(saveOrUpdateRole.getOperatorId()); - return target; - }).collect(Collectors.toList()); - saasPgroupPermissionRelationService.saveOrUpdate(Lists.newArrayList(saasPermissionGroup.getId()), pgpRelations); - } + // 保存新的菜单资源树权限 + saveSaasFeatureResourcePermission(saveOrUpdateRole, saasFeatureResources, saasPermissionGroup); return saasRole.getId(); } - private void validRoleName(SaveOrUpdateRoleVO saveOrUpdateRole) { - List groupTrees = saveOrUpdateRole.getGroupTree(); - if (CollectionUtil.isEmpty(groupTrees)) { + /** + * 后续cms,cmp的菜单切到saas_feature_resource后,就去掉这个方法 + * @param saveOrUpdateRole + * @param saasFeatures + * @param saasPermissionGroup + */ + private void saveSaasFeaturePermission(SaveOrUpdateRoleVO saveOrUpdateRole, + List saasFeatures, + SaasPermissionGroup saasPermissionGroup) { + if (CollectionUtils.isEmpty(saveOrUpdateRole.getSelectedPPIds())) { return; } - String currentWorkspaceCode = groupTrees.get(0).getWorkspaceTypeCode(); - List roleGroups = saasRoleGroupDao.lambdaQuery() - .in(SaasRoleGroup::getWorkspaceTypeCode, currentWorkspaceCode) - .eq(SaasRoleGroup::getWorkspaceId, saveOrUpdateRole.getWorkspaceId()) - .eq(SaasRoleGroup::getOuId, saveOrUpdateRole.getOwnerOuId()) - .eq(SaasRoleGroup::getIsDelete, TableIsDeleteEnum.NORMAL.value).list(); - List roleGroupIds = roleGroups.stream().map(SaasRoleGroup::getId).collect(Collectors.toList()); - if (CollectionUtil.isEmpty(roleGroupIds)) { - return; - } - List roleGroupRelations = roleGroupRelationDao.lambdaQuery() - .in(SaasRoleGroupRelation::getSaasRoleGroupId, roleGroupIds) - .eq(SaasRoleGroupRelation::getIsDelete, TableIsDeleteEnum.NORMAL.value).list(); - if (CollectionUtil.isNotEmpty(roleGroupRelations)) { - List saasRoleIds = roleGroupRelations.stream().map(SaasRoleGroupRelation::getRoleId).collect(Collectors.toList()); - //确保这些角色id 都是正常使用的 - List roles = saasRoleDao.lambdaQuery() - .eq(SaasRole::getWorkspaceId, saveOrUpdateRole.getWorkspaceId()) - .eq(SaasRole::getId, saasRoleIds) - .eq(SaasRole::getName, saveOrUpdateRole.getName()) - .eq(SaasRole::getOwnerOuId, saveOrUpdateRole.getOwnerOuId()) - .eq(SaasRole::getIsDelete, TableIsDeleteEnum.NORMAL.value).list(); - if (CollectionUtil.isNotEmpty(roles)) { - //新增角色 判断角色名称重复 - if (Objects.isNull(saveOrUpdateRole.getId())) { - throw new ServiceException("同一企业单位、同一工作台类型,角色名称不能重复!"); - } else { - //如果是更新角色,必须是当前角色 - if (!(roles.size() == 1 && (roles.get(0).getId().equals(saveOrUpdateRole.getId())))) { - throw new ServiceException("同一企业单位、同一工作台类型,角色名称不能重复!"); - } - } - } -// Optional repeatGroupName = roles.stream() -// .filter(g -> !Objects.equals(g.getId(), saveOrUpdateRole.getId()) && StringUtils.equalsIgnoreCase(g.getName(), saveOrUpdateRole.getName())).findFirst(); -// if (repeatGroupName.isPresent()) { -// throw new ServiceException("同一个单位、同一工作台类型内,角色名称不能重复!"); -// } + Map saasFeatureMap = saasFeatures.stream() + .collect(Collectors.toMap(SaasFeature::getId, SaasFeature::getFeatureType)); + + // 保存权限集和权限点映射关系 + List pgpRelations = saveOrUpdateRole.getSelectedPPIds().stream().map(ppId -> { + SaasPgroupPermissionRelation target = new SaasPgroupPermissionRelation(); + target.setGroupId(saasPermissionGroup.getId()); + target.setFeatureId(ppId); + target.setCreateBy(saveOrUpdateRole.getOperatorId()); + target.setUpdateBy(saveOrUpdateRole.getOperatorId()); + target.setFeatureType(saasFeatureMap.get(ppId)); + target.setType(OLD_FEATURE); + return target; + }).collect(Collectors.toList()); + SaasPgroupPermissionRelationService.UpsertPermissionRelationParam upsertPermissionRelationParam = SaasPgroupPermissionRelationService.UpsertPermissionRelationParam.builder() + .groupIds(Lists.newArrayList(saasPermissionGroup.getId())) + .relations(pgpRelations) + .type(OLD_FEATURE) + .build(); + saasPgroupPermissionRelationService.saveOrUpdate(upsertPermissionRelationParam); + } + + /** + * + * @param saveOrUpdateRole + * @param resourcePermissions + * @param saasPermissionGroup + */ + private void saveSaasFeatureResourcePermission(SaveOrUpdateRoleVO saveOrUpdateRole, + List resourcePermissions, + SaasPermissionGroup saasPermissionGroup) { + if (CollectionUtils.isEmpty(saveOrUpdateRole.getPermissionIds())) { + return; } + + Map resourcePermissionMap = resourcePermissions.stream() + .collect(Collectors.toMap(ResourcePermission::getId, ResourcePermission::getFeatureType)); + + // 保存权限集和权限点映射关系 + List pgpRelations = saveOrUpdateRole.getPermissionIds().stream().map(ppId -> { + SaasPgroupPermissionRelation target = new SaasPgroupPermissionRelation(); + target.setGroupId(saasPermissionGroup.getId()); + target.setFeatureId(ppId); + target.setCreateBy(saveOrUpdateRole.getOperatorId()); + target.setUpdateBy(saveOrUpdateRole.getOperatorId()); + target.setFeatureType(resourcePermissionMap.get(ppId)); + target.setType(NEW_FEATURE); + return target; + }).collect(Collectors.toList()); + SaasPgroupPermissionRelationService.UpsertPermissionRelationParam upsertPermissionRelationParam = SaasPgroupPermissionRelationService.UpsertPermissionRelationParam.builder() + .groupIds(Lists.newArrayList(saasPermissionGroup.getId())) + .relations(pgpRelations) + .type(NEW_FEATURE) + .build(); + saasPgroupPermissionRelationService.saveOrUpdate(upsertPermissionRelationParam); } @Override @@ -630,9 +643,10 @@ public class RoleServiceImpl extends ServiceImpl return saveOrUpdateRoleVO.getProductUnitType(); } - private void validFeature(List featureIds) { + @Override + public List validFeature(List featureIds) { if (CollectionUtils.isEmpty(featureIds)) { - return; + return Collections.emptyList(); } List saasFeatures = saasFeatureDao.lambdaQuery().in(SaasFeature::getId, featureIds) .eq(SaasFeature::getIsDelete, TableIsDeleteEnum.NORMAL.value).list(); @@ -644,6 +658,7 @@ public class RoleServiceImpl extends ServiceImpl if (CollectionUtils.isNotEmpty(invalidFeatues)) { throw new ServiceException("权限点信息错误"); } + return saasFeatures; } private SaasPermissionGroup validPermissionGroupCommon(SaveOrUpdateRoleVO saveOrUpdateRole) { @@ -1385,9 +1400,9 @@ public class RoleServiceImpl extends ServiceImpl return resp; } - private void validPermission(Set permissionIds) { + private List validPermission(Set permissionIds) { if (CollectionUtils.isEmpty(permissionIds)) { - return; + return Collections.emptyList(); } List resourcePermissions = saasFeatureResourceService.permissionQuery(ResourcePermissionQueryDTO.builder() .ids(Lists.newArrayList(permissionIds)) @@ -1396,6 +1411,7 @@ public class RoleServiceImpl extends ServiceImpl permissionIds.removeAll(resourcePermissions.stream().map(ResourcePermission::getId).collect(Collectors.toSet())); throw new ServiceException(String.format("权限点 %s 信息错误", permissionIds)); } + return resourcePermissions; } private Map> listSaasRoleUser(PageSaasRoleParam param, diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPgroupPermissionRelationServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPgroupPermissionRelationServiceImpl.java index c8350d2e..3b37ef19 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPgroupPermissionRelationServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPgroupPermissionRelationServiceImpl.java @@ -35,19 +35,27 @@ public class SaasPgroupPermissionRelationServiceImpl @Override @Transactional(rollbackFor = Exception.class) - public void saveOrUpdate(List groupIds, List relations) { + public void saveOrUpdate(UpsertPermissionRelationParam param) { + + List groupIds = param.getGroupIds(); + List relations = param.getRelations(); if (CollectionUtils.isEmpty(groupIds) && CollectionUtils.isEmpty(relations)) { return; } // 移除权限点 - if (CollectionUtils.isEmpty(groupIds)) { - groupIds = relations.stream().map(SaasPgroupPermissionRelation::getGroupId).distinct().sorted().collect(Collectors.toList()); + if (CollectionUtils.isEmpty(param.getGroupIds())) { + groupIds = param.getRelations().stream().map(SaasPgroupPermissionRelation::getGroupId).distinct().sorted().collect(Collectors.toList()); } else if (Objects.isNull(relations)){ relations = new ArrayList<>(); } + + // 因为同一个角色会绑定两个菜单资源树的情况,不能相互覆盖,因为项企分离时,CMS做了新旧版本灰度,新版本使用saas_feature_resource,旧版本使用saas_feature + // 所以SaasPgroupPermissionRelation加了type做区分,写的时候要按照type来隔离 List exists = saasPgroupPermissionRelationDao.lambdaQuery() .in(SaasPgroupPermissionRelation::getGroupId, groupIds) - .eq(SaasPgroupPermissionRelation::getIsDelete, TableIsDeleteEnum.NORMAL.value).list(); + .eq(SaasPgroupPermissionRelation::getIsDelete, TableIsDeleteEnum.NORMAL.value) + .eq(SaasPgroupPermissionRelation::getType, param.getType()) + .list(); Collection insertList = CollectionUtils.subtract(relations, exists); Collection deleteList = CollectionUtils.subtract(exists, relations); if (CollectionUtils.isNotEmpty(insertList)) { From bdddb409be263d60adf3b70d3e0bd8f803a7121f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Thu, 20 Jun 2024 09:20:39 +0800 Subject: [PATCH 14/69] =?UTF-8?q?feat(REQ-2545):=20=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E4=B8=8B=E5=85=83=E7=B4=A0=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/client/feign/PageElementApi.java | 10 ++-- .../GetUserHasPermissionPageElementReq.java | 41 +++++++++++++ .../GetUserHasPermissionPageElementResp.java | 25 ++++++++ .../permission/PageElementController.java | 11 ++-- ...PageElementFeatureResourceRelationDao.java | 6 +- ...aasPageElementFeatureResourceRelation.java | 24 ++++---- .../service/SaasPageElementService.java | 14 +++-- .../impl/SaasPageElementServiceImpl.java | 60 ++++++++++++++++--- 8 files changed, 158 insertions(+), 33 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetUserHasPermissionPageElementReq.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/res/GetUserHasPermissionPageElementResp.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PageElementApi.java b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PageElementApi.java index 07166076..76373ffd 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PageElementApi.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PageElementApi.java @@ -2,10 +2,8 @@ package cn.axzo.tyr.client.feign; import cn.axzo.framework.domain.web.result.ApiPageResult; import cn.axzo.framework.domain.web.result.ApiResult; -import cn.axzo.tyr.client.model.req.GetPageElementReq; -import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; -import cn.axzo.tyr.client.model.req.PageElementReportReq; -import cn.axzo.tyr.client.model.req.PageQueryElementReq; +import cn.axzo.tyr.client.model.req.*; +import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; import cn.axzo.tyr.client.model.res.PageElementResp; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; @@ -39,4 +37,8 @@ public interface PageElementApi { /** 分页查询页面资源 **/ @PostMapping("/api/pageElement/page") ApiPageResult page(@RequestBody @Valid PageQueryElementReq req); + + /** 根据用户传入的页面code,查询用户有权限的元素code **/ + @PostMapping("/api/pageElement/getUserHasPermissionPageElement") + ApiResult getUserHasPermissionPageElement(@RequestBody @Valid GetUserHasPermissionPageElementReq req); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetUserHasPermissionPageElementReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetUserHasPermissionPageElementReq.java new file mode 100644 index 00000000..0edcee11 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetUserHasPermissionPageElementReq.java @@ -0,0 +1,41 @@ +package cn.axzo.tyr.client.model.req; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/17 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class GetUserHasPermissionPageElementReq { + + /** + * 页面的元素 + */ +// @NotNull(message = "页面的元素不能为空") + private String pageElementCode; + + /** 登录端 **/ +// @NotNull(message = "登录端不能为空") + private String terminal; + +// @NotNull(message = "人员ID不能为空") + private Long personId; + +// @NotNull(message = "单位ID不能为空") + private Long ouId; + +// @NotNull(message = "租户ID不能为空") + private Long workspaceId; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/GetUserHasPermissionPageElementResp.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/GetUserHasPermissionPageElementResp.java new file mode 100644 index 00000000..d6ea631b --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/GetUserHasPermissionPageElementResp.java @@ -0,0 +1,25 @@ +package cn.axzo.tyr.client.model.res; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/17 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class GetUserHasPermissionPageElementResp { + + /** + * 页面元素的elementCodes + */ + private List pageElementCodes; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PageElementController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PageElementController.java index f708e574..7fc95122 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PageElementController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PageElementController.java @@ -3,10 +3,8 @@ package cn.axzo.tyr.server.controller.permission; import cn.axzo.framework.domain.web.result.ApiPageResult; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.tyr.client.feign.PageElementApi; -import cn.axzo.tyr.client.model.req.GetPageElementReq; -import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; -import cn.axzo.tyr.client.model.req.PageElementReportReq; -import cn.axzo.tyr.client.model.req.PageQueryElementReq; +import cn.axzo.tyr.client.model.req.*; +import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; import cn.axzo.tyr.client.model.res.PageElementResp; import cn.axzo.tyr.server.service.SaasPageElementService; import lombok.RequiredArgsConstructor; @@ -48,4 +46,9 @@ public class PageElementController implements PageElementApi { public ApiPageResult page(PageQueryElementReq req) { return ApiPageResult.ok(saasPageElementService.page(req)); } + + @Override + public ApiResult getUserHasPermissionPageElement(GetUserHasPermissionPageElementReq req) { + return ApiResult.ok(saasPageElementService.getUserHasPermissionPageElement(req)); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementFeatureResourceRelationDao.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementFeatureResourceRelationDao.java index 0036cdaa..071abc22 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementFeatureResourceRelationDao.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementFeatureResourceRelationDao.java @@ -1,6 +1,7 @@ package cn.axzo.tyr.server.repository.dao; import cn.axzo.basics.common.constant.enums.DeleteEnum; +import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; import cn.axzo.tyr.server.repository.mapper.SaasPageElementFeatureResourceRelationMapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -22,12 +23,13 @@ public class SaasPageElementFeatureResourceRelationDao extends ServiceImpl listByUniCodeAndTerminal(String featureResourceUniCode, String terminal) { + public List listByUniCodeAndTerminal(List featureResourceUniCodes, String terminal) { return lambdaQuery() .eq(SaasPageElementFeatureResourceRelation::getIsDelete, DeleteEnum.NORMAL.getValue()) - .eq(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode, featureResourceUniCode) + .in(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode, featureResourceUniCodes) .eq(SaasPageElementFeatureResourceRelation::getTerminal, terminal) .list(); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElementFeatureResourceRelation.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElementFeatureResourceRelation.java index 26929c13..95e74fd6 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElementFeatureResourceRelation.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElementFeatureResourceRelation.java @@ -20,6 +20,18 @@ import lombok.*; @TableName("saas_page_element_feature_resource_relation") public class SaasPageElementFeatureResourceRelation extends BaseEntity { + /** + * 创建人 + */ + @TableField("create_by") + private Long createBy; + + /** + * 更新人 + */ + @TableField("update_by") + private Long updateBy; + /** * 页面元素code */ @@ -37,16 +49,4 @@ public class SaasPageElementFeatureResourceRelation extends BaseEntity page(PageQueryElementReq request); + + /** + * 根据用户传入的页面code,查询用户有权限的元素code + * + * @param request + * @return + */ + GetUserHasPermissionPageElementResp getUserHasPermissionPageElement(GetUserHasPermissionPageElementReq request); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java index 6ae88c25..25728237 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java @@ -7,10 +7,8 @@ import cn.axzo.framework.domain.page.PageResp; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.common.enums.PageElementTypeEnum; -import cn.axzo.tyr.client.model.req.GetPageElementReq; -import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; -import cn.axzo.tyr.client.model.req.PageElementReportReq; -import cn.axzo.tyr.client.model.req.PageQueryElementReq; +import cn.axzo.tyr.client.model.req.*; +import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; import cn.axzo.tyr.client.model.res.PageElementResp; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; import cn.axzo.tyr.server.repository.dao.SaasPageElementDao; @@ -33,7 +31,10 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.function.Function; @@ -84,7 +85,7 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { .one(); AssertUtil.notNull(saasFeatureResource, "页面或组件信息不存在"); - List relations = saasPageElementFeatureResourceRelationDao.listByUniCodeAndTerminal(saasFeatureResource.getUniCode(), saasFeatureResource.getTerminal()); + List relations = saasPageElementFeatureResourceRelationDao.listByUniCodeAndTerminal(Lists.newArrayList(saasFeatureResource.getUniCode()), saasFeatureResource.getTerminal()); if (CollectionUtils.isEmpty(relations)) { return Collections.emptyList(); } @@ -107,7 +108,7 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { @Override public List getByTerminalAndUniCode(String terminal, String featureResourceUniCode) { - List relations = saasPageElementFeatureResourceRelationDao.listByUniCodeAndTerminal(featureResourceUniCode, terminal); + List relations = saasPageElementFeatureResourceRelationDao.listByUniCodeAndTerminal(Lists.newArrayList(featureResourceUniCode), terminal); if (CollectionUtils.isEmpty(relations)) { return Collections.emptyList(); } @@ -161,6 +162,34 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { return PageResp.list(page.getCurrent(), page.getSize(), page.getTotal(), list); } + @Override + public GetUserHasPermissionPageElementResp getUserHasPermissionPageElement(GetUserHasPermissionPageElementReq request) { + List relations = saasPageElementFeatureResourceRelationDao.listByPageElementCode(request.getPageElementCode(), request.getTerminal()); + if (CollectionUtils.isEmpty(relations)) { + log.warn("绑定关系不存在,页面元素编码:{}", request.getPageElementCode()); + return null; + } + + List saasFeatureResources = listDescendantByUniCodeAndTerminal(request.getTerminal(), relations.stream().map(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode).collect(Collectors.toList())); + if (CollectionUtils.isEmpty(saasFeatureResources)) { + return null; + } + + // TODO 过滤用户有权限的featureIds + List hasPermissionFeatureIds = saasFeatureResources.stream().map(BaseEntity::getId).collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(hasPermissionFeatureIds)) { + log.warn("不存在有权限的组件,页面元素编码:{}", request.getPageElementCode()); + return null; + } + + List hasPermissionUniCodes = saasFeatureResources.stream().filter(e -> hasPermissionFeatureIds.contains(e.getId())).map(SaasFeatureResource::getUniCode).collect(Collectors.toList()); + List resourceRelations = saasPageElementFeatureResourceRelationDao.listByUniCodeAndTerminal(hasPermissionUniCodes, request.getTerminal()); + return GetUserHasPermissionPageElementResp.builder() + .pageElementCodes(CollectionUtils.emptyIfNull(resourceRelations).stream().map(SaasPageElementFeatureResourceRelation::getPageElementCode).collect(Collectors.toList())) + .build(); + } + private List processParam2Entities(PageElementReportReq request) { List saasPageElements = Lists.newArrayList(); @@ -281,4 +310,21 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { } }); } + + public List listDescendantByUniCodeAndTerminal(String terminal, List uniCodes) { + List pageResources = saasFeatureResourceDao.lambdaQuery() + .eq(SaasFeatureResource::getTerminal, terminal) + .in(SaasFeatureResource::getUniCode, uniCodes) + .eq(SaasFeatureResource::getFeatureType, FeatureResourceType.PAGE.getCode()) + .orderByDesc(BaseEntity::getId) + .list(); + if (CollectionUtils.isEmpty(pageResources)) { + log.warn("页面资源(featureResource)不存在。 terminal:{} uniCodes:{}", terminal, uniCodes); + return Collections.emptyList(); + } + return saasFeatureResourceDao.lambdaQuery() + .eq(SaasFeatureResource::getTerminal, terminal) + .and(w -> pageResources.forEach(p -> w.or().likeRight(SaasFeatureResource::getPath, p.getPath()))) + .list(); + } } From 58362775aeded6a99517b732a868153e59ac8a0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Fri, 21 Jun 2024 14:24:44 +0800 Subject: [PATCH 15/69] =?UTF-8?q?feat(REQ-2545):=20=E4=BA=A7=E5=93=81?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/tyr/client/feign/ProductApi.java | 15 ++- .../model/product/ProductDetailReq.java | 34 ++++++ .../product/ProductFeatureRelationVO.java | 5 + .../tyr/client/model/product/ProductVO.java | 33 ++++++ .../tyr/client/model/req/ProductSaveReq.java | 22 ++++ .../server/controller/PrivateController.java | 1 + .../controller/product/ProductController.java | 17 ++- .../server/repository/SaasBasicDictDao.java | 4 +- .../SaasProductModuleFeatureRelation.java | 11 ++ .../ProductFeatureRelationService.java | 10 ++ .../tyr/server/service/ProductService.java | 2 +- .../ProductFeatureRelationServiceImpl.java | 52 ++++++++- .../service/impl/ProductServiceImpl.java | 105 +++++++++++++++--- 13 files changed, 273 insertions(+), 38 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/product/ProductDetailReq.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/ProductApi.java b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/ProductApi.java index d3338727..b9923753 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/ProductApi.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/ProductApi.java @@ -2,14 +2,7 @@ package cn.axzo.tyr.client.feign; import cn.axzo.framework.domain.web.result.ApiPageResult; import cn.axzo.framework.domain.web.result.ApiResult; -import cn.axzo.tyr.client.model.product.ProductAddReq; -import cn.axzo.tyr.client.model.product.ProductFeatureRelationSearchReq; -import cn.axzo.tyr.client.model.product.ProductFeatureRelationUpdateReq; -import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO; -import cn.axzo.tyr.client.model.product.ProductSearchListReq; -import cn.axzo.tyr.client.model.product.ProductSearchPageReq; -import cn.axzo.tyr.client.model.product.ProductUpdateReq; -import cn.axzo.tyr.client.model.product.ProductVO; +import cn.axzo.tyr.client.model.product.*; import cn.axzo.tyr.client.model.req.ProductSaveReq; import cn.axzo.tyr.client.model.req.UpdateProductStatusReq; import cn.axzo.tyr.client.model.res.GovernmentTerminalResp; @@ -155,4 +148,10 @@ public interface ProductApi { */ @GetMapping("api/auth/product/getWorkspaceProduct") ApiResult getWorkspaceProduct(@RequestParam @NotNull(message = "workspaceType不能为空") String workspaceType); + + /** + * 获取指定ID的产品详细信息 + */ + @PostMapping("api/auth/product/getDetail") + ApiResult getDetail(@Validated @RequestBody ProductDetailReq req); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/product/ProductDetailReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/product/ProductDetailReq.java new file mode 100644 index 00000000..3f0dbec4 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/product/ProductDetailReq.java @@ -0,0 +1,34 @@ +package cn.axzo.tyr.client.model.product; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/20 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ProductDetailReq { + + /** + * 产品ID + */ + @NotNull(message = "产品ID不能为空") + @Min(value = 1, message = "") + private Long productId; + + /** + * 是否查询功能权限点 + */ + @Builder.Default + private Boolean queryFeatureScope = Boolean.FALSE; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/product/ProductFeatureRelationVO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/product/ProductFeatureRelationVO.java index 2f7cf654..e8a962c9 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/product/ProductFeatureRelationVO.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/product/ProductFeatureRelationVO.java @@ -40,4 +40,9 @@ public class ProductFeatureRelationVO { * 权限点 ID */ private Long featureId; + + /** + * 关联类型(0:saas_feature,1:saas_feature_resource) + */ + private Integer type; } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/product/ProductVO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/product/ProductVO.java index 06da4b01..c35f4baf 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/product/ProductVO.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/product/ProductVO.java @@ -8,6 +8,7 @@ import lombok.experimental.Accessors; import java.util.Date; import java.util.List; +import java.util.Set; /** * 产品模型 @@ -144,6 +145,16 @@ public class ProductVO { */ private List featureScopes; + /** + * 新老产品标记,前端确认查询权限树的接口。0:旧权限,1:新权限树 + */ + private Integer relationType; + + /** + * 功能范围(非政务产品) + */ + private List relations; + @Data @Builder @NoArgsConstructor @@ -209,4 +220,26 @@ public class ProductVO { */ private String featureResourceName; } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class ProductFeatureRelation { + + /** + * 单位类型 + */ + private Long dictCodeId; + + /** + * 总数 + */ + private Integer totalCount; + + /** + * 勾选的最末级 feature 的 ID 集合 + */ + private List featureIds; + } } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ProductSaveReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ProductSaveReq.java index ffbf15d5..d53f501b 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ProductSaveReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ProductSaveReq.java @@ -11,6 +11,7 @@ import javax.validation.constraints.Min; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.util.List; +import java.util.Set; /** * @author likunpeng @@ -163,5 +164,26 @@ public class ProductSaveReq { * 政务端featureResourceId */ private List governmentFeatureResourceIds; + + /** + * 产品与功能点的关联关系 + */ + private List relations; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class ProductFeatureRelation { + /** + * 单位类型 + */ + private Long dictCodeId; + + /** + * 勾选的最末级 feature 的 ID 集合 + */ + private Set featureIds; } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java index c2a2f12c..842d1521 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java @@ -307,6 +307,7 @@ public class PrivateController { return tyrSaasAuthService.authPermission(request); } + /** 刷新表saas_pgroup_permission_relation的type字段 **/ @PostMapping("/api/private/pgroupPermissionRelation/refresh") public ApiResult refreshPgroupPermissionRelation(@Validated @RequestBody RefreshPgroupPermissionRelationParam request) { List workspaceTypes = Lists.newArrayList(3,6); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/product/ProductController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/product/ProductController.java index 10bf85de..316874ee 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/product/ProductController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/product/ProductController.java @@ -3,14 +3,7 @@ package cn.axzo.tyr.server.controller.product; import cn.axzo.framework.domain.web.result.ApiPageResult; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.tyr.client.feign.ProductApi; -import cn.axzo.tyr.client.model.product.ProductAddReq; -import cn.axzo.tyr.client.model.product.ProductFeatureRelationSearchReq; -import cn.axzo.tyr.client.model.product.ProductFeatureRelationUpdateReq; -import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO; -import cn.axzo.tyr.client.model.product.ProductSearchListReq; -import cn.axzo.tyr.client.model.product.ProductSearchPageReq; -import cn.axzo.tyr.client.model.product.ProductUpdateReq; -import cn.axzo.tyr.client.model.product.ProductVO; +import cn.axzo.tyr.client.model.product.*; import cn.axzo.tyr.client.model.req.ProductSaveReq; import cn.axzo.tyr.client.model.req.UpdateProductStatusReq; import cn.axzo.tyr.client.model.res.GovernmentTerminalResp; @@ -72,7 +65,7 @@ public class ProductController implements ProductApi { */ @Override public ApiResult getById(Long id) { - return productService.getById(id); + return productService.getById(id, Boolean.FALSE); } /** @@ -159,6 +152,7 @@ public class ProductController implements ProductApi { */ @Override public ApiResult saveOrUpdate(ProductSaveReq req) { + permissionCacheService.markTempDisable(PermissionCacheKey.builder().disableAll(true).build()); return productService.saveOrUpdate(req); } @@ -183,4 +177,9 @@ public class ProductController implements ProductApi { public ApiResult getWorkspaceProduct(String workspaceType) { return productService.getWorkspaceProduct(workspaceType); } + + @Override + public ApiResult getDetail(ProductDetailReq req) { + return productService.getById(req.getProductId(), req.getQueryFeatureScope()); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/SaasBasicDictDao.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/SaasBasicDictDao.java index 82516fe2..36e98ade 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/SaasBasicDictDao.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/SaasBasicDictDao.java @@ -12,6 +12,7 @@ import cn.axzo.tyr.server.repository.mapper.SaasBasicDictMapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.apache.commons.collections4.CollectionUtils; import org.springframework.stereotype.Service; import java.util.List; @@ -33,7 +34,8 @@ public class SaasBasicDictDao extends ServiceImpl updateFeatureRelation(List req); + void updateFeatureResourceRelation(List req); + ApiResult> featureListByProduct(List productIds); /** @@ -37,4 +39,12 @@ public interface ProductFeatureRelationService { boolean refreshFeature(Integer workspaceType, Long productId); void removeByProductId(Long productId); + + /** + * 新增、编辑产品时做新老产品判断时使用 + * + * @param productId + * @return + */ + SaasProductModuleFeatureRelation getOneByProductId(Long productId); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductService.java index 1b5eb975..9ea8aaf1 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductService.java @@ -26,7 +26,7 @@ public interface ProductService { ApiPageResult page(ProductSearchPageReq req); - ApiResult getById(Long id); + ApiResult getById(Long id, Boolean queryFeatureScope); ApiResult add(ProductAddReq req); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductFeatureRelationServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductFeatureRelationServiceImpl.java index 9931d60f..3d1b5678 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductFeatureRelationServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductFeatureRelationServiceImpl.java @@ -14,8 +14,10 @@ import cn.axzo.tyr.client.model.product.ProductFeatureRelationUpdateReq; import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO; import cn.axzo.tyr.server.repository.dao.ProductModuleDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; +import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; import cn.axzo.tyr.server.repository.entity.ProductFeatureQuery; import cn.axzo.tyr.server.repository.entity.SaasFeature; +import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; import cn.axzo.tyr.server.repository.dao.SaasProductModuleFeatureRelationDao; import cn.axzo.tyr.server.service.ProductFeatureRelationService; @@ -64,7 +66,8 @@ public class ProductFeatureRelationServiceImpl implements ProductFeatureRelation private final SaasProductModuleFeatureRelationDao saasProductModuleFeatureRelationDao; private final ServicePkgClient servicePkgClient; private final SaasFeatureDao saasFeatureDao; - private final ProductModuleDao productModuleDao; + private final ProductModuleDao productModuleDao; + private final SaasFeatureResourceDao saasFeatureResourceDao; @Override public ApiResult> featureList(ProductFeatureRelationSearchReq req) { @@ -98,6 +101,43 @@ public class ProductFeatureRelationServiceImpl implements ProductFeatureRelation return ApiResult.ok(true); } + @Override + @Transactional(rollbackFor = Exception.class) + public void updateFeatureResourceRelation(List req) { + List productIds = req.stream().map(ProductFeatureRelationUpdateReq::getProductModuleId).distinct().collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(productIds)) { + saasProductModuleFeatureRelationDao.remove(new LambdaQueryWrapper() + .in(SaasProductModuleFeatureRelation::getProductModuleId, productIds)); + } + + Set allFeatureResourceIds = req.stream().map(ProductFeatureRelationUpdateReq::getFeatureIds) + .filter(CollectionUtil::isNotEmpty).flatMap(List::stream).collect(Collectors.toSet()); + if (CollectionUtil.isEmpty(allFeatureResourceIds)) { + log.warn("product has no featureResourceIds to bind."); + return; + } + Map resourceMap = saasFeatureResourceDao.lambdaQuery() + .in(BaseEntity::getId, allFeatureResourceIds) + .list().stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity(), (v1, v2) -> v1)); + + List saveList = new ArrayList<>(); + req.forEach(i -> i.getFeatureIds().forEach(featureId -> { + SaasFeatureResource saasFeatureResource = resourceMap.get(featureId); + SaasProductModuleFeatureRelation relation = new SaasProductModuleFeatureRelation(); + relation.setProductModuleId(i.getProductModuleId()); + relation.setDictCodeId(i.getDictCodeId()); + relation.setDictCode(i.getDictCode()); + relation.setFeatureId(featureId); + relation.setType(Objects.isNull(i.getFeatureRelationType()) ? 0 : i.getFeatureRelationType()); + if (Objects.nonNull(saasFeatureResource)) { + relation.setFeatureType(saasFeatureResource.getFeatureType()); + relation.setTerminal(saasFeatureResource.getTerminal()); + } + saveList.add(relation); + })); + saasProductModuleFeatureRelationDao.saveBatch(saveList); + } + @Override public ApiResult> featureListByProduct(List productIds) { if (CollectionUtil.isEmpty(productIds)) { @@ -235,4 +275,14 @@ public class ProductFeatureRelationServiceImpl implements ProductFeatureRelation public void removeByProductId(Long productId) { saasProductModuleFeatureRelationDao.removeByProductId(Collections.singletonList(productId)); } + + @Override + public SaasProductModuleFeatureRelation getOneByProductId(Long productId) { + List list = saasProductModuleFeatureRelationDao.lambdaQuery() + .eq(SaasProductModuleFeatureRelation::getProductModuleId, productId) + .orderByDesc(BaseEntity::getId) + .last("LIMIT 1") + .list(); + return org.apache.commons.collections4.CollectionUtils.isEmpty(list) ? null : list.get(0); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductServiceImpl.java index 5a81c75c..0bad980b 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductServiceImpl.java @@ -8,6 +8,7 @@ import cn.axzo.framework.domain.web.result.ApiPageResult; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.common.enums.ProductModuleFeatureRelationTypeEnum; +import cn.axzo.tyr.client.model.dict.request.BasicDictQueryReq; import cn.axzo.tyr.client.model.dict.response.BasicDictNodeResp; import cn.axzo.tyr.client.model.enums.ProductModuleCategoryEnum; import cn.axzo.tyr.client.model.enums.WorkspaceTypeCodeEnum; @@ -19,6 +20,7 @@ import cn.axzo.tyr.client.model.res.WorkspaceProductResp; import cn.axzo.tyr.server.repository.entity.ProductModule; import cn.axzo.tyr.server.repository.dao.ProductModuleDao; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; +import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductService; import cn.axzo.tyr.server.service.SaasBasicDictService; @@ -27,16 +29,17 @@ import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.google.common.collect.Lists; import com.google.common.collect.Sets; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.compress.utils.Lists; +import org.apache.commons.collections4.CollectionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; /** @@ -65,7 +68,7 @@ public class ProductServiceImpl implements ProductService { .eq(Objects.nonNull(req.getAuthType()),ProductModule::getAuthType,req.getAuthType()) .eq(ProductModule::getIsDelete, 0); StringBuilder condition = new StringBuilder(); - if (org.apache.commons.collections.CollectionUtils.isNotEmpty(req.getOuTypes())) { + if (CollectionUtils.isNotEmpty(req.getOuTypes())) { condition = new StringBuilder(); for (Integer value : req.getOuTypes()) { condition.append(" FIND_IN_SET('" + value + "', ou_type) OR"); @@ -104,13 +107,13 @@ public class ProductServiceImpl implements ProductService { } @Override - public ApiResult getById(Long id) { + public ApiResult getById(Long id, Boolean queryFeatureScope) { ProductModule byId = productModuleDao.getById(id); ProductVO productVO = BeanMapper.copyBean(byId, ProductVO.class); productVO.setOuTypes(byId.parseOuType()); productVO.setProductCategoryDesc(ProductModuleCategoryEnum.getDescByCode(productVO.getCategory())); productVO.setDictWorkspaceTypeDesc(WorkspaceTypeCodeEnum.getDescByCode(productVO.getDictWorkspaceTypeCode())); - productVO.setSkus(org.apache.commons.collections.CollectionUtils.isEmpty(byId.getSkus()) ? Collections.emptyList() + productVO.setSkus(CollectionUtils.isEmpty(byId.getSkus()) ? Collections.emptyList() : byId.getSkus().stream().map(e -> ProductVO.Sku.builder() .skuName(e.getSkuName()) .model(e.getModel()) @@ -122,8 +125,19 @@ public class ProductServiceImpl implements ProductService { .videos(byId.getMaterial().getVideos()) .detailImages(byId.getMaterial().getDetailImages()) .build()); - if (WorkspaceTypeCodeEnum.GOVERNMENT.getCode().equals(productVO.getDictWorkspaceTypeCode())) { - fillFeatureScope(productVO); + if (Boolean.TRUE.equals(queryFeatureScope)) { + if (WorkspaceTypeCodeEnum.GOVERNMENT.getCode().equals(productVO.getDictWorkspaceTypeCode())) { + fillFeatureScope(productVO); + } else { + fillNonGaFeatureRelation(productVO); + } + } else { + ProductFeatureRelationSearchReq req = new ProductFeatureRelationSearchReq(); + req.setProductModuleId(id); + ApiResult> result = productFeatureRelationService.featureList(req); + if (CollectionUtils.isNotEmpty(result.getData())) { + productVO.setRelationType(result.getData().get(0).getType()); + } } return ApiResult.ok(productVO); } @@ -216,6 +230,8 @@ public class ProductServiceImpl implements ProductService { // 保存商品权限信息 if (WorkspaceTypeCodeEnum.GOVERNMENT.getCode().equals(productModule.getDictWorkspaceTypeCode())) { saveGovernmentFeatureResource(productModule.getId(), productModule.getDictWorkspaceTypeId(), productModule.getDictWorkspaceTypeCode(), req.getFeatureScope().getGovernmentFeatureResourceIds()); + } else { + saveNonGaFeatureResource(productModule.getId(), req.getFeatureScope().getRelations()); } return ApiResult.ok(productModule.getId()); } @@ -287,16 +303,18 @@ public class ProductServiceImpl implements ProductService { ProductModuleCategoryEnum productModuleCategoryEnum = ProductModuleCategoryEnum.getByCode(req.getProductCategory()); AssertUtil.notNull(productModuleCategoryEnum, "产品类型有误"); -// if (WorkspaceTypeCodeEnum.GENERAL_ENT.equals(workspaceTypeCodeEnum) || WorkspaceTypeCodeEnum.GENERAL_PROJECT.equals(workspaceTypeCodeEnum)) { -// AssertUtil.notNull(req.getMaxPersonCount(), "人数上限不能为空"); -// AssertUtil.notNull(req.getPrice(), "价格不能为空"); -// if (ProductModuleCategoryEnum.PRODUCT_VERSION.getCode().equals(req.getProductCategory())) { -// AssertUtil.notNull(req.getVersion(), "版本升级序列不能为空"); -// } -// } if (WorkspaceTypeCodeEnum.GOVERNMENT.equals(workspaceTypeCodeEnum)) { AssertUtil.isTrue(Objects.nonNull(req.getFeatureScope()) - && org.apache.commons.collections4.CollectionUtils.isNotEmpty(req.getFeatureScope().getGovernmentFeatureResourceIds()), "功能范围选择有误"); + && CollectionUtils.isNotEmpty(req.getFeatureScope().getGovernmentFeatureResourceIds()), "功能范围选择有误"); + } else { + if (Objects.isNull(req.getId())) { + AssertUtil.isTrue(Objects.nonNull(req.getFeatureScope()) + && CollectionUtils.isNotEmpty(req.getFeatureScope().getRelations()), "产品的功能范围选择有误"); + } else { + SaasProductModuleFeatureRelation oneRelation = productFeatureRelationService.getOneByProductId(req.getId()); + AssertUtil.isTrue(Objects.isNull(oneRelation) + || ProductModuleFeatureRelationTypeEnum.FEATURE_RESOURCE.getCode().equals(oneRelation.getType()), "请在老的产品管理菜单编辑产品权限。"); + } } productModule.setProductName(req.getProductName()); productModule.setIcon(req.getIcon()); @@ -309,7 +327,7 @@ public class ProductServiceImpl implements ProductService { productModule.setMaxPersonCount(req.getMaxPersonCount()); productModule.setMaxWorkspaceCount(req.getMaxWorkspaceCount()); productModule.setPrice(req.getPrice()); - productModule.setSkus(org.apache.commons.collections.CollectionUtils.isEmpty(req.getSkus()) ? Lists.newArrayList() + productModule.setSkus(CollectionUtils.isEmpty(req.getSkus()) ? Lists.newArrayList() : req.getSkus().stream().map(e -> ProductModule.Sku.builder() .skuName(e.getSkuName()) .model(e.getModel()) @@ -339,7 +357,7 @@ public class ProductServiceImpl implements ProductService { req.setDictCodeId(dictWorkspaceTypeId); req.setDictCode(dictWorkspaceTypeCode); req.setProductModuleId(productId); - Set featureIds = org.apache.commons.collections.CollectionUtils.isEmpty(frs) ? Sets.newHashSet() + Set featureIds = CollectionUtils.isEmpty(frs) ? Sets.newHashSet() : frs.stream().map(BaseEntity::getId).collect(Collectors.toSet()); featureIds.addAll(rootFeatureIds); req.getFeatureIds().addAll(featureIds); @@ -347,15 +365,44 @@ public class ProductServiceImpl implements ProductService { productFeatureRelationService.updateFeatureRelation(Collections.singletonList(req)); } + /** + * 保存非政务端产品功能权限 + */ + private void saveNonGaFeatureResource(Long productId, List relations) { + List dictCodeIds = Lists.newArrayList(); + for (ProductSaveReq.ProductFeatureRelation relation : relations) { + AssertUtil.notNull(relation.getDictCodeId(), "功能范围选择的字典ID不能未空。"); + dictCodeIds.add(relation.getDictCodeId()); + } + + Map nodeMap = saasBasicDictService.getBasicDictNodeList(BasicDictQueryReq.builder().ids(dictCodeIds).build()) + .stream().collect(Collectors.toMap(BasicDictNodeResp::getId, Function.identity(), (v1, v2) -> v1)); + + List reqs = Lists.newArrayList(); + for (ProductSaveReq.ProductFeatureRelation relation : relations) { + ProductFeatureRelationUpdateReq req = new ProductFeatureRelationUpdateReq(); + req.setDictCodeId(relation.getDictCodeId()); + req.setDictCode(nodeMap.getOrDefault(relation.getDictCodeId(), new BasicDictNodeResp()).getCode()); + req.setProductModuleId(productId); + if (CollectionUtils.isNotEmpty(relation.getFeatureIds())) { + req.getFeatureIds().addAll(relation.getFeatureIds()); + } + req.setFeatureRelationType(ProductModuleFeatureRelationTypeEnum.FEATURE_RESOURCE.getCode()); + reqs.add(req); + } + productFeatureRelationService.updateFeatureResourceRelation(reqs); + } + private void fillFeatureScope(ProductVO product) { ProductFeatureRelationSearchReq req = new ProductFeatureRelationSearchReq(); req.setProductModuleId(product.getId()); req.setDictCodeId(product.getDictWorkspaceTypeId()); req.setDictCode(product.getDictWorkspaceTypeCode()); ApiResult> result = productFeatureRelationService.featureList(req); - if (org.apache.commons.collections.CollectionUtils.isEmpty(result.getData())) { + if (CollectionUtils.isEmpty(result.getData())) { return; } + product.setRelationType(result.getData().get(0).getType()); List featureIds = result.getData().stream().map(ProductFeatureRelationVO::getFeatureId).collect(Collectors.toList()); List featureResources = saasFeatureResourceService.listByParentIdAndTerminalAndIds(0L, TerminalInfo.NT_PC_GA_GENERAL, featureIds); if (CollectionUtil.isNotEmpty(featureResources)) { @@ -366,6 +413,28 @@ public class ProductServiceImpl implements ProductService { } } + private void fillNonGaFeatureRelation(ProductVO product) { + ProductFeatureRelationSearchReq req = new ProductFeatureRelationSearchReq(); + req.setProductModuleId(product.getId()); + ApiResult> result = productFeatureRelationService.featureList(req); + if (CollectionUtils.isEmpty(result.getData())) { + return; + } + product.setRelationType(result.getData().get(0).getType()); + + Map> relationMap = result.getData().stream().collect(Collectors.groupingBy(ProductFeatureRelationVO::getDictCodeId)); + List relations = Lists.newArrayList(); + relationMap.forEach((k, v) -> { + ProductVO.ProductFeatureRelation pr = ProductVO.ProductFeatureRelation.builder() + .dictCodeId(k) + .totalCount(v.size()) + .featureIds(v.stream().map(ProductFeatureRelationVO::getFeatureId).collect(Collectors.toList())) + .build(); + relations.add(pr); + }); + product.setRelations(relations); + } + private WorkspaceProductResp.Product buildRespProduct(ProductModule pm) { return Optional.ofNullable(pm).map(e -> WorkspaceProductResp.Product.builder() .productId(e.getId()) From 30eaf00d106e1764e2cc6c6bbabff69f03c489eb Mon Sep 17 00:00:00 2001 From: lilong Date: Mon, 24 Jun 2024 17:01:30 +0800 Subject: [PATCH 16/69] =?UTF-8?q?feat:(REQ-2545)=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=96=B0=E7=9A=84=E6=9F=A5=E8=AF=A2=E8=8F=9C=E5=8D=95=E7=9A=84?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/feign/PermissionQueryApi.java | 13 ++ .../req/PagePgroupPermissionRelationReq.java | 22 ++ .../model/req/PageSaasFeatureResourceReq.java | 46 +++++ .../client/model/req/PermissionCheckReq.java | 4 +- .../client/model/req/TreePermissionReq.java | 49 +++++ .../model/res/SaasPermissionRelationRes.java | 28 +++ .../tyr/client/model/res/SaasRoleRes.java | 5 + .../client/model/res/TreePermissionResp.java | 95 +++++++++ .../model/roleuser/dto/SaasRoleUserV2DTO.java | 17 ++ .../req/ListRoleUserRelationParam.java | 19 ++ .../permission/PermissionQueryController.java | 7 + .../entity/ProductFeatureQuery.java | 11 + .../entity/SaasFeatureResource.java | 10 + .../entity/SaasPgroupPermissionRelation.java | 5 + .../SaasProductModuleFeatureRelation.java | 1 - .../service/PermissionQueryService.java | 10 + .../axzo/tyr/server/service/RoleService.java | 47 ++--- .../service/SaasFeatureResourceService.java | 20 +- .../SaasPgroupPermissionRelationService.java | 2 + .../service/WorkspaceProductService.java | 62 ++++++ .../impl/PermissionQueryServiceImpl.java | 189 +++++++++++++++++- .../ProductFeatureRelationServiceImpl.java | 33 +-- .../server/service/impl/RoleServiceImpl.java | 149 +++++++++----- .../impl/SaasFeatureResourceServiceImpl.java | 101 +++------- ...asPgroupPermissionRelationServiceImpl.java | 27 +++ .../impl/SaasRoleUserRelationServiceImpl.java | 16 +- .../impl/WorkspaceProductServiceImpl.java | 106 ++++++++++ 27 files changed, 913 insertions(+), 181 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageSaasFeatureResourceReq.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/TreePermissionReq.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasPermissionRelationRes.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/res/TreePermissionResp.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/WorkspaceProductService.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/WorkspaceProductServiceImpl.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PermissionQueryApi.java b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PermissionQueryApi.java index a555dc04..3c77b8ff 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PermissionQueryApi.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/PermissionQueryApi.java @@ -5,10 +5,12 @@ import cn.axzo.tyr.client.model.req.NavTreeReq; import cn.axzo.tyr.client.model.req.PagePermissionReq; import cn.axzo.tyr.client.model.req.PagePermissionResp; import cn.axzo.tyr.client.model.req.PermissionCheckReq; +import cn.axzo.tyr.client.model.req.TreePermissionReq; import cn.axzo.tyr.client.model.req.TreeProductFeatureResourceReq; import cn.axzo.tyr.client.model.res.FeatureResourceDTO; import cn.axzo.tyr.client.model.res.NavTreeResp; import cn.axzo.tyr.client.model.res.ProductFeatureResourceResp; +import cn.axzo.tyr.client.model.res.TreePermissionResp; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; @@ -29,6 +31,7 @@ public interface PermissionQueryApi { /** 返回有权限的导航菜单页面 **/ @PostMapping(value = "/api/v3/permission/query/getNavTree") + @Deprecated ApiResult> getNavTree(@RequestBody @Valid NavTreeReq req); /** 页面权限详情:页面自身及所有下级 **/ @@ -54,4 +57,14 @@ public interface PermissionQueryApi { */ @PostMapping(value = "/api/v3/productPermission/list") ApiResult> listFeatureResource(@RequestBody @Validated TreeProductFeatureResourceReq request); + + /** + * 查询用户有权限的菜单资源树 + * getNavTree已经废弃,不在原方法上改的原因:OMS端现在没有保存角色的菜单权限,且不通用,不能传入指定类型的节点和树种某个节点下的子节点 + * 待oms端把菜单的权限点保存且使用前端的页面元素后就可以切换这个接口 + * @param req + * @return + */ + @PostMapping(value = "/api/v3/permission/featureResource/tree") + ApiResult> treePermission(@RequestBody @Validated TreePermissionReq req); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PagePgroupPermissionRelationReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PagePgroupPermissionRelationReq.java index ffb9ab6d..4442ee16 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PagePgroupPermissionRelationReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PagePgroupPermissionRelationReq.java @@ -3,6 +3,7 @@ package cn.axzo.tyr.client.model.req; import cn.axzo.foundation.dao.support.wrapper.CriteriaField; import cn.axzo.foundation.dao.support.wrapper.Operator; import cn.axzo.foundation.page.IPageReq; +import cn.axzo.tyr.client.common.enums.FeatureResourceType; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -30,4 +31,25 @@ public class PagePgroupPermissionRelationReq implements IPageReq { @CriteriaField(field = "id", operator = Operator.IN) private List ids; + + @CriteriaField(field = "groupId", operator = Operator.IN) + private List groupIds; + + @CriteriaField(field = "featureId", operator = Operator.IN) + private List featureIds; + + @CriteriaField(field = "type", operator = Operator.EQ) + private Integer type; + + /** + * 查询菜单树节点类型 + */ + @CriteriaField(ignore = true) + private List featureResourceTypes; + + /** + * 端,查询权限点时,会根据端过滤,增加效率,目前只有CMS端的新版本才冗余了端 + */ + @CriteriaField(ignore = true) + private String terminal; } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageSaasFeatureResourceReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageSaasFeatureResourceReq.java new file mode 100644 index 00000000..2bd0ef57 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageSaasFeatureResourceReq.java @@ -0,0 +1,46 @@ +package cn.axzo.tyr.client.model.req; + +import cn.axzo.foundation.dao.support.wrapper.CriteriaField; +import cn.axzo.foundation.dao.support.wrapper.Operator; +import cn.axzo.foundation.page.IPageReq; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PageSaasFeatureResourceReq implements IPageReq { + + @CriteriaField(ignore = true) + Integer page; + + @CriteriaField(ignore = true) + Integer pageSize; + + /** + * 排序:使用示例,createTime__DESC + */ + @CriteriaField(ignore = true) + List sort; + + @CriteriaField(field = "id", operator = Operator.IN) + private List ids; + + /** + * 授权类型0-全部角色 1-指定角色 + * FeatureResourceAuthType.ALL_ROLE + */ + @CriteriaField(field = "authType", operator = Operator.EQ) + private Integer authType; + + /** + * 资源所属端 + */ + @CriteriaField(field = "terminal", operator = Operator.EQ) + private String terminal; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PermissionCheckReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PermissionCheckReq.java index c354c77a..11064145 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PermissionCheckReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PermissionCheckReq.java @@ -34,6 +34,8 @@ public class PermissionCheckReq { @NotNull(message = "租户ID不能为空") private Long workspaceId; - /** 登录端 **/ + /** + * 登录端,历史的cms和cmp,cm端没有给端,给了会有问题 + */ private String terminal; } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/TreePermissionReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/TreePermissionReq.java new file mode 100644 index 00000000..94aefc5a --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/TreePermissionReq.java @@ -0,0 +1,49 @@ +package cn.axzo.tyr.client.model.req; + +import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.client.model.base.WorkspaceOUPair; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TreePermissionReq { + + @NotNull(message = "人员ID不能为空") + private Long personId; + + /** + * 端 + */ + @NotNull(message = "端不能为空") + private String terminal; + + /** + * 项目与企业 + */ + @NotEmpty(message = "项目与企业对不能为空") + private List workspaceOUPairs; + + /** + * 查询菜单树节点类型 + */ + private List featureResourceTypes; + + /** + * 父节点id + */ + private Long parentFeatureId; + + /** + * 是否需要返回权限码 + */ + private boolean needFeatureCodes; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasPermissionRelationRes.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasPermissionRelationRes.java new file mode 100644 index 00000000..f8ba9b09 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasPermissionRelationRes.java @@ -0,0 +1,28 @@ +package cn.axzo.tyr.client.model.res; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaasPermissionRelationRes { + + /** + * 菜单资源树节点id + */ + private Long featureId; + + /** + * 新旧菜单资源数标识 + */ + private Integer type; + + /** + * 菜单资源树节点类型 + */ + private Integer featureType; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasRoleRes.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasRoleRes.java index d84e548e..cc686432 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasRoleRes.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasRoleRes.java @@ -114,6 +114,11 @@ public class SaasRoleRes { */ private List saasRoleUsers; + /** + * 角色关联的权限点id信息,没有featureCode,直接查询的pgPermissionRelation + */ + private List permissionRelations; + @Data @Builder @NoArgsConstructor diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/TreePermissionResp.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/TreePermissionResp.java new file mode 100644 index 00000000..5eb21fde --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/TreePermissionResp.java @@ -0,0 +1,95 @@ +package cn.axzo.tyr.client.model.res; + + +import cn.axzo.basics.common.model.IBaseTree; +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Set; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TreePermissionResp implements IBaseTree { + + /** + * 菜单树节点id + */ + private Long featureId; + + /** + * 菜单树节点名字 + */ + private String featureName; + + /** + * 菜单资源类型1-菜单 2-页面 3-应用入口 4-组件 5-root节点 6-分组 + */ + private Integer featureType; + + /** + * 跳转类型 1-站内跳转 2-站外跳转 + */ + private Integer redirectType; + + /** + * 资源跳转URI + */ + private String linkUrl; + + /** + * 菜单树节点对应的前端featureCodes + */ + private Set featureCodes; + + /** 图标 **/ + private String icon; + + /** + * 上级资源ID + */ + private Long parentId; + + /** + * 资源状态 0-隐藏 1-展示 + */ + private Integer status; + + /** + * 菜单页面编码,端唯一 + */ + private String uniCode; + + /** + * 菜单树子节点信息 + */ + private List children; + + @JsonIgnore + @Override + public Long getNodeCode() { + return this.getFeatureId(); + } + + @JsonIgnore + @Override + public Long getParentNodeCode() { + return this.getParentId(); + } + + @JsonIgnore + @Override + public List getNodeChildren() { + return this.getChildren(); + } + + @Override + public void setNodeChildren(List nodeChildren) { + this.children = nodeChildren; + } +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/dto/SaasRoleUserV2DTO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/dto/SaasRoleUserV2DTO.java index f548e0d8..0bc3965e 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/dto/SaasRoleUserV2DTO.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/dto/SaasRoleUserV2DTO.java @@ -1,5 +1,6 @@ package cn.axzo.tyr.client.model.roleuser.dto; +import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; import cn.axzo.tyr.client.model.res.SaasPermissionRes; import lombok.AllArgsConstructor; import lombok.Builder; @@ -38,6 +39,17 @@ public class SaasRoleUserV2DTO { * 用户名字 */ private String realName; + + /** + * 单位Id + */ + private Long ouId; + + /** + * 项目id + */ + private Long workspaceId; + } @Data @@ -72,5 +84,10 @@ public class SaasRoleUserV2DTO { * 角色权限 */ private List saasPermissions; + + /** + * 角色关联的权限点id信息,没有featureCode,直接查询的pgPermissionRelation + */ + private List permissionRelations; } } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/req/ListRoleUserRelationParam.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/req/ListRoleUserRelationParam.java index 7bc6c4e5..9bcbb2be 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/req/ListRoleUserRelationParam.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/req/ListRoleUserRelationParam.java @@ -2,6 +2,7 @@ package cn.axzo.tyr.client.model.roleuser.req; import cn.axzo.foundation.dao.support.wrapper.CriteriaField; import cn.axzo.foundation.dao.support.wrapper.Operator; +import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.model.enums.IdentityType; import lombok.AllArgsConstructor; import lombok.Builder; @@ -63,6 +64,24 @@ public class ListRoleUserRelationParam { @CriteriaField(ignore = true) private List featureIds; + @CriteriaField(ignore = true) + private Boolean needPermissionRelation; + + /** + * 查询菜单树节点类型 + */ + @CriteriaField(ignore = true) + private List featureResourceTypes; + + /** + * 新旧权限点,needPermissionRelation = true时最好带上,因为新旧权限点会有冲突的情况发生 + */ + @CriteriaField(ignore = true) + private Integer type; + + @CriteriaField(ignore = true) + private String terminal; + @Data @Builder @NoArgsConstructor diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PermissionQueryController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PermissionQueryController.java index e89272ee..70c389f1 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PermissionQueryController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/PermissionQueryController.java @@ -6,10 +6,12 @@ import cn.axzo.tyr.client.model.req.NavTreeReq; import cn.axzo.tyr.client.model.req.PagePermissionReq; import cn.axzo.tyr.client.model.req.PagePermissionResp; import cn.axzo.tyr.client.model.req.PermissionCheckReq; +import cn.axzo.tyr.client.model.req.TreePermissionReq; import cn.axzo.tyr.client.model.req.TreeProductFeatureResourceReq; import cn.axzo.tyr.client.model.res.FeatureResourceDTO; import cn.axzo.tyr.client.model.res.NavTreeResp; import cn.axzo.tyr.client.model.res.ProductFeatureResourceResp; +import cn.axzo.tyr.client.model.res.TreePermissionResp; import cn.axzo.tyr.server.service.PermissionQueryService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -55,4 +57,9 @@ public class PermissionQueryController implements PermissionQueryApi { public ApiResult> listFeatureResource(TreeProductFeatureResourceReq request) { return ApiResult.ok(permissionService.listFeatureResource(request)); } + + @Override + public ApiResult> treePermission(TreePermissionReq req) { + return ApiResult.ok(permissionService.treePermission(req)); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/ProductFeatureQuery.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/ProductFeatureQuery.java index b72f1969..39d0c16e 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/ProductFeatureQuery.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/ProductFeatureQuery.java @@ -1,5 +1,6 @@ package cn.axzo.tyr.server.repository.entity; +import cn.axzo.tyr.client.common.enums.FeatureResourceType; import lombok.Builder; import lombok.Data; @@ -24,4 +25,14 @@ public class ProductFeatureQuery { private Integer workspaceJoinType; private Set featureIds; + + /** + * 菜单资源数节点类型 + */ + private List featureResourceTypes; + + /** + * 区分新老菜单资源树 + */ + private Integer type; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java index 36d3c024..d080639d 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java @@ -33,6 +33,16 @@ public class SaasFeatureResource extends BaseEntity { */ public static final Long DEFAULT_WORKSPACE_TYPE = 0L; + /** + * 显示状态 + */ + public static final Integer DISPLAY_STATUS = 1; + + /** + * 隐藏状态 + */ + public static final Integer HIDE_STATUS = 0; + /** * 资源编码-权限码 diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPgroupPermissionRelation.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPgroupPermissionRelation.java index 6c689cc6..3ab81d9d 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPgroupPermissionRelation.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPgroupPermissionRelation.java @@ -65,6 +65,11 @@ public class SaasPgroupPermissionRelation extends BaseEntity getNavTree(NavTreeReq req); boolean hasPermission(PermissionCheckReq req); @@ -41,4 +44,11 @@ public interface PermissionQueryService { * @return */ List listFeatureResource(TreeProductFeatureResourceReq request); + + /** + * 查询人的权限点树 + * @param req + * @return + */ + List treePermission(TreePermissionReq req); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java index c804fe92..b693be66 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java @@ -4,12 +4,12 @@ import cn.axzo.foundation.dao.support.wrapper.CriteriaField; import cn.axzo.foundation.dao.support.wrapper.Operator; import cn.axzo.foundation.page.IPageReq; import cn.axzo.framework.domain.page.PageResp; +import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.model.enums.IdentityType; import cn.axzo.tyr.client.model.req.ChangeGroupLeaderRoleReq; import cn.axzo.tyr.client.model.req.FeatureRoleRelationReq; import cn.axzo.tyr.client.model.req.QueryByIdentityIdTypeReq; import cn.axzo.tyr.client.model.req.QueryRoleByNameReq; -import cn.axzo.tyr.client.model.req.QuerySaasRoleGroupReq; import cn.axzo.tyr.client.model.req.QuerySaasRoleReq; import cn.axzo.tyr.client.model.req.RoleWithUserQueryReq; import cn.axzo.tyr.client.model.res.FeatureRoleRelationResp; @@ -28,8 +28,6 @@ import cn.axzo.tyr.server.model.RoleWithFeature; import cn.axzo.tyr.server.repository.entity.SaasFeature; import cn.axzo.tyr.server.repository.entity.SaasRole; import cn.axzo.tyr.server.repository.entity.SaasRoleWithUser; -import cn.axzo.tyr.server.service.impl.TyrSaasAuthServiceImpl; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import lombok.AllArgsConstructor; import lombok.Data; @@ -67,17 +65,6 @@ public interface RoleService extends IService { List listRoleUserByPermissionGroup(List permissionGroupIdList, Set workspaceIds); - - /** - * * 过滤角色的按钮权限 - * * 1.分组上的适用单位类型过滤 - * * 2.角色的例外过滤 - * @param role - * @param userRoleInfoMap - * @return 按钮级别权限点ID - */ - Set filterPermissionPoint(Set role, TyrSaasAuthServiceImpl.OUWRoleInfo userRoleInfoMap); - /** * 通过角色名字获取角色信息 * @param req @@ -88,17 +75,6 @@ public interface RoleService extends IService { /** 分页查询角色含用户 **/ PageResp queryRoleWithUser(RoleWithUserQueryReq req); - /** - * 通过角色类型获取角色 - * @param req - * @param roleTypes - * @return - */ - List queryRoleByRoleTypes(QueryByIdentityIdTypeReq req, List roleTypes); - - List listForOUWorkspace(Long ouId, Long workspaceId, Integer workspaceJoinType); - - List queryInitRoleByWorkspaceId(String workspaceType); /** @@ -187,6 +163,27 @@ public interface RoleService extends IService { */ @CriteriaField(ignore = true) private List featureIds; + + @CriteriaField(ignore = true) + private Boolean needPermissionRelation; + + /** + * 查询菜单树节点类型 + */ + @CriteriaField(ignore = true) + private List featureResourceTypes; + + /** + * 新旧权限点,needPermissionRelation = true时最好带上,因为新旧权限点会有冲突的情况发生 + */ + @CriteriaField(ignore = true) + private Integer type; + + /** + * 端,查询权限点时,会根据端过滤,增加效率,目前只有CMS端的新版本才冗余了端 + */ + @CriteriaField(ignore = true) + private String terminal; } @SuperBuilder diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java index 0cd54a4b..4bc1172e 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java @@ -1,12 +1,14 @@ package cn.axzo.tyr.server.service; +import cn.axzo.foundation.page.PageResp; +import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; import cn.axzo.tyr.server.model.ResourcePermission; import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; -import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; -import io.swagger.models.auth.In; +import com.baomidou.mybatisplus.extension.service.IService; import java.util.List; import java.util.Set; @@ -18,15 +20,12 @@ import java.util.Set; * @author: ZhanSiHu * @date: 2024/4/3 10:17 */ -public interface SaasFeatureResourceService { +public interface SaasFeatureResourceService extends IService { Long saveOrUpdateMenu(FeatureResourceTreeSaveReq req); void updateFeatureAuthType(Long featureId, Integer authType); - /**递归的**/ - List listDescendant(Long featureId); - /**递归的**/ List batchListDescendant(List featureIds); @@ -34,9 +33,6 @@ public interface SaasFeatureResourceService { FeatureResourceTreeNode getTreeFeatureDescendant(Long featureId, Integer featureType); - /**删除指定菜单**/ - void deleteMenuFeature(Long featureId, Long operatorId); - /**菜单重排序**/ void reorderMenuFeature(Long featureId, Integer offset); @@ -53,7 +49,9 @@ public interface SaasFeatureResourceService { Set listAuthFree(); - List listNavMenu(String terminal); - List listByParentIdAndTerminalAndIds(Long parentId, String terminal, List featureIds); + + List list(PageSaasFeatureResourceReq param); + + PageResp page(PageSaasFeatureResourceReq param); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPgroupPermissionRelationService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPgroupPermissionRelationService.java index 5c7e1abf..1c814364 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPgroupPermissionRelationService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPgroupPermissionRelationService.java @@ -16,6 +16,8 @@ public interface SaasPgroupPermissionRelationService extends IService page(PagePgroupPermissionRelationReq param); + List list(PagePgroupPermissionRelationReq param); + @Data @Builder @NoArgsConstructor diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/WorkspaceProductService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/WorkspaceProductService.java new file mode 100644 index 00000000..4bf1cf20 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/WorkspaceProductService.java @@ -0,0 +1,62 @@ +package cn.axzo.tyr.server.service; + +import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Set; + +public interface WorkspaceProductService { + + + List listWorkspaceProduct(WorkspaceProductParam param); + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class WorkspaceProductParam { + /** + * 端 + */ + private String terminal; + + /** + * 项目id + */ + private Set workspaceIds; + + /** + * 查询菜单树节点类型 + */ + private List featureResourceTypes; + + /** + * 区分新老菜单资源树 + */ + private Integer type; + } + + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class WorkspaceProduct { + + /** + * 项目id + */ + private Long workspaceId; + + /** + * 产品资源树关系 + */ + private List saasProductModuleFeatureRelations; + } +} + diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java index b001080c..1feaa34c 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java @@ -11,6 +11,7 @@ import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.thrones.client.saas.ServicePkgClient; import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct; import cn.axzo.thrones.client.saas.entity.servicepkg.ServicePkgDetailRes; +import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType; import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.common.enums.RoleTypeEnum; import cn.axzo.tyr.client.model.base.WorkspaceOUPair; @@ -20,12 +21,18 @@ import cn.axzo.tyr.client.model.req.IdentityAuthReq; import cn.axzo.tyr.client.model.req.NavTreeReq; import cn.axzo.tyr.client.model.req.PagePermissionReq; import cn.axzo.tyr.client.model.req.PagePermissionResp; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.client.model.req.PermissionCheckReq; +import cn.axzo.tyr.client.model.req.TreePermissionReq; import cn.axzo.tyr.client.model.req.TreeProductFeatureResourceReq; import cn.axzo.tyr.client.model.res.FeatureResourceDTO; import cn.axzo.tyr.client.model.res.IdentityAuthRes; import cn.axzo.tyr.client.model.res.NavTreeResp; import cn.axzo.tyr.client.model.res.ProductFeatureResourceResp; +import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; +import cn.axzo.tyr.client.model.res.TreePermissionResp; +import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO; +import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam; import cn.axzo.tyr.server.model.PermissionDO; import cn.axzo.tyr.server.model.PermissionQueryContext; import cn.axzo.tyr.server.model.ResourcePermission; @@ -35,20 +42,28 @@ import cn.axzo.tyr.server.model.UserIdentity; import cn.axzo.tyr.server.model.WorkspaceFeatureRelation; import cn.axzo.tyr.server.repository.dao.ProductModuleDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; +import cn.axzo.tyr.server.repository.dao.SaasPageElementFeatureResourceRelationDao; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; +import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; +import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation; import cn.axzo.tyr.server.service.PermissionQueryService; import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import cn.axzo.tyr.server.service.SaasRoleUserRelationService; import cn.axzo.tyr.server.service.TyrSaasAuthService; +import cn.axzo.tyr.server.service.WorkspaceProductService; import cn.axzo.tyr.server.util.KeyUtil; import cn.axzo.tyr.server.utils.RpcInternalUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; +import com.google.common.collect.Lists; import com.google.common.collect.Sets; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Value; @@ -56,6 +71,7 @@ import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Service; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -63,10 +79,14 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import static cn.axzo.tyr.server.repository.entity.SaasFeatureResource.DISPLAY_STATUS; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; + /** * 权限查询服务实现 * @@ -88,6 +108,10 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { private final ProductModuleDao productModuleDao; private final ProductFeatureRelationService productFeatureRelationService; private final SaasFeatureResourceDao saasFeatureResourceDao; + private final SaasFeatureResourceService saasFeatureResourceService; + private final SaasRoleUserRelationService saasRoleUserRelationService; + private final WorkspaceProductService workspaceProductService; + private final SaasPageElementFeatureResourceRelationDao saasPageElementFeatureResourceRelationDao; @Value("${use.old.auth:true}") private boolean USE_OLD_AUTH; @@ -103,7 +127,6 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { //查询权限 List permissions = queryUserPermission(context); -// List permissions = queryAllPermission(context); if (CollectionUtil.isEmpty(permissions)) { return Collections.emptyList(); } @@ -204,7 +227,6 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .appendPersonId(req.getPersonId()); //查询权限 List permissions = queryUserPermission(context); -// List permissions = queryAllPermission(context); Set featureIds = permissions.stream().map(PermissionDO::getFeatureIds).flatMap(Set::stream).collect(Collectors.toSet()); //权限过滤 return resourceList.stream() @@ -252,6 +274,61 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .collect(Collectors.toList()); } + @Override + public List treePermission(TreePermissionReq req) { + + Set featureIds = listUserPermissionFeatureIds(req); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyList(); + } + + List saasFeatureResources = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() + .ids(Lists.newArrayList(featureIds)) + .terminal(req.getTerminal()) + .sort(Lists.newArrayList("displayOrder__ASC")) + .build()); + // 有可能存在资源树被删除的情况 + if (CollectionUtils.isEmpty(saasFeatureResources)) { + return Collections.emptyList(); + } + + Map> featureCodes = listFeatureCodes(saasFeatureResources, req); + + List treePermissionResps = saasFeatureResources.stream() + .map(e -> TreePermissionResp.builder() + .featureId(e.getId()) + .featureName(e.getFeatureName()) + .featureType(e.getFeatureType()) + .redirectType(e.getRedirectType()) + .linkUrl(e.getLinkUrl()) + .icon(e.getIcon()) + .parentId(e.getParentId()) + .status(e.getStatus()) + .uniCode(e.getUniCode()) + .featureCodes(featureCodes.get(e.getUniCode())) + .build()) + .collect(Collectors.toList()); + // 组装导航树 + // 过滤掉隐藏的节点,因为存在某些节点被隐藏,需要把这些节点和子节点给过滤掉 + return TreeUtil.buildTree(treePermissionResps, (Function) e -> Objects.equals(DISPLAY_STATUS, e.getStatus())); + } + + private Map> listFeatureCodes(List saasFeatureResources, + TreePermissionReq req) { + + if (CollectionUtils.isEmpty(saasFeatureResources) || BooleanUtils.isNotTrue(req.isNeedFeatureCodes())) { + return Collections.emptyMap(); + } + + List uniCodes = saasFeatureResources.stream() + .map(SaasFeatureResource::getUniCode) + .collect(Collectors.toList()); + return saasPageElementFeatureResourceRelationDao.listByUniCodeAndTerminal(uniCodes, req.getTerminal()).stream() + .collect(Collectors.groupingBy(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode, + Collectors.mapping(SaasPageElementFeatureResourceRelation::getPageElementCode, Collectors.toSet()))); + } + private List getProductFeatureRelationByWorkspace(Set workspaceIds) { List servicePkgDetailRes = RpcInternalUtil.rpcListProcessor(() -> servicePkgClient.getServicePkgDetailBySpaceId(workspaceIds), "查询租户的产品", workspaceIds).getData(); @@ -487,4 +564,112 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { } return relations; } + + private Set listUserPermissionFeatureIds(TreePermissionReq treePermissionReq) { + + List workspaceOuPairs = treePermissionReq.getWorkspaceOUPairs().stream() + .map(e -> ListRoleUserRelationParam.WorkspaceOuPair.builder() + .workspaceId(e.getWorkspaceId()) + .ouId(e.getOuId()) + .build()) + .collect(Collectors.toList()); + + ListRoleUserRelationParam listRoleUserRelationParam = ListRoleUserRelationParam.builder() + .personId(treePermissionReq.getPersonId()) + .workspaceOuPairs(Lists.newArrayList(workspaceOuPairs)) + .needRole(true) + .needPermissionRelation(true) + .featureResourceTypes(treePermissionReq.getFeatureResourceTypes()) + .type(NEW_FEATURE) + .terminal(treePermissionReq.getTerminal()) + .build(); + List saasRoleUserV2DTOS = saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream() + .filter(e -> e.getSaasRole() != null && CollectionUtils.isNotEmpty(e.getSaasRole().getPermissionRelations())) + .collect(Collectors.toList()); + + if (CollectionUtil.isEmpty(saasRoleUserV2DTOS)) { + log.warn("no user role relation found"); + return Collections.emptySet(); + } + //查询租户产品权限点 + Set workspaceIds = treePermissionReq.getWorkspaceOUPairs().stream() + .map(WorkspaceOUPair::getWorkspaceId) + .collect(Collectors.toSet()); + WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() + .terminal(treePermissionReq.getTerminal()) + .workspaceIds(workspaceIds) + .featureResourceTypes(treePermissionReq.getFeatureResourceTypes()) + .build(); + List workspaceProducts = workspaceProductService.listWorkspaceProduct(workspaceProductParam); + + //免授权 + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .terminal(treePermissionReq.getTerminal()) + .authType(FeatureResourceAuthType.ALL_ROLE.getCode()) + .build(); + List authFreeFeatureIds = featureResourceService.list(pageSaasFeatureResourceReq).stream() + .map(SaasFeatureResource::getId) + .collect(Collectors.toList()); + + //取交集确定权限 + return mixFeatureIds(saasRoleUserV2DTOS, workspaceProducts, authFreeFeatureIds); + } + + private Set mixFeatureIds(List saasRoleUsers, + List workspaceProducts, + List authFreeFeatureIds) { + + Map workspaceProductMap = workspaceProducts.stream() + .collect(Collectors.toMap(WorkspaceProductService.WorkspaceProduct::getWorkspaceId, Function.identity())); + + return saasRoleUsers.stream() + .filter(roleUser -> { + WorkspaceProductService.WorkspaceProduct workspaceProduct = workspaceProductMap.get(roleUser.getSaasRoleUser().getWorkspaceId()); + if (workspaceProduct == null || CollectionUtils.isEmpty(workspaceProduct.getSaasProductModuleFeatureRelations())) { + log.warn("no workspace product feature found for id:{}", roleUser.getSaasRoleUser().getWorkspaceId()); + return false; + } + return true; + }) + .map(roleUser -> { + WorkspaceProductService.WorkspaceProduct workspaceProduct = workspaceProductMap.get(roleUser.getSaasRoleUser().getWorkspaceId()); + + SaasRoleUserV2DTO.SaasRole saasRole = roleUser.getSaasRole(); + if (RoleTypeEnum.isAdmin(saasRole.getRoleType())) { + return resolveAdminRole(workspaceProduct, saasRole); + } + return resolveNormalRole(workspaceProduct, saasRole, authFreeFeatureIds); + }) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + } + + private List resolveAdminRole(WorkspaceProductService.WorkspaceProduct workspaceProduct, + SaasRoleUserV2DTO.SaasRole saasRole) { + + //超管和管理员 直接取和角色类型匹配的租户产品权限 + return workspaceProduct.getSaasProductModuleFeatureRelations().stream() + .filter(f -> Objects.equals(f.getDictCode(), saasRole.getProductUnitType().toString()) + || !NumberUtil.isPositiveNumber(saasRole.getProductUnitType())) + .map(SaasProductModuleFeatureRelation::getFeatureId) + .collect(Collectors.toList()); + } + + private List resolveNormalRole(WorkspaceProductService.WorkspaceProduct workspaceProduct, + SaasRoleUserV2DTO.SaasRole saasRole, + List authFreeFeatureIds) { + //普通角色:角色同类型的租户产品权限已分配 且角色上已分配 + 免授权 + Set roleFeatureIds = Optional.ofNullable(saasRole.getPermissionRelations()) + .map(e -> e.stream() + .map(SaasPermissionRelationRes::getFeatureId) + .collect(Collectors.toSet())) + .orElseGet(Collections::emptySet); + + return workspaceProduct.getSaasProductModuleFeatureRelations().stream() + .filter(f -> Objects.equals(f.getDictCode(), saasRole.getProductUnitType().toString()) + || !NumberUtil.isPositiveNumber(saasRole.getProductUnitType())) + .map(SaasProductModuleFeatureRelation::getFeatureId) + .filter(id -> roleFeatureIds.contains(id) || authFreeFeatureIds.contains(id)) + .collect(Collectors.toList()); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductFeatureRelationServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductFeatureRelationServiceImpl.java index 3d1b5678..653097ef 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductFeatureRelationServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductFeatureRelationServiceImpl.java @@ -1,33 +1,30 @@ package cn.axzo.tyr.server.service.impl; import cn.axzo.basics.common.BeanMapper; -import cn.axzo.basics.common.util.AssertUtil; +import cn.axzo.framework.auth.domain.TerminalInfo; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.thrones.client.saas.ServicePkgClient; import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct; import cn.axzo.thrones.client.saas.entity.servicepkg.ServicePkgDetailRes; -import cn.axzo.tyr.client.common.enums.ProductModuleFeatureRelationTypeEnum; -import cn.axzo.tyr.client.model.permission.PermissionPointTreeNode; +import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.model.product.ProductFeatureRelationSearchReq; import cn.axzo.tyr.client.model.product.ProductFeatureRelationUpdateReq; import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO; import cn.axzo.tyr.server.repository.dao.ProductModuleDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; +import cn.axzo.tyr.server.repository.dao.SaasProductModuleFeatureRelationDao; import cn.axzo.tyr.server.repository.entity.ProductFeatureQuery; import cn.axzo.tyr.server.repository.entity.SaasFeature; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; -import cn.axzo.tyr.server.repository.dao.SaasProductModuleFeatureRelationDao; import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.hutool.core.collection.CollectionUtil; -import cn.hutool.core.collection.ListUtil; import cn.hutool.core.date.StopWatch; -import cn.hutool.core.stream.SimpleCollector; import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.google.common.collect.Lists; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -36,21 +33,16 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; -import java.util.function.BiConsumer; -import java.util.function.BinaryOperator; import java.util.function.Function; -import java.util.function.Supplier; import java.util.stream.Collectors; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; import static cn.axzo.tyr.server.util.RpcInternalUtil.checkAndGetData; /** @@ -224,7 +216,20 @@ public class ProductFeatureRelationServiceImpl implements ProductFeatureRelation SaasProductModuleFeatureRelation::getProductModuleId, condition.getProductIds()) .eq(Objects.nonNull(condition.getWorkspaceJoinType()), SaasProductModuleFeatureRelation::getDictCode, condition.getWorkspaceJoinType()) - .in(CollectionUtil.isNotEmpty(condition.getFeatureIds()), SaasProductModuleFeatureRelation::getFeatureId, condition.getFeatureIds()); + .in(CollectionUtil.isNotEmpty(condition.getFeatureIds()), SaasProductModuleFeatureRelation::getFeatureId, condition.getFeatureIds()) + .eq(Objects.nonNull(condition.getType()), SaasProductModuleFeatureRelation::getType, condition.getType()); + if (!CollectionUtils.isEmpty(condition.getFeatureResourceTypes())) { + wrapper.in(SaasProductModuleFeatureRelation::getFeatureType, Lists.transform(condition.getFeatureResourceTypes(), FeatureResourceType::getCode)); + } + + // 目前只有新版本的CMS端产品配置时才冗余了terminal + if (Objects.equals(NEW_FEATURE, condition.getType()) && StringUtils.hasLength(condition.getTerminal())) { + TerminalInfo terminalInfo = new TerminalInfo(condition.getTerminal()); + if (terminalInfo.isCMS()) { + wrapper.eq(SaasProductModuleFeatureRelation::getTerminal, condition.getTerminal()); + } + } + return this.saasProductModuleFeatureRelationDao.list(wrapper); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java index b1af4330..1146ec2d 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java @@ -10,9 +10,9 @@ import cn.axzo.tyr.client.common.enums.RoleResourceTypeEnum; import cn.axzo.tyr.client.common.enums.RoleTypeEnum; import cn.axzo.tyr.client.model.enums.IdentityType; import cn.axzo.tyr.client.model.enums.PermissionGroupType; -import cn.axzo.tyr.client.model.permission.PermissionPointTreeNode; import cn.axzo.tyr.client.model.req.ChangeGroupLeaderRoleReq; import cn.axzo.tyr.client.model.req.FeatureRoleRelationReq; +import cn.axzo.tyr.client.model.req.PagePgroupPermissionRelationReq; import cn.axzo.tyr.client.model.req.QueryByIdentityIdTypeReq; import cn.axzo.tyr.client.model.req.QueryRoleByNameReq; import cn.axzo.tyr.client.model.req.QuerySaasPermissionGroupReq; @@ -24,6 +24,7 @@ import cn.axzo.tyr.client.model.res.IsSuperAdminRes; import cn.axzo.tyr.client.model.res.QueryBatchByIdentityIdTypeRes; import cn.axzo.tyr.client.model.res.QueryRoleByNameResp; import cn.axzo.tyr.client.model.res.RoleWithUserRes; +import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; import cn.axzo.tyr.client.model.res.SaasPermissionRes; import cn.axzo.tyr.client.model.res.SaasRoleGroupRes; import cn.axzo.tyr.client.model.res.SaasRoleRes; @@ -34,7 +35,6 @@ import cn.axzo.tyr.client.model.vo.SaasPermissionGroupVO; import cn.axzo.tyr.client.model.vo.SaasRoleAndGroupVO; import cn.axzo.tyr.client.model.vo.SaasRoleCategoryVO; import cn.axzo.tyr.client.model.vo.SaasRoleGroupCodeVO; -import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO; import cn.axzo.tyr.client.model.vo.SaasRoleVO; import cn.axzo.tyr.client.model.vo.SaveOrUpdateRoleVO; import cn.axzo.tyr.server.model.ResourcePermission; @@ -102,7 +102,6 @@ import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -722,36 +721,6 @@ public class RoleServiceImpl extends ServiceImpl .list(); } - @Override - public Set filterPermissionPoint(Set role, TyrSaasAuthServiceImpl.OUWRoleInfo userRoleInfoMap) { - // 按钮级别权限点ID - Set result = new HashSet<>(); - if (CollectionUtils.isEmpty(role)) { - return result; - } - Set initRoleId = new HashSet<>(); - //有标准角,查询角色分组 - if (role.stream().anyMatch(r -> Objects.equals(RoleTypeEnum.INIT.getValue(), r.getRoleType()))) { - List roleGroupList = saasRoleGroupService.getList(QuerySaasRoleGroupReq.builder() - .workspaceTypeCode(Collections.singletonList(userRoleInfoMap.getWorkspaceType().toString())) - // .ouTypeCode(Collections.singletonList(userRoleInfoMap.getWorkspaceJoinType().getValue().toString())) - .build()); - initRoleId = roleGroupList.stream().map(SaasRoleGroupVO::getRoleIds).filter(CollectionUtil::isNotEmpty).flatMap(List::stream).collect(Collectors.toSet()); - } - - Set finalInitRoleId = initRoleId; - List resultRole = role.stream().filter(r -> - Objects.equals(r.getRoleType(), RoleTypeEnum.COMMON.getValue()) - || finalInitRoleId.contains(r.getId())) - .collect(Collectors.toList()); - - return resultRole.stream().map( - e -> e.getMatchFeature(userRoleInfoMap.workspaceId, userRoleInfoMap.getOuId())) - .flatMap(List::stream) - .map(PermissionPointTreeNode::getPermissionPointId) - .collect(Collectors.toSet()); - } - @Override public PageResp queryRoleWithUser(RoleWithUserQueryReq req) { page2Default(req); @@ -810,25 +779,6 @@ public class RoleServiceImpl extends ServiceImpl } } - @Override - public List queryRoleByRoleTypes(QueryByIdentityIdTypeReq req, List roleTypes) { - List roleIds = roleUserRelationDao.query(req.getIdentityId(), req.getIdentityType(), - req.getWorkspaceId(), req.getOuId()).stream().map(SaasRoleUserRelation::getRoleId).collect(Collectors.toList()); - List list = new ArrayList<>(); - if (CollectionUtils.isNotEmpty(roleIds)) { - list = saasRoleDao.lambdaQuery() - .in(BaseEntity::getId, roleIds) - .in(SaasRole::getRoleType, roleTypes) - .list(); - } - return BeanUtil.copyToList(list, SaasRoleVO.class); - } - - @Override - public List listForOUWorkspace(Long ouId, Long workspaceId, Integer workspaceJoinType) { - return saasRoleDao.listForOUWorkspace(ouId, workspaceId, workspaceJoinType); - } - @Override public List findRoleByName(QueryRoleByNameReq req) { // TODO jhy 这个方法有问题 @@ -1203,21 +1153,26 @@ public class RoleServiceImpl extends ServiceImpl Map> saasRoleUsers = listSaasRoleUser(param, page.getRecords()); + Map> permissionRelations = listRolePermissionRelations(param, page.getRecords()); + return PageConverter.toResp(page, (record) -> from(record, saasRoleGroups, BooleanUtils.isTrue(param.getNeedPermissionOld()) ? saasPermissionsOld : saasPermissions, - saasRoleUsers)); + saasRoleUsers, + permissionRelations)); } private SaasRoleRes from(SaasRole saasRole, Map> saasRoleGroups, Map> saasPermissions, - Map> saasRoleUsers) { + Map> saasRoleUsers, + Map> permissionRelations) { SaasRoleRes saasRoleRes = SaasRoleRes.builder().build(); BeanUtils.copyProperties(saasRole, saasRoleRes); saasRoleRes.setSaasRoleGroups(saasRoleGroups.get(saasRoleRes.getId())); saasRoleRes.setSaasPermissions(saasPermissions.get(saasRoleRes.getId())); saasRoleRes.setSaasRoleUsers(saasRoleUsers.get(saasRoleRes.getId())); + saasRoleRes.setPermissionRelations(permissionRelations.get(saasRoleRes.getId())); return saasRoleRes; } @@ -1496,4 +1451,90 @@ public class RoleServiceImpl extends ServiceImpl Collectors.toList()))); } + private Map> listRolePermissionRelations(PageSaasRoleParam param, + List saasRoles) { + if (CollectionUtils.isEmpty(saasRoles) || BooleanUtils.isNotTrue(param.getNeedPermissionRelation())) { + return Collections.emptyMap(); + } + + List saasPgroupRoleRelations = saasPgroupRoleRelationDao.findByRoleIds(Lists.transform(saasRoles, SaasRole::getId)); + + if (CollectionUtils.isEmpty(saasPgroupRoleRelations)) { + return Collections.emptyMap(); + } + + PagePgroupPermissionRelationReq pagePgroupPermissionRelationReq = PagePgroupPermissionRelationReq.builder() + .groupIds(Lists.transform(saasPgroupRoleRelations, SaasPgroupRoleRelation::getGroupId)) + .featureIds(param.getFeatureIds()) + .featureResourceTypes(param.getFeatureResourceTypes()) + .type(param.getType()) + .terminal(param.getTerminal()) + .build(); + List saasPgroupPermissionRelations = saasPgroupPermissionRelationService.list(pagePgroupPermissionRelationReq); + + Map> pgroupPermissions = saasPgroupPermissionRelations.stream() + .collect(Collectors.groupingBy(SaasPgroupPermissionRelation::getGroupId)); + + return saasPgroupRoleRelations.stream() + .map(e -> { + List permissionRelations = pgroupPermissions.get(e.getGroupId()); + if (CollectionUtils.isEmpty(permissionRelations)) { + return null; + } + + return permissionRelations.stream() + .map(permissionRelation -> SaasPermissionRelationWrapper.from(e, permissionRelation)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + }) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.groupingBy(SaasPermissionRelationWrapper::getRoleId, + Collectors.mapping(e -> SaasPermissionRelationRes.builder() + .featureId(e.getFeatureId()) + .type(e.getType()) + .featureType(e.getFeatureType()) + .build(), + Collectors.toList()))); + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + static class SaasPermissionRelationWrapper { + + /** + * 角色id + */ + private Long roleId; + + /** + * 菜单资源树节点id + */ + private Long featureId; + + /** + * 新旧菜单资源数标识 + */ + private Integer type; + + /** + * 菜单资源树节点类型 + */ + private Integer featureType; + + public static SaasPermissionRelationWrapper from(SaasPgroupRoleRelation saasPgroupRoleRelation, + SaasPgroupPermissionRelation permissionRelation) { + if (permissionRelation == null) { + return null; + } + return SaasPermissionRelationWrapper.builder() + .roleId(saasPgroupRoleRelation.getRoleId()) + .featureId(permissionRelation.getFeatureId()) + .type(permissionRelation.getType()) + .featureType(permissionRelation.getFeatureType()) + .build(); + } + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java index 2c6dd3dd..c20503b4 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java @@ -3,6 +3,9 @@ package cn.axzo.tyr.server.service.impl; import cn.axzo.basics.common.BeanMapper; import cn.axzo.basics.common.util.StopWatchUtil; import cn.axzo.basics.common.util.TreeUtil; +import cn.axzo.foundation.dao.support.converter.PageConverter; +import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper; +import cn.axzo.foundation.page.PageResp; import cn.axzo.framework.domain.web.code.BaseCode; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType; @@ -12,6 +15,7 @@ import cn.axzo.tyr.client.model.req.FeatureComponentSaveReq; import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.client.model.res.FeatureResourceDTO; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; import cn.axzo.tyr.client.model.res.PageElementBasicDTO; @@ -22,15 +26,16 @@ import cn.axzo.tyr.server.model.convert.SaasFeatureResourceConvert; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import cn.axzo.tyr.server.repository.entity.SaasPageElement; -import cn.axzo.tyr.server.service.SaasCommonDictService; +import cn.axzo.tyr.server.repository.mapper.SaasFeatureResourceMapper; import cn.axzo.tyr.server.service.SaasFeatureResourceService; import cn.axzo.tyr.server.service.SaasPageElementService; -import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService; import cn.azxo.framework.common.utils.StringUtils; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; -import com.alibaba.nacos.common.utils.UuidUtils; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; @@ -41,7 +46,6 @@ import org.springframework.transaction.annotation.Transactional; import java.util.Collections; import java.util.Comparator; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Function; @@ -60,16 +64,13 @@ import static cn.axzo.tyr.server.repository.entity.SaasFeatureResource.DEFAULT_W @Slf4j @Service @RequiredArgsConstructor -public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceService { +public class SaasFeatureResourceServiceImpl extends ServiceImpl + implements SaasFeatureResourceService { - /** 功能资源树根节点所有端配置的scope **/ - private static final String RESOURCE_TERMINAL_SCOPE = "resource.terminal"; private final SaasFeatureResourceDao featureResourceDao; private final SaasFeatureResourceCacheService saasFeatureResourceCacheService; - private final SaasCommonDictService saasCommonDictService; - private final SaasPgroupPermissionRelationService pgroupPermissionRelationService; private final SaasPageElementService saasPageElementService; @Override @@ -331,15 +332,6 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic } } - // 查询resource节点及子节点 - @Override - public List listDescendant(Long featureId) { - return featureResourceDao.lambdaQuery() - .eq(BaseEntity::getIsDelete,0) - .apply("FIND_IN_SET('" + featureId + "', path)") - .list(); - } - // 查询resource节点及子节点 @Override public List batchListDescendant(List featureIds) { @@ -363,29 +355,6 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic .one(); } - @Override - @Transactional(rollbackFor = Exception.class) - @CacheEvict(value = SaasFeatureResourceCacheService.CACHE_FEATURE_RESOURCE_TREE,allEntries = true) - public void deleteMenuFeature(Long featureId, Long operatorId) { - -// if (featureId == null) { -// return; -// } -// List featureDescendant = featureResourceDao.lambdaQuery() -// .eq(BaseEntity::getIsDelete,0) -// .apply("FIND_IN_SET('" + featureId + "', path)") -// .list(); -// List featureIds = featureDescendant.stream().map(SaasFeatureResource::getId).collect(Collectors.toList()); -// pgroupPermissionRelationService.deleteByFeatureIds(featureIds); -// // 删除自己及自己的子集 -// featureResourceDao.lambdaUpdate() -// .eq(BaseEntity::getIsDelete,0) -// .apply("FIND_IN_SET('" + featureId + "', path)") -// .set(SaasFeatureResource::getUpdateBy, operatorId) -// .set(BaseEntity::getIsDelete,1) -// .update(); - } - @Override @Transactional(rollbackFor = Exception.class) @CacheEvict(value = SaasFeatureResourceCacheService.CACHE_FEATURE_RESOURCE_TREE,allEntries = true) @@ -458,19 +427,6 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic return true; } - private List fillChildren2Root(List rootNodes, List childrenNodes) { - Map rootNodeMap = rootNodes.stream().collect(Collectors.toMap(FeatureResourceDTO::getTerminal, Function.identity(), (v1, v2) -> v1)); - for(FeatureResourceTreeNode child : childrenNodes) { - FeatureResourceTreeNode rootNode = rootNodeMap.get(child.getTerminal()); - if (child.getParentId() > 0 || Objects.isNull(rootNode)) { - continue; - } - rootNode.getChildren().add(child); - } - - return rootNodes; - } - /** * 菜单/页面/应用/分组,权限码每个端唯一, * 组件权限码不校验唯一 @@ -509,24 +465,6 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic .list().stream().map(SaasFeatureResource::getId).collect(Collectors.toSet()); } - @Override - public List listNavMenu(String terminal) { - //按需扩展要查询的字段 - return featureResourceDao.lambdaQuery() - .select(SaasFeatureResource::getId, - SaasFeatureResource::getParentId, - SaasFeatureResource::getFeatureCode, - SaasFeatureResource::getFeatureName, - SaasFeatureResource::getFeatureType, - SaasFeatureResource::getLinkUrl, - SaasFeatureResource::getIcon) - .eq(SaasFeatureResource::getStatus, FeatureResourceStatus.NORMAL.getCode()) - .eq(SaasFeatureResource::getFeatureType, FeatureResourceType.MENU.getCode()) - .eq(SaasFeatureResource::getTerminal, terminal) - .orderByAsc(SaasFeatureResource::getDisplayOrder) - .list(); - } - @Override public List listByParentIdAndTerminalAndIds(Long parentId, String terminal, List featureIds) { return featureResourceDao.lambdaQuery() @@ -537,6 +475,25 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic .list(); } + @Override + public List list(PageSaasFeatureResourceReq param) { + return PageConverter.drainAll(pageNumber -> { + param.setPage(pageNumber); + param.setPageSize(500); + return page(param); + }); + } + + @Override + public PageResp page(PageSaasFeatureResourceReq param) { + QueryWrapper wrapper = QueryWrapperHelper.fromBean(param, SaasFeatureResource.class); + wrapper.eq("is_delete", 0); + + IPage page = this.page(PageConverter.toMybatis(param, SaasFeatureResource.class), wrapper); + + return PageConverter.toResp(page, Function.identity()); + } + private void fillPageElement2PageFeatureResource(FeatureResourceTreeNode featureResourceTreeNode) { if (!FeatureResourceType.PAGE.getCode().equals(featureResourceTreeNode.getFeatureType())) { return; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPgroupPermissionRelationServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPgroupPermissionRelationServiceImpl.java index 3b37ef19..9b8e3049 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPgroupPermissionRelationServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPgroupPermissionRelationServiceImpl.java @@ -4,6 +4,8 @@ import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum; import cn.axzo.foundation.dao.support.converter.PageConverter; import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper; import cn.axzo.foundation.page.PageResp; +import cn.axzo.framework.auth.domain.TerminalInfo; +import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.model.req.PagePgroupPermissionRelationReq; import cn.axzo.tyr.server.repository.dao.SaasPgroupPermissionRelationDao; import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation; @@ -12,11 +14,13 @@ import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; import java.util.ArrayList; import java.util.Collection; @@ -25,6 +29,8 @@ import java.util.Objects; import java.util.function.Function; import java.util.stream.Collectors; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; + @Slf4j @Service @RequiredArgsConstructor @@ -71,8 +77,29 @@ public class SaasPgroupPermissionRelationServiceImpl QueryWrapper wrapper = QueryWrapperHelper.fromBean(param, SaasPgroupPermissionRelation.class); wrapper.eq("is_delete", 0); + if (CollectionUtils.isNotEmpty(param.getFeatureResourceTypes())) { + wrapper.in("feature_type", Lists.transform(param.getFeatureResourceTypes(), FeatureResourceType::getCode)); + } + + // 目前只有新版本的CMS端产品配置时才冗余了terminal + if (Objects.equals(NEW_FEATURE, param.getType()) && StringUtils.hasLength(param.getTerminal())) { + TerminalInfo terminalInfo = new TerminalInfo(param.getTerminal()); + if (terminalInfo.isCMS()) { + wrapper.eq("terminal", param.getTerminal()); + } + } + IPage page = this.page(PageConverter.toMybatis(param, SaasPgroupPermissionRelation.class), wrapper); return PageConverter.toResp(page, Function.identity()); } + + @Override + public List list(PagePgroupPermissionRelationReq param) { + return PageConverter.drainAll(pageNumber -> { + param.setPage(pageNumber); + param.setPageSize(500); + return page(param); + }); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleUserRelationServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleUserRelationServiceImpl.java index d429eb0d..43c53402 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleUserRelationServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleUserRelationServiceImpl.java @@ -42,6 +42,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; @@ -201,9 +202,18 @@ public class SaasRoleUserRelationServiceImpl extends ServiceImpl saasRoleUsers, Map saasRoles) { + SaasRoleUserV2DTO.SaasRoleUser saasRoleUser = SaasRoleUserV2DTO.SaasRoleUser.builder() + .ouId(saasRoleUserRelation.getOuId()) + .workspaceId(saasRoleUserRelation.getWorkspaceId()) + .personId(saasRoleUserRelation.getNaturalPersonId()) + .realName(Optional.ofNullable(saasRoleUsers.get(saasRoleUserRelation.getNaturalPersonId())) + .map(SaasRoleUserV2DTO.SaasRoleUser::getRealName) + .orElse(null)) + .build(); + return SaasRoleUserV2DTO.builder() .roleId(saasRoleUserRelation.getRoleId()) - .saasRoleUser(saasRoleUsers.get(saasRoleUserRelation.getNaturalPersonId())) + .saasRoleUser(saasRoleUser) .saasRole(saasRoles.get(saasRoleUserRelation.getRoleId())) .build(); } @@ -223,6 +233,10 @@ public class SaasRoleUserRelationServiceImpl extends ServiceImpl { diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/WorkspaceProductServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/WorkspaceProductServiceImpl.java new file mode 100644 index 00000000..7f2d2436 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/WorkspaceProductServiceImpl.java @@ -0,0 +1,106 @@ +package cn.axzo.tyr.server.service.impl; + +import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; +import cn.axzo.thrones.client.saas.ServicePkgClient; +import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct; +import cn.axzo.thrones.client.saas.entity.servicepkg.ServicePkgDetailRes; +import cn.axzo.tyr.server.repository.dao.ProductModuleDao; +import cn.axzo.tyr.server.repository.entity.ProductFeatureQuery; +import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; +import cn.axzo.tyr.server.service.ProductFeatureRelationService; +import cn.axzo.tyr.server.service.WorkspaceProductService; +import cn.axzo.tyr.server.utils.RpcInternalUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.lang.Pair; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class WorkspaceProductServiceImpl implements WorkspaceProductService { + + @Autowired + private ServicePkgClient servicePkgClient; + @Autowired + private ProductModuleDao productModuleDao; + @Autowired + private ProductFeatureRelationService productFeatureRelationService; + + @Override + public List listWorkspaceProduct(WorkspaceProductParam param) { + + if (CollectionUtils.isEmpty(param.getWorkspaceIds())) { + return Collections.emptyList(); + } + + List servicePkgDetailRes = RpcInternalUtil.rpcListProcessor(() -> servicePkgClient.getServicePkgDetailBySpaceId(param.getWorkspaceIds()), + "查询项目的产品", param.getWorkspaceIds()).getData(); + if (CollectionUtil.isEmpty(servicePkgDetailRes)) { + return Collections.emptyList(); + } + + Set productIds = servicePkgDetailRes.stream() + .map(ServicePkgDetailRes::getProducts) + .filter(CollectionUtil::isNotEmpty) + .flatMap(List::stream) + .map(ServicePkgProduct::getProductId) + .collect(Collectors.toSet()); + if (CollectionUtil.isEmpty(productIds)) { + log.warn("no product found for workspace :{}", param.getWorkspaceIds()); + return Collections.emptyList(); + } + + // 已被删除产品过滤一层 + productIds = productModuleDao.listByIds(productIds) + .stream() + .filter(productModule -> Objects.equals(productModule.getIsDelete(),0L)) + .map(BaseEntity::getId) + .collect(Collectors.toSet()); + if (CollectionUtil.isEmpty(productIds)) { + log.warn("all product is deleted for workspace :{}", param.getWorkspaceIds()); + return Collections.emptyList(); + } + + ProductFeatureQuery productFeatureQuery = ProductFeatureQuery.builder() + .productIds(productIds) + .featureResourceTypes(param.getFeatureResourceTypes()) + .type(param.getType()) + .terminal(param.getTerminal()) + .build(); + Map> saasProductModuleFeatureRelations = productFeatureRelationService.queryOnCondition(productFeatureQuery).stream() + .collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId)); + + return servicePkgDetailRes.stream() + .filter(e -> CollectionUtils.isNotEmpty(e.getProducts())) + .map(e -> { + List features = e.getProducts().stream() + .map(product -> saasProductModuleFeatureRelations.get(product.getProductId())) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + return Pair.of(e.getSpaceId(), features); + }) + // 考虑一个项目有多个服务包的情况 + .collect(Collectors.toMap(Pair::getKey, Pair::getValue, (f, s) -> { + f.addAll(s); + return f; + })) + .entrySet() + .stream() + .map(e -> WorkspaceProduct.builder() + .workspaceId(e.getKey()) + .saasProductModuleFeatureRelations(e.getValue()) + .build()) + .collect(Collectors.toList()); + } +} From 35e661e2f5a6d35f804ed9bdfd9a7437cdefa1a7 Mon Sep 17 00:00:00 2001 From: lilong Date: Mon, 24 Jun 2024 18:30:25 +0800 Subject: [PATCH 17/69] =?UTF-8?q?feat:(REQ-2545)=20=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E6=97=B6=EF=BC=8C=E6=94=AF=E6=8C=81=E6=9F=A5?= =?UTF-8?q?=E6=89=BE=E6=8C=87=E5=AE=9A=E8=8A=82=E7=82=B9=E4=B8=8B=E7=9A=84?= =?UTF-8?q?=E5=AD=90=E8=8A=82=E7=82=B9=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/req/PageSaasFeatureResourceReq.java | 18 +++++++++++++ .../service/WorkspaceProductService.java | 2 ++ .../impl/PermissionQueryServiceImpl.java | 25 +++++++++++++++++++ .../impl/SaasFeatureResourceServiceImpl.java | 20 +++++++++++++++ .../impl/WorkspaceProductServiceImpl.java | 1 + 5 files changed, 66 insertions(+) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageSaasFeatureResourceReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageSaasFeatureResourceReq.java index 2bd0ef57..1bf06bda 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageSaasFeatureResourceReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageSaasFeatureResourceReq.java @@ -3,11 +3,14 @@ package cn.axzo.tyr.client.model.req; import cn.axzo.foundation.dao.support.wrapper.CriteriaField; import cn.axzo.foundation.dao.support.wrapper.Operator; import cn.axzo.foundation.page.IPageReq; +import cn.axzo.foundation.page.PageResp; +import cn.axzo.tyr.client.common.enums.FeatureResourceType; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.util.Collections; import java.util.List; @Data @@ -43,4 +46,19 @@ public class PageSaasFeatureResourceReq implements IPageReq { */ @CriteriaField(field = "terminal", operator = Operator.EQ) private String terminal; + + @CriteriaField(ignore = true) + private Long parentId; + + @CriteriaField(field = "featureType", operator = Operator.IN) + private List featureResourceTypes; + + public PageResp toEmpty() { + return PageResp.builder() + .current(this.getPage()) + .size(this.getPageSize()) + .total(0) + .data(Collections.emptyList()) + .build(); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/WorkspaceProductService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/WorkspaceProductService.java index 4bf1cf20..a249e62f 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/WorkspaceProductService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/WorkspaceProductService.java @@ -39,6 +39,8 @@ public interface WorkspaceProductService { * 区分新老菜单资源树 */ private Integer type; + + private Set featureIds; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java index 1feaa34c..fc021d8b 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java @@ -567,6 +567,12 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { private Set listUserPermissionFeatureIds(TreePermissionReq treePermissionReq) { + List featureIds = resolveFeatureIds(treePermissionReq); + + if (Objects.nonNull(treePermissionReq.getParentFeatureId()) && CollectionUtils.isEmpty(featureIds)) { + return Collections.emptySet(); + } + List workspaceOuPairs = treePermissionReq.getWorkspaceOUPairs().stream() .map(e -> ListRoleUserRelationParam.WorkspaceOuPair.builder() .workspaceId(e.getWorkspaceId()) @@ -582,6 +588,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .featureResourceTypes(treePermissionReq.getFeatureResourceTypes()) .type(NEW_FEATURE) .terminal(treePermissionReq.getTerminal()) + .featureIds(featureIds) .build(); List saasRoleUserV2DTOS = saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream() .filter(e -> e.getSaasRole() != null && CollectionUtils.isNotEmpty(e.getSaasRole().getPermissionRelations())) @@ -615,6 +622,24 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { return mixFeatureIds(saasRoleUserV2DTOS, workspaceProducts, authFreeFeatureIds); } + private List resolveFeatureIds(TreePermissionReq treePermissionReq) { + if (Objects.isNull(treePermissionReq.getParentFeatureId())) { + return Collections.emptyList(); + } + + List featureTypes = Optional.ofNullable(treePermissionReq.getFeatureResourceTypes()) + .map(e -> e.stream().map(FeatureResourceType::getCode).collect(Collectors.toList())) + .orElse(null); + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .parentId(treePermissionReq.getParentFeatureId()) + .featureResourceTypes(featureTypes) + .build(); + return featureResourceService.list(pageSaasFeatureResourceReq).stream() + .map(SaasFeatureResource::getId) + .collect(Collectors.toList()); + } + private Set mixFeatureIds(List saasRoleUsers, List workspaceProducts, List authFreeFeatureIds) { diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java index c20503b4..08a44ceb 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java @@ -486,14 +486,34 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl page(PageSaasFeatureResourceReq param) { + + String parentPath = resolveParentPath(param); + if (Objects.nonNull(param.getParentId()) && StringUtils.isBlank(parentPath)) { + return param.toEmpty(); + } + QueryWrapper wrapper = QueryWrapperHelper.fromBean(param, SaasFeatureResource.class); wrapper.eq("is_delete", 0); + wrapper.likeRight(StringUtils.isNotBlank(parentPath), "path", parentPath); IPage page = this.page(PageConverter.toMybatis(param, SaasFeatureResource.class), wrapper); return PageConverter.toResp(page, Function.identity()); } + private String resolveParentPath(PageSaasFeatureResourceReq param) { + if (Objects.isNull(param.getParentId())) { + return null; + } + + SaasFeatureResource parent = this.getById(param.getParentId()); + if (Objects.isNull(parent)) { + return null; + } + + return parent.getPath(); + } + private void fillPageElement2PageFeatureResource(FeatureResourceTreeNode featureResourceTreeNode) { if (!FeatureResourceType.PAGE.getCode().equals(featureResourceTreeNode.getFeatureType())) { return; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/WorkspaceProductServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/WorkspaceProductServiceImpl.java index 7f2d2436..dee57b10 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/WorkspaceProductServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/WorkspaceProductServiceImpl.java @@ -76,6 +76,7 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { .featureResourceTypes(param.getFeatureResourceTypes()) .type(param.getType()) .terminal(param.getTerminal()) + .featureIds(param.getFeatureIds()) .build(); Map> saasProductModuleFeatureRelations = productFeatureRelationService.queryOnCondition(productFeatureQuery).stream() .collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId)); From 55114c7d4ed8e4f0b4791bbacc6bd1df87583779 Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 25 Jun 2024 09:31:26 +0800 Subject: [PATCH 18/69] =?UTF-8?q?feat:(REQ-2545)=20OMS=E9=A2=84=E8=AE=BE?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E5=A2=9E=E5=8A=A0=E6=9D=83=E9=99=90=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E5=86=97=E4=BD=99=E7=AB=AF=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/req/FeatureRoleRelationReq.java | 2 ++ .../tyr/server/model/ResourcePermission.java | 5 ++++ .../server/service/impl/RoleServiceImpl.java | 28 +++++++++++-------- .../impl/SaasFeatureResourceServiceImpl.java | 3 +- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureRoleRelationReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureRoleRelationReq.java index ab463e31..2afd9e5a 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureRoleRelationReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureRoleRelationReq.java @@ -39,5 +39,7 @@ public class FeatureRoleRelationReq { /** 授权类型 0-全部角色 1-指定角色 **/ private Integer authType; + + private String terminal; } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/model/ResourcePermission.java b/tyr-server/src/main/java/cn/axzo/tyr/server/model/ResourcePermission.java index 02460801..046f712a 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/model/ResourcePermission.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/model/ResourcePermission.java @@ -27,4 +27,9 @@ public class ResourcePermission { private Integer featureType; private Integer authType; + + /** + * 资源所属端 + */ + private String terminal; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java index 1146ec2d..e58875e8 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java @@ -426,20 +426,23 @@ public class RoleServiceImpl extends ServiceImpl return; } - Map resourcePermissionMap = resourcePermissions.stream() - .collect(Collectors.toMap(ResourcePermission::getId, ResourcePermission::getFeatureType)); + Map resourcePermissionMap = resourcePermissions.stream() + .collect(Collectors.toMap(ResourcePermission::getId, Function.identity())); // 保存权限集和权限点映射关系 - List pgpRelations = saveOrUpdateRole.getPermissionIds().stream().map(ppId -> { - SaasPgroupPermissionRelation target = new SaasPgroupPermissionRelation(); - target.setGroupId(saasPermissionGroup.getId()); - target.setFeatureId(ppId); - target.setCreateBy(saveOrUpdateRole.getOperatorId()); - target.setUpdateBy(saveOrUpdateRole.getOperatorId()); - target.setFeatureType(resourcePermissionMap.get(ppId)); - target.setType(NEW_FEATURE); - return target; - }).collect(Collectors.toList()); + List pgpRelations = saveOrUpdateRole.getPermissionIds().stream() + .map(ppId -> { + ResourcePermission resourcePermission = resourcePermissionMap.get(ppId); + SaasPgroupPermissionRelation target = new SaasPgroupPermissionRelation(); + target.setGroupId(saasPermissionGroup.getId()); + target.setFeatureId(ppId); + target.setCreateBy(saveOrUpdateRole.getOperatorId()); + target.setUpdateBy(saveOrUpdateRole.getOperatorId()); + target.setFeatureType(resourcePermission.getFeatureType()); + target.setType(NEW_FEATURE); + target.setTerminal(resourcePermission.getTerminal()); + return target; + }).collect(Collectors.toList()); SaasPgroupPermissionRelationService.UpsertPermissionRelationParam upsertPermissionRelationParam = SaasPgroupPermissionRelationService.UpsertPermissionRelationParam.builder() .groupIds(Lists.newArrayList(saasPermissionGroup.getId())) .relations(pgpRelations) @@ -1323,6 +1326,7 @@ public class RoleServiceImpl extends ServiceImpl relation.setCreateBy(operatorId); relation.setFeatureType(item.getFeatureType()); relation.setType(NEW_FEATURE); + relation.setTerminal(item.getTerminal()); insertRelation.add(relation); }); saasPgroupPermissionRelationDao.saveBatch(insertRelation); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java index 08a44ceb..7f603622 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java @@ -99,7 +99,8 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl Date: Tue, 25 Jun 2024 15:22:20 +0800 Subject: [PATCH 19/69] =?UTF-8?q?feat(REQ-2545):=20=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E5=A2=9E=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/base/BaseFeatureResourceDO.java | 3 ++ .../model/base/FeatureResourceExtraDO.java | 30 +++++++++++++++++++ .../client/model/res/FeatureResourceDTO.java | 3 +- .../entity/SaasFeatureResource.java | 8 +++-- .../ProductFeatureRelationService.java | 5 ++++ 5 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/base/FeatureResourceExtraDO.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/base/BaseFeatureResourceDO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/base/BaseFeatureResourceDO.java index ecbb2581..63a61833 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/base/BaseFeatureResourceDO.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/base/BaseFeatureResourceDO.java @@ -43,4 +43,7 @@ public class BaseFeatureResourceDO { /** 组件元素的code列表 */ private List pageElementCodes; + + /** 图片资源对象 **/ + private FeatureResourceExtraDO extra; } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/base/FeatureResourceExtraDO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/base/FeatureResourceExtraDO.java new file mode 100644 index 00000000..5b17780b --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/base/FeatureResourceExtraDO.java @@ -0,0 +1,30 @@ +package cn.axzo.tyr.client.model.base; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/24 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FeatureResourceExtraDO implements Serializable { + + /** + * 选中的图标 + */ + private String activeIcon; + + /** + * 更多图标 + */ + private String moreIcon; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourceDTO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourceDTO.java index 4a5a8539..fdaf8221 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourceDTO.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourceDTO.java @@ -1,5 +1,6 @@ package cn.axzo.tyr.client.model.res; +import cn.axzo.tyr.client.model.base.FeatureResourceExtraDO; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -110,7 +111,7 @@ public class FeatureResourceDTO implements Serializable { /** * 扩展字段 */ - private String extra; + private FeatureResourceExtraDO extra; /** * 授权类型0-全部角色 1-指定角色 diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java index d080639d..b942ceb0 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java @@ -1,8 +1,11 @@ package cn.axzo.tyr.server.repository.entity; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; +import cn.axzo.tyr.client.model.base.FeatureResourceExtraDO; import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -24,7 +27,7 @@ import java.util.stream.Collectors; @NoArgsConstructor @AllArgsConstructor @TableName("saas_feature_resource") -public class SaasFeatureResource extends BaseEntity { +public class SaasFeatureResource extends BaseEntity { private static final long serialVersionUID = 1L; @@ -129,7 +132,8 @@ public class SaasFeatureResource extends BaseEntity { /** * 扩展字段 */ - private String extra; + @TableField(value = "extra", typeHandler = FastjsonTypeHandler.class) + private FeatureResourceExtraDO extra; /** * 授权类型0-全部角色 1-指定角色 diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductFeatureRelationService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductFeatureRelationService.java index c3d46ddb..ec988bbf 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductFeatureRelationService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductFeatureRelationService.java @@ -22,6 +22,11 @@ public interface ProductFeatureRelationService { ApiResult updateFeatureRelation(List req); + /** + * 更新产品功能权限关系,仅支持saas_feature_resource功能点 + * + * @param req + */ void updateFeatureResourceRelation(List req); ApiResult> featureListByProduct(List productIds); From 25af37d4c5c4681d2ae822b6f7aee6b4d87b77d2 Mon Sep 17 00:00:00 2001 From: lilong Date: Wed, 26 Jun 2024 10:04:12 +0800 Subject: [PATCH 20/69] =?UTF-8?q?feat:(REQ-2545)=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E5=88=86=E5=89=B2=E5=88=86=E7=BB=84=E6=9E=9A?= =?UTF-8?q?=E4=B8=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/tyr/client/common/enums/FeatureResourceType.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/FeatureResourceType.java b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/FeatureResourceType.java index c4730478..b7d0673d 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/FeatureResourceType.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/FeatureResourceType.java @@ -25,6 +25,8 @@ public enum FeatureResourceType { COMPONENT(4, "组件"), ROOT(5, "ROOT"), GROUP(6, "分组"), + // 用户pc端菜单直接的分割分组线 + MENU_PARTITION_GROUP(7, "菜单分割分组"), ; private static final Map MAPPING = new HashMap<>(); From 4cf7460b5093b29e397e8de111ea5c9d6975660e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Wed, 26 Jun 2024 11:29:18 +0800 Subject: [PATCH 21/69] =?UTF-8?q?feat(REQ-2545):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E8=8F=9C=E5=8D=95=E4=B8=AD=E7=9A=84=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E8=8F=9C=E5=8D=95=E7=BB=91=E5=AE=9A=E8=A7=92=E8=89=B2?= =?UTF-8?q?code=E7=9A=84=E8=BF=9E=E8=A1=A8=E6=9F=A5=E8=AF=A2=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/FeatureResourceRoleCodeDTO.java | 22 ------- .../dao/SaasFeatureResourceDao.java | 13 ---- .../mapper/SaasFeatureResourceMapper.java | 5 -- .../impl/FeatureResourceSyncServiceImpl.java | 63 ++++++++++++++++--- .../mapper/SaasFeatureResourceMapper.xml | 29 ++++----- 5 files changed, 71 insertions(+), 61 deletions(-) delete mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/model/FeatureResourceRoleCodeDTO.java diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/model/FeatureResourceRoleCodeDTO.java b/tyr-server/src/main/java/cn/axzo/tyr/server/model/FeatureResourceRoleCodeDTO.java deleted file mode 100644 index cdf167ba..00000000 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/model/FeatureResourceRoleCodeDTO.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.axzo.tyr.server.model; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -/** - * @author likunpeng - * @version 1.0 - * @date 2024/5/22 - */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class FeatureResourceRoleCodeDTO { - - private Long featureResourceId; - - private String roleCode; -} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java index a7124ff8..9c09c7bf 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java @@ -2,18 +2,14 @@ package cn.axzo.tyr.server.repository.dao; import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum; import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; -import cn.axzo.tyr.server.model.FeatureResourceRoleCodeDTO; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import cn.axzo.tyr.server.repository.mapper.SaasFeatureResourceMapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.google.common.collect.Maps; import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Repository; import java.util.List; -import java.util.Map; import java.util.Objects; -import java.util.stream.Collectors; /** *

@@ -44,13 +40,4 @@ public class SaasFeatureResourceDao extends ServiceImpl> getFeatureResourceRoleCodeMap(List featureResourceIds) { - if (org.apache.commons.collections4.CollectionUtils.isEmpty(featureResourceIds)) { - return Maps.newHashMap(); - } - List featureResourceRoleCodes = this.baseMapper.listRoleCodes(featureResourceIds); - return org.apache.commons.collections4.CollectionUtils.emptyIfNull(featureResourceRoleCodes).stream() - .collect(Collectors.groupingBy(FeatureResourceRoleCodeDTO::getFeatureResourceId, Collectors.mapping(FeatureResourceRoleCodeDTO::getRoleCode, Collectors.toList()))); - } - } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasFeatureResourceMapper.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasFeatureResourceMapper.java index f8c0b32d..37c03d23 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasFeatureResourceMapper.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasFeatureResourceMapper.java @@ -1,13 +1,10 @@ package cn.axzo.tyr.server.repository.mapper; -import cn.axzo.tyr.server.model.FeatureResourceRoleCodeDTO; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Update; -import java.util.List; - /** *

* 功能资源表 Mapper 接口 @@ -22,6 +19,4 @@ public interface SaasFeatureResourceMapper extends BaseMapper listRoleCodes(@Param("ids") List ids); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/FeatureResourceSyncServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/FeatureResourceSyncServiceImpl.java index a1b89eb4..315b774e 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/FeatureResourceSyncServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/FeatureResourceSyncServiceImpl.java @@ -1,6 +1,7 @@ package cn.axzo.tyr.server.service.impl; import cn.axzo.basics.common.BeanMapper; +import cn.axzo.basics.common.constant.enums.DeleteEnum; import cn.axzo.basics.common.util.TreeUtil; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.common.enums.FeatureResourceType; @@ -28,11 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; @@ -92,7 +89,7 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic allFeatureResourceIds.addAll(CollectionUtils.emptyIfNull(componentList).stream().map(BaseEntity::getId).collect(Collectors.toList())); resourceList.addAll(componentList); } - Map> featureResourceRoleCodeMap = featureResourceDao.getFeatureResourceRoleCodeMap(allFeatureResourceIds); + Map> featureResourceRoleCodeMap = getFeatureResourceRoleCodeMap(allFeatureResourceIds); List dtoList = BeanMapper.copyList(resourceList, FeatureResourceTreeNode.class); dtoList.forEach(e -> { @@ -220,7 +217,7 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic return; } - List existRoleCodes = featureResourceDao.getFeatureResourceRoleCodeMap(Lists.newArrayList(featureResourceId)) + List existRoleCodes = getFeatureResourceRoleCodeMap(Lists.newArrayList(featureResourceId)) .get(featureResourceId); if (CollectionUtils.isNotEmpty(existRoleCodes)) { @@ -248,4 +245,56 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic saasPgroupPermissionRelationDao.saveBatch(insertRelation); } } + + private Map> getFeatureResourceRoleCodeMap(List allFeatureResourceIds) { + allFeatureResourceIds = allFeatureResourceIds.stream().distinct().collect(Collectors.toList()); + List permissionRelations = saasPgroupPermissionRelationDao.lambdaQuery() + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.value) + .in(SaasPgroupPermissionRelation::getFeatureId, allFeatureResourceIds) + .eq(SaasPgroupPermissionRelation::getType, SaasPgroupPermissionRelation.NEW_FEATURE) + .list(); + if (CollectionUtils.isEmpty(permissionRelations)) { + return Collections.emptyMap(); + } + + List roleRelations = saasPgroupRoleRelationDao.lambdaQuery() + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.value) + .in(SaasPgroupRoleRelation::getGroupId, permissionRelations.stream().map(SaasPgroupPermissionRelation::getGroupId).collect(Collectors.toSet())) + .list(); + if (CollectionUtils.isEmpty(roleRelations)) { + return Collections.emptyMap(); + } + + List roles = saasRoleDao.lambdaQuery() + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.value) + .in(BaseEntity::getId, roleRelations.stream().map(SaasPgroupRoleRelation::getRoleId).collect(Collectors.toSet())) + .list(); + if (CollectionUtils.isEmpty(roles)) { + return Collections.emptyMap(); + } + + Map> featureIdToGroupIdsMap = permissionRelations.stream() + .collect(Collectors.groupingBy(SaasPgroupPermissionRelation::getFeatureId, + Collectors.mapping(SaasPgroupPermissionRelation::getGroupId, Collectors.toList()))); + + Map> groupIdToRoleIdsMap = roleRelations.stream() + .collect(Collectors.groupingBy(SaasPgroupRoleRelation::getGroupId, + Collectors.mapping(SaasPgroupRoleRelation::getRoleId, Collectors.toList()))); + + Map roleIdToRoleCodeMap = roles.stream() + .collect(Collectors.toMap(SaasRole::getId, SaasRole::getRoleCode)); + + Map> featureRoleMap = new HashMap<>(); + featureIdToGroupIdsMap.forEach((featureId, groupIds) -> { + List roleCodes = groupIds.stream() + .flatMap(groupId -> groupIdToRoleIdsMap.getOrDefault(groupId, Collections.emptyList()).stream()) + .map(roleId -> roleIdToRoleCodeMap.get(roleId)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + featureRoleMap.put(featureId, roleCodes); + }); + + return featureRoleMap; + } } diff --git a/tyr-server/src/main/resources/mapper/SaasFeatureResourceMapper.xml b/tyr-server/src/main/resources/mapper/SaasFeatureResourceMapper.xml index 9941520c..df4395bc 100644 --- a/tyr-server/src/main/resources/mapper/SaasFeatureResourceMapper.xml +++ b/tyr-server/src/main/resources/mapper/SaasFeatureResourceMapper.xml @@ -3,18 +3,19 @@ "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - + + + + + + + + + + + + + + + \ No newline at end of file From 052899e355b45afc62ee710c3b670abfe7ebe20a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Wed, 26 Jun 2024 16:49:01 +0800 Subject: [PATCH 22/69] =?UTF-8?q?feat(REQ-2545):=20=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E6=9C=89=E6=9D=83=E9=99=90=E7=9A=84=E7=BB=84?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GetUserHasPermissionPageElementReq.java | 24 +++++++++++-------- .../server/service/impl/RoleServiceImpl.java | 1 + .../impl/SaasPageElementServiceImpl.java | 23 ++++++++++++++++-- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetUserHasPermissionPageElementReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetUserHasPermissionPageElementReq.java index 0edcee11..16788bd8 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetUserHasPermissionPageElementReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetUserHasPermissionPageElementReq.java @@ -5,9 +5,9 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; -import java.util.List; /** * @author likunpeng @@ -20,22 +20,26 @@ import java.util.List; @AllArgsConstructor public class GetUserHasPermissionPageElementReq { - /** - * 页面的元素 - */ -// @NotNull(message = "页面的元素不能为空") + /** 页面的元素 **/ + @NotBlank(message = "页面的元素不能为空") private String pageElementCode; /** 登录端 **/ -// @NotNull(message = "登录端不能为空") + @NotBlank(message = "登录端不能为空") private String terminal; -// @NotNull(message = "人员ID不能为空") + /** 人员ID **/ + @NotNull(message = "人员ID不能为空") + @Min(value = 1, message = "人员ID有误") private Long personId; -// @NotNull(message = "单位ID不能为空") + /** 单位ID **/ + @NotNull(message = "单位ID不能为空") + @Min(value = 1, message = "单位ID有误") private Long ouId; -// @NotNull(message = "租户ID不能为空") + /** 租户ID **/ + @NotNull(message = "租户ID不能为空") + @Min(value = 1, message = "租户ID有误") private Long workspaceId; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java index e58875e8..3d710a21 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java @@ -1194,6 +1194,7 @@ public class RoleServiceImpl extends ServiceImpl List saasPgroupPermissionRelations = saasPgroupPermissionRelationDao.lambdaQuery() .in(SaasPgroupPermissionRelation::getGroupId, Lists.transform(saasPgroupRoleRelations, SaasPgroupRoleRelation::getGroupId)) .eq(SaasPgroupPermissionRelation::getIsDelete, TableIsDeleteEnum.NORMAL.value) + .eq(Objects.nonNull(param.getType()), SaasPgroupPermissionRelation::getType, param.getType()) .list(); if (CollectionUtils.isEmpty(saasPgroupPermissionRelations)) { return Collections.emptyMap(); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java index 25728237..15be684d 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java @@ -10,13 +10,18 @@ import cn.axzo.tyr.client.common.enums.PageElementTypeEnum; import cn.axzo.tyr.client.model.req.*; import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; import cn.axzo.tyr.client.model.res.PageElementResp; +import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; +import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO; +import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; import cn.axzo.tyr.server.repository.dao.SaasPageElementDao; import cn.axzo.tyr.server.repository.dao.SaasPageElementFeatureResourceRelationDao; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import cn.axzo.tyr.server.repository.entity.SaasPageElement; import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; +import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation; import cn.axzo.tyr.server.service.SaasPageElementService; +import cn.axzo.tyr.server.service.SaasRoleUserRelationService; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -53,6 +58,7 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { private final SaasPageElementDao saasPageElementDao; private final SaasPageElementFeatureResourceRelationDao saasPageElementFeatureResourceRelationDao; private final SaasFeatureResourceDao saasFeatureResourceDao; + private final SaasRoleUserRelationService saasRoleUserRelationService; @Qualifier("asyncExecutor") @Autowired @@ -175,8 +181,21 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { return null; } - // TODO 过滤用户有权限的featureIds - List hasPermissionFeatureIds = saasFeatureResources.stream().map(BaseEntity::getId).collect(Collectors.toList()); + // 过滤用户有权限的featureIds + List saasRoleUsers = saasRoleUserRelationService.listV2(ListRoleUserRelationParam.builder() + .personId(request.getPersonId()) + .workspaceOuPairs(Lists.newArrayList(ListRoleUserRelationParam.WorkspaceOuPair.builder().ouId(request.getOuId()).workspaceId(request.getWorkspaceId()).build())) + .needRole(Boolean.TRUE) + .needPermissionRelation(Boolean.TRUE) + .type(SaasPgroupPermissionRelation.NEW_FEATURE) + .featureIds(saasFeatureResources.stream().map(BaseEntity::getId).collect(Collectors.toList())) + .terminal(request.getTerminal()) + .build()); + List hasPermissionFeatureIds = CollectionUtils.emptyIfNull(saasRoleUsers).stream() + .filter(e -> Objects.nonNull(e.getSaasRole()) && CollectionUtils.isNotEmpty(e.getSaasRole().getPermissionRelations())) + .flatMap(e -> e.getSaasRole().getPermissionRelations().stream().map(SaasPermissionRelationRes::getFeatureId)) + .distinct().collect(Collectors.toList()); + log.info("getUserHasPermissionPageElement pageElementCode:{}, hasPermissionFeatureIds:{}", request.getPageElementCode(), hasPermissionFeatureIds); if (CollectionUtils.isEmpty(hasPermissionFeatureIds)) { log.warn("不存在有权限的组件,页面元素编码:{}", request.getPageElementCode()); From 3ab3f0cf2bfa6c9f61c696bd144b74cad814ee5e Mon Sep 17 00:00:00 2001 From: lilong Date: Thu, 27 Jun 2024 14:17:07 +0800 Subject: [PATCH 23/69] =?UTF-8?q?feat:(REQ-2545)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=8E=86=E5=8F=B2=E6=9F=A5=E8=AF=A2=E8=8F=9C=E5=8D=95=E5=92=8C?= =?UTF-8?q?=E9=89=B4=E6=9D=83=E6=8E=A5=E5=8F=A3=EF=BC=8C=E5=90=8C=E6=97=B6?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=96=B0=E6=97=A7=E7=89=88=E6=9C=AC=E7=9A=84?= =?UTF-8?q?featureCodes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/feign/FeatureResourceApi.java | 7 +- .../model/req/DeleteFeatureResourceReq.java | 21 ++ .../tyr/client/model/req/IdentityAuthReq.java | 6 + ...PageElementFeatureResourceRelationReq.java | 33 ++ .../model/req/PageSaasFeatureResourceReq.java | 10 + .../model/res/SaasFeatureResourceResp.java | 146 ++++++++ .../config/exception/BizResultCode.java | 3 +- .../permission/FeatureResourceController.java | 12 +- .../controller/role/SaasRoleController.java | 37 +- .../service/SaasFeatureResourceService.java | 9 +- ...ElementFeatureResourceRelationService.java | 15 + .../SaasPgroupPermissionRelationService.java | 10 + .../impl/PermissionQueryServiceImpl.java | 107 +++--- .../ProductFeatureRelationServiceImpl.java | 27 +- .../impl/SaasCommonDictServiceImpl.java | 3 +- .../impl/SaasFeatureResourceServiceImpl.java | 97 +++++- ...entFeatureResourceRelationServiceImpl.java | 43 +++ ...asPgroupPermissionRelationServiceImpl.java | 10 + .../service/impl/TyrSaasAuthServiceImpl.java | 329 +++++++++++++++--- 19 files changed, 769 insertions(+), 156 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeleteFeatureResourceReq.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementFeatureResourceRelationReq.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasFeatureResourceResp.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementFeatureResourceRelationService.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementFeatureResourceRelationServiceImpl.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/FeatureResourceApi.java b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/FeatureResourceApi.java index ef3833f4..4481c42b 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/FeatureResourceApi.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/FeatureResourceApi.java @@ -1,12 +1,13 @@ package cn.axzo.tyr.client.feign; import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.tyr.client.model.req.DeleteFeatureResourceReq; +import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; import cn.axzo.tyr.client.model.req.ResourceSyncReq; -import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; -import cn.axzo.tyr.client.model.res.FeatureResourceDetailResp; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -44,7 +45,7 @@ public interface FeatureResourceApi { /** 删除菜单/页面/组件 **/ @PostMapping("/api/featureResource/delete") - ApiResult deleteFeatureResource(@RequestParam Long featureId, @RequestParam Long operatorId); + ApiResult deleteFeatureResource(@Validated @RequestParam DeleteFeatureResourceReq req); /** 重排序菜单/页面/组件 **/ diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeleteFeatureResourceReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeleteFeatureResourceReq.java new file mode 100644 index 00000000..73d74382 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeleteFeatureResourceReq.java @@ -0,0 +1,21 @@ +package cn.axzo.tyr.client.model.req; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DeleteFeatureResourceReq { + + @NotNull(message = "featureId不能为空") + private Long featureId; + + @NotNull(message = "operatorId不能为空") + private Long operatorId; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/IdentityAuthReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/IdentityAuthReq.java index 396e5c4f..7ebfe9cb 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/IdentityAuthReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/IdentityAuthReq.java @@ -65,6 +65,12 @@ public class IdentityAuthReq { @Builder.Default private boolean useCache = true; + /** + * 权限点类型(0:saas_feature,1:saas_feature_resource) + * 为了兼容第三方调用查询用户的权限点,会把新旧权限点都查询出来,灰度端历史版本由使用方传入版本 + */ + private Integer type; + public IdentityAuthRes toEmpty() { IdentityAuthRes result = new IdentityAuthRes(); result.setIdentity(this.getIdentityId()); diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementFeatureResourceRelationReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementFeatureResourceRelationReq.java new file mode 100644 index 00000000..6d78e100 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementFeatureResourceRelationReq.java @@ -0,0 +1,33 @@ +package cn.axzo.tyr.client.model.req; + +import cn.axzo.foundation.dao.support.wrapper.CriteriaField; +import cn.axzo.foundation.dao.support.wrapper.Operator; +import cn.axzo.foundation.page.IPageReq; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PageElementFeatureResourceRelationReq implements IPageReq { + + @CriteriaField(ignore = true) + Integer page; + + @CriteriaField(ignore = true) + Integer pageSize; + + /** + * 排序:使用示例,createTime__DESC + */ + @CriteriaField(ignore = true) + List sort; + + @CriteriaField(field = "featureResourceUniCode", operator = Operator.IN) + private List featureResourceUniCodes; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageSaasFeatureResourceReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageSaasFeatureResourceReq.java index 1bf06bda..9cb70535 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageSaasFeatureResourceReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageSaasFeatureResourceReq.java @@ -53,6 +53,16 @@ public class PageSaasFeatureResourceReq implements IPageReq { @CriteriaField(field = "featureType", operator = Operator.IN) private List featureResourceTypes; + @CriteriaField(field = "path", operator = Operator.SW) + private String path; + + /** + * CMS端saas_feature_resource.feature_codes已经废弃,后续其他端也会这样迁移 + * 新的存在saas_page_element_feature_resource_relation + */ + @CriteriaField(ignore = true) + private Boolean needFeatureCodes; + public PageResp toEmpty() { return PageResp.builder() .current(this.getPage()) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasFeatureResourceResp.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasFeatureResourceResp.java new file mode 100644 index 00000000..d8905e45 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasFeatureResourceResp.java @@ -0,0 +1,146 @@ +package cn.axzo.tyr.client.model.res; + +import cn.axzo.tyr.client.model.base.FeatureResourceExtraDO; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; +import java.util.Set; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaasFeatureResourceResp { + + private Long id; + + private Date createAt; + + private Date updateAt; + + /** + * 资源编码-权限码 + */ + private Set featureCodes; + + /** + * 资源名称 + */ + private String featureName; + + /** + * 资源类型1-菜单 2-页面 3-应用入口 4-组件;5-root节点 + */ + private Integer featureType; + + /** + * 资源所属端 + */ + private String terminal; + + /** + * 组件细分类型 1-跳转子页面 2-跳转公共组件 3-弹出窗口 4-下拉项 5-操作按钮 6-数据卡片 7-站外跳转 + */ + private Integer componentType; + + /** + * 上级资源ID + */ + private Long parentId; + + /** + * 资源ID层级路径, 逗号分隔 + */ + private String path; + + /** + * 展示顺序 + */ + private Integer displayOrder; + + /** + * 资源状态 0-隐藏 1-展示 + */ + private Integer status; + + /** + * 资源图标 + */ + private String icon; + + /** + * 跳转类型 1-站内跳转 2-站外跳转 + */ + private Integer redirectType; + + /** + * 资源跳转URI + */ + private String linkUrl; + + /** + * 路由类型1-PC 2-小程序 3-原生 + */ + private Integer linkType; + + /** + * APP适配参数 + */ + private String linkExt; + + /** + * 小程序id + */ + private Integer appItemId; + + /** + * 资源同步版本 + */ + private Integer syncVersion; + + /** + * 扩展字段 + */ + @TableField(value = "extra", typeHandler = FastjsonTypeHandler.class) + private FeatureResourceExtraDO extra; + + /** + * 授权类型0-全部角色 1-指定角色 + */ + private Integer authType; + + /** + * 子级鉴权类型 0-不鉴权1-鉴权 + */ + private Integer subAuthType; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 更新人 + */ + private Long updateBy; + + /** + * 应用范围(租户类型):1:企业工作台 2;项目工作台 + */ + private Long workspaceType; + + /** + * 最低版本序列,主要支持版本灰度策略 + */ + private Integer version; + + /** + * 唯一编码,用于pre环境菜单同步 + */ + private String uniCode; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/config/exception/BizResultCode.java b/tyr-server/src/main/java/cn/axzo/tyr/server/config/exception/BizResultCode.java index 07316d28..935536c8 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/config/exception/BizResultCode.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/config/exception/BizResultCode.java @@ -11,7 +11,8 @@ public enum BizResultCode implements IResultCode { CANT_DELETE_ROLE_GROUP("100001", "不能删除角色分组,当前角色分组下有子角色分组"), ROLE_GROUP_NOT_FOUND("100002", "角色分组不存在"), REDIS_ROLE_NOT_NULL("100003", "角色id不能为空"), - REDIS_PRODUCT_NOT_NULL("100004", "产品id不能为空"); + REDIS_PRODUCT_NOT_NULL("100004", "产品id不能为空"), + FEATURE_RESOURCE_NOT_FOUND("100005", "菜单资源不存在"); private String errorCode; private String errorMessage; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/FeatureResourceController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/FeatureResourceController.java index 02bbfe39..ef63b95b 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/FeatureResourceController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/FeatureResourceController.java @@ -1,12 +1,11 @@ package cn.axzo.tyr.server.controller.permission; -import cn.axzo.basics.common.exception.ServiceException; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.tyr.client.feign.FeatureResourceApi; +import cn.axzo.tyr.client.model.req.DeleteFeatureResourceReq; import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; import cn.axzo.tyr.client.model.req.ResourceSyncReq; -import cn.axzo.tyr.client.model.res.FeatureResourceDetailResp; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; import cn.axzo.tyr.server.service.FeatureResourceSyncService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; @@ -58,11 +57,10 @@ public class FeatureResourceController implements FeatureResourceApi { } @Override - public ApiResult deleteFeatureResource(Long featureId, Long operatorId) { - throw new ServiceException("暂时不支持删除权限点"); -// log.info("deleteFeatureResource featureId : {}, operatorId : {}", featureId, operatorId); -// featureResourceService.deleteMenuFeature(featureId, operatorId); -// return ApiResult.ok(); + public ApiResult deleteFeatureResource(DeleteFeatureResourceReq req) { + log.info("deleteFeatureResource req : {}", req); + featureResourceService.deleteFeatureResource(req); + return ApiResult.ok(); } @Override diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/role/SaasRoleController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/role/SaasRoleController.java index 36f1ce0d..c2f8cabb 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/role/SaasRoleController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/role/SaasRoleController.java @@ -35,7 +35,6 @@ import cn.axzo.tyr.client.model.vo.SaasRoleVO; import cn.axzo.tyr.client.model.vo.SaveOrUpdateRoleVO; import cn.axzo.tyr.server.model.PermissionCacheKey; import cn.axzo.tyr.server.repository.dao.SaasRoleGroupRelationDao; -import cn.axzo.tyr.server.repository.dao.SaasRoleUserRelationDao; import cn.axzo.tyr.server.repository.entity.SaasRole; import cn.axzo.tyr.server.repository.entity.SaasRoleGroupRelation; import cn.axzo.tyr.server.service.PermissionCacheService; @@ -52,8 +51,6 @@ import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.util.Collections; @@ -83,8 +80,6 @@ public class SaasRoleController implements TyrSaasRoleApi { @Autowired PermissionCacheService permissionCacheService; @Autowired - private SaasRoleUserRelationDao saasRoleUserRelationDao; - @Autowired private SaasCommonDictService saasCommonDictService; @Autowired private SaasRoleGroupService saasRoleGroupService; @@ -219,7 +214,9 @@ public class SaasRoleController implements TyrSaasRoleApi { // 因为根节点在roleGroup里面没有,都是workspaceTypeCode,描述是放在字典表里 List commonDicts = listRootRole(req); - + if (CollectionUtils.isEmpty(commonDicts)) { + return ApiListResult.ok(); + } List roots = commonDicts.stream() .map(e -> RoleTreeRes.builder() @@ -453,18 +450,32 @@ public class SaasRoleController implements TyrSaasRoleApi { } private List listRootRole(TreeRoleReq req) { - CommonDictQueryReq commonDictQueryReq = CommonDictQueryReq.builder() - .codes(StringUtils.isBlank(req.getWorkspaceTypeCode()) ? null : Lists.newArrayList(req.getWorkspaceTypeCode())) - .scope("role") - .build(); + + List workspaceTypeCodes = StringUtils.isNotBlank(req.getWorkspaceTypeCode()) ? Lists.newArrayList(req.getWorkspaceTypeCode()) + : Lists.newArrayList(); + if (StringUtils.isNotBlank(req.getTerminal())) { - List workspaceTypeCodes = TERMINAL_WORKSPACE_CODES.get(req.getTerminal()); - if (CollectionUtils.isEmpty(workspaceTypeCodes)) { + List terminalWorkspaceTypeCodes = TERMINAL_WORKSPACE_CODES.get(req.getTerminal()); + if (CollectionUtils.isEmpty(terminalWorkspaceTypeCodes)) { return Collections.emptyList(); } - commonDictQueryReq.setCodes(workspaceTypeCodes); + + if (StringUtils.isBlank(req.getWorkspaceTypeCode())) { + workspaceTypeCodes = terminalWorkspaceTypeCodes; + } else { + workspaceTypeCodes = terminalWorkspaceTypeCodes.stream() + .filter(e -> Objects.equals(e, req.getWorkspaceTypeCode())) + .collect(Collectors.toList()); + if (CollectionUtils.isEmpty(workspaceTypeCodes)) { + return Collections.emptyList(); + } + } } + CommonDictQueryReq commonDictQueryReq = CommonDictQueryReq.builder() + .codes(workspaceTypeCodes) + .scope("role") + .build(); return saasCommonDictService.query(commonDictQueryReq); } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java index 4bc1172e..1e10c7c4 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java @@ -1,10 +1,12 @@ package cn.axzo.tyr.server.service; import cn.axzo.foundation.page.PageResp; +import cn.axzo.tyr.client.model.req.DeleteFeatureResourceReq; import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; +import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.server.model.ResourcePermission; import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; @@ -51,7 +53,10 @@ public interface SaasFeatureResourceService extends IService listByParentIdAndTerminalAndIds(Long parentId, String terminal, List featureIds); - List list(PageSaasFeatureResourceReq param); + List list(PageSaasFeatureResourceReq param); + + PageResp page(PageSaasFeatureResourceReq param); + + void deleteFeatureResource(DeleteFeatureResourceReq param); - PageResp page(PageSaasFeatureResourceReq param); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementFeatureResourceRelationService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementFeatureResourceRelationService.java new file mode 100644 index 00000000..51a9e2f9 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementFeatureResourceRelationService.java @@ -0,0 +1,15 @@ +package cn.axzo.tyr.server.service; + +import cn.axzo.foundation.page.PageResp; +import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq; +import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +public interface SaasPageElementFeatureResourceRelationService extends IService { + + List list(PageElementFeatureResourceRelationReq param); + + PageResp page(PageElementFeatureResourceRelationReq param); +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPgroupPermissionRelationService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPgroupPermissionRelationService.java index 1c814364..3651d466 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPgroupPermissionRelationService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPgroupPermissionRelationService.java @@ -18,6 +18,8 @@ public interface SaasPgroupPermissionRelationService extends IService list(PagePgroupPermissionRelationReq param); + void delete(DeleteParam param); + @Data @Builder @NoArgsConstructor @@ -40,4 +42,12 @@ public interface SaasPgroupPermissionRelationService extends IService ids; + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java index fc021d8b..29617e7f 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java @@ -29,6 +29,7 @@ import cn.axzo.tyr.client.model.res.FeatureResourceDTO; import cn.axzo.tyr.client.model.res.IdentityAuthRes; import cn.axzo.tyr.client.model.res.NavTreeResp; import cn.axzo.tyr.client.model.res.ProductFeatureResourceResp; +import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; import cn.axzo.tyr.client.model.res.TreePermissionResp; import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO; @@ -44,7 +45,6 @@ import cn.axzo.tyr.server.repository.dao.ProductModuleDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; import cn.axzo.tyr.server.repository.dao.SaasPageElementFeatureResourceRelationDao; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; -import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation; import cn.axzo.tyr.server.service.PermissionQueryService; @@ -63,7 +63,6 @@ import com.google.common.collect.Sets; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Value; @@ -283,8 +282,9 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { return Collections.emptyList(); } - List saasFeatureResources = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() + List saasFeatureResources = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() .ids(Lists.newArrayList(featureIds)) + .needFeatureCodes(true) .terminal(req.getTerminal()) .sort(Lists.newArrayList("displayOrder__ASC")) .build()); @@ -293,42 +293,18 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { return Collections.emptyList(); } - Map> featureCodes = listFeatureCodes(saasFeatureResources, req); - List treePermissionResps = saasFeatureResources.stream() - .map(e -> TreePermissionResp.builder() - .featureId(e.getId()) - .featureName(e.getFeatureName()) - .featureType(e.getFeatureType()) - .redirectType(e.getRedirectType()) - .linkUrl(e.getLinkUrl()) - .icon(e.getIcon()) - .parentId(e.getParentId()) - .status(e.getStatus()) - .uniCode(e.getUniCode()) - .featureCodes(featureCodes.get(e.getUniCode())) - .build()) + .map(e -> { + TreePermissionResp treePermissionResp = TreePermissionResp.builder().build(); + BeanUtils.copyProperties(e, treePermissionResp); + return treePermissionResp; + }) .collect(Collectors.toList()); // 组装导航树 // 过滤掉隐藏的节点,因为存在某些节点被隐藏,需要把这些节点和子节点给过滤掉 return TreeUtil.buildTree(treePermissionResps, (Function) e -> Objects.equals(DISPLAY_STATUS, e.getStatus())); } - private Map> listFeatureCodes(List saasFeatureResources, - TreePermissionReq req) { - - if (CollectionUtils.isEmpty(saasFeatureResources) || BooleanUtils.isNotTrue(req.isNeedFeatureCodes())) { - return Collections.emptyMap(); - } - - List uniCodes = saasFeatureResources.stream() - .map(SaasFeatureResource::getUniCode) - .collect(Collectors.toList()); - return saasPageElementFeatureResourceRelationDao.listByUniCodeAndTerminal(uniCodes, req.getTerminal()).stream() - .collect(Collectors.groupingBy(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode, - Collectors.mapping(SaasPageElementFeatureResourceRelation::getPageElementCode, Collectors.toSet()))); - } - private List getProductFeatureRelationByWorkspace(Set workspaceIds) { List servicePkgDetailRes = RpcInternalUtil.rpcListProcessor(() -> servicePkgClient.getServicePkgDetailBySpaceId(workspaceIds), "查询租户的产品", workspaceIds).getData(); @@ -573,6 +549,42 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { return Collections.emptySet(); } + List saasRoleUserV2DTOS = listUserPermission(treePermissionReq, featureIds); + + List workspaceProducts = listWorkspaceProducts(treePermissionReq); + + //免授权 + List authFreeFeatureIds = listNotAuthFeatures(treePermissionReq); + + //取交集确定权限 + return mixFeatureIds(saasRoleUserV2DTOS, workspaceProducts, authFreeFeatureIds); + } + + private List listNotAuthFeatures(TreePermissionReq treePermissionReq) { + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .terminal(treePermissionReq.getTerminal()) + .authType(FeatureResourceAuthType.ALL_ROLE.getCode()) + .build(); + return featureResourceService.list(pageSaasFeatureResourceReq).stream() + .map(SaasFeatureResourceResp::getId) + .collect(Collectors.toList()); + } + + private List listWorkspaceProducts(TreePermissionReq treePermissionReq) { + //查询租户产品权限点 + Set workspaceIds = treePermissionReq.getWorkspaceOUPairs().stream() + .map(WorkspaceOUPair::getWorkspaceId) + .collect(Collectors.toSet()); + WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() + .terminal(treePermissionReq.getTerminal()) + .workspaceIds(workspaceIds) + .featureResourceTypes(treePermissionReq.getFeatureResourceTypes()) + .type(NEW_FEATURE) + .build(); + return workspaceProductService.listWorkspaceProduct(workspaceProductParam); + } + + private List listUserPermission(TreePermissionReq treePermissionReq, List featureIds) { List workspaceOuPairs = treePermissionReq.getWorkspaceOUPairs().stream() .map(e -> ListRoleUserRelationParam.WorkspaceOuPair.builder() .workspaceId(e.getWorkspaceId()) @@ -590,36 +602,9 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .terminal(treePermissionReq.getTerminal()) .featureIds(featureIds) .build(); - List saasRoleUserV2DTOS = saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream() + return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream() .filter(e -> e.getSaasRole() != null && CollectionUtils.isNotEmpty(e.getSaasRole().getPermissionRelations())) .collect(Collectors.toList()); - - if (CollectionUtil.isEmpty(saasRoleUserV2DTOS)) { - log.warn("no user role relation found"); - return Collections.emptySet(); - } - //查询租户产品权限点 - Set workspaceIds = treePermissionReq.getWorkspaceOUPairs().stream() - .map(WorkspaceOUPair::getWorkspaceId) - .collect(Collectors.toSet()); - WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() - .terminal(treePermissionReq.getTerminal()) - .workspaceIds(workspaceIds) - .featureResourceTypes(treePermissionReq.getFeatureResourceTypes()) - .build(); - List workspaceProducts = workspaceProductService.listWorkspaceProduct(workspaceProductParam); - - //免授权 - PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() - .terminal(treePermissionReq.getTerminal()) - .authType(FeatureResourceAuthType.ALL_ROLE.getCode()) - .build(); - List authFreeFeatureIds = featureResourceService.list(pageSaasFeatureResourceReq).stream() - .map(SaasFeatureResource::getId) - .collect(Collectors.toList()); - - //取交集确定权限 - return mixFeatureIds(saasRoleUserV2DTOS, workspaceProducts, authFreeFeatureIds); } private List resolveFeatureIds(TreePermissionReq treePermissionReq) { @@ -636,7 +621,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .featureResourceTypes(featureTypes) .build(); return featureResourceService.list(pageSaasFeatureResourceReq).stream() - .map(SaasFeatureResource::getId) + .map(SaasFeatureResourceResp::getId) .collect(Collectors.toList()); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductFeatureRelationServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductFeatureRelationServiceImpl.java index 653097ef..9b73479b 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductFeatureRelationServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductFeatureRelationServiceImpl.java @@ -1,7 +1,6 @@ package cn.axzo.tyr.server.service.impl; import cn.axzo.basics.common.BeanMapper; -import cn.axzo.framework.auth.domain.TerminalInfo; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.thrones.client.saas.ServicePkgClient; @@ -42,7 +41,6 @@ import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; -import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; import static cn.axzo.tyr.server.util.RpcInternalUtil.checkAndGetData; /** @@ -136,17 +134,18 @@ public class ProductFeatureRelationServiceImpl implements ProductFeatureRelation return ApiResult.ok(Collections.emptyList()); } List list = saasProductModuleFeatureRelationDao.lambdaQuery() - .select(SaasProductModuleFeatureRelation::getFeatureId - ,SaasProductModuleFeatureRelation::getProductModuleId - ,SaasProductModuleFeatureRelation::getDictCode - ,SaasProductModuleFeatureRelation::getDictCodeId - , BaseEntity::getId) + .select(SaasProductModuleFeatureRelation::getFeatureId, + SaasProductModuleFeatureRelation::getProductModuleId, + SaasProductModuleFeatureRelation::getDictCode, + SaasProductModuleFeatureRelation::getDictCodeId, + BaseEntity::getId, + SaasProductModuleFeatureRelation::getType) .in(SaasProductModuleFeatureRelation::getProductModuleId, productIds) .list(); return ApiResult.ok(BeanMapper.copyList(list, ProductFeatureRelationVO.class)); } - + @Override public Map> getByWorkspace(Set workspaceId) { StopWatch stopWatch = StopWatch.create(" get product by workspace"); @@ -217,19 +216,13 @@ public class ProductFeatureRelationServiceImpl implements ProductFeatureRelation .eq(Objects.nonNull(condition.getWorkspaceJoinType()), SaasProductModuleFeatureRelation::getDictCode, condition.getWorkspaceJoinType()) .in(CollectionUtil.isNotEmpty(condition.getFeatureIds()), SaasProductModuleFeatureRelation::getFeatureId, condition.getFeatureIds()) - .eq(Objects.nonNull(condition.getType()), SaasProductModuleFeatureRelation::getType, condition.getType()); + .eq(Objects.nonNull(condition.getType()), SaasProductModuleFeatureRelation::getType, condition.getType()) + .eq(StringUtils.hasLength(condition.getTerminal()), SaasProductModuleFeatureRelation::getTerminal, condition.getTerminal()); + if (!CollectionUtils.isEmpty(condition.getFeatureResourceTypes())) { wrapper.in(SaasProductModuleFeatureRelation::getFeatureType, Lists.transform(condition.getFeatureResourceTypes(), FeatureResourceType::getCode)); } - // 目前只有新版本的CMS端产品配置时才冗余了terminal - if (Objects.equals(NEW_FEATURE, condition.getType()) && StringUtils.hasLength(condition.getTerminal())) { - TerminalInfo terminalInfo = new TerminalInfo(condition.getTerminal()); - if (terminalInfo.isCMS()) { - wrapper.eq(SaasProductModuleFeatureRelation::getTerminal, condition.getTerminal()); - } - } - return this.saasProductModuleFeatureRelationDao.list(wrapper); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasCommonDictServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasCommonDictServiceImpl.java index 9e3729cf..5ca0695c 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasCommonDictServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasCommonDictServiceImpl.java @@ -30,8 +30,7 @@ public class SaasCommonDictServiceImpl implements SaasCommonDictService { private final SaasCommonDictDao commonDictDao; @Override - public List - query(CommonDictQueryReq req) { + public List query(CommonDictQueryReq req) { List list = commonDictDao.lambdaQuery() .eq(Objects.nonNull(req.getScope()), SaasCommonDict::getScope, req.getScope()) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java index 7f603622..0c5ffd69 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java @@ -1,24 +1,30 @@ package cn.axzo.tyr.server.service.impl; import cn.axzo.basics.common.BeanMapper; +import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum; import cn.axzo.basics.common.util.StopWatchUtil; import cn.axzo.basics.common.util.TreeUtil; import cn.axzo.foundation.dao.support.converter.PageConverter; import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper; +import cn.axzo.foundation.exception.Axssert; import cn.axzo.foundation.page.PageResp; import cn.axzo.framework.domain.web.code.BaseCode; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType; import cn.axzo.tyr.client.common.enums.FeatureResourceStatus; import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.client.model.req.DeleteFeatureResourceReq; import cn.axzo.tyr.client.model.req.FeatureComponentSaveReq; import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; +import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq; +import cn.axzo.tyr.client.model.req.PagePgroupPermissionRelationReq; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.client.model.res.FeatureResourceDTO; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; import cn.axzo.tyr.client.model.res.PageElementBasicDTO; +import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.server.common.util.Throws; import cn.axzo.tyr.server.model.ResourcePermission; import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO; @@ -26,9 +32,13 @@ import cn.axzo.tyr.server.model.convert.SaasFeatureResourceConvert; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import cn.axzo.tyr.server.repository.entity.SaasPageElement; +import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; +import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation; import cn.axzo.tyr.server.repository.mapper.SaasFeatureResourceMapper; import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import cn.axzo.tyr.server.service.SaasPageElementFeatureResourceRelationService; import cn.axzo.tyr.server.service.SaasPageElementService; +import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService; import cn.azxo.framework.common.utils.StringUtils; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; @@ -36,9 +46,12 @@ import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.springframework.beans.BeanUtils; import org.springframework.cache.annotation.CacheEvict; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -46,12 +59,14 @@ import org.springframework.transaction.annotation.Transactional; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.function.Function; import java.util.stream.Collectors; +import static cn.axzo.tyr.server.config.exception.BizResultCode.FEATURE_RESOURCE_NOT_FOUND; import static cn.axzo.tyr.server.repository.entity.SaasFeatureResource.DEFAULT_WORKSPACE_TYPE; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; /** * 功能资源服务实现 @@ -72,6 +87,8 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl listNavByIds(List featureIds, List featureTypes) { @@ -477,7 +494,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl list(PageSaasFeatureResourceReq param) { + public List list(PageSaasFeatureResourceReq param) { return PageConverter.drainAll(pageNumber -> { param.setPage(pageNumber); param.setPageSize(500); @@ -486,7 +503,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl page(PageSaasFeatureResourceReq param) { + public PageResp page(PageSaasFeatureResourceReq param) { String parentPath = resolveParentPath(param); if (Objects.nonNull(param.getParentId()) && StringUtils.isBlank(parentPath)) { @@ -499,7 +516,36 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl page = this.page(PageConverter.toMybatis(param, SaasFeatureResource.class), wrapper); - return PageConverter.toResp(page, Function.identity()); + Map> uniCodeFeatureCodeMap = listFeatureCodes(param, page.getRecords()); + + return PageConverter.toResp(page, e -> from(e, uniCodeFeatureCodeMap)); + } + + private SaasFeatureResourceResp from(SaasFeatureResource featureResource, + Map> uniCodeFeatureCodeMap) { + SaasFeatureResourceResp saasFeatureResourceResp = SaasFeatureResourceResp.builder().build(); + BeanUtils.copyProperties(featureResource, saasFeatureResourceResp); + + saasFeatureResourceResp.setFeatureCodes(uniCodeFeatureCodeMap.get(featureResource.getUniCode())); + return saasFeatureResourceResp; + } + + private Map> listFeatureCodes(PageSaasFeatureResourceReq param, + List saasFeatureResources) { + + if (CollectionUtils.isEmpty(saasFeatureResources) || BooleanUtils.isNotTrue(param.getNeedFeatureCodes())) { + return Collections.emptyMap(); + } + + List uniCodes = Lists.transform(saasFeatureResources, SaasFeatureResource::getUniCode); + PageElementFeatureResourceRelationReq pageElementFeatureResourceRelationReq = PageElementFeatureResourceRelationReq.builder() + .featureResourceUniCodes(uniCodes) + .build(); + return saasPageElementFeatureResourceRelationService.list(pageElementFeatureResourceRelationReq) + .stream() + .collect(Collectors.groupingBy(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode, + Collectors.mapping(SaasPageElementFeatureResourceRelation::getPageElementCode, Collectors.toSet()))); + } private String resolveParentPath(PageSaasFeatureResourceReq param) { @@ -530,4 +576,47 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl deleteFeatureResource = this.list(PageSaasFeatureResourceReq.builder() + .path(featureResource.getPath()) + .build()); + + // 删除自己及自己的子集 + this.updateBatchById(deleteFeatureResource.stream() + .map(e -> { + SaasFeatureResource saasFeatureResource = new SaasFeatureResource(); + saasFeatureResource.setId(e.getId()); + saasFeatureResource.setUpdateBy(param.getOperatorId()); + saasFeatureResource.setIsDelete(TableIsDeleteEnum.DELETE.value); + return saasFeatureResource; + }) + .collect(Collectors.toList())); + + deletePermissionRelations(deleteFeatureResource); + } + + private void deletePermissionRelations(List deleteFeatureResource) { + + PagePgroupPermissionRelationReq pagePgroupPermissionRelationReq = PagePgroupPermissionRelationReq.builder() + .featureIds(Lists.transform(deleteFeatureResource, SaasFeatureResourceResp::getId)) + .type(NEW_FEATURE) + .build(); + List permissionRelations = saasPgroupPermissionRelationService.list(pagePgroupPermissionRelationReq); + + if (CollectionUtils.isEmpty(permissionRelations)) { + return; + } + SaasPgroupPermissionRelationService.DeleteParam deleteParam = SaasPgroupPermissionRelationService.DeleteParam.builder() + .ids(Lists.transform(permissionRelations, SaasPgroupPermissionRelation::getId)) + .build(); + saasPgroupPermissionRelationService.delete(deleteParam); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementFeatureResourceRelationServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementFeatureResourceRelationServiceImpl.java new file mode 100644 index 00000000..abb33ff7 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementFeatureResourceRelationServiceImpl.java @@ -0,0 +1,43 @@ +package cn.axzo.tyr.server.service.impl; + +import cn.axzo.foundation.dao.support.converter.PageConverter; +import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper; +import cn.axzo.foundation.page.PageResp; +import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq; +import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; +import cn.axzo.tyr.server.repository.mapper.SaasPageElementFeatureResourceRelationMapper; +import cn.axzo.tyr.server.service.SaasPageElementFeatureResourceRelationService; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.function.Function; + +@Slf4j +@Service +public class SaasPageElementFeatureResourceRelationServiceImpl extends ServiceImpl + implements SaasPageElementFeatureResourceRelationService { + + @Override + public List list(PageElementFeatureResourceRelationReq param) { + return PageConverter.drainAll(pageNumber -> { + param.setPage(pageNumber); + param.setPageSize(500); + return page(param); + }); + } + + @Override + public PageResp page(PageElementFeatureResourceRelationReq param) { + + QueryWrapper wrapper = QueryWrapperHelper.fromBean(param, SaasPageElementFeatureResourceRelation.class); + wrapper.eq("is_delete", 0); + + IPage page = this.page(PageConverter.toMybatis(param, SaasPageElementFeatureResourceRelation.class), wrapper); + + return PageConverter.toResp(page, Function.identity()); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPgroupPermissionRelationServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPgroupPermissionRelationServiceImpl.java index 9b8e3049..dd91dcfe 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPgroupPermissionRelationServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPgroupPermissionRelationServiceImpl.java @@ -11,6 +11,7 @@ import cn.axzo.tyr.server.repository.dao.SaasPgroupPermissionRelationDao; import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation; import cn.axzo.tyr.server.repository.mapper.SaasPgroupPermissionRelationMapper; import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService; +import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -102,4 +103,13 @@ public class SaasPgroupPermissionRelationServiceImpl return page(param); }); } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(DeleteParam param) { + if (CollectionUtil.isEmpty(param.getIds())) { + return; + } + this.removeByIds(param.getIds()); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java index 4c22051d..931bddad 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java @@ -7,6 +7,7 @@ import cn.axzo.pokonyan.util.TraceSupplier; import cn.axzo.thrones.client.saas.ServicePkgClient; import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct; import cn.axzo.thrones.client.saas.entity.servicepkg.ServicePkgDetailRes; +import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType; import cn.axzo.tyr.client.common.enums.RoleTypeEnum; import cn.axzo.tyr.client.common.enums.WorkspaceJoinType; import cn.axzo.tyr.client.model.enums.DelegatedType; @@ -21,6 +22,7 @@ import cn.axzo.tyr.client.model.req.ListPermissionFromFeatureReq; import cn.axzo.tyr.client.model.req.ListPermissionFromIdentityReq; import cn.axzo.tyr.client.model.req.ListPermissionFromRoleGroupReq; import cn.axzo.tyr.client.model.req.OUWorkspacePair; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.client.model.req.PermissionCheckReq; import cn.axzo.tyr.client.model.req.QueryPermissionByIdsReq; import cn.axzo.tyr.client.model.req.QuerySaasRoleReq; @@ -29,7 +31,6 @@ import cn.axzo.tyr.client.model.res.IdentityAuthRes; import cn.axzo.tyr.client.model.res.ListIdentityFromPermissionResp; import cn.axzo.tyr.client.model.res.ListPermissionFromRoleGroupResp; import cn.axzo.tyr.client.model.res.QueryIdentityByPermissionResp; -import cn.axzo.tyr.client.model.res.SaasPermissionRes; import cn.axzo.tyr.client.model.res.SaasRoleRes; import cn.axzo.tyr.client.model.res.SimplePermissionPointResp; import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO; @@ -54,9 +55,11 @@ import cn.axzo.tyr.server.service.PermissionCacheService; import cn.axzo.tyr.server.service.PermissionPointService; import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.RoleService; +import cn.axzo.tyr.server.service.SaasFeatureResourceService; import cn.axzo.tyr.server.service.SaasRoleGroupService; import cn.axzo.tyr.server.service.SaasRoleUserRelationService; import cn.axzo.tyr.server.service.TyrSaasAuthService; +import cn.axzo.tyr.server.service.WorkspaceProductService; import cn.axzo.tyr.server.util.KeyUtil; import cn.axzo.tyr.server.utils.RpcExternalUtil; import cn.azxo.framework.common.model.CommonResponse; @@ -98,6 +101,8 @@ import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE; import static cn.axzo.tyr.server.util.RpcInternalUtil.checkAndGetData; import static cn.axzo.tyr.server.util.RpcInternalUtil.rpcListProcessor; @@ -128,6 +133,8 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { private final SaasRoleUserRelationService saasRoleUserRelationService; private final SaasFeatureDao saasFeatureDao; private final SaasProductModuleFeatureRelationDao saasProductModuleFeatureRelationDao; + private final WorkspaceProductService workspaceProductService; + private final SaasFeatureResourceService saasFeatureResourceService; /** * 通过身份查询人员权限 @@ -346,6 +353,54 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return permissionSet.containsAll(checkCodes); } +// private IdentityAuthRes listAllNotAuthPermission(IdentityAuthReq identityAuthReq) { +// // 目前只有CMS端会同时在saas_feature和saas_feature_resource中使用 +// permissionPointService.queryList(PermissionPointListQueryRequest.builder() +// .delegatedType(DelegatedType.NO_NEED.getCode()) +// .build()); +// +// PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() +// .terminal(TerminalInfo.NT_CMS_WEB_GENERAL) +// .authType(FeatureResourceAuthType.ALL_ROLE.getCode()) +// .build(); +// saasFeatureResourceService.list(pageSaasFeatureResourceReq); +// +// Set workspaceIds = identityAuthReq.getWorkspaceOusPairs().stream() +// .map(IdentityAuthReq.WorkspaceOuPair::getWorkspaceId) +// .collect(Collectors.toSet()); +// +// WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() +// .workspaceIds(workspaceIds) +// .featureIds() +// .build(); +// workspaceProductService.listWorkspaceProduct(workspaceProductParam); +// +// +// IdentityAuthRes result = new IdentityAuthRes(); +// result.setIdentity(identityAuthReq.getIdentityId()); +// result.setIdentityType(identityAuthReq.getIdentityType()); +// result.setPersonId(identityAuthReq.getPersonId()); +// +// List workspacePermissions = identityAuthReq.getWorkspaceOusPairs().stream() +// .map(e -> { +// +// IdentityAuthRes.WorkspacePermission workspacePermission = IdentityAuthRes.WorkspacePermission.builder() +// .workspaceId(e.getWorkspaceId()) +// .ouId(e.getOuId()) +// .build(); +// +// IdentityAuthRes.PermissionPoint.builder() +// .featureCode(e.getCode()) +// .featureId(e.getId()) +// .terminal(e.getTerminal()) +// .build(); +// return workspacePermission; +// }) +// .collect(Collectors.toList()); +// +// result.setPermissions(workspacePermissions); +// return result; +// } private IdentityAuthRes findIdentityAuth(IdentityAuthReq identityAuthReq) { //用户角色关系 @@ -357,19 +412,26 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { Set realWorkspaceId = saasRoleUserRelations.stream().map(SaasRoleUserRelation::getWorkspaceId).collect(Collectors.toSet()); //工作台对应产品 key = workspaceId - CompletableFuture>> workspacePermissionPointFuture = CompletableFuture - .supplyAsync(TraceSupplier.create(() -> productFeatureRelationService.getByWorkspace(realWorkspaceId)), executor); + CompletableFuture> workspacePermissionPointFuture = CompletableFuture + .supplyAsync(TraceSupplier.create(() -> { + WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() + .workspaceIds(realWorkspaceId) + .type(identityAuthReq.getType()) + .build(); + return workspaceProductService.listWorkspaceProduct(workspaceProductParam); + }), executor); //查询工作台下授予的角色和权限 List owRoles = listRolesWithPermission(saasRoleUserRelations, identityAuthReq); - Map> workspaceProductPermissionMap = workspacePermissionPointFuture.join(); + Map workspaceProductPermissionMap = workspacePermissionPointFuture.join().stream() + .collect(Collectors.toMap(WorkspaceProductService.WorkspaceProduct::getWorkspaceId, Function.identity())); List> futureList = new ArrayList<>(); for (OUWRoleInfo owRoleInfo : owRoles) { // 工作台的产品权限点 - List productFeatureRelationVOS = workspaceProductPermissionMap.get(owRoleInfo.getWorkspaceId()); + WorkspaceProductService.WorkspaceProduct workspaceProduct = workspaceProductPermissionMap.get(owRoleInfo.getWorkspaceId()); //构建每个工作台的实际权限点 - futureList.add(CompletableFuture.supplyAsync(TraceSupplier.create(() -> buildPermissions(owRoleInfo, productFeatureRelationVOS)), executor) + futureList.add(CompletableFuture.supplyAsync(TraceSupplier.create(() -> buildPermissions(owRoleInfo, workspaceProduct)), executor) .exceptionally(t -> { LogUtil.error("获取角色对应权限失败", t); throw new ServiceException(t); @@ -387,14 +449,14 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return result; } - private IdentityAuthRes.WorkspacePermission buildPermissions(OUWRoleInfo ouwRoleInfo, List productFeatures) { + private IdentityAuthRes.WorkspacePermission buildPermissions(OUWRoleInfo ouwRoleInfo, WorkspaceProductService.WorkspaceProduct workspaceProduct) { IdentityAuthRes.WorkspacePermission resultPermission = IdentityAuthRes.WorkspacePermission.builder() .workspaceId(ouwRoleInfo.getWorkspaceId()) .ouId(ouwRoleInfo.getOuId()) .build(); - if (CollectionUtil.isEmpty(productFeatures)) { + if (Objects.isNull(workspaceProduct) || CollectionUtil.isEmpty(workspaceProduct.getSaasProductModuleFeatureRelations())) { log.warn("no product features found for workspace :{}", ouwRoleInfo.getWorkspaceId()); return resultPermission; } @@ -405,25 +467,26 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return resultPermission; } + List productFeatures = workspaceProduct.getSaasProductModuleFeatureRelations(); + // 因为存在同时有saas_feature和saas_feature_resource的权限,所以要返回type,根据type解析code //超管和管理员权限 - Pair> adminPermissions = buildAdminPermission(ouwRoleInfo, productFeatures); + Pair> adminPermissions = buildAdminPermission(ouwRoleInfo, productFeatures); //标准角和自定义角色权限 - Set normalPermissions = buildNormalPermission(ouwRoleInfo, productFeatures); - Set allPermissionIds = new HashSet<>(); - allPermissionIds.addAll(adminPermissions.getValue()); - allPermissionIds.addAll(normalPermissions); + Set normalPermissions = buildNormalPermission(ouwRoleInfo, productFeatures); + Set allPermissions = Sets.newHashSet(); + allPermissions.addAll(adminPermissions.getValue()); + allPermissions.addAll(normalPermissions); //查询权限点及父级权限点 - List allPermissionPoint = permissionPointService.listPermissionByIds( - QueryPermissionByIdsReq.builder() - .ids(allPermissionIds) - .includeParent(true) - .build()); + List allOldPermissionPoint = listOldFeatures(allPermissions); + + List newPermissionPoints = listNewFeatures(allPermissions); + //组装返回值 //是否超管 resultPermission.setSuperAdmin(BooleanUtil.isTrue(adminPermissions.getKey())); //权限数据 - resultPermission.getPermissionPoint().addAll(allPermissionPoint.stream() + resultPermission.getPermissionPoint().addAll(allOldPermissionPoint.stream() .map(permissionPointTreeNode -> IdentityAuthRes.PermissionPoint.builder() .featureCode(permissionPointTreeNode.getCode()) .featureId(permissionPointTreeNode.getId()) @@ -431,14 +494,63 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .build()) .collect(Collectors.toList())); + resultPermission.getPermissionPoint().addAll(newPermissionPoints); return resultPermission; } - private Set buildNormalPermission(OUWRoleInfo userRoleInfoMap, List productFeatures) { + private List listNewFeatures(Set featureWrappers) { + List featureIds = featureWrappers.stream() + .filter(e -> Objects.equals(e.getType(), NEW_FEATURE)) + .map(FeatureWrapper::getFeatureId) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyList(); + } + + // 因为新版本配置权限点的时候,会在选中某个权限节点时,把所有父节点也冗余到权限里,所以只需要查询权限点信息 + return saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() + .ids(featureIds) + .needFeatureCodes(true) + .build()) + .stream() + .filter(e -> !CollectionUtils.isEmpty(e.getFeatureCodes())) + .map(e -> + // 兼容历史情况,根据featureCode组装数据 + e.getFeatureCodes().stream() + .map(featureCode -> IdentityAuthRes.PermissionPoint.builder() + .featureCode(featureCode) + .featureId(e.getId()) + .terminal(e.getTerminal()) + .build()) + .collect(Collectors.toList())) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + private List listOldFeatures(Set featureWrappers) { + Set featureIds = featureWrappers.stream() + .filter(e -> Objects.equals(e.getType(), OLD_FEATURE)) + .map(FeatureWrapper::getFeatureId) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyList(); + } + + return permissionPointService.listPermissionByIds( + QueryPermissionByIdsReq.builder() + .ids(featureIds) + .includeParent(true) + .build()); + } + + private Set buildNormalPermission(OUWRoleInfo userRoleInfoMap, List productFeatures) { log.info("build permission for ou:{}, workspace:{}", userRoleInfoMap.getOuId(), userRoleInfoMap.getWorkspaceId()); - Set allMatchedProductFeatureIds = new HashSet<>(); - Set allAuthPermissionIds = new HashSet<>(); + Set allMatchedProductFeatures = new HashSet<>(); + Set allAuthFeatures = new HashSet<>(); + //聚合实际授权的权限:角色权限和产品权限交集 for (SaasRoleRes role : userRoleInfoMap.getRoles()) { //跳过超管和管理员 @@ -448,40 +560,89 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } log.info("build permission for role:{}", role.getId()); - Set rolePermissionIds = Optional.ofNullable(role.getSaasPermissions()) + Set rolePermissions = Optional.ofNullable(role.getPermissionRelations()) .map(e -> e.stream() .filter(Objects::nonNull) - .map(SaasPermissionRes::getId) + .map(f -> FeatureWrapper.builder() + .featureId(f.getFeatureId()) + .type(f.getType()) + .build()) .collect(Collectors.toSet())) .orElseGet(Sets::newHashSet); //角色标签类型匹配产品标签类型 - Set productPermissionIds = productFeatures.stream() + Set productPermissions = productFeatures.stream() .filter(productFeatureRelationVO -> Objects.equals(productFeatureRelationVO.getDictCode(), String.valueOf(role.getProductUnitType()))) - .map(ProductFeatureRelationVO::getFeatureId) + .map(e -> FeatureWrapper.builder() + .featureId(e.getFeatureId()) + .type(e.getType()) + .build()) .collect(Collectors.toSet()); - allMatchedProductFeatureIds.addAll(productPermissionIds); + allMatchedProductFeatures.addAll(productPermissions); // 产品对应权限点 与 角色权限点 取交集 - Collection resultHashAuthPointId = CollectionUtil.intersection(productPermissionIds, rolePermissionIds); + Collection resultHashAuthPointId = CollectionUtil.intersection(productPermissions, rolePermissions); if (CollectionUtil.isNotEmpty(resultHashAuthPointId)) { log.info("add auth permission for role:{}", role.getId()); - allAuthPermissionIds.addAll(resultHashAuthPointId); + allAuthFeatures.addAll(resultHashAuthPointId); } } - if (CollectionUtil.isEmpty(allMatchedProductFeatureIds)) { + if (CollectionUtil.isEmpty(allMatchedProductFeatures)) { log.info("no normal roles found"); - return allAuthPermissionIds; + return allAuthFeatures; } - // 免授权权限点统一处理 - List noNeedPermissionPoint = permissionPointService.queryList(PermissionPointListQueryRequest.builder() - .ids(new ArrayList<>(allMatchedProductFeatureIds)) - .delegatedType(DelegatedType.NO_NEED.getCode()) - .build()); - allAuthPermissionIds.addAll(noNeedPermissionPoint.stream().map(PermissionPointTreeNode::getPermissionPointId).collect(Collectors.toSet())); - return allAuthPermissionIds; + Set newFeatureNoAuth = listNoAuthFeatureResources(allMatchedProductFeatures); + + Set oldFeatureNoAuth = listNoAuthFeatures(allMatchedProductFeatures); + allAuthFeatures.addAll(newFeatureNoAuth); + allAuthFeatures.addAll(oldFeatureNoAuth); + return allAuthFeatures; } - private Pair> buildAdminPermission(OUWRoleInfo userRoleInfoMap, List productFeatures) { + private Set listNoAuthFeatures(Set featureWrappers) { + List featureIds = featureWrappers.stream() + .filter(e -> Objects.equals(e.getType(), OLD_FEATURE)) + .map(FeatureWrapper::getFeatureId) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptySet(); + } + + return permissionPointService.queryList(PermissionPointListQueryRequest.builder() + .ids(featureIds) + .delegatedType(DelegatedType.NO_NEED.getCode()) + .build()) + .stream() + .map(e -> FeatureWrapper.builder() + .featureId(e.getPermissionPointId()) + .type(OLD_FEATURE) + .build()) + .collect(Collectors.toSet()); + } + + private Set listNoAuthFeatureResources(Set featureWrappers) { + List featureIds = featureWrappers.stream() + .filter(e -> Objects.equals(e.getType(), NEW_FEATURE)) + .map(FeatureWrapper::getFeatureId) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptySet(); + } + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(featureIds) + .authType(FeatureResourceAuthType.ALL_ROLE.getCode()) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .map(e -> FeatureWrapper.builder() + .featureId(e.getId()) + .type(NEW_FEATURE) + .build()) + .collect(Collectors.toSet()); + } + + private Pair> buildAdminPermission(OUWRoleInfo userRoleInfoMap, List productFeatures) { Boolean superAdmin = false; //超管和管理员角色 List adminRoles = userRoleInfoMap.getRoles().stream() @@ -495,28 +656,45 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { log.info("build admin permission for ou:{}, workspace:{}", userRoleInfoMap.getOuId(), userRoleInfoMap.getWorkspaceId()); //聚合超管和管理员的权限点: 直接取角色标签和产品标签相匹配的权限点 - Set permissionIds = new HashSet<>(); + Set permissions = Sets.newHashSet(); for (SaasRoleRes adminRole : adminRoles) { //超管:查询工作台对应产品,获取权限点, ( 权限点通过单位类型过滤) if (RoleTypeEnum.SUPER_ADMIN.getValue().equals(adminRole.getRoleType())) { superAdmin = true; } //角色标签类型匹配产品标签类型 - Set buttonPermissionPointId = productFeatures.stream() + Set permission = productFeatures.stream() .filter(productFeatureRelationVO -> Objects.equals(productFeatureRelationVO.getDictCode(), String.valueOf(adminRole.getProductUnitType()))) - .map(ProductFeatureRelationVO::getFeatureId) + .map(e -> FeatureWrapper.builder() + .featureId(e.getFeatureId()) + .type(e.getType()) + .build()) .collect(Collectors.toSet()); - if (CollectionUtil.isEmpty(buttonPermissionPointId)) { + if (CollectionUtil.isEmpty(permission)) { log.warn("empty permission for admin role:{}", adminRole.getId()); continue; } log.info("add all permissions for role:{}", adminRole.getId()); - permissionIds.addAll(buttonPermissionPointId); + permissions.addAll(permission); } - return Pair.of(superAdmin, permissionIds); + return Pair.of(superAdmin, permissions); + } + + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + static class FeatureWrapper { + private Long featureId; + + /** + * 关联类型(0:saas_feature,1:saas_feature_resource) + */ + private Integer type; } private List listRolesWithPermission(List roleUserRelations, IdentityAuthReq identityAuthReq) { @@ -535,7 +713,8 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { //获取角色和关联权限信息 RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() .roleIds(Lists.newArrayList(roleIds)) - .needPermissionOld(true) + .needPermissionRelation(true) + .type(identityAuthReq.getType()) .build(); Map saasRoleRes = roleService.list(listSaasRoleParam).stream() .collect(Collectors.toMap(SaasRoleRes::getId, Function.identity())); @@ -727,6 +906,13 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { //不走缓存的情况:关闭缓存开关 - 缓存临时禁用 - 请求指明不走缓存 - 角色预览操作 //请求参数去重: ou-workspace req.distinctOUWorkspacePair(); + + // 因为目前只有/yoke/webApi/profile/user/v3/application接口会传入featureId,使用的是app端,所以这里只需要查询saas_feature的权限点 + // 以为下面要根据featureId进行匹配,为了解决saas_feature和saas_feature_resource有冲突的数据,必须给type + if (!CollectionUtils.isEmpty(req.getFeatureId())) { + req.setType(OLD_FEATURE); + } + boolean notUseCache = !req.isUseCache() || CollectionUtil.isNotEmpty(req.getSpecifyRoleIds()) || permissionCacheService.cacheDisable( @@ -1055,6 +1241,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { */ public boolean authPermission(PermissionCheckReq req) { // saas_feature表会被废弃,所以直接查询,没提供统一的查询 + // 会存在灰度用户的情况,接口对应的featureCode分别是saas_feature和saas_feature_resource的权限码 List saasFeatures = saasFeatureDao.lambdaQuery() .in(SaasFeature::getFeatureCode, req.getFeatureCodes()) .eq(SaasFeature::getIsDelete, TableIsDeleteEnum.NORMAL.value) @@ -1102,6 +1289,56 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return matchNormalRole(saasRoleUserRelations, permissionProducts); } +// private boolean authPermissionNewFeature(PermissionCheckReq req) { +// // saas_feature表会被废弃,所以直接查询,没提供统一的查询 +// // 会存在灰度用户的情况,接口对应的featureCode分别是saas_feature和saas_feature_resource的权限码 +// List saasFeatures = saasFeatureResourceService.lambdaQuery() +// .in(SaasFeature::getFeatureCode, req.getFeatureCodes()) +// .eq(SaasFeature::getIsDelete, TableIsDeleteEnum.NORMAL.value) +// .eq(StringUtils.isNotBlank(req.getTerminal()), SaasFeature::getTerminal, req.getTerminal()) +// .list(); +// if (CollectionUtils.isEmpty(saasFeatures)) { +// log.info("featureCode not found:{}", req.getFeatureCodes()); +// return false; +// } +// +// //用户角色关系,以及对应角色的权限点 +// List saasRoleUserRelations = listRoleUserRelations(req, saasFeatures); +// if (CollectionUtils.isEmpty(saasRoleUserRelations)) { +// return false; +// } +// +// // 查询租户开通的所有产品 +// Set productIds = listProducts(req); +// if (CollectionUtils.isEmpty(productIds)) { +// log.info("product not found:{}", req.getWorkspaceId()); +// return false; +// } +// +// // 查询产品开通的这些权限点的信息 +// List permissionProducts = listPermissionProduct(saasFeatures, productIds); +// if (CollectionUtils.isEmpty(productIds)) { +// log.info("permission product not found:{}", req.getWorkspaceId()); +// return false; +// } +// +// // 是否有免授权的权限码,且在租户开通了这个产品 +// boolean matchedNoNeedAuthFeature = matchNoAuthFeature(saasFeatures, permissionProducts); +// if (BooleanUtil.isTrue(matchedNoNeedAuthFeature)) { +// log.info("has no need auth feature:{}", req.getWorkspaceId()); +// return true; +// } +// +// // 是否有管理员角色,且租户开通了管理员角色的单位类型对应的产品权限码 +// boolean matchedAdminRole = matchAdminRole(saasRoleUserRelations, permissionProducts); +// if (BooleanUtil.isTrue(matchedAdminRole)) { +// log.info("admin role has permission:{}", req.getWorkspaceId()); +// return true; +// } +// +// return matchNormalRole(saasRoleUserRelations, permissionProducts); +// } + private boolean matchNormalRole(List saasRoleUserRelations, List permissionProducts) { List normalRoles = saasRoleUserRelations.stream() From 65b48ba39f4e2c1856f98632601fba613c36cff1 Mon Sep 17 00:00:00 2001 From: lilong Date: Thu, 27 Jun 2024 15:13:16 +0800 Subject: [PATCH 24/69] =?UTF-8?q?feat:(REQ-2545)=20=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E5=A2=9E=E5=8A=A0featureId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java index 29617e7f..4a85e114 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java @@ -297,6 +297,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .map(e -> { TreePermissionResp treePermissionResp = TreePermissionResp.builder().build(); BeanUtils.copyProperties(e, treePermissionResp); + treePermissionResp.setFeatureId(e.getId()); return treePermissionResp; }) .collect(Collectors.toList()); From 561ed2de182e47333c981219064801309e05370e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Fri, 28 Jun 2024 09:46:36 +0800 Subject: [PATCH 25/69] =?UTF-8?q?feat(REQ-2545):=20=E5=88=86=E9=A1=B5?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E7=BB=84=E4=BB=B6=E6=8E=A5=E5=8F=A3=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E5=8F=82=E6=95=B0=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/tyr/client/model/res/PageElementResp.java | 2 +- .../service/impl/SaasPageElementServiceImpl.java | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementResp.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementResp.java index 311b7c28..c32c9411 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementResp.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementResp.java @@ -46,7 +46,7 @@ public class PageElementResp { /** * 页面路由地址 */ - private String linkUr; + private String linkUrl; /** * 是否已勾选 diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java index 15be684d..b976594f 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java @@ -244,12 +244,15 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { if (CollectionUtils.isEmpty(relations)) { continue; } - SaasFeatureResource saasFeatureResource = saasFeatureResourceDao.lambdaQuery() + List saasFeatureResources = saasFeatureResourceDao.lambdaQuery() .eq(SaasFeatureResource::getUniCode, relations.get(0).getFeatureResourceUniCode()) .eq(SaasFeatureResource::getTerminal, request.getTerminal()) - .one(); - if (Objects.isNull(saasFeatureResource) - || !FeatureResourceType.PAGE.getCode().equals(saasFeatureResource.getFeatureType()) + .list(); + if (CollectionUtils.isEmpty(saasFeatureResources)) { + continue; + } + SaasFeatureResource saasFeatureResource = saasFeatureResources.get(0); + if (!FeatureResourceType.PAGE.getCode().equals(saasFeatureResource.getFeatureType()) || pageElement.getLinkUrl().equals(saasFeatureResource.getLinkUrl())) { continue; } From bdb778db76e2b930fcbf37a0401f15eaffccbfd9 Mon Sep 17 00:00:00 2001 From: lilong Date: Fri, 28 Jun 2024 11:34:27 +0800 Subject: [PATCH 26/69] =?UTF-8?q?feat:(REQ-2545)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E6=9F=A5=E8=AF=A2=E5=92=8C=E9=89=B4=E6=9D=83?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=81=B0=E5=BA=A6=E7=89=88=E6=9C=AC=E5=B9=B6=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/model/req/FeatureIdPair.java | 22 + ...PageElementFeatureResourceRelationReq.java | 7 + .../req/PagePgroupPermissionRelationReq.java | 6 + .../model/req/PageSaasFeatureResourceReq.java | 7 + .../req/ListRoleUserRelationParam.java | 8 + .../entity/ProductFeatureQuery.java | 7 +- .../entity/SaasFeatureResource.java | 15 + .../repository/mapper/SaasRoleMapper.java | 2 - .../axzo/tyr/server/service/RoleService.java | 3 +- .../server/service/TyrSaasAuthService.java | 9 +- .../service/WorkspaceProductService.java | 10 +- .../impl/PermissionQueryServiceImpl.java | 3 +- .../ProductFeatureRelationServiceImpl.java | 14 +- .../server/service/impl/RoleServiceImpl.java | 9 +- .../impl/SaasFeatureResourceServiceImpl.java | 8 + .../impl/SaasRoleUserRelationServiceImpl.java | 1 + .../service/impl/TyrSaasAuthServiceImpl.java | 574 +++++++++++------- .../impl/WorkspaceProductServiceImpl.java | 4 +- .../main/resources/mapper/SaasRoleMapper.xml | 11 - 19 files changed, 470 insertions(+), 250 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureIdPair.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureIdPair.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureIdPair.java new file mode 100644 index 00000000..3991f6d0 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureIdPair.java @@ -0,0 +1,22 @@ +package cn.axzo.tyr.client.model.req; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Set; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FeatureIdPair { + + /** + * 区分新老菜单资源树 + */ + private Integer type; + + private Set featureIds; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementFeatureResourceRelationReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementFeatureResourceRelationReq.java index 6d78e100..b4f9abc2 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementFeatureResourceRelationReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementFeatureResourceRelationReq.java @@ -9,6 +9,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; +import java.util.Set; @Data @Builder @@ -30,4 +31,10 @@ public class PageElementFeatureResourceRelationReq implements IPageReq { @CriteriaField(field = "featureResourceUniCode", operator = Operator.IN) private List featureResourceUniCodes; + + @CriteriaField(field = "pageElementCode", operator = Operator.IN) + private Set pageElementCodes; + + @CriteriaField(field = "terminal", operator = Operator.EQ) + private String terminal; } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PagePgroupPermissionRelationReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PagePgroupPermissionRelationReq.java index 4442ee16..3039feb2 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PagePgroupPermissionRelationReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PagePgroupPermissionRelationReq.java @@ -52,4 +52,10 @@ public class PagePgroupPermissionRelationReq implements IPageReq { */ @CriteriaField(ignore = true) private String terminal; + + /** + * 新老版本两个情况,可以配对查询 + */ + @CriteriaField(ignore = true) + private List featureIdPairs; } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageSaasFeatureResourceReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageSaasFeatureResourceReq.java index 9cb70535..02de287b 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageSaasFeatureResourceReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageSaasFeatureResourceReq.java @@ -12,6 +12,7 @@ import lombok.NoArgsConstructor; import java.util.Collections; import java.util.List; +import java.util.Set; @Data @Builder @@ -63,6 +64,12 @@ public class PageSaasFeatureResourceReq implements IPageReq { @CriteriaField(ignore = true) private Boolean needFeatureCodes; + @CriteriaField(field = "uniCode", operator = Operator.IN) + private Set uniCodes; + + @CriteriaField(ignore = true) + private Set paths; + public PageResp toEmpty() { return PageResp.builder() .current(this.getPage()) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/req/ListRoleUserRelationParam.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/req/ListRoleUserRelationParam.java index 9bcbb2be..b8e91d5b 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/req/ListRoleUserRelationParam.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/req/ListRoleUserRelationParam.java @@ -4,6 +4,7 @@ import cn.axzo.foundation.dao.support.wrapper.CriteriaField; import cn.axzo.foundation.dao.support.wrapper.Operator; import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.model.enums.IdentityType; +import cn.axzo.tyr.client.model.req.FeatureIdPair; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -11,6 +12,7 @@ import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import java.util.List; +import java.util.Set; @SuperBuilder @Data @@ -82,6 +84,12 @@ public class ListRoleUserRelationParam { @CriteriaField(ignore = true) private String terminal; + /** + * 权限点从saas_feature_resource表查询 + */ + @CriteriaField(ignore = true) + private Boolean needPermission; + @Data @Builder @NoArgsConstructor diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/ProductFeatureQuery.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/ProductFeatureQuery.java index 39d0c16e..18ae541d 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/ProductFeatureQuery.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/ProductFeatureQuery.java @@ -1,6 +1,7 @@ package cn.axzo.tyr.server.repository.entity; import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.client.model.req.FeatureIdPair; import lombok.Builder; import lombok.Data; @@ -23,14 +24,16 @@ public class ProductFeatureQuery { private String terminal; private Integer workspaceJoinType; - - private Set featureIds; +// +// private Set featureIds; /** * 菜单资源数节点类型 */ private List featureResourceTypes; + private List featureIdPairs; + /** * 区分新老菜单资源树 */ diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java index b942ceb0..32d51b8e 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java @@ -8,11 +8,13 @@ import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.Getter; import lombok.NoArgsConstructor; import org.apache.commons.lang3.StringUtils; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; /** @@ -177,5 +179,18 @@ public class SaasFeatureResource extends BaseEntity { return StrUtil.split(this.path, ",").stream().filter(StringUtils::isNotBlank).map(Long::valueOf).collect(Collectors.toList()); } + @Getter + @AllArgsConstructor + public enum AuthType { + ALL_ROLE(0, "全部角色"), + ASSIGN_ROLE(1, "指定角色"); + private Integer value; + + private String desc; + + public static boolean isAllRole(Integer authType) { + return Objects.equals(ALL_ROLE.getValue(), authType); + } + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasRoleMapper.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasRoleMapper.java index 23ea0923..3a992c58 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasRoleMapper.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasRoleMapper.java @@ -26,8 +26,6 @@ public interface SaasRoleMapper extends BaseMapper { List listForOUWorkspace(Long ouId, Long workspaceId, Integer workspaceJoinType); - List listRoleByFeatures(@Param("featureIds") Set featureIds); - List listFeatureByIds(@Param("roleIds") Set roleIds, @Param("featureIds") Set featureIds); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java index b693be66..bf464d0d 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java @@ -7,6 +7,7 @@ import cn.axzo.framework.domain.page.PageResp; import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.model.enums.IdentityType; import cn.axzo.tyr.client.model.req.ChangeGroupLeaderRoleReq; +import cn.axzo.tyr.client.model.req.FeatureIdPair; import cn.axzo.tyr.client.model.req.FeatureRoleRelationReq; import cn.axzo.tyr.client.model.req.QueryByIdentityIdTypeReq; import cn.axzo.tyr.client.model.req.QueryRoleByNameReq; @@ -83,8 +84,6 @@ public interface RoleService extends IService { */ void deleteRole(DeleteRoleVO deleteRoleParam); - List queryRoleByFeatures(Set matchedFeatureIds); - List getByIds(Set ids); List queryByCategoryCode(List categoryCodes); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/TyrSaasAuthService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/TyrSaasAuthService.java index e08de57c..81ccc0b3 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/TyrSaasAuthService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/TyrSaasAuthService.java @@ -54,9 +54,16 @@ public interface TyrSaasAuthService { List listAuthByResourceAndRoleGroup(ListPermissionFromRoleGroupReq listPermissionFromRoleGroupReq); /** - * 接口鉴权 + * 基于saas_feature的接口鉴权 * @param req * @return */ boolean authPermission(PermissionCheckReq req); + + /** + * 基于saas_feature_resource的接口鉴权 + * @param req + * @return + */ + boolean authNewPermission(PermissionCheckReq req); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/WorkspaceProductService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/WorkspaceProductService.java index a249e62f..b18d6c6b 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/WorkspaceProductService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/WorkspaceProductService.java @@ -1,6 +1,7 @@ package cn.axzo.tyr.server.service; import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.client.model.req.FeatureIdPair; import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; import lombok.AllArgsConstructor; import lombok.Builder; @@ -30,20 +31,19 @@ public interface WorkspaceProductService { */ private Set workspaceIds; + private Integer type; + /** * 查询菜单树节点类型 */ private List featureResourceTypes; /** - * 区分新老菜单资源树 + * 因为存在一个租户不同版本的菜单资源 */ - private Integer type; - - private Set featureIds; + private List featureIdPairs; } - @Data @Builder @NoArgsConstructor diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java index 4a85e114..47f2e314 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionQueryServiceImpl.java @@ -173,7 +173,8 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { return hasPermissionV2(req); } log.info("user new auth"); - return saasAuthService.authPermission(req); + // 因为会存在灰度的情况,只要在新版或者旧版有一个能鉴权通过就行 + return saasAuthService.authPermission(req) || saasAuthService.authNewPermission(req); } //权限编码转ID List resourcePermissions = featureResourceService.permissionQuery( diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductFeatureRelationServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductFeatureRelationServiceImpl.java index 9b73479b..44f2b717 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductFeatureRelationServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductFeatureRelationServiceImpl.java @@ -10,6 +10,7 @@ import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.model.product.ProductFeatureRelationSearchReq; import cn.axzo.tyr.client.model.product.ProductFeatureRelationUpdateReq; import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO; +import cn.axzo.tyr.client.model.req.FeatureIdPair; import cn.axzo.tyr.server.repository.dao.ProductModuleDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; @@ -215,7 +216,7 @@ public class ProductFeatureRelationServiceImpl implements ProductFeatureRelation SaasProductModuleFeatureRelation::getProductModuleId, condition.getProductIds()) .eq(Objects.nonNull(condition.getWorkspaceJoinType()), SaasProductModuleFeatureRelation::getDictCode, condition.getWorkspaceJoinType()) - .in(CollectionUtil.isNotEmpty(condition.getFeatureIds()), SaasProductModuleFeatureRelation::getFeatureId, condition.getFeatureIds()) +// .in(CollectionUtil.isNotEmpty(condition.getFeatureIds()), SaasProductModuleFeatureRelation::getFeatureId, condition.getFeatureIds()) .eq(Objects.nonNull(condition.getType()), SaasProductModuleFeatureRelation::getType, condition.getType()) .eq(StringUtils.hasLength(condition.getTerminal()), SaasProductModuleFeatureRelation::getTerminal, condition.getTerminal()); @@ -223,6 +224,17 @@ public class ProductFeatureRelationServiceImpl implements ProductFeatureRelation wrapper.in(SaasProductModuleFeatureRelation::getFeatureType, Lists.transform(condition.getFeatureResourceTypes(), FeatureResourceType::getCode)); } + if (!CollectionUtils.isEmpty(condition.getFeatureIdPairs())) { + wrapper.and(j -> { + for (FeatureIdPair featureIdPair : condition.getFeatureIdPairs()) { + j.or(k -> { + k.in(!CollectionUtils.isEmpty(featureIdPair.getFeatureIds()), SaasProductModuleFeatureRelation::getFeatureId, featureIdPair.getFeatureIds()); + k.eq(Objects.nonNull(featureIdPair.getType()), SaasProductModuleFeatureRelation::getType, featureIdPair.getType()); + }); + } + }); + } + return this.saasProductModuleFeatureRelationDao.list(wrapper); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java index 3d710a21..e3ad93f7 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java @@ -876,11 +876,6 @@ public class RoleServiceImpl extends ServiceImpl saasPgroupRoleRelationDao.deleteByRoleId(deleteRoleParam.getRoleIds()); } - @Override - public List queryRoleByFeatures(Set matchedFeatureIds) { - return saasRoleDao.getBaseMapper().listRoleByFeatures(matchedFeatureIds); - } - @Override public List getByIds(Set ids) { return saasRoleDao.listByIds(ids); @@ -1194,7 +1189,8 @@ public class RoleServiceImpl extends ServiceImpl List saasPgroupPermissionRelations = saasPgroupPermissionRelationDao.lambdaQuery() .in(SaasPgroupPermissionRelation::getGroupId, Lists.transform(saasPgroupRoleRelations, SaasPgroupRoleRelation::getGroupId)) .eq(SaasPgroupPermissionRelation::getIsDelete, TableIsDeleteEnum.NORMAL.value) - .eq(Objects.nonNull(param.getType()), SaasPgroupPermissionRelation::getType, param.getType()) + .in(CollectionUtils.isNotEmpty(param.getFeatureIds()), SaasPgroupPermissionRelation::getFeatureId, param.getFeatureIds()) + .eq(SaasPgroupPermissionRelation::getType, NEW_FEATURE) .list(); if (CollectionUtils.isEmpty(saasPgroupPermissionRelations)) { return Collections.emptyMap(); @@ -1415,6 +1411,7 @@ public class RoleServiceImpl extends ServiceImpl .in(SaasPgroupPermissionRelation::getGroupId, Lists.transform(saasPgroupRoleRelations, SaasPgroupRoleRelation::getGroupId)) .in(CollectionUtils.isNotEmpty(param.getFeatureIds()), SaasPgroupPermissionRelation::getFeatureId, param.getFeatureIds()) .eq(SaasPgroupPermissionRelation::getIsDelete, TableIsDeleteEnum.NORMAL.value) + .eq(SaasPgroupPermissionRelation::getType, OLD_FEATURE) .list(); if (CollectionUtils.isEmpty(saasPgroupPermissionRelations)) { return Collections.emptyMap(); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java index 0c5ffd69..585342a8 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java @@ -514,6 +514,14 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl { + for (String path : param.getPaths()) { + j.or(k -> k.likeRight("path", path)); + } + }); + } + IPage page = this.page(PageConverter.toMybatis(param, SaasFeatureResource.class), wrapper); Map> uniCodeFeatureCodeMap = listFeatureCodes(param, page.getRecords()); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleUserRelationServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleUserRelationServiceImpl.java index 43c53402..bd939e0b 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleUserRelationServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleUserRelationServiceImpl.java @@ -237,6 +237,7 @@ public class SaasRoleUserRelationServiceImpl extends ServiceImpl { diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java index 931bddad..086550ef 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java @@ -16,12 +16,15 @@ import cn.axzo.tyr.client.model.permission.PermissionPointListQueryRequest; import cn.axzo.tyr.client.model.permission.PermissionPointTreeNode; import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO; import cn.axzo.tyr.client.model.req.CheckIdentityPermissionReq; +import cn.axzo.tyr.client.model.req.FeatureIdPair; import cn.axzo.tyr.client.model.req.IdentityAuthReq; import cn.axzo.tyr.client.model.req.ListIdentityFromPermissionReq; import cn.axzo.tyr.client.model.req.ListPermissionFromFeatureReq; import cn.axzo.tyr.client.model.req.ListPermissionFromIdentityReq; import cn.axzo.tyr.client.model.req.ListPermissionFromRoleGroupReq; import cn.axzo.tyr.client.model.req.OUWorkspacePair; +import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq; +import cn.axzo.tyr.client.model.req.PagePgroupPermissionRelationReq; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.client.model.req.PermissionCheckReq; import cn.axzo.tyr.client.model.req.QueryPermissionByIdsReq; @@ -31,6 +34,7 @@ import cn.axzo.tyr.client.model.res.IdentityAuthRes; import cn.axzo.tyr.client.model.res.ListIdentityFromPermissionResp; import cn.axzo.tyr.client.model.res.ListPermissionFromRoleGroupResp; import cn.axzo.tyr.client.model.res.QueryIdentityByPermissionResp; +import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.client.model.res.SaasRoleRes; import cn.axzo.tyr.client.model.res.SimplePermissionPointResp; import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO; @@ -45,9 +49,13 @@ import cn.axzo.tyr.server.repository.entity.ProductFeatureInfo; import cn.axzo.tyr.server.repository.entity.ProductFeatureQuery; import cn.axzo.tyr.server.repository.entity.RolePermission; import cn.axzo.tyr.server.repository.entity.SaasFeature; +import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; +import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; +import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation; import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; import cn.axzo.tyr.server.repository.entity.SaasRole; import cn.axzo.tyr.server.repository.entity.SaasRoleGroup; +import cn.axzo.tyr.server.repository.entity.SaasRoleGroupRelation; import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation; import cn.axzo.tyr.server.repository.entity.SaasRoleWithUser; import cn.axzo.tyr.server.repository.mapper.TyrSaasAuthMapper; @@ -56,6 +64,9 @@ import cn.axzo.tyr.server.service.PermissionPointService; import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import cn.axzo.tyr.server.service.SaasPageElementFeatureResourceRelationService; +import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService; +import cn.axzo.tyr.server.service.SaasRoleGroupRelationService; import cn.axzo.tyr.server.service.SaasRoleGroupService; import cn.axzo.tyr.server.service.SaasRoleUserRelationService; import cn.axzo.tyr.server.service.TyrSaasAuthService; @@ -79,6 +90,7 @@ import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.cloud.context.config.annotation.RefreshScope; @@ -104,7 +116,6 @@ import java.util.stream.Collectors; import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE; import static cn.axzo.tyr.server.util.RpcInternalUtil.checkAndGetData; -import static cn.axzo.tyr.server.util.RpcInternalUtil.rpcListProcessor; /** * @author tanjie@axzo.cn @@ -124,7 +135,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { private final ServicePkgClient servicePkgClient; @Qualifier("authExecutor") @Autowired - private Executor executor; + private Executor executor; private final ProductFeatureRelationService productFeatureRelationService; private final PermissionPointService permissionPointService; @@ -135,6 +146,9 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { private final SaasProductModuleFeatureRelationDao saasProductModuleFeatureRelationDao; private final WorkspaceProductService workspaceProductService; private final SaasFeatureResourceService saasFeatureResourceService; + private final SaasPageElementFeatureResourceRelationService saasPageElementFeatureResourceRelationService; + private final SaasPgroupPermissionRelationService saasPgroupPermissionRelationService; + private final SaasRoleGroupRelationService saasRoleGroupRelationService; /** * 通过身份查询人员权限 @@ -353,55 +367,6 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return permissionSet.containsAll(checkCodes); } -// private IdentityAuthRes listAllNotAuthPermission(IdentityAuthReq identityAuthReq) { -// // 目前只有CMS端会同时在saas_feature和saas_feature_resource中使用 -// permissionPointService.queryList(PermissionPointListQueryRequest.builder() -// .delegatedType(DelegatedType.NO_NEED.getCode()) -// .build()); -// -// PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() -// .terminal(TerminalInfo.NT_CMS_WEB_GENERAL) -// .authType(FeatureResourceAuthType.ALL_ROLE.getCode()) -// .build(); -// saasFeatureResourceService.list(pageSaasFeatureResourceReq); -// -// Set workspaceIds = identityAuthReq.getWorkspaceOusPairs().stream() -// .map(IdentityAuthReq.WorkspaceOuPair::getWorkspaceId) -// .collect(Collectors.toSet()); -// -// WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() -// .workspaceIds(workspaceIds) -// .featureIds() -// .build(); -// workspaceProductService.listWorkspaceProduct(workspaceProductParam); -// -// -// IdentityAuthRes result = new IdentityAuthRes(); -// result.setIdentity(identityAuthReq.getIdentityId()); -// result.setIdentityType(identityAuthReq.getIdentityType()); -// result.setPersonId(identityAuthReq.getPersonId()); -// -// List workspacePermissions = identityAuthReq.getWorkspaceOusPairs().stream() -// .map(e -> { -// -// IdentityAuthRes.WorkspacePermission workspacePermission = IdentityAuthRes.WorkspacePermission.builder() -// .workspaceId(e.getWorkspaceId()) -// .ouId(e.getOuId()) -// .build(); -// -// IdentityAuthRes.PermissionPoint.builder() -// .featureCode(e.getCode()) -// .featureId(e.getId()) -// .terminal(e.getTerminal()) -// .build(); -// return workspacePermission; -// }) -// .collect(Collectors.toList()); -// -// result.setPermissions(workspacePermissions); -// return result; -// } - private IdentityAuthRes findIdentityAuth(IdentityAuthReq identityAuthReq) { //用户角色关系 List saasRoleUserRelations = listRoleUserRelations(identityAuthReq); @@ -516,14 +481,14 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .stream() .filter(e -> !CollectionUtils.isEmpty(e.getFeatureCodes())) .map(e -> - // 兼容历史情况,根据featureCode组装数据 - e.getFeatureCodes().stream() - .map(featureCode -> IdentityAuthRes.PermissionPoint.builder() - .featureCode(featureCode) - .featureId(e.getId()) - .terminal(e.getTerminal()) - .build()) - .collect(Collectors.toList())) + // 兼容历史情况,根据featureCode组装数据 + e.getFeatureCodes().stream() + .map(featureCode -> IdentityAuthRes.PermissionPoint.builder() + .featureCode(featureCode) + .featureId(e.getId()) + .terminal(e.getTerminal()) + .build()) + .collect(Collectors.toList())) .flatMap(Collection::stream) .collect(Collectors.toList()); } @@ -609,9 +574,9 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } return permissionPointService.queryList(PermissionPointListQueryRequest.builder() - .ids(featureIds) - .delegatedType(DelegatedType.NO_NEED.getCode()) - .build()) + .ids(featureIds) + .delegatedType(DelegatedType.NO_NEED.getCode()) + .build()) .stream() .map(e -> FeatureWrapper.builder() .featureId(e.getPermissionPointId()) @@ -811,8 +776,47 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { //比较code return authRes.getPermissions().stream() .anyMatch(e -> e.getPermissionPoint() - .stream() - .anyMatch(p -> codeSet.contains(p.getFeatureCode()))); + .stream() + .anyMatch(p -> codeSet.contains(p.getFeatureCode()))); + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + static class ListSaasFeatureResourceParam { + private Set featureCodes; + + private String terminal; + } + + private List listSaasFeatureResource(ListSaasFeatureResourceParam req) { + + PageElementFeatureResourceRelationReq pageElementFeatureResourceRelationReq = PageElementFeatureResourceRelationReq.builder() + .pageElementCodes(req.getFeatureCodes()) + .terminal(req.getTerminal()) + .build(); + List relations = saasPageElementFeatureResourceRelationService.list(pageElementFeatureResourceRelationReq); + + if (CollectionUtils.isEmpty(relations)) { + log.info("not found in SaasPageElementFeatureResourceRelation, featureCodes:{},terminal:{}", + req.getFeatureCodes(), req.getTerminal()); + return Collections.emptyList(); + } + + Set uniCodes = relations.stream().map(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode).collect(Collectors.toSet()); + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .uniCodes(uniCodes) + .build(); + List featureResources = saasFeatureResourceService.list(pageSaasFeatureResourceReq); + + if (CollectionUtils.isEmpty(featureResources)) { + log.info("not found in SaasFeatureResource, unicode:{}", uniCodes); + return Collections.emptyList(); + } + return saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() + .paths(featureResources.stream().map(SaasFeatureResourceResp::getPath).collect(Collectors.toSet())) + .build()); } @Override @@ -823,7 +827,15 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { //code查询权限点信息 List features = permissionPointService.listNodeWithChildrenByCode(req.getFeatureCode(), req.getTerminal()); - if (CollectionUtil.isEmpty(features)) { + + // 兼容新老版本,需要通过featureCode查询新版本的features,原逻辑是查询当前菜单资源的所有子数据 + ListSaasFeatureResourceParam listSaasFeatureResourceParam = ListSaasFeatureResourceParam.builder() + .featureCodes(Sets.newHashSet(req.getFeatureCode())) + .terminal(req.getTerminal()) + .build(); + List saasFeatureResources = listSaasFeatureResource(listSaasFeatureResourceParam); + + if (CollectionUtil.isEmpty(features) && CollectionUtils.isEmpty(saasFeatureResources)) { log.warn("no features data found for:{}", req.getFeatureCode()); return result; } @@ -831,20 +843,41 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { Optional freeFeature = features.stream() .filter(f -> DelegatedType.NO_NEED.sameCode(f.getDelegatedType())) .findAny(); - if (freeFeature.isPresent()) { - log.warn("free feature found :{}", freeFeature.get().getId()); + + Optional freeFeatureResource = saasFeatureResources.stream() + .filter(e -> SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) + .findFirst(); + + if (freeFeature.isPresent() || freeFeatureResource.isPresent()) { + log.warn("free feature found : featureId:{}, featureResourceId:{}", + freeFeature.map(SaasFeature::getId).orElse(null), + freeFeatureResource.map(SaasFeatureResourceResp::getId).orElse(null)); throw new ServiceException("不能查询免授权权限点人员"); } Set featureIds = features.stream().map(SaasFeature::getId).collect(Collectors.toSet()); - //权限匹配 - 有该权限的工作台产品 productUnitType -> featureIds - Map> workspaceFeatureMap = matchWorkspaceFeature(req.getWorkspaceId(), featureIds); - if (CollectionUtil.isEmpty(workspaceFeatureMap)) { + Set newFeatureIds = saasFeatureResources.stream().map(SaasFeatureResourceResp::getId).collect(Collectors.toSet()); + + WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() + .workspaceIds(Sets.newHashSet(req.getWorkspaceId())) + .featureIdPairs(Lists.newArrayList( + FeatureIdPair.builder().featureIds(featureIds).type(OLD_FEATURE).build(), + FeatureIdPair.builder().featureIds(newFeatureIds).type(NEW_FEATURE).build() + )) + .build(); + List workspaceProducts = workspaceProductService.listWorkspaceProduct(workspaceProductParam) + .stream() + .map(WorkspaceProductService.WorkspaceProduct::getSaasProductModuleFeatureRelations) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + if (CollectionUtil.isEmpty(workspaceProducts)) { log.warn("no matched product feature in workspace"); return result; } - List matchedUsers = getWorkspaceUser(req.getWorkspaceId(), req.getOuId(), workspaceFeatureMap); + List matchedUsers = getWorkspaceUser(req.getWorkspaceId(), req.getOuId(), workspaceProducts); if (CollectionUtil.isEmpty(matchedUsers)) { return result; } @@ -852,25 +885,6 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return result; } - private Map> matchWorkspaceFeature(Long workspaceId, Set featureIds) { - //查询工作台下产品 - List productList = checkAndGetData(servicePkgClient.listProductInWorkSpace(workspaceId)); - if (CollectionUtil.isEmpty(productList)) { - log.warn("------trace-L-I-F-P----> no product found for workspace"); - return Collections.emptyMap(); - } - //产品包含的权限-过滤参建类型 和 feature - return productFeatureRelationService.queryOnCondition(ProductFeatureQuery.builder() - .productIds(productList.stream() - .map(ServicePkgProduct::getProductId) - .collect(Collectors.toSet())) - .featureIds(featureIds) - .build()) - .stream() - .collect(Collectors.groupingBy(r -> Integer.valueOf(r.getDictCode()), - Collectors.mapping(SaasProductModuleFeatureRelation::getFeatureId, Collectors.toSet()))); - } - @Override public List batchListIdentityFromPermission(List reqList) { //异步处理 @@ -1033,10 +1047,12 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { permissionInfo.forEach(e -> e.setSimpleFeatureInfos(authMap.get(NumberUtil.parseLong(e.getRoleId())))); return permissionInfo; } + /** * 通过工作台ID过滤指定角色的权限 + * * @param filterRoleAuths - * @return KEY :role Id ; VALUE: feature id ; + * @return KEY :role Id ; VALUE: feature id ; */ public Map> filterAuthByRoleAndProduct(List filterRoleAuths) { List roleIds = filterRoleAuths.stream().map(FilterRoleAuth::getRoleId).distinct().collect(Collectors.toList()); @@ -1098,12 +1114,13 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return oldFeatureLists; })); } + @Data @Builder @NoArgsConstructor @AllArgsConstructor public static class OUWRoleInfo { - + Long workspaceId; Integer workspaceType; Long ouId; @@ -1117,30 +1134,63 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { //code查询权限点信息 List features = permissionPointService.listNodeWithChildrenByCodes(req.getFeatureCodes(), null); - if (CollectionUtil.isEmpty(features)) { + + // 兼容新老版本,需要通过featureCode查询新版本的features,原逻辑是查询当前菜单资源的所有子数据 + ListSaasFeatureResourceParam listSaasFeatureResourceParam = ListSaasFeatureResourceParam.builder() + .featureCodes(Sets.newHashSet(req.getFeatureCodes())) + .build(); + List saasFeatureResources = listSaasFeatureResource(listSaasFeatureResourceParam); + + if (CollectionUtil.isEmpty(features) && CollectionUtils.isEmpty(saasFeatureResources)) { log.warn("no features data found for:{}", req.getFeatureCodes()); return Collections.emptyList(); } Set featureIds = features.stream().map(SaasFeature::getId).collect(Collectors.toSet()); - //权限匹配 - 工作台是否有指定权限 productUnitType -> featureIds - Map> workspaceFeatureMap = matchWorkspaceFeature(req.getWorkspaceId(), featureIds); - if (CollectionUtil.isEmpty(workspaceFeatureMap)) { + Set newFeatureIds = saasFeatureResources.stream().map(SaasFeatureResourceResp::getId).collect(Collectors.toSet()); + WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() + .workspaceIds(Sets.newHashSet(req.getWorkspaceId())) + .featureIdPairs(Lists.newArrayList( + FeatureIdPair.builder().featureIds(featureIds).type(OLD_FEATURE).build(), + FeatureIdPair.builder().featureIds(newFeatureIds).type(NEW_FEATURE).build() + )) + .build(); + List workspaceProducts = workspaceProductService.listWorkspaceProduct(workspaceProductParam) + .stream() + .map(WorkspaceProductService.WorkspaceProduct::getSaasProductModuleFeatureRelations) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + if (CollectionUtil.isEmpty(workspaceProducts)) { log.warn("no matched feature in workspace product"); return Collections.emptyList(); } //是否免授权权限点 - Set matchedFeatureIds = workspaceFeatureMap.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()); + Set matchedOldFeatureIds = workspaceProducts.stream() + .filter(e -> Objects.equals(OLD_FEATURE, e.getType())) + .map(SaasProductModuleFeatureRelation::getFeatureId) + .collect(Collectors.toSet()); Optional freeFeature = features.stream() - .filter(f -> matchedFeatureIds.contains(f.getId())) + .filter(f -> matchedOldFeatureIds.contains(f.getId())) .filter(f -> DelegatedType.NO_NEED.sameCode(f.getDelegatedType())) .findAny(); - if (freeFeature.isPresent()) { + + Set matchedNewFeatureIds = workspaceProducts.stream() + .filter(e -> Objects.equals(NEW_FEATURE, e.getType())) + .map(SaasProductModuleFeatureRelation::getFeatureId) + .collect(Collectors.toSet()); + + Optional freeFeatureResource = saasFeatureResources.stream() + .filter(f -> matchedNewFeatureIds.contains(f.getId())) + .filter(e -> SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) + .findFirst(); + if (freeFeature.isPresent() || freeFeatureResource.isPresent()) { throw new ServiceException("免授权权限点调用查人接口"); } //从相关角色查询用户-超管和普通角色 - List users = getWorkspaceUser(req.getWorkspaceId(), null, workspaceFeatureMap); + List users = getWorkspaceUser(req.getWorkspaceId(), null, workspaceProducts); if (CollectionUtil.isEmpty(users)) { return Collections.emptyList(); } @@ -1158,19 +1208,66 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return result; } - private List getWorkspaceUser(Long workspaceId, Long ouId, Map> workspaceFeatureMap) { + private List listFeatureRoles(Set featureIds, Integer type) { + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyList(); + } - Set productTypes = workspaceFeatureMap.keySet(); - Set matchedFeatureIds = workspaceFeatureMap.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()); + List relations = saasPgroupPermissionRelationService.list(PagePgroupPermissionRelationReq.builder() + .featureIds(Lists.newArrayList(featureIds)) + .type(type) + .build()); + if (CollectionUtils.isEmpty(relations)) { + return Collections.emptyList(); + } - List matchedRoles = new ArrayList<>(); + List roleGroupRelations = saasRoleGroupRelationService.list(SaasRoleGroupRelationService.ListSaasRoleGroupRelationParam.builder() + .saasRoleGroupIds(Lists.transform(relations, SaasPgroupPermissionRelation::getGroupId)) + .build()); + if (CollectionUtils.isEmpty(roleGroupRelations)) { + return Collections.emptyList(); + } + + return roleService.list(RoleService.ListSaasRoleParam.builder() + .roleIds(Lists.transform(roleGroupRelations, SaasRoleGroupRelation::getRoleId)) + .build()) + .stream() + .map(e -> { + SaasRole saasRole = new SaasRole(); + BeanUtils.copyProperties(e, saasRole); + return saasRole; + }) + .collect(Collectors.toList()); + } + + private List getWorkspaceUser(Long workspaceId, Long ouId, + List workspaceProducts) { + Set newProductTypes = workspaceProducts.stream() + .filter(e -> Objects.equals(e.getType(), NEW_FEATURE)) + .map(SaasProductModuleFeatureRelation::getDictCode) + .map(Integer::valueOf) + .collect(Collectors.toSet()); + + Set newMatchedFeatureIds = workspaceProducts.stream() + .filter(e -> Objects.equals(e.getType(), NEW_FEATURE)) + .map(SaasProductModuleFeatureRelation::getFeatureId) + .collect(Collectors.toSet()); + + Set oldProductTypes = workspaceProducts.stream() + .filter(e -> Objects.equals(e.getType(), OLD_FEATURE)) + .map(SaasProductModuleFeatureRelation::getDictCode) + .map(Integer::valueOf) + .collect(Collectors.toSet()); + + Set oldMatchedFeatureIds = workspaceProducts.stream() + .filter(e -> Objects.equals(e.getType(), OLD_FEATURE)) + .map(SaasProductModuleFeatureRelation::getFeatureId) + .collect(Collectors.toSet()); //超管和管理员 List adminRoles = roleService.listAdmins(workspaceId, ouId); if (CollectionUtil.isEmpty(adminRoles)) { log.warn("no admin roles found for workspaceId:{}, ouId:{}", workspaceId, ouId); - } else { - matchedRoles.addAll(adminRoles); } Set superAdmins = adminRoles.stream() @@ -1179,18 +1276,32 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .collect(Collectors.toSet()); //普通角色 权限点查角色 -- 不考虑 角色权限集例外 - List normalRoles = roleService.queryRoleByFeatures(matchedFeatureIds); - if (CollectionUtil.isEmpty(normalRoles)) { - log.warn("no role found for featureIds:{}", matchedFeatureIds); - } else { - matchedRoles.addAll(normalRoles); - } + // 多版本只会存在一段时间,减少代码复杂度,所以查询多次 + List oldNormalSaasRoles = listFeatureRoles(oldMatchedFeatureIds, OLD_FEATURE); + List newNormalSaasRoles = listFeatureRoles(newMatchedFeatureIds, NEW_FEATURE); - //匹配角色和产品标签 - List roleIds = matchedRoles.stream() - .filter(r -> productTypes.contains(r.getProductUnitType())) + List roleIds = Lists.newArrayList(); + // 超管不用区分新老版本 + List adminRoleIds = adminRoles.stream() + .filter(r -> newProductTypes.contains(r.getProductUnitType()) || oldProductTypes.contains(r.getProductUnitType())) .map(SaasRole::getId) .collect(Collectors.toList()); + + List oldNormalRoleIds = oldNormalSaasRoles.stream() + .filter(r -> oldProductTypes.contains(r.getProductUnitType())) + .map(SaasRole::getId) + .collect(Collectors.toList()); + + List newNormalRoleIds = newNormalSaasRoles.stream() + .filter(r -> newProductTypes.contains(r.getProductUnitType())) + .map(SaasRole::getId) + .collect(Collectors.toList()); + + //匹配角色和产品标签 + roleIds.addAll(adminRoleIds); + roleIds.addAll(oldNormalRoleIds); + roleIds.addAll(newNormalRoleIds); + if (CollectionUtil.isEmpty(roleIds)) { log.warn("no role matched product unit types"); return Collections.emptyList(); @@ -1228,27 +1339,82 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } /** - * 判断用户是否有指定权限码的权限 - * 1、查询用户的角色id、租户的产品id(db) - * 2、根据权限点找对应的产品、单位类型(redis) - * 3、租户开通的产品是否在权限点对应的产品,不满足条件直接返回false - * 4、查询是否有免授权的权限点 - * 4、有管理员角色:租户的产品要在权限点的产品里、单位类型要是管理员角色的单位类型,满足条件则返回true - * 6、根据权限点找对应的角色(redis) - * 7、有非管理员角色: + * 基于saas_feature_resource的鉴权 * @param req * @return */ + @Override + public boolean authNewPermission(PermissionCheckReq req) { + ListSaasFeatureResourceParam listSaasFeatureResourceParam = ListSaasFeatureResourceParam.builder() + .featureCodes(Sets.newHashSet(req.getFeatureCodes())) + .terminal(req.getTerminal()) + .build(); + List saasFeatureResources = listSaasFeatureResource(listSaasFeatureResourceParam); + + if (CollectionUtils.isEmpty(saasFeatureResources)) { + log.info("featureCode not found in featureResource:{}", req.getFeatureCodes()); + return false; + } + + //用户角色关系,以及对应角色的权限点 + List saasRoleUserRelations = listRoleUserRelationsNew(req, saasFeatureResources); + if (CollectionUtils.isEmpty(saasRoleUserRelations)) { + return false; + } + + Set featureIds = saasFeatureResources.stream() + .map(SaasFeatureResourceResp::getId) + .collect(Collectors.toSet()); + + WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() + .workspaceIds(Sets.newHashSet(req.getWorkspaceId())) + .featureIdPairs(Lists.newArrayList( + FeatureIdPair.builder().featureIds(featureIds).type(NEW_FEATURE).build() + )) + .build(); + Set workspaceProductFeatures = workspaceProductService.listWorkspaceProduct(workspaceProductParam).stream() + .map(WorkspaceProductService.WorkspaceProduct::getSaasProductModuleFeatureRelations) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(workspaceProductFeatures)) { + log.info("product not found:{}", req.getWorkspaceId()); + return false; + } + + // 是否有免授权的权限码,且在租户开通了这个产品 + boolean matchedNoNeedAuthFeature = matchNoAuthFeatureNew(saasFeatureResources, workspaceProductFeatures); + if (BooleanUtil.isTrue(matchedNoNeedAuthFeature)) { + log.info("has no need auth feature:{}", req.getWorkspaceId()); + return true; + } + + // 是否有管理员角色,且租户开通了管理员角色的单位类型对应的产品权限码 + boolean matchedAdminRole = matchAdminRole(saasRoleUserRelations, workspaceProductFeatures); + if (BooleanUtil.isTrue(matchedAdminRole)) { + log.info("admin role has permission:{}", req.getWorkspaceId()); + return true; + } + + return matchNormalRole(saasRoleUserRelations, workspaceProductFeatures); + } + + /** + * 基于saas_feature的鉴权,后续会去掉 + * @param req + * @return + */ + @Override public boolean authPermission(PermissionCheckReq req) { // saas_feature表会被废弃,所以直接查询,没提供统一的查询 - // 会存在灰度用户的情况,接口对应的featureCode分别是saas_feature和saas_feature_resource的权限码 List saasFeatures = saasFeatureDao.lambdaQuery() .in(SaasFeature::getFeatureCode, req.getFeatureCodes()) .eq(SaasFeature::getIsDelete, TableIsDeleteEnum.NORMAL.value) .eq(StringUtils.isNotBlank(req.getTerminal()), SaasFeature::getTerminal, req.getTerminal()) .list(); if (CollectionUtils.isEmpty(saasFeatures)) { - log.info("featureCode not found:{}", req.getFeatureCodes()); + log.info("featureCode not found in saasFeature:{}", req.getFeatureCodes()); return false; } @@ -1258,89 +1424,46 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return false; } - // 查询租户开通的所有产品 - Set productIds = listProducts(req); - if (CollectionUtils.isEmpty(productIds)) { + Set featureIds = saasFeatures.stream() + .map(SaasFeature::getId) + .collect(Collectors.toSet()); + + WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() + .workspaceIds(Sets.newHashSet(req.getWorkspaceId())) + .featureIdPairs(Lists.newArrayList( + FeatureIdPair.builder().featureIds(featureIds).type(NEW_FEATURE).build() + )) + .build(); + Set workspaceProductFeatures = workspaceProductService.listWorkspaceProduct(workspaceProductParam).stream() + .map(WorkspaceProductService.WorkspaceProduct::getSaasProductModuleFeatureRelations) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(workspaceProductFeatures)) { log.info("product not found:{}", req.getWorkspaceId()); return false; } - // 查询产品开通的这些权限点的信息 - List permissionProducts = listPermissionProduct(saasFeatures, productIds); - if (CollectionUtils.isEmpty(productIds)) { - log.info("permission product not found:{}", req.getWorkspaceId()); - return false; - } - // 是否有免授权的权限码,且在租户开通了这个产品 - boolean matchedNoNeedAuthFeature = matchNoAuthFeature(saasFeatures, permissionProducts); + boolean matchedNoNeedAuthFeature = matchNoAuthFeature(saasFeatures, workspaceProductFeatures); if (BooleanUtil.isTrue(matchedNoNeedAuthFeature)) { log.info("has no need auth feature:{}", req.getWorkspaceId()); return true; } // 是否有管理员角色,且租户开通了管理员角色的单位类型对应的产品权限码 - boolean matchedAdminRole = matchAdminRole(saasRoleUserRelations, permissionProducts); + boolean matchedAdminRole = matchAdminRole(saasRoleUserRelations, workspaceProductFeatures); if (BooleanUtil.isTrue(matchedAdminRole)) { log.info("admin role has permission:{}", req.getWorkspaceId()); return true; } - return matchNormalRole(saasRoleUserRelations, permissionProducts); + return matchNormalRole(saasRoleUserRelations, workspaceProductFeatures); } -// private boolean authPermissionNewFeature(PermissionCheckReq req) { -// // saas_feature表会被废弃,所以直接查询,没提供统一的查询 -// // 会存在灰度用户的情况,接口对应的featureCode分别是saas_feature和saas_feature_resource的权限码 -// List saasFeatures = saasFeatureResourceService.lambdaQuery() -// .in(SaasFeature::getFeatureCode, req.getFeatureCodes()) -// .eq(SaasFeature::getIsDelete, TableIsDeleteEnum.NORMAL.value) -// .eq(StringUtils.isNotBlank(req.getTerminal()), SaasFeature::getTerminal, req.getTerminal()) -// .list(); -// if (CollectionUtils.isEmpty(saasFeatures)) { -// log.info("featureCode not found:{}", req.getFeatureCodes()); -// return false; -// } -// -// //用户角色关系,以及对应角色的权限点 -// List saasRoleUserRelations = listRoleUserRelations(req, saasFeatures); -// if (CollectionUtils.isEmpty(saasRoleUserRelations)) { -// return false; -// } -// -// // 查询租户开通的所有产品 -// Set productIds = listProducts(req); -// if (CollectionUtils.isEmpty(productIds)) { -// log.info("product not found:{}", req.getWorkspaceId()); -// return false; -// } -// -// // 查询产品开通的这些权限点的信息 -// List permissionProducts = listPermissionProduct(saasFeatures, productIds); -// if (CollectionUtils.isEmpty(productIds)) { -// log.info("permission product not found:{}", req.getWorkspaceId()); -// return false; -// } -// -// // 是否有免授权的权限码,且在租户开通了这个产品 -// boolean matchedNoNeedAuthFeature = matchNoAuthFeature(saasFeatures, permissionProducts); -// if (BooleanUtil.isTrue(matchedNoNeedAuthFeature)) { -// log.info("has no need auth feature:{}", req.getWorkspaceId()); -// return true; -// } -// -// // 是否有管理员角色,且租户开通了管理员角色的单位类型对应的产品权限码 -// boolean matchedAdminRole = matchAdminRole(saasRoleUserRelations, permissionProducts); -// if (BooleanUtil.isTrue(matchedAdminRole)) { -// log.info("admin role has permission:{}", req.getWorkspaceId()); -// return true; -// } -// -// return matchNormalRole(saasRoleUserRelations, permissionProducts); -// } - private boolean matchNormalRole(List saasRoleUserRelations, - List permissionProducts) { + Set permissionProducts) { List normalRoles = saasRoleUserRelations.stream() .filter(e -> !RoleTypeEnum.isAdmin(e.getSaasRole().getRoleType())) .collect(Collectors.toList()); @@ -1377,14 +1500,32 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return false; } + private boolean matchNoAuthFeatureNew(List saasFeatureResources, + Set permissionProducts) { + + Set noNeedAuthFeatureIds = saasFeatureResources.stream() + .filter(e -> SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) + .map(SaasFeatureResourceResp::getId) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(noNeedAuthFeatureIds)) { + log.info("not found no need auth featureCode"); + return false; + } + + return permissionProducts.stream() + .anyMatch(e -> noNeedAuthFeatureIds.contains(e.getFeatureId())); + } + /** * 租户开通的产品是否有不需要鉴权的权限码 + * * @param saasFeatures * @param permissionProducts * @return */ private boolean matchNoAuthFeature(List saasFeatures, - List permissionProducts) { + Set permissionProducts) { Set noNeedAuthFeatureIds = saasFeatures.stream() .filter(e -> Objects.equals(e.getDelegatedType(), DelegatedType.NO_NEED.getCode())) @@ -1402,12 +1543,13 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { /** * 匹配管理员角色是否有权限点的权限 + * * @param saasRoleUserRelations * @param permissionProducts * @return */ private boolean matchAdminRole(List saasRoleUserRelations, - List permissionProducts) { + Set permissionProducts) { List adminRoles = saasRoleUserRelations.stream() .filter(e -> RoleTypeEnum.isAdmin(e.getSaasRole().getRoleType())) @@ -1425,18 +1567,13 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .anyMatch(adminRole -> ouTypes.contains(String.valueOf(adminRole.getSaasRole().getProductUnitType()))); } - private List listPermissionProduct(List saasFeatures, - Set productIds) { - - return saasProductModuleFeatureRelationDao.lambdaQuery() - .in(SaasProductModuleFeatureRelation::getProductModuleId, productIds) - .in(SaasProductModuleFeatureRelation::getFeatureId, Lists.transform(saasFeatures, SaasFeature::getId)) - .eq(SaasProductModuleFeatureRelation::getIsDelete, TableIsDeleteEnum.NORMAL.value) - .list(); - } - - private List listRoleUserRelations(PermissionCheckReq identityAuthReq, - List saasFeatures) { + /** + * 兼容历史版本,全部切完后去掉 + * @param identityAuthReq + * @param saasFeatures + * @return + */ + private List listRoleUserRelations(PermissionCheckReq identityAuthReq, List saasFeatures) { List workspaceOuPairs = Lists.newArrayList( ListRoleUserRelationParam.WorkspaceOuPair.builder() @@ -1456,20 +1593,23 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .collect(Collectors.toList()); } - public Set listProducts(PermissionCheckReq req) { + private List listRoleUserRelationsNew(PermissionCheckReq identityAuthReq, List saasFeatureResources) { - List servicePkgDetailRes = rpcListProcessor(() -> servicePkgClient.getServicePkgDetailBySpaceId(Sets.newHashSet(req.getWorkspaceId())), - "查询租户的产品", req.getWorkspaceId()).getData(); - - if (CollectionUtil.isEmpty(servicePkgDetailRes)) { - return Collections.emptySet(); - } - - return servicePkgDetailRes.stream() - .map(ServicePkgDetailRes::getProducts) - .filter(CollectionUtil::isNotEmpty) - .flatMap(Collection::stream) - .map(ServicePkgProduct::getProductId) - .collect(Collectors.toSet()); + List workspaceOuPairs = Lists.newArrayList( + ListRoleUserRelationParam.WorkspaceOuPair.builder() + .workspaceId(identityAuthReq.getWorkspaceId()) + .ouId(identityAuthReq.getOuId()) + .build() + ); + ListRoleUserRelationParam listRoleUserRelationParam = ListRoleUserRelationParam.builder() + .personId(identityAuthReq.getPersonId()) + .workspaceOuPairs(Lists.newArrayList(workspaceOuPairs)) + .needRole(true) + .needPermission(true) + .featureIds(Lists.transform(saasFeatureResources, SaasFeatureResourceResp::getId)) + .build(); + return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream() + .filter(e -> e.getSaasRole() != null) + .collect(Collectors.toList()); } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/WorkspaceProductServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/WorkspaceProductServiceImpl.java index dee57b10..d2af52c1 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/WorkspaceProductServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/WorkspaceProductServiceImpl.java @@ -74,9 +74,9 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { ProductFeatureQuery productFeatureQuery = ProductFeatureQuery.builder() .productIds(productIds) .featureResourceTypes(param.getFeatureResourceTypes()) - .type(param.getType()) .terminal(param.getTerminal()) - .featureIds(param.getFeatureIds()) + .type(param.getType()) + .featureIdPairs(param.getFeatureIdPairs()) .build(); Map> saasProductModuleFeatureRelations = productFeatureRelationService.queryOnCondition(productFeatureQuery).stream() .collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId)); diff --git a/tyr-server/src/main/resources/mapper/SaasRoleMapper.xml b/tyr-server/src/main/resources/mapper/SaasRoleMapper.xml index 283bec6a..2e417232 100644 --- a/tyr-server/src/main/resources/mapper/SaasRoleMapper.xml +++ b/tyr-server/src/main/resources/mapper/SaasRoleMapper.xml @@ -115,17 +115,6 @@ - -