From e52beb9c0cfc6b79b8a87eac18401140e6f4db59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Mon, 3 Jun 2024 11:12:08 +0800 Subject: [PATCH 001/112] =?UTF-8?q?feat(REQ-2200):=20=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=9D=83=E9=99=90=E5=A2=9E=E5=8A=A0=E6=9E=9A=E4=B8=BE=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/tyr/client/common/enums/RowPermissionEnum.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/RowPermissionEnum.java b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/RowPermissionEnum.java index c8c09f5e..964c1ee3 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/RowPermissionEnum.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/RowPermissionEnum.java @@ -18,7 +18,7 @@ public enum RowPermissionEnum { DEPARTMENT_SUBORDINATE(4, "本部门及以下数据"), - UNIT_ONLY(5, "仅本单位数据"), + UNIT_ONLY(5, "仅本单位数据(包含班组)"), UNIT_DIRECT_SUBORDINATE(6, "本单位及下级直属单位数据"), @@ -26,6 +26,8 @@ public enum RowPermissionEnum { UNIT_ALL_SUBORDINATE(8, "本单位及以下协同(直属+合作)单位数据"), WORKSPACE(9, "本项目部数据"), + + UNIT_ONLY_EXCLUDE_TEAM(10, "仅本单位数据(不包含班组)"), ; From c3f7639dfbc8bc25c32a6d6ef5e4ba04ecbe07bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Mon, 3 Jun 2024 16:38:35 +0800 Subject: [PATCH 002/112] =?UTF-8?q?feat(REQ-2300):=20=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=9D=83=E9=99=90=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/DataObjectApi.java | 15 +- .../client/model/req/QueryDataObjectReq.java | 32 ++++ .../data/object/DataObjectController.java | 11 +- .../tyr/server/service/DataObjectService.java | 3 + .../service/impl/DataObjectServiceImpl.java | 179 ++++++++++-------- 5 files changed, 149 insertions(+), 91 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/QueryDataObjectReq.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/DataObjectApi.java b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/DataObjectApi.java index fcf9572f..f6f07c1e 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/DataObjectApi.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/DataObjectApi.java @@ -2,11 +2,7 @@ package cn.axzo.tyr.client.feign; import cn.axzo.basics.common.page.PageResult; import cn.axzo.framework.domain.web.result.ApiResult; -import cn.axzo.tyr.client.common.annotation.RepeatedSubmit; -import cn.axzo.tyr.client.model.req.CreateDataObjectReq; -import cn.axzo.tyr.client.model.req.DeleteDataObjectReq; -import cn.axzo.tyr.client.model.req.EditDataObjectReq; -import cn.axzo.tyr.client.model.req.PageDataObjectReq; +import cn.axzo.tyr.client.model.req.*; import cn.axzo.tyr.client.model.res.DataObjectRes; import cn.axzo.tyr.client.model.res.EnumRes; import cn.axzo.tyr.client.model.res.SimpleDataObjectRes; @@ -28,7 +24,6 @@ public interface DataObjectApi { @PostMapping("/api/dataObject/create") ApiResult createDataObject(@RequestBody @Valid CreateDataObjectReq req); - /** * 修改数据对象 * @param req @@ -63,4 +58,12 @@ public interface DataObjectApi { */ @GetMapping("/api/dataObject/get") ApiResult getDataObject(@RequestParam Long dataObjectId); + + /** + * 根据租户范围、数据对象code查询数据对象 + * @param req + * @return + */ + @PostMapping("/api/dataObject/query") + ApiResult queryDataObject(@RequestBody @Valid QueryDataObjectReq req); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/QueryDataObjectReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/QueryDataObjectReq.java new file mode 100644 index 00000000..152f8124 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/QueryDataObjectReq.java @@ -0,0 +1,32 @@ +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.io.Serializable; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/6/3 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class QueryDataObjectReq implements Serializable { + + /** + * 数据对象code + */ + @NotBlank(message = "数据对象code不能为空") + private String dataObjectCode; + + /** + * 租户范围 1:单位租户 2:项目租户 3:政务监管平台 6:OMS + */ + private Integer tenantScope; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/data/object/DataObjectController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/data/object/DataObjectController.java index e8366555..e0fb5b4e 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/data/object/DataObjectController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/data/object/DataObjectController.java @@ -1,6 +1,5 @@ package cn.axzo.tyr.server.controller.data.object; -import cn.axzo.basics.auth.enums.WorkspaceTypeWithLegacyEnum; import cn.axzo.basics.common.page.PageResult; import cn.axzo.framework.domain.ServiceException; import cn.axzo.framework.domain.web.result.ApiResult; @@ -10,12 +9,8 @@ import cn.axzo.tyr.client.common.enums.EnumTypeEnum; import cn.axzo.tyr.client.common.enums.ReturnCodeEnum; import cn.axzo.tyr.client.common.enums.RowPermissionEnum; import cn.axzo.tyr.client.common.enums.TenantScopeEnum; -import cn.axzo.tyr.client.common.enums.WorkspaceJoinType; import cn.axzo.tyr.client.feign.DataObjectApi; -import cn.axzo.tyr.client.model.req.CreateDataObjectReq; -import cn.axzo.tyr.client.model.req.DeleteDataObjectReq; -import cn.axzo.tyr.client.model.req.EditDataObjectReq; -import cn.axzo.tyr.client.model.req.PageDataObjectReq; +import cn.axzo.tyr.client.model.req.*; import cn.axzo.tyr.client.model.res.DataObjectRes; import cn.axzo.tyr.client.model.res.EnumRes; import cn.axzo.tyr.client.model.res.SimpleDataObjectRes; @@ -91,4 +86,8 @@ public class DataObjectController implements DataObjectApi { return ApiResult.ok(dataObjectService.getDataObject(dataObjectId)); } + @Override + public ApiResult queryDataObject(QueryDataObjectReq req) { + return ApiResult.ok(dataObjectService.queryDataObject(req)); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/DataObjectService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/DataObjectService.java index dd9de34d..75672788 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/DataObjectService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/DataObjectService.java @@ -4,6 +4,7 @@ import cn.axzo.basics.common.page.PageResult; import cn.axzo.tyr.client.model.req.CreateDataObjectReq; import cn.axzo.tyr.client.model.req.EditDataObjectReq; import cn.axzo.tyr.client.model.req.PageDataObjectReq; +import cn.axzo.tyr.client.model.req.QueryDataObjectReq; import cn.axzo.tyr.client.model.res.DataObjectRes; import cn.axzo.tyr.client.model.res.SimpleDataObjectRes; @@ -17,4 +18,6 @@ public interface DataObjectService { PageResult pageDataObject(PageDataObjectReq req); DataObjectRes getDataObject(Long dataObjectId); + + DataObjectRes queryDataObject(QueryDataObjectReq req); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java index a18ea7e2..11eaeba1 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java @@ -1,5 +1,6 @@ package cn.axzo.tyr.server.service.impl; +import cn.axzo.basics.common.constant.enums.DeleteEnum; import cn.axzo.basics.common.exception.ServiceException; import cn.axzo.basics.common.page.PageResult; import cn.axzo.tyr.client.common.enums.ReturnCodeEnum; @@ -16,6 +17,7 @@ import cn.axzo.tyr.client.model.data.object.RuleScopeQueryBO; import cn.axzo.tyr.client.model.req.CreateDataObjectReq; import cn.axzo.tyr.client.model.req.EditDataObjectReq; import cn.axzo.tyr.client.model.req.PageDataObjectReq; +import cn.axzo.tyr.client.model.req.QueryDataObjectReq; import cn.axzo.tyr.client.model.res.DataObjectRes; import cn.axzo.tyr.client.model.res.SimpleDataObjectRes; import cn.axzo.tyr.server.repository.dao.DataObjectAttrDao; @@ -36,6 +38,7 @@ import com.google.common.collect.Lists; import groovy.lang.Tuple2; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.support.TransactionTemplate; @@ -274,87 +277,21 @@ public class DataObjectServiceImpl implements DataObjectService { if (Objects.isNull(dataObject)) { throw new cn.axzo.framework.domain.ServiceException(ReturnCodeEnum.DATA_NOT_EXIST.getMessage()); } - DataObjectRes res = DataObjectMapper.INSTANCE.dataObject2DataObjectRes(dataObject); - // 获取数据对象字段 - DataObjectAttrQueryBO bo1 = DataObjectAttrQueryBO.builder().dataObjectId(dataObjectId).build(); - List objectAttrList = dataObjectAttrDao.listByBO(bo1); - Map attrMap; - if (CollUtil.isNotEmpty(objectAttrList)) { - List attributeBOS = DataObjectMapper.INSTANCE.dataObjectAttrs2AttributeBOs(objectAttrList); - List attributeBOList = attributeBOS.stream().sorted(Comparator.comparing(AttributeBO::getSort)).collect(Collectors.toList()); - res.setAttrs(attributeBOList); - attrMap = attributeBOList.stream().collect(Collectors.toMap(AttributeBO::getAttrCode, AttributeBO::getAttrName, (a, b) -> a)); - } else { - attrMap = null; + return buildDataObjectRes(dataObject); + } + + @Override + public DataObjectRes queryDataObject(QueryDataObjectReq req) { + List dataObjects = dataObjectDao.lambdaQuery() + .eq(DataObject::getIsDelete, DeleteEnum.NORMAL.getValue()) + .eq(StringUtils.isNotBlank(req.getDataObjectCode()), DataObject::getDataObjectCode, req.getDataObjectCode()) + .eq(Objects.nonNull(req.getTenantScope()), DataObject::getTenantScope, req.getTenantScope()) + .list(); + if (CollectionUtils.isEmpty(dataObjects)) { + throw new cn.axzo.framework.domain.ServiceException(ReturnCodeEnum.DATA_NOT_EXIST.getMessage()); } - - // 获取数据对象规则 - DataObjectRuleQueryBO bo2 = DataObjectRuleQueryBO.builder().dataObjectId(dataObjectId).build(); - List dataObjectRules = dataObjectRuleDao.listByBO(bo2); - if (CollUtil.isNotEmpty(dataObjectRules)) { - res.setDataObjectRuleBOList(new ArrayList<>(dataObjectRules.size() - 1)); - dataObjectRules.forEach(e -> { - if (YesNoEnum.YES.getValue().equals(e.getIsDefault())) { - DefaultDataObjectRuleBO ruleBO = DataObjectMapper.INSTANCE.rule2DefaultRuleBO(e); - res.setDefaultDataObjectRuleBO(ruleBO); - } else { - DataObjectRuleBO ruleBO = DataObjectMapper.INSTANCE.rule2RuleBO(e); - res.getDataObjectRuleBOList().add(ruleBO); - } - }); - if (CollUtil.isNotEmpty(res.getDataObjectRuleBOList())) { - List sortedRuleList = res.getDataObjectRuleBOList().stream().sorted(Comparator.comparing(DataObjectRuleBO::getSort)).collect(Collectors.toList()); - res.setDataObjectRuleBOList(sortedRuleList); - } - } - - - // 获取数据对象规则字段 - RuleAttrQueryBO bo3 = RuleAttrQueryBO.builder().dataObjectId(dataObjectId).build(); - List ruleAttrList = dataObjectRuleAttrDao.listByBO(bo3); - if (CollUtil.isNotEmpty(attrMap) && CollUtil.isNotEmpty(ruleAttrList)) { - Map> ruleAttrMap = ruleAttrList.stream().collect(Collectors.groupingBy(DataObjectRuleAttr::getDataObjectRuleId)); - // 默认 - List ruleAttrList1 = ruleAttrMap.get(res.getDefaultDataObjectRuleBO().getDataObjectRuleId()); - if (CollUtil.isNotEmpty(ruleAttrList1)) { - List permissionBOs = DataObjectMapper.INSTANCE.ruleAttrs2AttrPermissionBOs(ruleAttrList1); - permissionBOs.forEach(e -> e.setAttrName(attrMap.get(e.getAttrCode()))); - List permissionBOList = permissionBOs.stream().sorted(Comparator.comparing(AttributePermissionBO::getSort)).collect(Collectors.toList()); - res.getDefaultDataObjectRuleBO().setAttributePermissionBOList(permissionBOList); - } - - //自定义 - if (CollUtil.isNotEmpty(res.getDataObjectRuleBOList())) { - res.getDataObjectRuleBOList().forEach(e -> buildRuleAttr(attrMap, ruleAttrMap, e)); - } - } - - // 获取数据对象规则范围 - RuleScopeQueryBO bo4 = RuleScopeQueryBO.builder().dataObjectId(dataObjectId).build(); - List scopeList = dataObjectRuleScopeDao.listByBO(bo4); - if (CollUtil.isNotEmpty(scopeList)) { - Map> scopeMap = scopeList.stream().collect(Collectors.groupingBy(DataObjectRuleScope::getDataObjectRuleId)); - // 默认 - List defaultScopeList = scopeMap.get(res.getDefaultDataObjectRuleBO().getDataObjectRuleId()); - if (CollUtil.isNotEmpty(defaultScopeList)) { - List relationIdList = defaultScopeList.stream().map(DataObjectRuleScope::getRelationId).collect(Collectors.toList()); - res.getDefaultDataObjectRuleBO().setRelationId(relationIdList); - } - - //自定义 - if (CollUtil.isNotEmpty(res.getDataObjectRuleBOList())) { - res.getDataObjectRuleBOList().forEach(e -> { - List scopeList1 = scopeMap.get(e.getDataObjectRuleId()); - if (CollUtil.isNotEmpty(scopeList1)) { - List relationIdList = scopeList1.stream().map(DataObjectRuleScope::getRelationId).collect(Collectors.toList()); - e.setRelationId(relationIdList); - } - }); - } - } - - return res; + return buildDataObjectRes(dataObjects.get(0)); } private static void buildRuleAttr(Map attrMap, Map> ruleAttrMap, DataObjectRuleBO e) { @@ -428,4 +365,88 @@ public class DataObjectServiceImpl implements DataObjectService { } } } + + private DataObjectRes buildDataObjectRes(DataObject dataObject) { + DataObjectRes res = DataObjectMapper.INSTANCE.dataObject2DataObjectRes(dataObject); + + // 获取数据对象字段 + DataObjectAttrQueryBO bo1 = DataObjectAttrQueryBO.builder().dataObjectId(dataObject.getId()).build(); + List objectAttrList = dataObjectAttrDao.listByBO(bo1); + Map attrMap; + if (CollUtil.isNotEmpty(objectAttrList)) { + List attributeBOS = DataObjectMapper.INSTANCE.dataObjectAttrs2AttributeBOs(objectAttrList); + List attributeBOList = attributeBOS.stream().sorted(Comparator.comparing(AttributeBO::getSort)).collect(Collectors.toList()); + res.setAttrs(attributeBOList); + attrMap = attributeBOList.stream().collect(Collectors.toMap(AttributeBO::getAttrCode, AttributeBO::getAttrName, (a, b) -> a)); + } else { + attrMap = null; + } + + // 获取数据对象规则 + DataObjectRuleQueryBO bo2 = DataObjectRuleQueryBO.builder().dataObjectId(dataObject.getId()).build(); + List dataObjectRules = dataObjectRuleDao.listByBO(bo2); + if (CollUtil.isNotEmpty(dataObjectRules)) { + res.setDataObjectRuleBOList(new ArrayList<>(dataObjectRules.size() - 1)); + dataObjectRules.forEach(e -> { + if (YesNoEnum.YES.getValue().equals(e.getIsDefault())) { + DefaultDataObjectRuleBO ruleBO = DataObjectMapper.INSTANCE.rule2DefaultRuleBO(e); + res.setDefaultDataObjectRuleBO(ruleBO); + } else { + DataObjectRuleBO ruleBO = DataObjectMapper.INSTANCE.rule2RuleBO(e); + res.getDataObjectRuleBOList().add(ruleBO); + } + }); + if (CollUtil.isNotEmpty(res.getDataObjectRuleBOList())) { + List sortedRuleList = res.getDataObjectRuleBOList().stream().sorted(Comparator.comparing(DataObjectRuleBO::getSort)).collect(Collectors.toList()); + res.setDataObjectRuleBOList(sortedRuleList); + } + } + + + // 获取数据对象规则字段 + RuleAttrQueryBO bo3 = RuleAttrQueryBO.builder().dataObjectId(dataObject.getId()).build(); + List ruleAttrList = dataObjectRuleAttrDao.listByBO(bo3); + if (CollUtil.isNotEmpty(attrMap) && CollUtil.isNotEmpty(ruleAttrList)) { + Map> ruleAttrMap = ruleAttrList.stream().collect(Collectors.groupingBy(DataObjectRuleAttr::getDataObjectRuleId)); + // 默认 + List ruleAttrList1 = ruleAttrMap.get(res.getDefaultDataObjectRuleBO().getDataObjectRuleId()); + if (CollUtil.isNotEmpty(ruleAttrList1)) { + List permissionBOs = DataObjectMapper.INSTANCE.ruleAttrs2AttrPermissionBOs(ruleAttrList1); + permissionBOs.forEach(e -> e.setAttrName(attrMap.get(e.getAttrCode()))); + List permissionBOList = permissionBOs.stream().sorted(Comparator.comparing(AttributePermissionBO::getSort)).collect(Collectors.toList()); + res.getDefaultDataObjectRuleBO().setAttributePermissionBOList(permissionBOList); + } + + //自定义 + if (CollUtil.isNotEmpty(res.getDataObjectRuleBOList())) { + res.getDataObjectRuleBOList().forEach(e -> buildRuleAttr(attrMap, ruleAttrMap, e)); + } + } + + // 获取数据对象规则范围 + RuleScopeQueryBO bo4 = RuleScopeQueryBO.builder().dataObjectId(dataObject.getId()).build(); + List scopeList = dataObjectRuleScopeDao.listByBO(bo4); + if (CollUtil.isNotEmpty(scopeList)) { + Map> scopeMap = scopeList.stream().collect(Collectors.groupingBy(DataObjectRuleScope::getDataObjectRuleId)); + // 默认 + List defaultScopeList = scopeMap.get(res.getDefaultDataObjectRuleBO().getDataObjectRuleId()); + if (CollUtil.isNotEmpty(defaultScopeList)) { + List relationIdList = defaultScopeList.stream().map(DataObjectRuleScope::getRelationId).collect(Collectors.toList()); + res.getDefaultDataObjectRuleBO().setRelationId(relationIdList); + } + + //自定义 + if (CollUtil.isNotEmpty(res.getDataObjectRuleBOList())) { + res.getDataObjectRuleBOList().forEach(e -> { + List scopeList1 = scopeMap.get(e.getDataObjectRuleId()); + if (CollUtil.isNotEmpty(scopeList1)) { + List relationIdList = scopeList1.stream().map(DataObjectRuleScope::getRelationId).collect(Collectors.toList()); + e.setRelationId(relationIdList); + } + }); + } + } + + return res; + } } From 030d848653a53b56fe8244faa3d2b7fabf4d65eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Mon, 3 Jun 2024 18:16:31 +0800 Subject: [PATCH 003/112] =?UTF-8?q?feat(REQ-2300):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=9D=83=E9=99=90=E6=9E=9A=E4=B8=BE=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/tyr/client/common/enums/AttrPermissionEnum.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/AttrPermissionEnum.java b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/AttrPermissionEnum.java index 7c9e53d2..31c63f6c 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/AttrPermissionEnum.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/AttrPermissionEnum.java @@ -15,7 +15,7 @@ public enum AttrPermissionEnum { DEPARTMENT_SUBORDINATE(4, "本部门及以下数据"), - UNIT_ONLY(5, "仅本单位数据"), + UNIT_ONLY(5, "仅本单位数据(包含班组)"), UNIT_DIRECT_SUBORDINATE(6, "本单位及下级直属单位数据"), @@ -24,6 +24,8 @@ public enum AttrPermissionEnum { UNIT_ALL_SUBORDINATE(8, "本单位及以下协同(直属+合作)单位数据"), WORKSPACE(9, "本项目部数据"), EQUAL_TO_ROW(10, "同行级数据权限"), + + UNIT_ONLY_EXCLUDE_TEAM(11, "仅本单位数据(不包含班组)"), ; private final Integer value; private final String desc; From 841660f4d1445b03885ebc3e041af1256b3c542f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Mon, 3 Jun 2024 18:24:32 +0800 Subject: [PATCH 004/112] =?UTF-8?q?feat(REQ-2300):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=9D=83=E9=99=90=E6=9E=9A=E4=B8=BE=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/tyr/client/common/enums/AttrPermissionEnum.java | 2 +- .../java/cn/axzo/tyr/client/common/enums/RowPermissionEnum.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/AttrPermissionEnum.java b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/AttrPermissionEnum.java index 31c63f6c..c4bd8666 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/AttrPermissionEnum.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/AttrPermissionEnum.java @@ -36,6 +36,6 @@ public enum AttrPermissionEnum { public static List listAttrPermissionForNotWorkspace() { return Lists.newArrayList(SELF_ONLY, SELF_SUBORDINATE, - DEPARTMENT_ONLY, DEPARTMENT_SUBORDINATE, UNIT_ONLY, EQUAL_TO_ROW); + DEPARTMENT_ONLY, DEPARTMENT_SUBORDINATE, UNIT_ONLY, UNIT_ONLY_EXCLUDE_TEAM, EQUAL_TO_ROW); } } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/RowPermissionEnum.java b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/RowPermissionEnum.java index 964c1ee3..729eb70f 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/RowPermissionEnum.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/RowPermissionEnum.java @@ -43,7 +43,7 @@ public enum RowPermissionEnum { public static List listRowPermissionForNotWorkspace() { return Lists.newArrayList(SELF_ONLY, SELF_SUBORDINATE, - DEPARTMENT_ONLY, DEPARTMENT_SUBORDINATE, UNIT_ONLY); + DEPARTMENT_ONLY, DEPARTMENT_SUBORDINATE, UNIT_ONLY, UNIT_ONLY_EXCLUDE_TEAM); } } From bd731682b4ed928b13563484d5703c5fc3ce5991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Tue, 4 Jun 2024 14:29:25 +0800 Subject: [PATCH 005/112] =?UTF-8?q?feat(REQ-2300):=20add=E5=A4=87=E6=B3=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/model/data/object/AttributePermissionBO.java | 2 +- .../cn/axzo/tyr/client/model/data/object/DataObjectRuleBO.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/data/object/AttributePermissionBO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/data/object/AttributePermissionBO.java index da93cc37..fe04cf30 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/data/object/AttributePermissionBO.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/data/object/AttributePermissionBO.java @@ -15,7 +15,7 @@ public class AttributePermissionBO { private Integer sort; // 序号 private String attrName; //字段名 private String attrCode; // 字段code - private Integer visibilityScope; // 字段值查看范围 1:仅本人数据 2:本人及下属数据 3:仅本部门数据 4:本部门及以下数据 5:仅本单位数据 6:本单位及下级直属单位数据 7:本单位及下级协同(直属+合作)单位数据 8:本单位及以下协同(直属+合作)单位数据 9:本项目部数据 10:同行级数据权限 + private Integer visibilityScope; // 字段值查看范围 1:仅本人数据 2:本人及下属数据 3:仅本部门数据 4:本部门及以下数据 5:仅本单位数据(包含班组) 6:本单位及下级直属单位数据 7:本单位及下级协同(直属+合作)单位数据 8:本单位及以下协同(直属+合作)单位数据 9:本项目部数据 10:同行级数据权限 11:仅本单位数据(不包含班组) private Integer isUnmaskable; // 是否可脱敏 1-不可操作脱敏 2-可操作脱敏 private Integer isEditable; // 是否可编辑 1-不可编辑 2-可编辑 } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/data/object/DataObjectRuleBO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/data/object/DataObjectRuleBO.java index c3e9f94b..fc5e43ba 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/data/object/DataObjectRuleBO.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/data/object/DataObjectRuleBO.java @@ -42,7 +42,8 @@ public class DataObjectRuleBO { /** * 行级数据权限(单选) 1:仅本人数据 2:本人及下属数据 3:仅本部门数据 4:本部门及以下数据 - * 5:仅本单位数据 6:本单位及下级直属单位数据 7:本单位及下级协同(直属+合作)单位数据 8:本单位及以下协同(直属+合作)单位数据 9:本项目部数据 + * 5:仅本单位数据(包含班组) 6:本单位及下级直属单位数据 7:本单位及下级协同(直属+合作)单位数据 8:本单位及以下协同(直属+合作)单位数据 + * 9:本项目部数据 10:仅本单位数据(不包含班组) */ private Integer rowPermission; /** From 50d569df410a7c7b40b7a4518b18bd67e53eceda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Tue, 4 Jun 2024 15:05:28 +0800 Subject: [PATCH 006/112] =?UTF-8?q?feat(REQ-2300):=20=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=9D=83=E9=99=90=E6=9F=A5=E8=AF=A2=E4=B8=8D=E6=8A=9B=E5=BC=82?= =?UTF-8?q?=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/server/service/impl/DataObjectServiceImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java index 11eaeba1..e60bcdea 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java @@ -33,6 +33,7 @@ import cn.axzo.tyr.server.repository.entity.DataObjectRuleScope; import cn.axzo.tyr.server.service.DataObjectService; import cn.axzo.tyr.server.utils.mapper.DataObjectMapper; import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.metadata.IPage; import com.google.common.collect.Lists; import groovy.lang.Tuple2; @@ -289,7 +290,8 @@ public class DataObjectServiceImpl implements DataObjectService { .eq(Objects.nonNull(req.getTenantScope()), DataObject::getTenantScope, req.getTenantScope()) .list(); if (CollectionUtils.isEmpty(dataObjects)) { - throw new cn.axzo.framework.domain.ServiceException(ReturnCodeEnum.DATA_NOT_EXIST.getMessage()); + log.warn("数据权限记录不存在,param:{}", JSON.toJSONString(req)); + return null; } return buildDataObjectRes(dataObjects.get(0)); } From e7c6dd2f928652c2620536404b395e651aeeb254 Mon Sep 17 00:00:00 2001 From: lilong Date: Thu, 25 Jul 2024 10:09:56 +0800 Subject: [PATCH 007/112] =?UTF-8?q?feat:(REQ-2720)=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E6=9D=83=E9=99=90=E3=80=81=E4=BA=A7=E5=93=81?= =?UTF-8?q?=E6=9D=83=E9=99=90=E4=BA=8B=E4=BB=B6=E5=92=8C=E6=B6=88=E8=B4=B9?= =?UTF-8?q?=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../req/PageProductFeatureRelationReq.java | 10 + .../cn/axzo/tyr/server/config/MqProducer.java | 40 ++++ .../config/RocketMQEventConfiguration.java | 20 +- .../inner/CacheProductPermissionHandler.java | 193 ++++++++++++++++++ .../inner/CacheRolePermissionHandler.java | 189 +++++++++++++++++ .../tyr/server/event/inner/EventTypeEnum.java | 27 +++ .../ProductPermissionCreatedPayload.java | 21 ++ .../payload/RolePermissionCreatedPayload.java | 23 +++ .../ProductPermissionCacheService.java | 32 ++- .../service/RolePermissionCacheService.java | 9 +- .../ProductFeatureRelationServiceImpl.java | 32 ++- .../ProductPermissionCacheServiceImpl.java | 156 ++++++++++++-- .../impl/RolePermissionCacheServiceImpl.java | 133 ++++++++++-- 13 files changed, 839 insertions(+), 46 deletions(-) create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/config/MqProducer.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/EventTypeEnum.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/ProductPermissionCreatedPayload.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/RolePermissionCreatedPayload.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageProductFeatureRelationReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageProductFeatureRelationReq.java index f5381af2..08a360dd 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageProductFeatureRelationReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageProductFeatureRelationReq.java @@ -9,6 +9,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; +import java.util.Set; @Data @Builder @@ -30,4 +31,13 @@ public class PageProductFeatureRelationReq implements IPageReq { @CriteriaField(field = "id", operator = Operator.IN) private List ids; + + /** + * 产品 ID + */ + @CriteriaField(field = "productModuleId", operator = Operator.IN) + private Set productModuleIds; + + @CriteriaField(field = "type", operator = Operator.EQ) + private Integer type; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/config/MqProducer.java b/tyr-server/src/main/java/cn/axzo/tyr/server/config/MqProducer.java new file mode 100644 index 00000000..b5171896 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/config/MqProducer.java @@ -0,0 +1,40 @@ +package cn.axzo.tyr.server.config; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventProducer; +import com.alibaba.fastjson.JSON; +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.stereotype.Component; + +import java.util.List; + +/** + * @author yanglin + */ +@Slf4j +@Component +@RefreshScope +public class MqProducer { + + @Autowired + private EventProducer eventProducer; + + @Value("${sendMq}") + private Boolean sendMq; + + public void send(Event event){ + log.info(JSON.toJSONString(event)); + if(sendMq != null && !sendMq){ + return; + } + //生产消息 + eventProducer.send(event); + } + + public void sendBatch(List events){ + events.forEach(this::send); + } +} \ No newline at end of file diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/config/RocketMQEventConfiguration.java b/tyr-server/src/main/java/cn/axzo/tyr/server/config/RocketMQEventConfiguration.java index 7b7b391f..71f60031 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/config/RocketMQEventConfiguration.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/config/RocketMQEventConfiguration.java @@ -70,7 +70,25 @@ public class RocketMQEventConfiguration { consumeMode = ConsumeMode.ORDERLY, nameServer = "${rocketmq.name-server}" ) - public static class DefaultListener extends BaseListener implements RocketMQListener { + public static class ThronesListener extends BaseListener implements RocketMQListener { + + @Autowired + private EventConsumer eventConsumer; + + @Override + public void onMessage(MessageExt message) { + super.onEvent(message, eventConsumer); + } + } + + @Slf4j + @Component + @RocketMQMessageListener(topic = "topic_tyr_${spring.profiles.active}", + consumerGroup = "GID_topic_tyr_${spring.application.name}_${spring.profiles.active}", + consumeMode = ConsumeMode.ORDERLY, + nameServer = "${rocketmq.name-server}" + ) + public static class TyrListener extends BaseListener implements RocketMQListener { @Autowired private EventConsumer eventConsumer; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java new file mode 100644 index 00000000..097067ee --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java @@ -0,0 +1,193 @@ +package cn.axzo.tyr.server.event.inner; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.framework.rocketmq.EventHandler; +import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; +import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload; +import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; +import cn.axzo.tyr.server.repository.entity.SaasFeature; +import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; +import cn.axzo.tyr.server.service.ProductFeatureRelationService; +import cn.axzo.tyr.server.service.ProductPermissionCacheService; +import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +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; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE; + +/** + * 缓存产品的权限 + */ +@Slf4j +@Component +public class CacheProductPermissionHandler implements EventHandler, InitializingBean { + + @Autowired + private EventConsumer eventConsumer; + @Autowired + private ProductPermissionCacheService productPermissionCacheService; + @Autowired + private ProductFeatureRelationService productFeatureRelationService; + @Autowired + private SaasFeatureResourceService saasFeatureResourceService; + @Autowired + private SaasFeatureDao saasFeatureDao; + + @Override + public void onEvent(Event event, EventConsumer.Context context) { + log.info("begin cached product permission handler rocketmq event: {}", event); + ProductPermissionCreatedPayload payload = event.normalizedData(ProductPermissionCreatedPayload.class); + + if (CollectionUtils.isEmpty(payload.getProductModuleIds())) { + return; + } + + PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() + .productModuleIds(payload.getProductModuleIds()) + .build(); + List productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq); + + if (CollectionUtils.isEmpty(productFeatures)) { + return; + } + + List productPermissions = resolveProductPermissions(productFeatures); + + if (CollectionUtils.isEmpty(productPermissions)) { + return; + } + + ProductPermissionCacheService.StoreProductPermissionParam storeProductPermissionParam = ProductPermissionCacheService.StoreProductPermissionParam.builder() + .productPermissions(productPermissions) + .build(); + productPermissionCacheService.store(storeProductPermissionParam); + + log.info("end cached product permission handler rocketmq event: {}", event); + } + + @Override + public void afterPropertiesSet() throws Exception { + eventConsumer.registerHandler(EventTypeEnum.PRODUCT_PERMISSION_CREATED.getEventCode(), this); + } + + public List resolveProductPermissions(List productPermissions) { + if (CollectionUtils.isEmpty(productPermissions)) { + return Collections.emptyList(); + } + + Map featureResources = listSaasFeatureResource(productPermissions); + + Map saasFeatures = listSaasFeature(productPermissions); + + return productPermissions.stream() + .collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId)) + .entrySet() + .stream() + .map(e -> { + List productFeatureRelations = e.getValue(); + + if (CollectionUtils.isEmpty(productFeatureRelations)) { + return null; + } + + List permissions = productFeatureRelations.stream() + .map(relation -> { + if (Objects.equals(relation.getType(), NEW_FEATURE)) { + SaasFeatureResourceResp featureResource = featureResources.get(relation.getFeatureId()); + if (Objects.isNull(featureResource) || CollectionUtils.isEmpty(featureResource.getFeatureCodes())) { + return null; + } + return featureResource.getFeatureCodes().stream() + .map(featureCode -> ProductPermissionCacheService.PermissionDTO.builder() + .featureId(featureResource.getId()) + .featureCode(featureCode) + .featureType(featureResource.getFeatureType()) + .terminal(featureResource.getTerminal()) + .cooperateType(relation.getDictCode()) + .build()) + .collect(Collectors.toList()); + } + + SaasFeature saasFeature = saasFeatures.get(relation.getFeatureId()); + if (Objects.isNull(saasFeature)) { + return null; + } + + return Lists.newArrayList(ProductPermissionCacheService.PermissionDTO.builder() + .featureId(saasFeature.getId()) + .featureCode(saasFeature.getFeatureCode()) + .featureType(saasFeature.getFeatureType()) + .terminal(saasFeature.getTerminal()) + .cooperateType(relation.getDictCode()) + .build()); + }) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(permissions)) { + return null; + } + + return ProductPermissionCacheService.ProductPermission.builder() + .productId(e.getKey()) + .permissions(permissions) + .build(); + + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + + private Map listSaasFeatureResource(List productPermissions) { + + List featureIds = productPermissions.stream() + .filter(e -> Objects.equals(e.getType(), NEW_FEATURE)) + .map(SaasProductModuleFeatureRelation::getFeatureId) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyMap(); + } + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(featureIds) + .needFeatureCodes(true) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity())); + } + + private Map listSaasFeature(List productPermissions) { + + List featureIds = productPermissions.stream() + .filter(e -> Objects.equals(e.getType(), OLD_FEATURE)) + .map(SaasProductModuleFeatureRelation::getFeatureId) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyMap(); + } + + return saasFeatureDao.listByIds(featureIds).stream() + .collect(Collectors.toMap(SaasFeature::getId, Function.identity())); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java new file mode 100644 index 00000000..e62ded89 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java @@ -0,0 +1,189 @@ +package cn.axzo.tyr.server.event.inner; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.framework.rocketmq.EventHandler; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; +import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; +import cn.axzo.tyr.client.model.res.SaasRoleRes; +import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; +import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; +import cn.axzo.tyr.server.repository.entity.SaasFeature; +import cn.axzo.tyr.server.service.RolePermissionCacheService; +import cn.axzo.tyr.server.service.RoleService; +import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +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; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE; + +/** + * 缓存角色的权限 + */ +@Slf4j +@Component +public class CacheRolePermissionHandler implements EventHandler, InitializingBean { + + @Autowired + private EventConsumer eventConsumer; + @Autowired + private RolePermissionCacheService rolePermissionCacheService; + @Autowired + private RoleService roleService; + @Autowired + private SaasFeatureResourceService saasFeatureResourceService; + @Autowired + private SaasFeatureDao saasFeatureDao; + + @Override + public void onEvent(Event event, EventConsumer.Context context) { + log.info("begin cached role permission handler rocketmq event: {}", event); + RolePermissionCreatedPayload payload = event.normalizedData(RolePermissionCreatedPayload.class); + + if (CollectionUtils.isEmpty(payload.getRoleIds())) { + return; + } + + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .roleIds(Lists.newArrayList(payload.getRoleIds())) + .needPermissionRelation(true) + .build(); + List roles = roleService.list(listSaasRoleParam); + + if (CollectionUtils.isEmpty(roles)) { + return; + } + + List rolePermissions = resolveRolePermission(roles); + + if (CollectionUtils.isEmpty(rolePermissions)) { + return; + } + + RolePermissionCacheService.StoreRolePermissionParam storeRolePermissionParam = RolePermissionCacheService.StoreRolePermissionParam.builder() + .rolePermissions(rolePermissions) + .build(); + rolePermissionCacheService.store(storeRolePermissionParam); + log.info("end cached role permission handler rocketmq event: {}", event); + } + + @Override + public void afterPropertiesSet() throws Exception { + eventConsumer.registerHandler(EventTypeEnum.ROLE_PERMISSION_CREATED.getEventCode(), this); + } + + public List resolveRolePermission(List roles) { + + + Map featureResources = listSaasFeatureResource(roles); + + Map saasFeatures = listSaasFeature(roles); + + return roles.stream() + .map(e -> { + if (CollectionUtils.isEmpty(e.getPermissionRelations())) { + return null; + } + + List permissions = e.getPermissionRelations().stream() + .map(permissionRelation -> { + if (Objects.equals(permissionRelation.getType(), NEW_FEATURE)) { + SaasFeatureResourceResp featureResource = featureResources.get(permissionRelation.getFeatureId()); + if (Objects.isNull(featureResource) || CollectionUtils.isEmpty(featureResource.getFeatureCodes())) { + return null; + } + return featureResource.getFeatureCodes().stream() + .map(featureCode -> RolePermissionCacheService.PermissionDTO.builder() + .featureId(featureResource.getId()) + .featureCode(featureCode) + .featureType(featureResource.getFeatureType()) + .terminal(featureResource.getTerminal()) + .build()) + .collect(Collectors.toList()); + } + SaasFeature saasFeature = saasFeatures.get(permissionRelation.getFeatureId()); + if (Objects.isNull(saasFeature)) { + return null; + } + return Lists.newArrayList(RolePermissionCacheService.PermissionDTO.builder() + .featureId(saasFeature.getId()) + .featureCode(saasFeature.getFeatureCode()) + .featureType(saasFeature.getFeatureType()) + .terminal(saasFeature.getTerminal()) + .build()); + }) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(permissions)) { + return null; + } + + return RolePermissionCacheService.RolePermission.builder() + .roleId(e.getId()) + .permissions(permissions) + .build(); + + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + + private Map listSaasFeatureResource(List roles) { + + List featureIds = roles.stream() + .filter(e -> !CollectionUtils.isEmpty(e.getPermissionRelations())) + .map(SaasRoleRes::getPermissionRelations) + .flatMap(Collection::stream) + .filter(e -> Objects.equals(e.getType(), NEW_FEATURE)) + .map(SaasPermissionRelationRes::getFeatureId) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyMap(); + } + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(featureIds) + .needFeatureCodes(true) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity())); + } + + private Map listSaasFeature(List roles) { + + List featureIds = roles.stream() + .filter(e -> !CollectionUtils.isEmpty(e.getPermissionRelations())) + .map(SaasRoleRes::getPermissionRelations) + .flatMap(Collection::stream) + .filter(e -> Objects.equals(e.getType(), OLD_FEATURE)) + .map(SaasPermissionRelationRes::getFeatureId) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyMap(); + } + + return saasFeatureDao.listByIds(featureIds).stream() + .collect(Collectors.toMap(SaasFeature::getId, Function.identity())); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/EventTypeEnum.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/EventTypeEnum.java new file mode 100644 index 00000000..d7c5bdfa --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/EventTypeEnum.java @@ -0,0 +1,27 @@ +package cn.axzo.tyr.server.event.inner; + +import cn.axzo.framework.rocketmq.Event; +import lombok.Getter; + +@Getter +public enum EventTypeEnum { + + PRODUCT_PERMISSION_CREATED("product-permission", "product-permission-created", "产品权限添加"), + ROLE_PERMISSION_CREATED("role-permission", "role-permission-created", "角色权限添加"), + ; + + EventTypeEnum(String model, String name, String desc) { + this.eventCode = Event.EventCode.builder() + .module(model) + .name(name) + .build(); + this.model = model; + this.name = name; + this.desc = desc; + } + + private String model; + private String name; + private String desc; + private Event.EventCode eventCode; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/ProductPermissionCreatedPayload.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/ProductPermissionCreatedPayload.java new file mode 100644 index 00000000..c6bd5ed5 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/ProductPermissionCreatedPayload.java @@ -0,0 +1,21 @@ +package cn.axzo.tyr.server.event.payload; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Set; + +/** + * 产品权限点做了更新,没有发送相关权限点消息,是因为日志太大,只能消费的时候实时查询 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductPermissionCreatedPayload implements Serializable { + + private Set productModuleIds; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/RolePermissionCreatedPayload.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/RolePermissionCreatedPayload.java new file mode 100644 index 00000000..5584cd3f --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/RolePermissionCreatedPayload.java @@ -0,0 +1,23 @@ +package cn.axzo.tyr.server.event.payload; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Set; + + +/** + * 角色权限点做了更新,没有发送相关权限点消息,是因为日志太大,只能消费的时候实时查询 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RolePermissionCreatedPayload implements Serializable { + + private Set roleIds; + +} 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 index bdad9d38..7ae8a81f 100644 --- 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 @@ -6,14 +6,29 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; +import java.util.Map; +import java.util.Set; public interface ProductPermissionCacheService { - List list(ListProductPermissionParam param); + /** + * 查询产品的权限信息 + * @param param + * @return + */ + Map> list(ListProductPermissionParam param); + /** + * 存储产品的权限信息 + * @param param + */ void store(StoreProductPermissionParam param); - + /** + * 产品是否有缓存权限 + * @param param + * @return + */ List hasProductIds(HasProductPermissionParam param); @Data @@ -47,7 +62,9 @@ public interface ProductPermissionCacheService { @NoArgsConstructor @AllArgsConstructor class ListProductPermissionParam { - private List productIds; + private Set productIds; + + private Set featureCodes; } @Data @@ -57,12 +74,17 @@ public interface ProductPermissionCacheService { class PermissionDTO { /** - * 产品关联的字典 Code 原值 + * 协同关系类型 + * 原saas_product_module_feature_relation.dictCode */ - private String dictCode; + private String cooperateType; private Long featureId; private String featureCode; + + private String terminal; + + private Integer featureType; } } \ 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 index e974b1a5..ae332e55 100644 --- 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 @@ -6,12 +6,13 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; +import java.util.Map; import java.util.Set; public interface RolePermissionCacheService { - List list(ListRolePermissionParam param); + Map> list(ListRolePermissionParam param); /** * redisKey:roleId @@ -53,7 +54,9 @@ public interface RolePermissionCacheService { @NoArgsConstructor @AllArgsConstructor class ListRolePermissionParam { - private List roleIds; + private Set roleIds; + + private Set featureCodes; } @Data @@ -80,5 +83,7 @@ public interface RolePermissionCacheService { * 资源所属端 */ private String terminal; + + private Integer featureType; } } 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 100bdb17..072cc28d 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 @@ -5,6 +5,7 @@ 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.result.ApiResult; +import cn.axzo.framework.rocketmq.Event; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.thrones.client.saas.ServicePkgClient; import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct; @@ -15,6 +16,8 @@ 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.client.model.req.PageProductFeatureRelationReq; +import cn.axzo.tyr.server.config.MqProducer; +import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload; import cn.axzo.tyr.server.repository.dao.ProductModuleDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; @@ -50,6 +53,7 @@ import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; +import static cn.axzo.tyr.server.event.inner.EventTypeEnum.PRODUCT_PERMISSION_CREATED; import static cn.axzo.tyr.server.util.RpcInternalUtil.checkAndGetData; /** @@ -68,6 +72,9 @@ public class ProductFeatureRelationServiceImpl extends ServiceImpl> featureList(ProductFeatureRelationSearchReq req) { @@ -115,6 +122,8 @@ public class ProductFeatureRelationServiceImpl extends ServiceImpl resourceMap = saasFeatureResourceDao.lambdaQuery() @@ -137,6 +146,27 @@ public class ProductFeatureRelationServiceImpl extends ServiceImpl req) { + + if (CollectionUtils.isEmpty(req)) { + return; + } + + Set productModuleIds = req.stream() + .map(ProductFeatureRelationUpdateReq::getProductModuleId) + .collect(Collectors.toSet()); + Event event = Event.builder() + .targetType(TARGET_TYPE) + .eventCode(PRODUCT_PERMISSION_CREATED.getEventCode()) + .data(ProductPermissionCreatedPayload.builder() + .productModuleIds(productModuleIds) + .build()) + .build(); + mqProducer.send(event); } @Override @@ -326,7 +356,7 @@ public class ProductFeatureRelationServiceImpl extends ServiceImpl list(PageProductFeatureRelationReq param) { return PageConverter.drainAll(pageNumber -> { param.setPage(pageNumber); - param.setPageSize(500); + param.setPageSize(1000); return page(param); }); } 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 index 4989fda3..3dddf88d 100644 --- 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 @@ -2,25 +2,36 @@ package cn.axzo.tyr.server.service.impl; import cn.axzo.foundation.exception.Axssert; import cn.axzo.pokonyan.config.redis.RedisClient; +import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq; +import cn.axzo.tyr.server.event.inner.CacheProductPermissionHandler; +import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; +import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductPermissionCacheService; import cn.hutool.core.lang.Pair; +import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import com.google.common.collect.Streams; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; 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.beans.factory.annotation.Value; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.core.RedisOperations; +import org.springframework.data.redis.core.RedisTemplate; 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.Map; import java.util.Objects; -import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -33,24 +44,75 @@ public class ProductPermissionCacheServiceImpl implements ProductPermissionCache private static final String PRODUCT_PERMISSION_KEY = "product:permission:%s"; @Autowired - protected StringRedisTemplate redisTemplate; + private RedisTemplate redisTemplate; + @Autowired + private ProductFeatureRelationService productFeatureRelationService; + @Autowired + private CacheProductPermissionHandler cacheProductPermissionHandler; + + /** 产品权限缓存过期时间 **/ + @Value("${product.permission.expire:180}") + private Long expireInDays; @Override - public List list(ListProductPermissionParam param) { + public Map> list(ListProductPermissionParam param) { + if (CollectionUtils.isEmpty(param.getProductIds())) { - return Collections.emptyList(); + return Collections.emptyMap(); } + Map> permissionCached = listProductPermissionCached(param); - Set redisKeys = param.getProductIds().stream() - .map(this::getKey) - .collect(Collectors.toSet()); + fillCacheProductPermissions(param, permissionCached); - Set redisValues = redisTemplate.opsForSet().union(redisKeys); + return permissionCached; + } - return redisValues.stream() - .filter(StringUtils::isNotBlank) - .map(value -> JSONObject.parseObject(value, PermissionDTO.class)) - .collect(Collectors.toList()); + private Map> listProductPermissionCached(ListProductPermissionParam param) { + + List redisValues = redisTemplate.executePipelined(new SessionCallback() { + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + + for (Long productId : param.getProductIds()) { + String redisKey = getKey(productId); + + if (CollectionUtils.isEmpty(param.getFeatureCodes())) { + RedisClient.HashOps.hGetAll(redisKey); + } else { + RedisClient.HashOps.hMultiGet(redisKey, Lists.newArrayList(param.getFeatureCodes())); + } + + } + return null; + } + }); + + return Streams.zip(param.getProductIds().stream(), + redisValues.stream(), + (productId, redisValue) -> { + + if (Objects.isNull(redisValue)) { + return null; + } + + if (CollectionUtils.isEmpty(param.getFeatureCodes())) { + List permissions = (List) ((Map) redisValue).values().stream() + .flatMap(e -> JSONArray.parseArray(JSONArray.toJSONString(e), PermissionDTO.class).stream()) + .collect(Collectors.toList()); + + return Pair.of(productId, permissions); + } + + List permissions = (List) ((List) redisValue).stream() + .filter(Objects::nonNull) + .flatMap(e -> JSONArray.parseArray((String) e, PermissionDTO.class).stream()) + .collect(Collectors.toList()); + + return Pair.of(productId, permissions); + + }) + .filter(Objects::nonNull) + .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); } @Override @@ -65,12 +127,14 @@ public class ProductPermissionCacheServiceImpl implements ProductPermissionCache for (ProductPermission productPermission : param.getProductPermissions()) { String redisKey = getKey(productPermission.getProductId()); - String[] redisValues = productPermission.getPermissions().stream() - .map(JSONObject::toJSONString) - .toArray(String[]::new); + Map redisValues = productPermission.getPermissions().stream() + .collect(Collectors.groupingBy(PermissionDTO::getFeatureCode)) + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); - RedisClient.SetOps.sAdd(redisKey, redisValues); - redisTemplate.expire(redisKey, 4, TimeUnit.DAYS); + RedisClient.HashOps.hPutAll(redisKey, redisValues); + redisTemplate.expire(redisKey, expireInDays, TimeUnit.DAYS); log.info("succeed to store product permission: redisKey:{} value:{}", redisKey, redisValues); } return null; @@ -100,7 +164,61 @@ public class ProductPermissionCacheServiceImpl implements ProductPermissionCache .collect(Collectors.toList()); } + /** + * 组装在缓存中没有查询到权限的产品 + * @param param + * @param permissionCached + */ + private void fillCacheProductPermissions(ListProductPermissionParam param, + Map> permissionCached) { + + Sets.SetView difference = Sets.difference(param.getProductIds(), permissionCached.keySet()); + if (difference.isEmpty()) { + return; + } + + PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() + .productModuleIds(difference) + .build(); + List productPermissions = productFeatureRelationService.list(pageProductFeatureRelationReq); + + List productPermissionsCache = cacheProductPermissionHandler.resolveProductPermissions(productPermissions); + if (CollectionUtils.isEmpty(productPermissionsCache)) return; + + StoreProductPermissionParam storeWorkspaceProductParam = StoreProductPermissionParam.builder() + .productPermissions(productPermissionsCache) + .build(); + store(storeWorkspaceProductParam); + + Map> productPermissionMap = productPermissionsCache.stream() + .collect(Collectors.toMap(ProductPermission::getProductId, ProductPermission::getPermissions)); + permissionCached.putAll(productPermissionMap); + } + private String getKey(Object... params) { return String.format(PRODUCT_PERMISSION_KEY, params); } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + static class PermissionWrapper { + + /** + * 协同关系类型 + * 原saas_product_module_feature_relation.dictCode + */ + private String cooperateType; + + private Long featureId; + + private String featureCode; + + private String terminal; + + private Integer featureType; + + private Long productId; + } } 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 index 455175da..b4471f17 100644 --- 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 @@ -2,14 +2,20 @@ package cn.axzo.tyr.server.service.impl; import cn.axzo.foundation.exception.Axssert; import cn.axzo.pokonyan.config.redis.RedisClient; +import cn.axzo.tyr.client.model.res.SaasRoleRes; +import cn.axzo.tyr.server.event.inner.CacheRolePermissionHandler; import cn.axzo.tyr.server.service.RolePermissionCacheService; +import cn.axzo.tyr.server.service.RoleService; import cn.hutool.core.lang.Pair; +import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; 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.beans.factory.annotation.Value; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisOperations; @@ -20,8 +26,8 @@ import org.springframework.util.CollectionUtils; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -35,23 +41,73 @@ public class RolePermissionCacheServiceImpl implements RolePermissionCacheServic @Autowired protected StringRedisTemplate redisTemplate; + @Autowired + private RoleService roleService; + @Autowired + private CacheRolePermissionHandler cacheRolePermissionHandler; + + + /** 角色权限缓存过期时间 **/ + @Value("${role.permission.expire:180}") + private Long expireInDays; @Override - public List list(ListRolePermissionParam param) { + public Map> list(ListRolePermissionParam param) { if (CollectionUtils.isEmpty(param.getRoleIds())) { - return Collections.emptyList(); + return Collections.emptyMap(); } - Set redisKeys = param.getRoleIds().stream() - .map(this::getKey) - .collect(Collectors.toSet()); + Map> permissions = listRolePermissionCached(param); - // 聚合是因为角色的权限点有重复,网络io压力大 - Set redisValues = redisTemplate.opsForSet().union(redisKeys); - return redisValues.stream() - .filter(StringUtils::isNotBlank) - .map(value -> JSONObject.parseObject(value, PermissionDTO.class)) - .collect(Collectors.toList()); + fillCacheRolePermissions(param, permissions); + return permissions; + } + + + private Map> listRolePermissionCached(ListRolePermissionParam param) { + + List redisValues = redisTemplate.executePipelined(new SessionCallback() { + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + + for (Long roleId : param.getRoleIds()) { + String redisKey = getKey(roleId); + if (CollectionUtils.isEmpty(param.getFeatureCodes())) { + RedisClient.HashOps.hGetAll(redisKey); + } else { + RedisClient.HashOps.hMultiGet(redisKey, Lists.newArrayList(param.getFeatureCodes())); + } + + } + return null; + } + }); + + return Streams.zip(param.getRoleIds().stream(), + redisValues.stream(), + (roleId, redisValue) -> { + + if (Objects.isNull(redisValue)) { + return null; + } + + if (CollectionUtils.isEmpty(param.getFeatureCodes())) { + + List permissions = (List) ((Map) redisValue).values().stream() + .flatMap(e -> JSONArray.parseArray(JSONArray.toJSONString(e), PermissionDTO.class).stream()) + .collect(Collectors.toList()); + return Pair.of(roleId, permissions); + } + + List permissions = (List) ((List) redisValue).stream() + .filter(Objects::nonNull) + .flatMap(e -> JSONArray.parseArray((String) e, PermissionDTO.class).stream()) + .collect(Collectors.toList()); + return Pair.of(roleId, permissions); + + }) + .filter(Objects::nonNull) + .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); } @Override @@ -66,12 +122,14 @@ public class RolePermissionCacheServiceImpl implements RolePermissionCacheServic for (RolePermission rolePermission : param.getRolePermissions()) { String redisKey = getKey(rolePermission.getRoleId()); - String[] redisValues = rolePermission.getPermissions().stream() - .map(JSONObject::toJSONString) - .toArray(String[]::new); + Map redisValues = rolePermission.getPermissions().stream() + .collect(Collectors.groupingBy(PermissionDTO::getFeatureCode)) + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); - RedisClient.SetOps.sAdd(redisKey, redisValues); - redisTemplate.expire(redisKey, 4, TimeUnit.DAYS); + RedisClient.HashOps.hPutAll(redisKey, redisValues); + redisTemplate.expire(redisKey, expireInDays, TimeUnit.DAYS); log.info("succeed to store role permission: redisKey:{} value:{}", redisKey, redisValues); } return null; @@ -100,6 +158,45 @@ public class RolePermissionCacheServiceImpl implements RolePermissionCacheServic .collect(Collectors.toList()); } + /** + * 组装在缓存中没有查询到权限的角色权限 + * @param param + * @param permissionCached + */ + private void fillCacheRolePermissions(ListRolePermissionParam param, + Map> permissionCached) { + + Sets.SetView difference = Sets.difference(param.getRoleIds(), permissionCached.keySet()); + if (difference.isEmpty()) { + return; + } + + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .roleIds(Lists.newArrayList(difference)) + .needPermissionRelation(true) + .build(); + List roles = roleService.list(listSaasRoleParam); + + if (CollectionUtils.isEmpty(roles)) { + return; + } + + List rolePermissions = cacheRolePermissionHandler.resolveRolePermission(roles); + + if (CollectionUtils.isEmpty(rolePermissions)) { + return; + } + + StoreRolePermissionParam storeRolePermissionParam = StoreRolePermissionParam.builder() + .rolePermissions(rolePermissions) + .build(); + store(storeRolePermissionParam); + + Map> rolePermissionMap = rolePermissions.stream() + .collect(Collectors.toMap(RolePermission::getRoleId, RolePermission::getPermissions)); + permissionCached.putAll(rolePermissionMap); + } + private String getKey(Object... params) { return String.format(ROLE_PERMISSION_KEY, params); } From 3ac973964445a5846413d31a76f9e072d580b19c Mon Sep 17 00:00:00 2001 From: lilong Date: Sat, 27 Jul 2024 20:56:12 +0800 Subject: [PATCH 008/112] =?UTF-8?q?feat:(REQ-2720)=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=9D=83=E9=99=90=E5=92=8C=E6=A0=B9=E6=8D=AE?= =?UTF-8?q?=E6=9D=83=E9=99=90=E6=9F=A5=E8=AF=A2=E4=BA=BA=E7=9A=84=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/model/req/IdentityAuthReq.java | 3 + ...PageElementFeatureResourceRelationReq.java | 2 +- .../tyr/client/model/res/IdentityAuthRes.java | 7 +- .../model/roleuser/dto/SaasRoleUserV2DTO.java | 13 + .../auth/TyrSaasAuthController.java | 1 + .../tyr/server/event/inner/EventTypeEnum.java | 2 + .../SaasFeatureResourceUpsertPayload.java | 18 + .../payload/SaasFeatureUpsetPayload.java | 18 + .../mapper/SaasRoleUserRelationMapper.java | 23 + .../axzo/tyr/server/service/RoleService.java | 6 + .../service/WorkspaceProductService.java | 45 + .../impl/PermissionQueryServiceImpl.java | 88 +- .../server/service/impl/RoleServiceImpl.java | 2 +- .../impl/SaasFeatureResourceServiceImpl.java | 23 +- ...entFeatureResourceRelationServiceImpl.java | 2 +- .../service/impl/TyrSaasAuthServiceImpl.java | 997 +++++++++--------- .../impl/WorkspaceProductServiceImpl.java | 112 +- .../mapper/SaasRoleUserRelationMapper.xml | 12 + 18 files changed, 777 insertions(+), 597 deletions(-) create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureUpsetPayload.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 368f705f..ab35eee3 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 @@ -112,6 +112,9 @@ public class IdentityAuthReq { /** 基于角色标签查询逻辑不再用该参数 **/ private Integer workspaceJoinType; + public String buildOuWorkspaceKey() { + return this.getOuId() + "_" + this.getWorkspaceId(); + } } } 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 b4f9abc2..e41f144f 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 @@ -30,7 +30,7 @@ public class PageElementFeatureResourceRelationReq implements IPageReq { List sort; @CriteriaField(field = "featureResourceUniCode", operator = Operator.IN) - private List featureResourceUniCodes; + private Set featureResourceUniCodes; @CriteriaField(field = "pageElementCode", operator = Operator.IN) private Set pageElementCodes; diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/IdentityAuthRes.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/IdentityAuthRes.java index 07a46c40..fa3a9a2b 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/IdentityAuthRes.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/IdentityAuthRes.java @@ -58,14 +58,9 @@ public class IdentityAuthRes { private String featureCode; - // private FeatureType featureType; + private Integer featureType; private String terminal; - - /** - * 应用范围(租户类型):1:企业工作台 2;项目工作台 - */ - private Long workspaceType; } 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 d031d60a..db940fbf 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 @@ -52,6 +52,19 @@ public class SaasRoleUserV2DTO { */ private Long workspaceId; + /** + * 身份Id + */ + private Long identityId; + + /** + * 身份类型 1:工人 2:从业人员 3:班组长 4:运营人员 5:政务人员 + */ + private Integer identityType; + + public String buildOuWorkspaceKey() { + return this.getOuId() + "_" + this.getWorkspaceId(); + } } @Data diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/auth/TyrSaasAuthController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/auth/TyrSaasAuthController.java index 0bce0cb4..a940aa93 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/auth/TyrSaasAuthController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/auth/TyrSaasAuthController.java @@ -85,6 +85,7 @@ public class TyrSaasAuthController implements TyrSaasAuthApi { @Override public ApiResult> listWorkspacePermissionIdentity(WorkspacePermissionIdentityReq req) { + return ApiResult.ok(tyrSaasAuthService.listWorkspacePermissionIdentity(req)); } @Override diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/EventTypeEnum.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/EventTypeEnum.java index d7c5bdfa..b6074238 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/EventTypeEnum.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/EventTypeEnum.java @@ -8,6 +8,8 @@ public enum EventTypeEnum { PRODUCT_PERMISSION_CREATED("product-permission", "product-permission-created", "产品权限添加"), ROLE_PERMISSION_CREATED("role-permission", "role-permission-created", "角色权限添加"), + SAAS_FEATURE_UPSERT("saas-feature", "saas-feature-upsert", "旧菜单树更新"), + SAAS_FEATURE_RESOURCE_UPSERT("saas-feature-resource", "saas-feature-resource-upsert", "新菜单树更新"), ; EventTypeEnum(String model, String name, String desc) { diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java new file mode 100644 index 00000000..6590c1cc --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java @@ -0,0 +1,18 @@ +package cn.axzo.tyr.server.event.payload; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Set; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaasFeatureResourceUpsertPayload implements Serializable { + + private Set ids; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureUpsetPayload.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureUpsetPayload.java new file mode 100644 index 00000000..7c6349cc --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureUpsetPayload.java @@ -0,0 +1,18 @@ +package cn.axzo.tyr.server.event.payload; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Set; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaasFeatureUpsetPayload implements Serializable { + + private Set ids; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasRoleUserRelationMapper.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasRoleUserRelationMapper.java index 7547cf51..af53ee17 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasRoleUserRelationMapper.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasRoleUserRelationMapper.java @@ -4,12 +4,35 @@ import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import java.util.Set; + @Mapper public interface SaasRoleUserRelationMapper extends BaseMapper { Page batListCleanRelation(IPage page, @Param("param") SaasRoleUserRelation cleanParam); + + /** + * 现在没有数据可以查询项目的角色 + * 通过权限点找有权限的人,需要这个接口 + * @param listRole + * @return + */ + Set listRoleIds(@Param("param") ListRole listRole); + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ListRole { + private Long ouId; + private Long workspaceId; + } } 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 bf464d0d..2c6921fe 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 @@ -183,6 +183,12 @@ public interface RoleService extends IService { */ @CriteriaField(ignore = true) private String terminal; + + @CriteriaField(field = "workspaceId", operator = Operator.EQ) + private Long workspaceId; + + @CriteriaField(field = "ownerOuId", operator = Operator.EQ) + private Long ouId; } @SuperBuilder 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 c3d4e4f1..b5f0441c 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 @@ -29,6 +29,26 @@ public interface WorkspaceProductService { */ void storeWorkspaceProduct(StoreWorkspaceProductParam param); + /** + * 从缓存中查询项目的产品及产品的权限 + * @param param + * @return + */ + List listWorkspaceProductPermissionCached(ListWorkspaceProductPermissionCacheParam param); + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ListWorkspaceProductPermissionCacheParam { + /** + * 项目id + */ + private Set workspaceIds; + + private Set featureCodes; + } + @Data @Builder @NoArgsConstructor @@ -74,6 +94,31 @@ public interface WorkspaceProductService { private List saasProductModuleFeatureRelations; } + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class WorkspaceProductPermission { + + /** + * 项目id + */ + private Long workspaceId; + + private List productPermissions; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ProductPermission { + + private Long productId; + + private List permissions; + } + @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 43a267bd..a508ddf8 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 @@ -19,9 +19,9 @@ import cn.axzo.tyr.client.model.base.FeatureResourceExtraDO; import cn.axzo.tyr.client.model.base.WorkspaceOUPair; import cn.axzo.tyr.client.model.enums.IdentityType; import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO; -import cn.axzo.tyr.client.model.req.FeatureIdPair; import cn.axzo.tyr.client.model.req.IdentityAuthReq; import cn.axzo.tyr.client.model.req.NavTreeReq; +import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq; import cn.axzo.tyr.client.model.req.PagePermissionReq; import cn.axzo.tyr.client.model.req.PagePermissionResp; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; @@ -46,14 +46,15 @@ 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.SaasPageElementFeatureResourceRelationService; import cn.axzo.tyr.server.service.SaasRoleUserRelationService; import cn.axzo.tyr.server.service.TyrSaasAuthService; import cn.axzo.tyr.server.service.WorkspaceProductService; @@ -91,7 +92,6 @@ 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; /** * 权限查询服务实现 @@ -117,7 +117,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { private final SaasFeatureResourceService saasFeatureResourceService; private final SaasRoleUserRelationService saasRoleUserRelationService; private final WorkspaceProductService workspaceProductService; - private final SaasPageElementFeatureResourceRelationDao saasPageElementFeatureResourceRelationDao; + private final SaasPageElementFeatureResourceRelationService saasPageElementFeatureResourceRelationService; @Qualifier("authExecutor") @Autowired @@ -331,6 +331,8 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { Set defaultFeatureIds = listNotAuthFeatureIds(); allFeatureIds.addAll(featureIds); allFeatureIds.addAll(defaultFeatureIds); + + if (CollectionUtils.isEmpty(allFeatureIds)) { return Collections.emptyList(); } @@ -653,26 +655,39 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { private Set listUserPermissionFeatureIds(TreePermissionReq treePermissionReq) { - List featureIds = resolveFeatureIds(treePermissionReq); + Set featureCodes = resolveFeatureCodes(treePermissionReq); - if (StringUtils.isNotBlank(treePermissionReq.getUniCode()) && CollectionUtils.isEmpty(featureIds)) { + if (StringUtils.isNotBlank(treePermissionReq.getUniCode()) && CollectionUtils.isEmpty(featureCodes)) { return Collections.emptySet(); } - List saasRoleUserV2DTOS = listUserPermission(treePermissionReq, featureIds); - // 用户可能没有角色 - if (CollectionUtils.isEmpty(saasRoleUserV2DTOS)) { - return Collections.emptySet(); - } + IdentityAuthReq identityAuthReq = IdentityAuthReq.builder() + .personId(treePermissionReq.getPersonId()) + .terminal(Lists.newArrayList(treePermissionReq.getTerminal())) + .workspaceOusPairs(treePermissionReq.getWorkspaceOUPairs().stream() + .map(e -> IdentityAuthReq.WorkspaceOuPair.builder() + .ouId(e.getOuId()) + .workspaceId(e.getWorkspaceId()) + .build()) + .collect(Collectors.toList())) + .featureCode(featureCodes) + .build(); - List workspaceProducts = listWorkspaceProducts(treePermissionReq, featureIds); + Set featureTypes = Optional.ofNullable(treePermissionReq.getFeatureResourceTypes()) + .map(e -> e.stream() + .map(FeatureResourceType::getCode) + .collect(Collectors.toSet())) + .orElse(null); - //免授权 - List authFreeFeatureIds = listNotAuthFeatures(treePermissionReq); + return saasAuthService.findIdentityAuthMix(identityAuthReq).getPermissions().stream() + .map(IdentityAuthRes.WorkspacePermission::getPermissionPoint) + .flatMap(Collection::stream) + .filter(e -> CollectionUtils.isEmpty(featureTypes) + || featureTypes.contains(e.getFeatureType())) + .map(IdentityAuthRes.PermissionPoint::getFeatureId) + .collect(Collectors.toSet()); - //取交集确定权限 - return mixFeatureIds(saasRoleUserV2DTOS, workspaceProducts, authFreeFeatureIds); } private List listNotAuthFeatures(TreePermissionReq treePermissionReq) { @@ -685,30 +700,22 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .collect(Collectors.toList()); } - private List listWorkspaceProducts(TreePermissionReq treePermissionReq, - List featureIds) { + private List listWorkspaceProducts(TreePermissionReq treePermissionReq, + Set featureCodes) { //查询租户产品权限点 Set workspaceIds = treePermissionReq.getWorkspaceOUPairs().stream() .map(WorkspaceOUPair::getWorkspaceId) .collect(Collectors.toSet()); - WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() - .terminal(treePermissionReq.getTerminal()) + WorkspaceProductService.ListWorkspaceProductPermissionCacheParam listWorkspaceProductPermissionCacheParam = WorkspaceProductService.ListWorkspaceProductPermissionCacheParam + .builder() .workspaceIds(workspaceIds) - .featureResourceTypes(treePermissionReq.getFeatureResourceTypes()) - .type(NEW_FEATURE) + .featureCodes(featureCodes) .build(); - - if (CollectionUtils.isNotEmpty(featureIds)) { - workspaceProductParam.setFeatureIdPairs(Lists.newArrayList(FeatureIdPair.builder() - .featureIds(Sets.newHashSet(featureIds)) - .type(NEW_FEATURE) - .build())); - } - return workspaceProductService.listWorkspaceProduct(workspaceProductParam); + return workspaceProductService.listWorkspaceProductPermissionCached(listWorkspaceProductPermissionCacheParam); } - private List listUserPermission(TreePermissionReq treePermissionReq, List featureIds) { + private List listUserPermission(TreePermissionReq treePermissionReq, Set featureCodes) { List workspaceOuPairs = treePermissionReq.getWorkspaceOUPairs().stream() .map(e -> ListRoleUserRelationParam.WorkspaceOuPair.builder() .workspaceId(e.getWorkspaceId()) @@ -720,28 +727,25 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .personId(treePermissionReq.getPersonId()) .workspaceOuPairs(Lists.newArrayList(workspaceOuPairs)) .needRole(true) - .needPermissionRelation(true) - .featureResourceTypes(treePermissionReq.getFeatureResourceTypes()) - .type(NEW_FEATURE) .terminal(treePermissionReq.getTerminal()) - .featureIds(featureIds) .build(); return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream() .filter(e -> e.getSaasRole() != null) .collect(Collectors.toList()); } - private List resolveFeatureIds(TreePermissionReq treePermissionReq) { + private Set resolveFeatureCodes(TreePermissionReq treePermissionReq) { if (StringUtils.isBlank(treePermissionReq.getUniCode())) { - return Collections.emptyList(); + return Collections.emptySet(); } - PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() - .uniCodes(Sets.newHashSet(treePermissionReq.getUniCode())) + PageElementFeatureResourceRelationReq pageElementFeatureResourceRelationReq = PageElementFeatureResourceRelationReq.builder() + .featureResourceUniCodes(Sets.newHashSet(treePermissionReq.getUniCode())) .build(); - return featureResourceService.list(pageSaasFeatureResourceReq).stream() - .map(SaasFeatureResourceResp::getId) - .collect(Collectors.toList()); + return saasPageElementFeatureResourceRelationService.list(pageElementFeatureResourceRelationReq) + .stream() + .map(SaasPageElementFeatureResourceRelation::getPageElementCode) + .collect(Collectors.toSet()); } private Set mixFeatureIds(List saasRoleUsers, 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 e3ad93f7..39062c0c 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 @@ -1131,7 +1131,7 @@ public class RoleServiceImpl extends ServiceImpl PageSaasRoleParam pageParam = PageSaasRoleParam.builder().build(); BeanUtils.copyProperties(param, pageParam); pageParam.setPage(pageNumber); - pageParam.setPageSize(500); + pageParam.setPageSize(10000); return page(pageParam); }); } 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 28297274..bbf6022a 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 @@ -8,6 +8,7 @@ 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.framework.rocketmq.Event; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType; import cn.axzo.tyr.client.common.enums.FeatureResourceStatus; @@ -26,6 +27,8 @@ 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.config.MqProducer; +import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; import cn.axzo.tyr.server.model.ResourcePermission; import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO; import cn.axzo.tyr.server.model.convert.SaasFeatureResourceConvert; @@ -46,6 +49,7 @@ 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 com.google.common.collect.Sets; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; @@ -64,6 +68,7 @@ import java.util.Set; import java.util.stream.Collectors; import static cn.axzo.tyr.server.config.exception.BizResultCode.FEATURE_RESOURCE_NOT_FOUND; +import static cn.axzo.tyr.server.event.inner.EventTypeEnum.SAAS_FEATURE_RESOURCE_UPSERT; import static cn.axzo.tyr.server.repository.entity.SaasFeatureResource.DEFAULT_WORKSPACE_TYPE; import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; @@ -88,7 +93,9 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl listNavByIds(List featureIds, List featureTypes) { //按需扩展要查询的字段 @@ -252,6 +259,18 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl mqUpsertIds = Sets.newHashSet(); + mqUpsertIds.add(baseResource.getId()); + + Event event = Event.builder() + .targetType(TARGET_TYPE) + .eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode()) + .data(SaasFeatureResourceUpsertPayload.builder() + .ids(mqUpsertIds) + .build()) + .build(); + mqProducer.send(event); return baseResource.getId(); } @@ -552,7 +571,9 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl uniCodes = Lists.transform(saasFeatureResources, SaasFeatureResource::getUniCode); + Set uniCodes = saasFeatureResources.stream() + .map(SaasFeatureResource::getUniCode) + .collect(Collectors.toSet()); PageElementFeatureResourceRelationReq pageElementFeatureResourceRelationReq = PageElementFeatureResourceRelationReq.builder() .featureResourceUniCodes(uniCodes) .build(); 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 index abb33ff7..c9f18b6b 100644 --- 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 @@ -25,7 +25,7 @@ public class SaasPageElementFeatureResourceRelationServiceImpl extends ServiceIm public List list(PageElementFeatureResourceRelationReq param) { return PageConverter.drainAll(pageNumber -> { param.setPage(pageNumber); - param.setPageSize(500); + param.setPageSize(1000); return page(param); }); } 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 301eee4f..a7ea8da4 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,18 +1,15 @@ package cn.axzo.tyr.server.service.impl; +import cn.axzo.apollo.workspace.common.enums.TableIsDeleteEnum; import cn.axzo.basics.common.BeanMapper; -import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum; -import cn.axzo.framework.domain.ServiceException; 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; import cn.axzo.tyr.client.model.enums.IdentityType; -import cn.axzo.tyr.client.model.enums.WorkspaceTypeCodeEnum; import cn.axzo.tyr.client.model.permission.PermissionPointListQueryRequest; import cn.axzo.tyr.client.model.permission.PermissionPointTreeNode; import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO; @@ -28,7 +25,6 @@ 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; import cn.axzo.tyr.client.model.req.QuerySaasRoleReq; import cn.axzo.tyr.client.model.req.WorkspacePermissionIdentityReq; import cn.axzo.tyr.client.model.res.IdentityAuthRes; @@ -37,7 +33,6 @@ 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; import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam; import cn.axzo.tyr.client.model.vo.SaasPermissionGroupVO; @@ -46,7 +41,6 @@ import cn.axzo.tyr.server.model.FilterRoleAuth; import cn.axzo.tyr.server.model.PermissionCacheKey; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.dao.SaasPgroupRoleRelationDao; -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; @@ -60,15 +54,17 @@ 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.SaasRoleUserRelationMapper; 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.ProductPermissionCacheService; +import cn.axzo.tyr.server.service.RolePermissionCacheService; 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; @@ -80,7 +76,6 @@ 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.BooleanUtil; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; @@ -147,14 +142,14 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { private final SaasRoleGroupService roleGroupService; private final SaasRoleUserRelationService saasRoleUserRelationService; private final SaasFeatureDao saasFeatureDao; - private final SaasProductModuleFeatureRelationDao saasProductModuleFeatureRelationDao; private final WorkspaceProductService workspaceProductService; private final SaasFeatureResourceService saasFeatureResourceService; private final SaasPageElementFeatureResourceRelationService saasPageElementFeatureResourceRelationService; private final SaasPgroupPermissionRelationService saasPgroupPermissionRelationService; - private final SaasRoleGroupRelationService saasRoleGroupRelationService; private final FeatureCodeUtil featureCodeUtil; private final SaasPgroupRoleRelationDao saasPgroupRoleRelationDao; + private final RolePermissionCacheService rolePermissionCacheService; + private SaasRoleUserRelationMapper saasRoleUserRelationMapper; /** * 通过身份查询人员权限 @@ -373,395 +368,6 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return permissionSet.containsAll(checkCodes); } - 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 - CompletableFuture> workspacePermissionPointFuture = CompletableFuture - .supplyAsync(TraceSupplier.create(() -> { - WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() - .workspaceIds(realWorkspaceId) - .build(); - return workspaceProductService.listWorkspaceProduct(workspaceProductParam); - }), executor); - //查询工作台下授予的角色和权限 - List owRoles = listRolesWithPermission(saasRoleUserRelations, identityAuthReq); - - Map workspaceProductPermissionMap = workspacePermissionPointFuture.join().stream() - .collect(Collectors.toMap(WorkspaceProductService.WorkspaceProduct::getWorkspaceId, Function.identity())); - - List> futureList = new ArrayList<>(); - for (OUWRoleInfo owRoleInfo : owRoles) { - // 工作台的产品权限点 - WorkspaceProductService.WorkspaceProduct workspaceProduct = workspaceProductPermissionMap.get(owRoleInfo.getWorkspaceId()); - //构建每个工作台的实际权限点 - futureList.add(CompletableFuture.supplyAsync(TraceSupplier.create(() -> buildPermissions(owRoleInfo, workspaceProduct)), executor) - .exceptionally(t -> { - LogUtil.error("获取角色对应权限失败", t); - throw new ServiceException(t); - })); - } - - //汇总结果 - IdentityAuthRes result = new IdentityAuthRes(); - result.setIdentity(identityAuthReq.getIdentityId()); - result.setIdentityType(identityAuthReq.getIdentityType()); - result.setPersonId(identityAuthReq.getPersonId()); - for (CompletableFuture future : futureList) { - result.getPermissions().add(future.join()); - } - return result; - } - - private IdentityAuthRes.WorkspacePermission buildPermissions(OUWRoleInfo ouwRoleInfo, WorkspaceProductService.WorkspaceProduct workspaceProduct) { - - IdentityAuthRes.WorkspacePermission resultPermission = IdentityAuthRes.WorkspacePermission.builder() - .workspaceId(ouwRoleInfo.getWorkspaceId()) - .ouId(ouwRoleInfo.getOuId()) - .build(); - - if (Objects.isNull(workspaceProduct) || CollectionUtil.isEmpty(workspaceProduct.getSaasProductModuleFeatureRelations())) { - log.warn("no product features found for workspace :{}", ouwRoleInfo.getWorkspaceId()); - return resultPermission; - } - - Set roles = ouwRoleInfo.getRoles(); - if (CollectionUtil.isEmpty(roles)) { - log.warn("no roles for ou:{} workspace:{}", ouwRoleInfo.getOuId(), ouwRoleInfo.getWorkspaceId()); - return resultPermission; - } - - List productFeatures = workspaceProduct.getSaasProductModuleFeatureRelations(); - // 因为存在同时有saas_feature和saas_feature_resource的权限,所以要返回type,根据type解析code - //超管和管理员权限 - Pair> adminPermissions = buildAdminPermission(ouwRoleInfo, productFeatures); - //标准角和自定义角色权限 - Set normalPermissions = buildNormalPermission(ouwRoleInfo, productFeatures); - Set allPermissions = Sets.newHashSet(); - allPermissions.addAll(adminPermissions.getValue()); - allPermissions.addAll(normalPermissions); - - //查询权限点及父级权限点 - List allOldPermissionPoint = listOldFeatures(allPermissions); - - List newPermissionPoints = listNewFeatures(allPermissions); - - //组装返回值 - //是否超管 - resultPermission.setSuperAdmin(BooleanUtil.isTrue(adminPermissions.getKey())); - //权限数据 - resultPermission.getPermissionPoint().addAll(allOldPermissionPoint.stream() - .map(permissionPointTreeNode -> IdentityAuthRes.PermissionPoint.builder() - .featureCode(permissionPointTreeNode.getCode()) - .featureId(permissionPointTreeNode.getId()) - .terminal(permissionPointTreeNode.getTerminal()) - .build()) - .collect(Collectors.toList())); - - resultPermission.getPermissionPoint().addAll(newPermissionPoints); - return resultPermission; - } - - 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()) - .workspaceType(e.getWorkspaceType()) - .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 allMatchedProductFeatures = new HashSet<>(); - Set allAuthFeatures = new HashSet<>(); - - //聚合实际授权的权限:角色权限和产品权限交集 - 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 rolePermissions = Optional.ofNullable(role.getPermissionRelations()) - .map(e -> e.stream() - .filter(Objects::nonNull) - .map(f -> FeatureWrapper.builder() - .featureId(f.getFeatureId()) - .type(f.getType()) - .build()) - .collect(Collectors.toSet())) - .orElseGet(Sets::newHashSet); - //角色标签类型匹配产品标签类型 - Set productPermissions = productFeatures.stream() - .filter(productFeatureRelationVO -> Objects.equals(productFeatureRelationVO.getDictCode(), String.valueOf(role.getProductUnitType()))) - .map(e -> FeatureWrapper.builder() - .featureId(e.getFeatureId()) - .type(e.getType()) - .build()) - .collect(Collectors.toSet()); - allMatchedProductFeatures.addAll(productPermissions); - // 产品对应权限点 与 角色权限点 取交集 - Collection resultHashAuthPointId = CollectionUtil.intersection(productPermissions, rolePermissions); - if (CollectionUtil.isNotEmpty(resultHashAuthPointId)) { - log.info("add auth permission for role:{}", role.getId()); - allAuthFeatures.addAll(resultHashAuthPointId); - } - } - if (CollectionUtil.isEmpty(allMatchedProductFeatures)) { - log.info("no normal roles found"); - return allAuthFeatures; - } - - Set newFeatureNoAuth = listNoAuthFeatureResources(allMatchedProductFeatures); - - Set oldFeatureNoAuth = listNoAuthFeatures(allMatchedProductFeatures); - allAuthFeatures.addAll(newFeatureNoAuth); - allAuthFeatures.addAll(oldFeatureNoAuth); - return allAuthFeatures; - } - - 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() - .filter(r -> RoleTypeEnum.isAdmin(r.getRoleType())) - .collect(Collectors.toList()); - if (CollectionUtil.isEmpty(adminRoles)) { - log.info("no admin roles"); - return Pair.of(superAdmin, Collections.emptySet()); - } - - log.info("build admin permission for ou:{}, workspace:{}", userRoleInfoMap.getOuId(), userRoleInfoMap.getWorkspaceId()); - - //聚合超管和管理员的权限点: 直接取角色标签和产品标签相匹配的权限点 - Set permissions = Sets.newHashSet(); - for (SaasRoleRes adminRole : adminRoles) { - //超管:查询工作台对应产品,获取权限点, ( 权限点通过单位类型过滤) - if (RoleTypeEnum.SUPER_ADMIN.getValue().equals(adminRole.getRoleType())) { - superAdmin = true; - } - //角色标签类型匹配产品标签类型 - Set permission = productFeatures.stream() - .filter(productFeatureRelationVO -> Objects.equals(productFeatureRelationVO.getDictCode(), - String.valueOf(adminRole.getProductUnitType()))) - .map(e -> FeatureWrapper.builder() - .featureId(e.getFeatureId()) - .type(e.getType()) - .build()) - .collect(Collectors.toSet()); - - if (CollectionUtil.isEmpty(permission)) { - log.warn("empty permission for admin role:{}", adminRole.getId()); - continue; - } - log.info("add all permissions for role:{}", adminRole.getId()); - permissions.addAll(permission); - } - - 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) { - - //拼装参数 - Set roleIds = new HashSet<>(); - //按ow分组角色ID: workspaceId-ouId --> roleIds - Map> owRoleIdMap = new HashMap<>(); - for (SaasRoleUserRelation relation : roleUserRelations) { - roleIds.add(relation.getRoleId()); - String key = KeyUtil.buildKeyBySeparator(relation.getWorkspaceId(), relation.getOuId()); - Set owRoleIds = owRoleIdMap.getOrDefault(key, new HashSet<>()); - owRoleIds.add(relation.getRoleId()); - owRoleIdMap.put(key, owRoleIds); - } - //获取角色和关联权限信息 - RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() - .roleIds(Lists.newArrayList(roleIds)) - .needPermissionRelation(true) - .build(); - Map saasRoleRes = roleService.list(listSaasRoleParam).stream() - .collect(Collectors.toMap(SaasRoleRes::getId, Function.identity())); - - //按ow组装拥有的角色 - List owRoleMap = new ArrayList<>(); - for (IdentityAuthReq.WorkspaceOuPair ow : identityAuthReq.getWorkspaceOusPairs()) { - OUWRoleInfo owRoleInfo = OUWRoleInfo.builder() - .workspaceId(ow.getWorkspaceId()) - .ouId(ow.getOuId()) - .build(); - String key = KeyUtil.buildKeyBySeparator(ow.getWorkspaceId(), ow.getOuId()); - Set owRoleIds = owRoleIdMap.get(key); - if (CollectionUtil.isEmpty(owRoleIds)) { - log.info("no roles found for ow:{}", key); - owRoleInfo.setRoles(Collections.emptySet()); - } else { - owRoleInfo.setRoles(owRoleIds.stream() - .map(saasRoleRes::get) - // 有saas_role_user_relation有记录,但是对应的saas_role不存在的情况 - .filter(Objects::nonNull) - .collect(Collectors.toSet())); - } - owRoleMap.add(owRoleInfo); - } - - return owRoleMap; - } - - private List listRoleUserRelations(IdentityAuthReq identityAuthReq) { - if (CollectionUtil.isNotEmpty(identityAuthReq.getSpecifyRoleIds())) { - //指定了角色 则不需要去查用户角色关系 - log.info("mock specify roles relation"); - return mockRoleUserRelation(identityAuthReq); - } - //查询人员角色关系 - Set workspaceIds = new HashSet<>(); - Set ouIds = new HashSet<>(); - Set owKeys = new HashSet<>(); - identityAuthReq.getWorkspaceOusPairs().forEach(ow -> { - workspaceIds.add(ow.getWorkspaceId()); - ouIds.add(ow.getOuId()); - owKeys.add(KeyUtil.buildKeyBySeparator(ow.getWorkspaceId(), ow.getOuId())); - }); - List relations = roleUserService.queryByWorkspaceIdOrOu(identityAuthReq.getPersonId(), - identityAuthReq.getIdentityId(), identityAuthReq.getIdentityType(), workspaceIds, ouIds); - if (CollectionUtil.isEmpty(relations)) { - log.warn("no user role relations found"); - return relations; - } - //工作台和单位需成对查询, 对结果二次过滤 - return relations.stream() - .filter(roleUserService -> owKeys.contains( - KeyUtil.buildKeyBySeparator(roleUserService.getWorkspaceId(), roleUserService.getOuId()))) - .collect(Collectors.toList()); - } - - private List mockRoleUserRelation(IdentityAuthReq identityAuthReq) { - final List relations = new ArrayList<>(); - // mock 看做已有指定的角色 - for (IdentityAuthReq.WorkspaceOuPair ow : identityAuthReq.getWorkspaceOusPairs()) { - List mockRelations = identityAuthReq.getSpecifyRoleIds().stream().map(id -> { - SaasRoleUserRelation relation = new SaasRoleUserRelation(); - relation.setRoleId(id); - relation.setOuId(ow.getOuId()); - relation.setWorkspaceId(ow.getWorkspaceId()); - relation.setIdentityId(identityAuthReq.getIdentityId()); - relation.setIdentityType(identityAuthReq.getIdentityType().getCode()); - // 使用角色ID替代,不需要在查询一次 - relation.setId(id); - return relation; - }).collect(Collectors.toList()); - relations.addAll(mockRelations); - } - return relations; - } - @Override public boolean hasPermissionForIdentityV2(CheckIdentityPermissionReq req) { if (CollectionUtil.isEmpty(req.getCodes())) { @@ -824,79 +430,213 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .build()); } - @Override - public ListIdentityFromPermissionResp listIdentityFromPermission(ListIdentityFromPermissionReq req) { - ListIdentityFromPermissionResp result = new ListIdentityFromPermissionResp(); - result.setOuId(req.getOuId()); - result.setWorkspaceId(req.getWorkspaceId()); + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + static class ListPermissionUser { + private Set featureCodes; - Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCode())); + private Long ouId; - //code查询权限点信息 - List features = permissionPointService.listNodeWithChildrenByCodes(Lists.newArrayList(newFeatureCodes), req.getTerminal()); + private Long workspaceId; - // 兼容新老版本,需要通过featureCode查询新版本的features,原逻辑是查询当前菜单资源的所有子数据 - ListSaasFeatureResourceParam listSaasFeatureResourceParam = ListSaasFeatureResourceParam.builder() - .featureCodes(newFeatureCodes) - .terminal(req.getTerminal()) + /** + * 指定端的权限 + */ + private String terminal; + } + + private List listPermissionUser(ListPermissionUser param) { + // TODO 查询免授权的featureCodes,判断featureCodes里是否有免授权的featureCodes + + WorkspaceProductService.ListWorkspaceProductPermissionCacheParam listWorkspaceProductPermissionCacheParam = WorkspaceProductService.ListWorkspaceProductPermissionCacheParam.builder() + .workspaceIds(Sets.newHashSet(param.getWorkspaceId())) + .featureCodes(param.getFeatureCodes()) .build(); - List saasFeatureResources = listSaasFeatureResource(listSaasFeatureResourceParam); - - if (CollectionUtil.isEmpty(features) && CollectionUtils.isEmpty(saasFeatureResources)) { - log.warn("no features data found for:{}", req.getFeatureCode()); - return result; - } - //是否免授权权限点 - Optional freeFeature = features.stream() - .filter(f -> DelegatedType.NO_NEED.sameCode(f.getDelegatedType())) - .findAny(); - - 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()); - Set newFeatureIds = saasFeatureResources.stream().map(SaasFeatureResourceResp::getId).collect(Collectors.toSet()); - - List featureIdPairs = Lists.newArrayList(); - if (!CollectionUtils.isEmpty(featureIds)) { - featureIdPairs.add(FeatureIdPair.builder().featureIds(featureIds).type(OLD_FEATURE).build()); - } - - if (!CollectionUtils.isEmpty(newFeatureIds)) { - featureIdPairs.add(FeatureIdPair.builder().featureIds(newFeatureIds).type(NEW_FEATURE).build()); - } - WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() - .workspaceIds(Sets.newHashSet(req.getWorkspaceId())) - .featureIdPairs(featureIdPairs) - .build(); - List workspaceProducts = workspaceProductService.listWorkspaceProduct(workspaceProductParam) + List productPermissions = workspaceProductService.listWorkspaceProductPermissionCached(listWorkspaceProductPermissionCacheParam) .stream() - .map(WorkspaceProductService.WorkspaceProduct::getSaasProductModuleFeatureRelations) - .filter(Objects::nonNull) + .map(WorkspaceProductService.WorkspaceProductPermission::getProductPermissions) + .filter(e -> !CollectionUtils.isEmpty(e)) .flatMap(Collection::stream) + .map(WorkspaceProductService.ProductPermission::getPermissions) + .filter(e -> !CollectionUtils.isEmpty(e)) + .flatMap(Collection::stream) + .filter(e -> StringUtils.isBlank(param.getTerminal()) || Objects.equals(e.getTerminal(), param.getTerminal())) .collect(Collectors.toList()); - if (CollectionUtil.isEmpty(workspaceProducts)) { + if (CollectionUtil.isEmpty(productPermissions)) { log.warn("no matched product feature in workspace"); - return result; + return Collections.emptyList(); } - List matchedUsers = getWorkspaceUser(req.getWorkspaceId(), req.getOuId(), workspaceProducts); - if (CollectionUtil.isEmpty(matchedUsers)) { + return getWorkspaceUserV2(param, productPermissions); + } + + @Override + public ListIdentityFromPermissionResp listIdentityFromPermission(ListIdentityFromPermissionReq req) { + + Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCode())); + ListPermissionUser listPermissionUser = ListPermissionUser.builder() + .featureCodes(newFeatureCodes) + .ouId(req.getOuId()) + .workspaceId(req.getWorkspaceId()) + .terminal(req.getTerminal()) + .build(); + List userVOS = listPermissionUser(listPermissionUser); + + ListIdentityFromPermissionResp result = ListIdentityFromPermissionResp.builder() + .ouId(req.getOuId()) + .workspaceId(req.getWorkspaceId()) + .build(); + + if (CollectionUtil.isEmpty(userVOS)) { return result; } - result.setUsers(matchedUsers); + result.setUsers(userVOS); return result; } + private List listAdminRole(ListPermissionUser req) { + //超管和管理员 + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .workspaceId(req.getWorkspaceId()) + .ouId(req.getOuId()) + .roleTypes(Lists.newArrayList(RoleTypeEnum.SUPER_ADMIN.getValue(), RoleTypeEnum.ADMIN.getValue())) + .build(); + return roleService.list(listSaasRoleParam); + } + + private Set resolvePermissionAdminRole(List adminRoles, + List productPermissions) { + Set cooperateTypes = productPermissions.stream() + .map(ProductPermissionCacheService.PermissionDTO::getCooperateType) + .collect(Collectors.toSet()); + // 有权限的管理员角色id + return adminRoles.stream() + .filter(r -> cooperateTypes.contains(String.valueOf(r.getProductUnitType()))) + .map(SaasRoleRes::getId) + .collect(Collectors.toSet()); + } + + private Set resolvePermissionNormalRole(ListPermissionUser req, + List productPermissions) { + + // 因为通过权限id找对应的角色数据量巨大,所以通过找项目的角色,再找有权限的角色比较快 + Set allRoleIds = saasRoleUserRelationMapper.listRoleIds(SaasRoleUserRelationMapper.ListRole.builder() + .ouId(req.getOuId()) + .workspaceId(req.getWorkspaceId()) + .build()); + + RolePermissionCacheService.ListRolePermissionParam listRolePermissionParam = RolePermissionCacheService.ListRolePermissionParam.builder() + .roleIds(allRoleIds) + .featureCodes(productPermissions.stream() + .map(ProductPermissionCacheService.PermissionDTO::getFeatureCode) + .collect(Collectors.toSet())) + .build(); + Map> normalRolePermissionMap = rolePermissionCacheService.list(listRolePermissionParam); + + Set normalRoleIds = normalRolePermissionMap.entrySet().stream() + .filter(e -> !CollectionUtils.isEmpty(e.getValue())) + .filter(e -> StringUtils.isBlank(req.getTerminal()) + || e.getValue().stream().anyMatch(p -> Objects.equals(p.getTerminal(), req.getTerminal()))) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); + Map normalRoles = roleService.list(RoleService.ListSaasRoleParam.builder() + .roleIds(Lists.newArrayList(normalRoleIds)) + .build()) + .stream() + .collect(Collectors.toMap(SaasRoleRes::getId, Function.identity())); + + Map> featureCodeCooperateTypeMap = productPermissions.stream() + .collect(Collectors.groupingBy(ProductPermissionCacheService.PermissionDTO::getFeatureCode, + Collectors.mapping(ProductPermissionCacheService.PermissionDTO::getCooperateType, Collectors.toSet()))); + return normalRolePermissionMap.entrySet().stream() + .filter(e -> { + SaasRoleRes saasRoleRes = normalRoles.get(e.getKey()); + if (Objects.isNull(saasRoleRes)) { + return false; + } + + return e.getValue().stream() + .filter(f -> StringUtils.isBlank(req.getTerminal()) + || e.getValue().stream().anyMatch(p -> Objects.equals(p.getTerminal(), req.getTerminal()))) + .anyMatch(f -> { + Set productCooperateTypes = featureCodeCooperateTypeMap.get(f.getFeatureCode()); + if (CollectionUtils.isEmpty(productCooperateTypes)) { + return false; + } + return productCooperateTypes.contains(String.valueOf(saasRoleRes.getProductUnitType())); + }); + }) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); + } + + private List getWorkspaceUserV2(ListPermissionUser req, + List productPermissions) { + + //超管和管理员 + List adminRoles = listAdminRole(req); + + Set adminPermissionRoleIds = resolvePermissionAdminRole(adminRoles, productPermissions); + Set normalPermissionRoleIds = resolvePermissionNormalRole(req, productPermissions); + + Set roleIds = Sets.newHashSet(); + roleIds.addAll(adminPermissionRoleIds); + roleIds.addAll(normalPermissionRoleIds); + + if (CollectionUtil.isEmpty(roleIds)) { + log.warn("no role matched product unit types"); + return Collections.emptyList(); + } + + //角色查人 + ListRoleUserRelationParam listRoleUserRelationParam = ListRoleUserRelationParam.builder() + .roleIds(Lists.newArrayList(roleIds)) + .workspaceOuPairs(Lists.newArrayList( + ListRoleUserRelationParam.WorkspaceOuPair.builder() + .ouId(req.getOuId()) + .workspaceId(req.getWorkspaceId()) + .build())) + .build(); + List saasRoleUsers = saasRoleUserRelationService.listV2(listRoleUserRelationParam); + if (CollectionUtil.isEmpty(saasRoleUsers)) { + log.warn("no user role relation found. roleIds:{}, ouId:{} workspaceId:{}", roleIds, req.getOuId(), req.getWorkspaceId()); + return Collections.emptyList(); + } + + Set superAdminRoleIds = adminRoles.stream() + .filter(r -> RoleTypeEnum.SUPER_ADMIN.getValue().equals(r.getRoleType())) + .map(SaasRoleRes::getId) + .collect(Collectors.toSet()); + + //ouId -> resp : ou-identityId-identityType维度去重 + Map distinctMap = Maps.newHashMap(); + //组装去重 + // copy原代码 + for (SaasRoleUserV2DTO relation : saasRoleUsers) { + SaasRoleUserV2DTO.SaasRoleUser saasRoleUser = relation.getSaasRoleUser(); + String key = KeyUtil.buildKeyBySeparator(saasRoleUser.getOuId(), saasRoleUser.getIdentityId(), saasRoleUser.getIdentityType()); + ListIdentityFromPermissionResp.UserVO user = distinctMap.get(key); + if (user == null) { + user = ListIdentityFromPermissionResp.UserVO.builder() + .ouId(saasRoleUser.getOuId()) + .identityId(saasRoleUser.getIdentityId()) + .identityType(saasRoleUser.getIdentityType()) + .personalId(saasRoleUser.getPersonId()) + .build(); + } + if (superAdminRoleIds.contains(relation.getRoleId())) { + //超管 + user.setSuperAdmin(true); + } + distinctMap.put(key, user); + } + + return Lists.newArrayList(distinctMap.values()); + } + @Override public List batchListIdentityFromPermission(List reqList) { //异步处理 @@ -990,7 +730,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } private List findIdentityPermission(IdentityAuthReq req) { - return findIdentityAuth(req).getPermissions(); + return findIdentityAuthV2(req).getPermissions(); } private List findIdentityPermissionFromCache(IdentityAuthReq req) { @@ -1170,73 +910,16 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { public List listWorkspacePermissionIdentity(WorkspacePermissionIdentityReq req) { Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCodes())); - req.setFeatureCodes(Lists.newArrayList(newFeatureCodes)); - //code查询权限点信息 - List features = permissionPointService.listNodeWithChildrenByCodes(req.getFeatureCodes(), null); + Set featureCodes = Sets.newHashSet(req.getFeatureCodes()); + featureCodes.addAll(newFeatureCodes); - // 兼容新老版本,需要通过featureCode查询新版本的features,原逻辑是查询当前菜单资源的所有子数据 - ListSaasFeatureResourceParam listSaasFeatureResourceParam = ListSaasFeatureResourceParam.builder() - .featureCodes(Sets.newHashSet(req.getFeatureCodes())) + ListPermissionUser listPermissionUser = ListPermissionUser.builder() + .featureCodes(featureCodes) + .workspaceId(req.getWorkspaceId()) .build(); - List saasFeatureResources = listSaasFeatureResource(listSaasFeatureResourceParam); + List users = listPermissionUser(listPermissionUser); - 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()); - Set newFeatureIds = saasFeatureResources.stream().map(SaasFeatureResourceResp::getId).collect(Collectors.toSet()); - List featureIdPairs = Lists.newArrayList(); - - if (!CollectionUtils.isEmpty(featureIds)) { - featureIdPairs.add(FeatureIdPair.builder().featureIds(featureIds).type(OLD_FEATURE).build()); - } - - if (!CollectionUtils.isEmpty(newFeatureIds)) { - featureIdPairs.add(FeatureIdPair.builder().featureIds(newFeatureIds).type(NEW_FEATURE).build()); - } - WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() - .workspaceIds(Sets.newHashSet(req.getWorkspaceId())) - .featureIdPairs(featureIdPairs) - .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 matchedOldFeatureIds = workspaceProducts.stream() - .filter(e -> Objects.equals(OLD_FEATURE, e.getType())) - .map(SaasProductModuleFeatureRelation::getFeatureId) - .collect(Collectors.toSet()); - Optional freeFeature = features.stream() - .filter(f -> matchedOldFeatureIds.contains(f.getId())) - .filter(f -> DelegatedType.NO_NEED.sameCode(f.getDelegatedType())) - .findAny(); - - 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, workspaceProducts); if (CollectionUtil.isEmpty(users)) { return Collections.emptyList(); } @@ -1651,4 +1334,276 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .filter(e -> e.getSaasRole() != null) .collect(Collectors.toList()); } + + private List mockRoleUserRelationV2(IdentityAuthReq identityAuthReq) { + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .roleIds(Lists.newArrayList(identityAuthReq.getSpecifyRoleIds())) + .build(); + Map saasRoles = roleService.list(listSaasRoleParam).stream() + .map(role -> SaasRoleUserV2DTO.SaasRole.builder() + .build()) + .collect(Collectors.toMap(SaasRoleUserV2DTO.SaasRole::getId, Function.identity())); + + return identityAuthReq.getWorkspaceOusPairs().stream() + .map(workspaceOuPair -> + identityAuthReq.getSpecifyRoleIds().stream() + .map(roleId -> { + SaasRoleUserV2DTO.SaasRole saasRole = saasRoles.get(roleId); + if (Objects.isNull(saasRole)) { + return null; + } + + SaasRoleUserV2DTO.SaasRoleUser saasRoleUser = SaasRoleUserV2DTO.SaasRoleUser.builder() + .ouId(workspaceOuPair.getOuId()) + .workspaceId(workspaceOuPair.getWorkspaceId()) + .identityId(identityAuthReq.getIdentityId()) + .identityType(identityAuthReq.getIdentityType().getCode()) + .build(); + return SaasRoleUserV2DTO.builder() + .roleId(roleId) + .saasRoleUser(saasRoleUser) + .saasRole(saasRole) + .build(); + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()) + ) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + private List listRoleUserRelationsV2(IdentityAuthReq identityAuthReq) { + if (CollectionUtil.isNotEmpty(identityAuthReq.getSpecifyRoleIds())) { + //指定了角色 则不需要去查用户角色关系 + log.info("mock specify roles relation"); + return mockRoleUserRelationV2(identityAuthReq); + } + + ListRoleUserRelationParam listRoleUserRelationParam = ListRoleUserRelationParam.builder() + .personId(identityAuthReq.getPersonId()) + .identityId(identityAuthReq.getIdentityId()) + .identityType(identityAuthReq.getIdentityType()) + .workspaceOuPairs(identityAuthReq.getWorkspaceOusPairs().stream() + .map(e -> ListRoleUserRelationParam.WorkspaceOuPair.builder() + .workspaceId(e.getWorkspaceId()) + .ouId(e.getOuId()) + .build()) + .collect(Collectors.toList())) + .needRole(true) + .build(); + + return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream() + .filter(e -> e.getSaasRole() != null) + .collect(Collectors.toList()); + } + + /** + * 出入参不变,方便切换, + * 基于redis缓存角色权限、产品权限进行解析 + * @param identityAuthReq + * @return + */ + private IdentityAuthRes findIdentityAuthV2(IdentityAuthReq identityAuthReq) { + + Map> workspaceProductPermissions = listWorkspaceProductPermission(identityAuthReq); + + List saasRoleUsers = listRoleUserRelationsV2(identityAuthReq); + Map> rolePermissions = listRolePermission(identityAuthReq, saasRoleUsers); + + Map> workspaceRoles = saasRoleUsers.stream() + .collect(Collectors.groupingBy(e -> e.getSaasRoleUser().buildOuWorkspaceKey(), + Collectors.mapping(SaasRoleUserV2DTO::getSaasRole, Collectors.toList()))); + + List permissions = identityAuthReq.getWorkspaceOusPairs().stream() + .map(workspaceOuPair -> { + List productPermissions = Optional.ofNullable(workspaceProductPermissions.get(workspaceOuPair.getWorkspaceId())) + .map(e -> e.stream() + .map(WorkspaceProductService.ProductPermission::getPermissions) + .filter(f -> !CollectionUtils.isEmpty(f)) + .flatMap(Collection::stream) + .collect(Collectors.toList())) + .orElse(null); + + if (CollectionUtils.isEmpty(productPermissions)) { + return IdentityAuthRes.WorkspacePermission.builder() + .workspaceId(workspaceOuPair.getWorkspaceId()) + .ouId(workspaceOuPair.getOuId()) + .build(); + } + + List saasRoles = workspaceRoles.get(workspaceOuPair.buildOuWorkspaceKey()); + + return buildPermissionsV2(workspaceOuPair, productPermissions, saasRoles, rolePermissions); + }) + .collect(Collectors.toList()); + + IdentityAuthRes result = new IdentityAuthRes(); + result.setIdentity(identityAuthReq.getIdentityId()); + result.setIdentityType(identityAuthReq.getIdentityType()); + result.setPersonId(identityAuthReq.getPersonId()); + result.setPermissions(permissions); + return result; + } + + private IdentityAuthRes.WorkspacePermission buildPermissionsV2(IdentityAuthReq.WorkspaceOuPair workspaceOuPair, + List productPermissions, + List saasRoles, + Map> rolePermissions) { + + IdentityAuthRes.WorkspacePermission workspacePermission = IdentityAuthRes.WorkspacePermission.builder() + .workspaceId(workspaceOuPair.getWorkspaceId()) + .ouId(workspaceOuPair.getOuId()) + .build(); + + //超管和管理员权限 + Set adminPermissionPoints = buildAdminPermissionV2(productPermissions, saasRoles); + Set noAuthPermissionPoints = buildNoAuthPermission(productPermissions); + Set normalPermissionPoints = buildNormalPermissionV2(productPermissions, saasRoles, rolePermissions); + + //组装返回值 + //是否超管 + boolean superAdmin = saasRoles.stream() + .anyMatch(e -> RoleTypeEnum.SUPER_ADMIN.getValue().equals(e.getRoleType())); + workspacePermission.setSuperAdmin(superAdmin); + + Set allPermissionPoints = Sets.newHashSet(); + allPermissionPoints.addAll(adminPermissionPoints); + allPermissionPoints.addAll(noAuthPermissionPoints); + allPermissionPoints.addAll(normalPermissionPoints); + // TODO 过滤掉已经删除的权限点 + + workspacePermission.setPermissionPoint(Lists.newArrayList(allPermissionPoints)); + return workspacePermission; + } + + private Set buildAdminPermissionV2(List productPermissions, + List saasRoles) { + //超管和管理员角色 + List adminRoles = Optional.ofNullable(saasRoles) + .map(e -> e.stream() + .filter(r -> RoleTypeEnum.isAdmin(r.getRoleType())) + .collect(Collectors.toList())) + .orElse(null); + if (CollectionUtil.isEmpty(adminRoles)) { + log.info("no admin roles"); + return Collections.emptySet(); + } + + //聚合超管和管理员的权限点: 直接取角色标签和产品标签相匹配的权限点 + Set productUnitTypes = adminRoles.stream() + .map(SaasRoleUserV2DTO.SaasRole::getProductUnitType) + .collect(Collectors.toSet()); + + return productPermissions.stream() + .filter(e -> productUnitTypes.contains(e.getCooperateType())) + .map(e -> IdentityAuthRes.PermissionPoint.builder() + .featureCode(e.getFeatureCode()) + .featureId(e.getFeatureId()) + .terminal(e.getTerminal()) + .featureType(e.getFeatureType()) + .build()) + .collect(Collectors.toSet()); + } + + + private Set buildNoAuthPermission(List productPermissions) { + // 旧的菜单树免授权的节点很少,所以直接查询,线上只有11个 + Set noAuthSaasFeatureCodes = permissionPointService.queryList(PermissionPointListQueryRequest.builder() + .delegatedType(DelegatedType.NO_NEED.getCode()) + .build()) + .stream() + .map(PermissionPointTreeNode::getCode) + .collect(Collectors.toSet()); + + // TODO 查询新权限树免授权的权限点 + + if (CollectionUtils.isEmpty(noAuthSaasFeatureCodes)) { + return Collections.emptySet(); + } + + return productPermissions.stream() + .filter(productPermission -> noAuthSaasFeatureCodes.contains(productPermission.getFeatureCode())) + .map(e -> IdentityAuthRes.PermissionPoint.builder() + .featureCode(e.getFeatureCode()) + .featureId(e.getFeatureId()) + .terminal(e.getTerminal()) + .featureType(e.getFeatureType()) + .build()) + .collect(Collectors.toSet()); + } + + private Set buildNormalPermissionV2(List productPermissions, + List saasRoles, + Map> rolePermissionMap) { + + List normalRoles =Optional.ofNullable(saasRoles) + .map(e -> e.stream() + .filter(r -> !RoleTypeEnum.isAdmin(r.getRoleType())) + .collect(Collectors.toList())) + .orElse(null); + if (CollectionUtil.isEmpty(normalRoles)) { + return Collections.emptySet(); + } + + return normalRoles.stream() + .map(role -> { + + Set rolePermissionFeatureCodes = Optional.ofNullable(rolePermissionMap.get(role.getId())) + .map(e -> e.stream() + .filter(Objects::nonNull) + .map(RolePermissionCacheService.PermissionDTO::getFeatureCode) + .collect(Collectors.toSet())) + .orElseGet(Sets::newHashSet); + + if (CollectionUtils.isEmpty(rolePermissionFeatureCodes)) { + return null; + } + + return productPermissions.stream() + .filter(productPermission -> Objects.equals(productPermission.getCooperateType(), role.getProductUnitType())) + .filter(productPermission -> rolePermissionFeatureCodes.contains(productPermission.getFeatureCode())) + .map(e -> IdentityAuthRes.PermissionPoint.builder() + .featureCode(e.getFeatureCode()) + .featureId(e.getFeatureId()) + .terminal(e.getTerminal()) + .featureType(e.getFeatureType()) + .build()) + .collect(Collectors.toSet()); + + }) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + } + + private Map> listWorkspaceProductPermission(IdentityAuthReq identityAuthReq) { + Set workspaceIds = identityAuthReq.getWorkspaceOusPairs().stream() + .map(IdentityAuthReq.WorkspaceOuPair::getWorkspaceId) + .collect(Collectors.toSet()); + // 查询项目的产品权限 + WorkspaceProductService.ListWorkspaceProductPermissionCacheParam listProductPermisssion = WorkspaceProductService.ListWorkspaceProductPermissionCacheParam.builder() + .workspaceIds(workspaceIds) + .featureCodes(identityAuthReq.getFeatureCode()) + .build(); + return workspaceProductService.listWorkspaceProductPermissionCached(listProductPermisssion).stream() + .collect(Collectors.toMap(WorkspaceProductService.WorkspaceProductPermission::getWorkspaceId, + WorkspaceProductService.WorkspaceProductPermission::getProductPermissions)); + } + + private Map> listRolePermission(IdentityAuthReq identityAuthReq, List saasRoleUsers) { + // 因为只有非管理员才会绑定权限 + Set normalRoleIds = saasRoleUsers.stream() + .filter(e -> !RoleTypeEnum.isAdmin(e.getSaasRole().getRoleType())) + .map(SaasRoleUserV2DTO::getRoleId) + .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(normalRoleIds)) { + return Collections.emptyMap(); + } + + RolePermissionCacheService.ListRolePermissionParam listRolePermissionParam = RolePermissionCacheService.ListRolePermissionParam.builder() + .roleIds(normalRoleIds) + .featureCodes(identityAuthReq.getFeatureCode()) + .build(); + return rolePermissionCacheService.list(listRolePermissionParam); + } } 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 a2c5ac57..b8cdf79a 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 @@ -10,12 +10,12 @@ 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.ProductPermissionCacheService; 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 com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.common.collect.Streams; @@ -53,7 +53,10 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { @Autowired private ProductFeatureRelationService productFeatureRelationService; @Autowired - protected StringRedisTemplate redisTemplate; + private StringRedisTemplate redisTemplate; + @Autowired + private ProductPermissionCacheService productPermissionCacheService; + /** 授权缓存过期时间 **/ @Value("${workspace.product.expire:90}") @@ -136,13 +139,7 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { return Collections.emptyList(); } - ListWorkspaceProductParam listWorkspaceProductParam = ListWorkspaceProductParam.builder() - .workspaceIds(param.getWorkspaceIds()) - .build(); - Map> workspaceProducts = listWorkspaceProduct(listWorkspaceProductParam); - - // 存在项目没有在缓存中查询到产品的情况 - fillCacheWorkspaseProducts(param, workspaceProducts); + Map> workspaceProducts = listWorkspaceProduct(param.getWorkspaceIds()); Set productIds = workspaceProducts.values().stream() .flatMap(Collection::stream) @@ -152,19 +149,8 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { return Collections.emptyList(); } - // 已被删除产品过滤一层 - Set finalProductIds = productModuleDao.listByIds(productIds) - .stream() - .filter(productModule -> Objects.equals(productModule.getIsDelete(),0L)) - .map(BaseEntity::getId) - .collect(Collectors.toSet()); - if (CollectionUtil.isEmpty(finalProductIds)) { - log.warn("all product is deleted for workspace :{}", param.getWorkspaceIds()); - return Collections.emptyList(); - } - ProductFeatureQuery productFeatureQuery = ProductFeatureQuery.builder() - .productIds(finalProductIds) + .productIds(productIds) .featureResourceTypes(param.getFeatureResourceTypes()) .terminal(param.getTerminal()) .type(param.getType()) @@ -238,13 +224,13 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { /** * 组装在缓存中没有查询到产品的项目 - * @param param + * @param workspaceIds * @param workspaceProducts */ - private void fillCacheWorkspaseProducts(WorkspaceProductParam param, + private void fillCacheWorkspaceProducts(Set workspaceIds, Map> workspaceProducts) { - Sets.SetView difference = Sets.difference(param.getWorkspaceIds(), workspaceProducts.keySet()); + Sets.SetView difference = Sets.difference(workspaceIds, workspaceProducts.keySet()); if (difference.isEmpty()) { return; } @@ -287,4 +273,82 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { private String getKey(Object... params) { return String.format(WORKSPACE_PRODUCT_KEY, params); } + + @Override + public List listWorkspaceProductPermissionCached(ListWorkspaceProductPermissionCacheParam param) { + Map> workspaceProducts = listWorkspaceProduct(param.getWorkspaceIds()); + + Set productIds = workspaceProducts.values().stream() + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(productIds)) { + return Collections.emptyList(); + } + + ProductPermissionCacheService.ListProductPermissionParam listProductPermissionParam = ProductPermissionCacheService.ListProductPermissionParam.builder() + .productIds(productIds) + .featureCodes(param.getFeatureCodes()) + .build(); + Map> productPermissionMap = productPermissionCacheService.list(listProductPermissionParam); + + return workspaceProducts.entrySet().stream() + .filter(e -> CollectionUtils.isNotEmpty(e.getValue())) + .map(e -> { + List productPermissions = e.getValue().stream() + .map(productId -> { + List permissions = productPermissionMap.get(productId); + if (CollectionUtils.isEmpty(permissions)) { + return null; + } + return ProductPermission.builder() + .productId(productId) + .permissions(permissions) + .build(); + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + return WorkspaceProductPermission.builder() + .workspaceId(e.getKey()) + .productPermissions(productPermissions) + .build(); + }) + .collect(Collectors.toList()); + } + + private Map> listWorkspaceProduct(Set workspaceIds) { + if (CollectionUtils.isEmpty(workspaceIds)) { + return Collections.emptyMap(); + } + + ListWorkspaceProductParam listWorkspaceProductParam = ListWorkspaceProductParam.builder() + .workspaceIds(workspaceIds) + .build(); + Map> workspaceProducts = listWorkspaceProduct(listWorkspaceProductParam); + + // 存在项目没有在缓存中查询到产品的情况 + fillCacheWorkspaceProducts(workspaceIds, workspaceProducts); + + Set productIds = workspaceProducts.values().stream() + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(productIds)) { + return Collections.emptyMap(); + } + + // 需要过滤掉已经被删除的产品 + Set finalProductIds = productModuleDao.listByIds(productIds).stream() + .filter(productModule -> Objects.equals(productModule.getIsDelete(),0L)) + .map(BaseEntity::getId) + .collect(Collectors.toSet()); + workspaceProducts.entrySet().forEach(e -> { + Set effectProductIds = e.getValue().stream() + .filter(finalProductIds::contains) + .collect(Collectors.toSet()); + e.setValue(effectProductIds); + }); + + return workspaceProducts; + } } diff --git a/tyr-server/src/main/resources/mapper/SaasRoleUserRelationMapper.xml b/tyr-server/src/main/resources/mapper/SaasRoleUserRelationMapper.xml index 2792daa9..c3f2882f 100644 --- a/tyr-server/src/main/resources/mapper/SaasRoleUserRelationMapper.xml +++ b/tyr-server/src/main/resources/mapper/SaasRoleUserRelationMapper.xml @@ -19,4 +19,16 @@ AND natural_person_id = #{param.naturalPersonId} + + \ No newline at end of file From dec1069f9e626a529ecf3ffe198de99282247b4a Mon Sep 17 00:00:00 2001 From: lilong Date: Sun, 28 Jul 2024 11:07:17 +0800 Subject: [PATCH 009/112] =?UTF-8?q?feat:(REQ-2720)=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E6=A0=91=E7=BC=93=E5=AD=98=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=9F=BA=E4=BA=8E=E8=8F=9C=E5=8D=95=E6=A0=91=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E7=9A=84=E9=89=B4=E6=9D=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/model/enums/DelegatedType.java | 5 + .../server/controller/PrivateController.java | 34 ++++- .../inner/CacheRolePermissionHandler.java | 2 +- .../event/inner/CacheSaasFeatureHandler.java | 69 +++++++++++ .../CacheSaasFeatureResourceHandler.java | 66 ++++++++++ .../SaasFeatureResourceUpsertPayload.java | 3 +- ...oad.java => SaasFeatureUpsertPayload.java} | 7 +- .../server/job/CacheProductPermissionJob.java | 54 ++++++++ .../server/job/CacheRolePermissionJob.java | 68 ++++++++++ .../tyr/server/job/CacheSaasFeatureJob.java | 86 +++++++++++++ .../service/SaasFeatureResourceService.java | 39 ++++++ .../impl/PermissionPointServiceImpl.java | 82 +++++++++---- .../impl/SaasFeatureResourceServiceImpl.java | 71 ++++++++++- .../service/impl/TyrSaasAuthServiceImpl.java | 116 +++++++++++++++--- 14 files changed, 652 insertions(+), 50 deletions(-) create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java rename tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/{SaasFeatureUpsetPayload.java => SaasFeatureUpsertPayload.java} (67%) create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductPermissionJob.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/enums/DelegatedType.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/enums/DelegatedType.java index 3dc3bbd2..b5685854 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/enums/DelegatedType.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/enums/DelegatedType.java @@ -5,6 +5,7 @@ import lombok.Getter; import java.util.HashMap; import java.util.Map; +import java.util.Objects; /** * 权限点授权策略类型 @@ -39,4 +40,8 @@ public enum DelegatedType { public boolean sameCode(Integer code) { return this.code.equals(code); } + + public static boolean notAuth(Integer delegatedType) { + return Objects.equals(NO_NEED.getCode(), delegatedType); + } } 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 7a042be8..94b47359 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 @@ -7,6 +7,7 @@ import cn.axzo.foundation.page.PageResp; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.framework.rocketmq.Event; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; +import cn.axzo.tyr.client.model.product.ProductSearchListReq; import cn.axzo.tyr.client.model.req.CommonDictQueryReq; import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; import cn.axzo.tyr.client.model.req.PagePgroupPermissionRelationReq; @@ -21,6 +22,9 @@ import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO; import cn.axzo.tyr.client.model.vo.SaveOrUpdateRoleVO; import cn.axzo.tyr.server.event.outer.CacheWorkspaceProductHandler; import cn.axzo.tyr.server.event.payload.ServicePkgProductCreatedPayload; +import cn.axzo.tyr.server.job.CacheProductPermissionJob; +import cn.axzo.tyr.server.job.CacheRolePermissionJob; +import cn.axzo.tyr.server.job.CacheSaasFeatureJob; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; import cn.axzo.tyr.server.repository.dao.SaasPgroupPermissionRelationDao; @@ -123,6 +127,12 @@ public class PrivateController { private CacheWorkspaceProductHandler cacheWorkspaceProductHandler; @Autowired private SaasRoleGroupDao saasRoleGroupDao; + @Autowired + private CacheProductPermissionJob cacheProductPermissionJob; + @Autowired + private CacheRolePermissionJob cacheRolePermissionJob; + @Autowired + private CacheSaasFeatureJob cacheSaasFeatureJob; /** * 统一层级的roleGroup按照id升序,sort从1递增 @@ -578,8 +588,8 @@ public class PrivateController { } @PostMapping("/api/private/workspaceProduct/store") - public Object storeWorkspaceProduct(@RequestBody WorkspaceProductService.StoreWorkspaceProductParam request) { - workspaceProductService.storeWorkspaceProduct(request); + public Object storeWorkspaceProduct(@RequestBody ProductSearchListReq request) throws Exception { + cacheProductPermissionJob.execute(JSON.toJSONString(request)); return "ok"; } @@ -651,6 +661,26 @@ public class PrivateController { return "ok"; } + @PostMapping("/api/private/rolePermission/store") + public Object storeRolePermission(@RequestBody RoleService.PageSaasRoleParam request) throws Exception { + cacheRolePermissionJob.execute(JSON.toJSONString(request)); + return "ok"; + } + + @PostMapping("/api/private/saasFeature/store") + public Object storeSaasFeature(@RequestBody StoreFeatureParam request) throws Exception { + cacheSaasFeatureJob.execute(request.getTerminal()); + return "ok"; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class StoreFeatureParam { + private String terminal; + } + @Data @Builder @NoArgsConstructor diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java index e62ded89..24e1a6c1 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java @@ -81,7 +81,7 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea log.info("end cached role permission handler rocketmq event: {}", event); } - @Override + @Override public void afterPropertiesSet() throws Exception { eventConsumer.registerHandler(EventTypeEnum.ROLE_PERMISSION_CREATED.getEventCode(), this); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java new file mode 100644 index 00000000..6980f956 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java @@ -0,0 +1,69 @@ +package cn.axzo.tyr.server.event.inner; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.framework.rocketmq.EventHandler; +import cn.axzo.tyr.client.model.enums.DelegatedType; +import cn.axzo.tyr.server.event.payload.SaasFeatureUpsertPayload; +import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; +import cn.axzo.tyr.server.repository.entity.SaasFeature; +import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import cn.axzo.tyr.server.service.SaasFeatureService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * 缓存全量权限点,因为鉴权等逻辑,需要查询免授权和权限点是否存在,数据量大,数据库压力大 + */ +@Slf4j +@Component +public class CacheSaasFeatureHandler implements EventHandler, InitializingBean { + + @Autowired + private EventConsumer eventConsumer; + @Autowired + private SaasFeatureDao saasFeatureDao; + @Autowired + private SaasFeatureResourceService saasFeatureResourceService; + + @Override + public void onEvent(Event event, EventConsumer.Context context) { + log.info("begin cached saasFeature handler rocketmq event: {}", event); + SaasFeatureUpsertPayload payload = event.normalizedData(SaasFeatureUpsertPayload.class); + + if (StringUtils.isBlank(payload.getTerminal())) { + return; + } + + List saasFeatures = saasFeatureDao.lambdaQuery() + .eq(SaasFeature::getTerminal, payload.getTerminal()) + .list() + .stream() + .map(e -> SaasFeatureResourceService.SaasFeatureResourceCache + .builder() + .featureId(e.getId()) + .notAuth(DelegatedType.notAuth(e.getDelegatedType())) + .build()) + .collect(Collectors.toList()); + + SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() + .terminal(payload.getTerminal()) + .features(saasFeatures) + .build(); + saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); + + + log.info("end cached saasFeature handler rocketmq event: {}", event); + } + + @Override + public void afterPropertiesSet() throws Exception { + eventConsumer.registerHandler(EventTypeEnum.SAAS_FEATURE_UPSERT.getEventCode(), this); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java new file mode 100644 index 00000000..9bfc9489 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java @@ -0,0 +1,66 @@ +package cn.axzo.tyr.server.event.inner; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.framework.rocketmq.EventHandler; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; +import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; +import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * 缓存全量权限点,因为鉴权等逻辑,需要查询免授权和权限点是否存在,数据量大,数据库压力大 + */ +@Slf4j +@Component +public class CacheSaasFeatureResourceHandler implements EventHandler, InitializingBean { + + @Autowired + private EventConsumer eventConsumer; + @Autowired + private SaasFeatureResourceService saasFeatureResourceService; + + @Override + public void onEvent(Event event, EventConsumer.Context context) { + log.info("begin cached saasFeatureResource handler rocketmq event: {}", event); + SaasFeatureResourceUpsertPayload payload = event.normalizedData(SaasFeatureResourceUpsertPayload.class); + + if (StringUtils.isBlank(payload.getTerminal())) { + return; + } + + // 直接查询缓存所有节点,因为修改的代码不好改 + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .terminal(payload.getTerminal()) + .build(); + + List saasFeatures = saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .map(e -> SaasFeatureResourceService.SaasFeatureResourceCache.builder() + .featureId(e.getId()) + .notAuth(SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) + .build()) + .collect(Collectors.toList()); + + SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() + .terminal(payload.getTerminal()) + .features(saasFeatures) + .build(); + saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); + + log.info("end cached saasFeatureResource handler rocketmq event: {}", event); + } + + @Override + public void afterPropertiesSet() throws Exception { + eventConsumer.registerHandler(EventTypeEnum.SAAS_FEATURE_RESOURCE_UPSERT.getEventCode(), this); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java index 6590c1cc..648fb7d9 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java @@ -6,7 +6,6 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; -import java.util.Set; @Data @Builder @@ -14,5 +13,5 @@ import java.util.Set; @AllArgsConstructor public class SaasFeatureResourceUpsertPayload implements Serializable { - private Set ids; + private String terminal; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureUpsetPayload.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureUpsertPayload.java similarity index 67% rename from tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureUpsetPayload.java rename to tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureUpsertPayload.java index 7c6349cc..312a86cd 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureUpsetPayload.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureUpsertPayload.java @@ -6,13 +6,14 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; -import java.util.Set; @Data @Builder @NoArgsConstructor @AllArgsConstructor -public class SaasFeatureUpsetPayload implements Serializable { +public class SaasFeatureUpsertPayload implements Serializable { - private Set ids; + private Long id; + + private String terminal; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductPermissionJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductPermissionJob.java new file mode 100644 index 00000000..299f47f3 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductPermissionJob.java @@ -0,0 +1,54 @@ +package cn.axzo.tyr.server.job; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.tyr.client.model.product.ProductSearchListReq; +import cn.axzo.tyr.client.model.product.ProductVO; +import cn.axzo.tyr.server.event.inner.CacheProductPermissionHandler; +import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload; +import cn.axzo.tyr.server.service.ProductService; +import com.alibaba.fastjson.JSONObject; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.IJobHandler; +import com.xxl.job.core.handler.annotation.XxlJob; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +@Component +public class CacheProductPermissionJob extends IJobHandler { + + @Autowired + private CacheProductPermissionHandler cacheProductPermissionHandler; + @Autowired + private ProductService productService; + + @Override + @XxlJob("CacheProductPermissionJob") + public ReturnT execute(String s) throws Exception { + + log.info("start CacheProductPermissionJob, s:{}", s); + ProductSearchListReq productSearchListReq = Optional.ofNullable(s) + .map(e -> JSONObject.parseObject(e, ProductSearchListReq.class)) + .orElseGet(ProductSearchListReq::new); + + Set productIds = productService.list(productSearchListReq).getData() + .stream() + .map(ProductVO::getId) + .collect(Collectors.toSet()); + + ProductPermissionCreatedPayload payload = ProductPermissionCreatedPayload.builder() + .productModuleIds(productIds) + .build(); + + Event event = Event.builder() + .data(payload) + .build(); + cacheProductPermissionHandler.onEvent(event, null); + return ReturnT.SUCCESS; + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java new file mode 100644 index 00000000..5e464316 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java @@ -0,0 +1,68 @@ +package cn.axzo.tyr.server.job; + +import cn.axzo.foundation.page.PageResp; +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.tyr.client.model.res.SaasRoleRes; +import cn.axzo.tyr.server.event.inner.CacheRolePermissionHandler; +import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; +import cn.axzo.tyr.server.service.RoleService; +import com.alibaba.fastjson.JSONObject; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.IJobHandler; +import com.xxl.job.core.handler.annotation.XxlJob; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +@Component +public class CacheRolePermissionJob extends IJobHandler { + + @Autowired + private CacheRolePermissionHandler cacheRolePermissionHandler; + @Autowired + private RoleService roleService; + + private static final Integer DEFAULT_PAGE_SIZE = 1000; + + @Override + @XxlJob("CacheRolePermissionJob") + public ReturnT execute(String s) throws Exception { + + log.info("start CacheRolePermissionJob, s:{}", s); + RoleService.PageSaasRoleParam pageSaasRoleParam = Optional.ofNullable(s) + .map(e -> JSONObject.parseObject(e, RoleService.PageSaasRoleParam.class)) + .orElseGet(() -> RoleService.PageSaasRoleParam.builder().build()); + + Integer pageNumber = 1; + while (true) { + pageSaasRoleParam.setPage(pageNumber++); + pageSaasRoleParam.setPageSize(DEFAULT_PAGE_SIZE); + + PageResp page = roleService.page(pageSaasRoleParam); + Set roleIds = page.getData().stream() + .map(SaasRoleRes::getId) + .collect(Collectors.toSet()); + + RolePermissionCreatedPayload payload = RolePermissionCreatedPayload.builder() + .roleIds(roleIds) + .build(); + + Event event = Event.builder() + .data(payload) + .build(); + + cacheRolePermissionHandler.onEvent(event, null); + + if (!page.hasNext()) { + break; + } + } + + return ReturnT.SUCCESS; + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java new file mode 100644 index 00000000..b0d0c165 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java @@ -0,0 +1,86 @@ +package cn.axzo.tyr.server.job; + +import cn.axzo.tyr.client.model.enums.DelegatedType; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; +import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; +import cn.axzo.tyr.server.repository.entity.SaasFeature; +import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; +import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.IJobHandler; +import com.xxl.job.core.handler.annotation.XxlJob; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Component +public class CacheSaasFeatureJob extends IJobHandler { + + @Autowired + private SaasFeatureDao saasFeatureDao; + @Autowired + private SaasFeatureResourceService saasFeatureResourceService; + + @Override + @XxlJob("CacheSaasFeatureJob") + public ReturnT execute(String s) throws Exception { + + log.info("start CacheSaasFeatureJob, s:{}", s); + + cacheSaasFeature(s); + + cacheSaasFeatureResource(s); + return ReturnT.SUCCESS; + } + + private void cacheSaasFeature(String terminal) { + Map> saasFeatures = saasFeatureDao.lambdaQuery() + .eq(StringUtils.isNotBlank(terminal), SaasFeature::getTerminal, terminal) + .list() + .stream() + .collect(Collectors.groupingBy(SaasFeature::getTerminal, + Collectors.mapping(e -> SaasFeatureResourceService.SaasFeatureResourceCache + .builder() + .featureId(e.getId()) + .notAuth(DelegatedType.notAuth(e.getDelegatedType())) + .build(), Collectors.toList()))); + + saasFeatures.entrySet().forEach(e -> { + SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() + .terminal(e.getKey()) + .features(e.getValue()) + .build(); + saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); + }); + } + + private void cacheSaasFeatureResource(String terminal) { + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .terminal(terminal) + .build(); + + Map> saasFeatureResources = saasFeatureResourceService.list(pageSaasFeatureResourceReq) + .stream() + .collect(Collectors.groupingBy(SaasFeatureResourceResp::getTerminal, + Collectors.mapping(e -> SaasFeatureResourceService.SaasFeatureResourceCache + .builder() + .featureId(e.getId()) + .notAuth(SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) + .build(), Collectors.toList()))); + + saasFeatureResources.entrySet().forEach(e -> { + SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() + .terminal(e.getKey()) + .features(e.getValue()) + .build(); + saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); + }); + } +} 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 1e10c7c4..0ca7f997 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 @@ -11,8 +11,13 @@ import cn.axzo.tyr.server.model.ResourcePermission; import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import com.baomidou.mybatisplus.extension.service.IService; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -59,4 +64,38 @@ public interface SaasFeatureResourceService extends IService> listCache(ListSaasFeatureResourceCache param); + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class StoreSaasFeatureResourceCache { + + private String terminal; + + private List features; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ListSaasFeatureResourceCache { + + private Set terminals; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class SaasFeatureResourceCache { + + private Long featureId; + + private boolean notAuth; + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionPointServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionPointServiceImpl.java index 51feb1b6..86c81b8d 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionPointServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionPointServiceImpl.java @@ -1,37 +1,29 @@ package cn.axzo.tyr.server.service.impl; -import static cn.axzo.tyr.client.model.enums.FeatureType.BUTTON; -import static cn.axzo.tyr.client.model.enums.FeatureType.MODULE; -import static cn.axzo.tyr.server.common.constants.PermissionConstant.*; - -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; - -import cn.axzo.tyr.client.model.enums.FeatureDataType; -import cn.axzo.tyr.client.model.req.QueryPermissionByIdsReq; -import cn.axzo.tyr.client.model.res.SimplePermissionPointResp; -import cn.hutool.core.date.StopWatch; -import cn.hutool.core.lang.Opt; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import com.baomidou.mybatisplus.core.conditions.Wrapper; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; - import cn.axzo.basics.common.BeanMapper; import cn.axzo.basics.common.util.StopWatchUtil; import cn.axzo.basics.common.util.TreeUtil; import cn.axzo.framework.domain.web.code.BaseCode; +import cn.axzo.framework.rocketmq.Event; import cn.axzo.tyr.client.model.dict.request.BasicDictNodeReq; import cn.axzo.tyr.client.model.dict.request.BasicDictQueryReq; import cn.axzo.tyr.client.model.dict.response.BasicDictNodeResp; import cn.axzo.tyr.client.model.dict.response.BasicDictTreeResp; import cn.axzo.tyr.client.model.enums.DictTypeFiledEnum; import cn.axzo.tyr.client.model.enums.DictWorkSpaceTypeEnum; +import cn.axzo.tyr.client.model.enums.FeatureDataType; import cn.axzo.tyr.client.model.enums.FeatureType; -import cn.axzo.tyr.client.model.permission.*; +import cn.axzo.tyr.client.model.permission.PermissionPointDTO; +import cn.axzo.tyr.client.model.permission.PermissionPointListQueryRequest; +import cn.axzo.tyr.client.model.permission.PermissionPointMoveRequest; +import cn.axzo.tyr.client.model.permission.PermissionPointTreeNode; +import cn.axzo.tyr.client.model.permission.PermissionPointTreeQueryReq; +import cn.axzo.tyr.client.model.permission.PermissionPointVO; +import cn.axzo.tyr.client.model.req.QueryPermissionByIdsReq; +import cn.axzo.tyr.client.model.res.SimplePermissionPointResp; import cn.axzo.tyr.server.common.util.Throws; +import cn.axzo.tyr.server.config.MqProducer; +import cn.axzo.tyr.server.event.payload.SaasFeatureUpsertPayload; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.dao.SaasPgroupPermissionRelationDao; import cn.axzo.tyr.server.repository.dao.SaasProductModuleFeatureRelationDao; @@ -40,10 +32,32 @@ import cn.axzo.tyr.server.service.PermissionPointService; import cn.axzo.tyr.server.service.SaasBasicDictService; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; -import static cn.axzo.tyr.server.util.RpcInternalUtil.checkAndGetData; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +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.function.Function; +import java.util.stream.Collectors; + +import static cn.axzo.tyr.client.model.enums.FeatureType.BUTTON; +import static cn.axzo.tyr.client.model.enums.FeatureType.MODULE; +import static cn.axzo.tyr.server.common.constants.PermissionConstant.FEATURE_BIZ_NO_PREFIX; +import static cn.axzo.tyr.server.common.constants.PermissionConstant.FEATURE_PATH_DELIMITER; +import static cn.axzo.tyr.server.common.constants.PermissionConstant.FEATURE_TOP_BIZ_NO; +import static cn.axzo.tyr.server.common.constants.PermissionConstant.FEATURE_TOP_PATH; +import static cn.axzo.tyr.server.event.inner.EventTypeEnum.SAAS_FEATURE_UPSERT; /** * 权限点服务实现 @@ -61,6 +75,9 @@ public class PermissionPointServiceImpl implements PermissionPointService { private final SaasBasicDictService saasBasicDictService; private final SaasPgroupPermissionRelationDao saasPgroupPermissionRelationDao; private final SaasProductModuleFeatureRelationDao saasProductModuleFeatureRelationDao; + private final MqProducer mqProducer; + + private static final String TARGET_TYPE = "saasFeatureId"; @Override public List listTreeNodes(PermissionPointTreeQueryReq request) { @@ -333,6 +350,11 @@ public class PermissionPointServiceImpl implements PermissionPointService { this.saasFeatureDao.updateById(saasFeature); //返回一些要用的数据 dto.setBusinessNo(feature.getBusinessNo()); + + sendMsg(SaasFeatureUpsertPayload.builder() + .id(dto.getId()) + .terminal(feature.getTerminal()) + .build()); return dto; } @@ -367,6 +389,11 @@ public class PermissionPointServiceImpl implements PermissionPointService { dto.setBusinessNo(saasFeature.getBusinessNo()); //调整排序 - 兼容处理老数据,数据规范化 changeSort(saasFeature, saasFeature.getSort()); + + sendMsg(SaasFeatureUpsertPayload.builder() + .id(dto.getId()) + .terminal(saasFeature.getTerminal()) + .build()); return dto; } @@ -426,6 +453,11 @@ public class PermissionPointServiceImpl implements PermissionPointService { //删除关联数据 this.saasPgroupPermissionRelationDao.removeByPermissionPointIds(delIds); this.saasProductModuleFeatureRelationDao.removeByPermissionPointIds(delIds); + + sendMsg(SaasFeatureUpsertPayload.builder() + .id(feature.getId()) + .terminal(feature.getTerminal()) + .build()); return bizNoList; } @@ -643,4 +675,12 @@ public class PermissionPointServiceImpl implements PermissionPointService { .build(); } + private void sendMsg(SaasFeatureUpsertPayload saasFeatureUpsertPayload) { + Event event = Event.builder() + .targetType(TARGET_TYPE) + .eventCode(SAAS_FEATURE_UPSERT.getEventCode()) + .data(saasFeatureUpsertPayload) + .build(); + mqProducer.send(event); + } } 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 bbf6022a..d9bf13de 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 @@ -10,6 +10,7 @@ import cn.axzo.foundation.page.PageResp; import cn.axzo.framework.domain.web.code.BaseCode; import cn.axzo.framework.rocketmq.Event; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; +import cn.axzo.pokonyan.config.redis.RedisClient; import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType; import cn.axzo.tyr.client.common.enums.FeatureResourceStatus; import cn.axzo.tyr.client.common.enums.FeatureResourceType; @@ -44,18 +45,28 @@ 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.lang.Pair; import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; 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 com.google.common.collect.Sets; +import com.google.common.collect.Streams; 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.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.CacheEvict; +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.core.RedisOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.SessionCallback; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -65,6 +76,7 @@ import java.util.List; import java.util.Map; 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.FEATURE_RESOURCE_NOT_FOUND; @@ -95,6 +107,15 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl redisTemplate; + + /** 菜单树过期时间 **/ + @Value("${saas.feature.resource.expire:180}") + private Long expireInDays; + + private static final String SAAS_FEATURE_RESOURCE_KEY = "saas:feature:resource:%s"; + private static final String TARGET_TYPE = "saasFeatureResourceId"; @Override public List listNavByIds(List featureIds, List featureTypes) { @@ -267,7 +288,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl deleteFeatureResource) { @@ -671,4 +701,43 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl> listCache(ListSaasFeatureResourceCache param) { + List redisValues = redisTemplate.executePipelined(new SessionCallback() { + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + + for (String terminal : param.getTerminals()) { + String redisKey = getKey(terminal); + + RedisClient.StringOps.get(redisKey); + } + return null; + } + }); + + return Streams.zip(param.getTerminals().stream(), + redisValues.stream(), + (terminal, redisValue) -> { + + if (Objects.isNull(redisValue)) { + return null; + } + return Pair.of(terminal, JSONArray.parseArray((String) redisValue, + SaasFeatureResourceCache.class)); + }) + .filter(Objects::nonNull) + .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); + } + + private String getKey(Object... params) { + return String.format(SAAS_FEATURE_RESOURCE_KEY, params); + } } 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 a7ea8da4..eddcdd13 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 @@ -2,6 +2,7 @@ package cn.axzo.tyr.server.service.impl; import cn.axzo.apollo.workspace.common.enums.TableIsDeleteEnum; import cn.axzo.basics.common.BeanMapper; +import cn.axzo.framework.domain.ServiceException; import cn.axzo.pokonyan.util.TraceSupplier; import cn.axzo.thrones.client.saas.ServicePkgClient; import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct; @@ -10,7 +11,6 @@ import cn.axzo.tyr.client.common.enums.RoleTypeEnum; import cn.axzo.tyr.client.common.enums.WorkspaceJoinType; import cn.axzo.tyr.client.model.enums.DelegatedType; 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.CheckIdentityPermissionReq; @@ -447,8 +447,52 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { private String terminal; } + private Set checkFeatureCodes(ListPermissionUser param) { + // 查询免授权的featureCodes,判断featureCodes里是否有免授权的featureCodes + // 兼容新老版本,需要通过featureCode查询新版本的features,原逻辑是查询当前菜单资源的所有子数据 + List features = permissionPointService.listNodeWithChildrenByCodes(Lists.newArrayList(param.getFeatureCodes()), param.getTerminal()); + + ListSaasFeatureResourceParam listSaasFeatureResourceParam = ListSaasFeatureResourceParam.builder() + .featureCodes(param.getFeatureCodes()) + .terminal(param.getTerminal()) + .build(); + List saasFeatureResources = listSaasFeatureResource(listSaasFeatureResourceParam); + if (CollectionUtil.isEmpty(features) && CollectionUtils.isEmpty(saasFeatureResources)) { + log.warn("no features data found for:{}", param.getFeatureCodes()); + return Collections.emptySet(); + } + + //是否免授权权限点 + Optional freeFeature = features.stream() + .filter(f -> DelegatedType.NO_NEED.sameCode(f.getDelegatedType())) + .findAny(); + if (freeFeature.isPresent()) { + throw new ServiceException("不能查询免授权权限点人员"); + } + + Optional freeFeatureResource = saasFeatureResources.stream() + .filter(e -> SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) + .findFirst(); + if (freeFeatureResource.isPresent()) { + throw new ServiceException("不能查询免授权权限点人员"); + } + + Set allFeatureIds = Sets.newHashSet(); + allFeatureIds.addAll(features.stream() + .map(SaasFeature::getId) + .collect(Collectors.toSet())); + + allFeatureIds.addAll(saasFeatureResources.stream() + .map(SaasFeatureResourceResp::getId) + .collect(Collectors.toSet())); + + return allFeatureIds; + } + private List listPermissionUser(ListPermissionUser param) { - // TODO 查询免授权的featureCodes,判断featureCodes里是否有免授权的featureCodes + + // 查询的featureCodes有可能已经被删除,但是saas_feature_code效率比较低,两个表的id不会重复,所以解析成id去过滤权限 + Set featureIds = checkFeatureCodes(param); WorkspaceProductService.ListWorkspaceProductPermissionCacheParam listWorkspaceProductPermissionCacheParam = WorkspaceProductService.ListWorkspaceProductPermissionCacheParam.builder() .workspaceIds(Sets.newHashSet(param.getWorkspaceId())) @@ -462,6 +506,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .map(WorkspaceProductService.ProductPermission::getPermissions) .filter(e -> !CollectionUtils.isEmpty(e)) .flatMap(Collection::stream) + .filter(e -> featureIds.contains(e.getFeatureId())) .filter(e -> StringUtils.isBlank(param.getTerminal()) || Objects.equals(e.getTerminal(), param.getTerminal())) .collect(Collectors.toList()); @@ -470,7 +515,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return Collections.emptyList(); } - return getWorkspaceUserV2(param, productPermissions); + return getWorkspaceUserV2(param, productPermissions, featureIds); } @Override @@ -520,13 +565,17 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } private Set resolvePermissionNormalRole(ListPermissionUser req, - List productPermissions) { + List productPermissions, + Set featureIds) { // 因为通过权限id找对应的角色数据量巨大,所以通过找项目的角色,再找有权限的角色比较快 Set allRoleIds = saasRoleUserRelationMapper.listRoleIds(SaasRoleUserRelationMapper.ListRole.builder() .ouId(req.getOuId()) .workspaceId(req.getWorkspaceId()) .build()); + if (CollectionUtils.isEmpty(allRoleIds)) { + return Collections.emptySet(); + } RolePermissionCacheService.ListRolePermissionParam listRolePermissionParam = RolePermissionCacheService.ListRolePermissionParam.builder() .roleIds(allRoleIds) @@ -538,6 +587,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { Set normalRoleIds = normalRolePermissionMap.entrySet().stream() .filter(e -> !CollectionUtils.isEmpty(e.getValue())) + .filter(e -> e.getValue().stream().anyMatch(p -> featureIds.contains(p.getFeatureId()))) .filter(e -> StringUtils.isBlank(req.getTerminal()) || e.getValue().stream().anyMatch(p -> Objects.equals(p.getTerminal(), req.getTerminal()))) .map(Map.Entry::getKey) @@ -574,13 +624,14 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } private List getWorkspaceUserV2(ListPermissionUser req, - List productPermissions) { + List productPermissions, + Set featureIds) { //超管和管理员 List adminRoles = listAdminRole(req); Set adminPermissionRoleIds = resolvePermissionAdminRole(adminRoles, productPermissions); - Set normalPermissionRoleIds = resolvePermissionNormalRole(req, productPermissions); + Set normalPermissionRoleIds = resolvePermissionNormalRole(req, productPermissions, featureIds); Set roleIds = Sets.newHashSet(); roleIds.addAll(adminPermissionRoleIds); @@ -1444,6 +1495,8 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { result.setPermissions(permissions); return result; } + + private IdentityAuthRes.WorkspacePermission buildPermissionsV2(IdentityAuthReq.WorkspaceOuPair workspaceOuPair, List productPermissions, @@ -1455,11 +1508,22 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .ouId(workspaceOuPair.getOuId()) .build(); + // 根据项目的产品找到对应端的所有权限点,因为可能存在某些权限点被删除或者是免授权,虽然有两颗权限点树,但是id不会重复,新的权限点从100000开始,历史的后续不会再使用 + Set terminals = productPermissions.stream() + .map(ProductPermissionCacheService.PermissionDTO::getTerminal) + .collect(Collectors.toSet()); + List allFeatures = listSaasFeatureCaches(terminals); + + if (CollectionUtils.isEmpty(allFeatures)) { + return workspacePermission; + } + //超管和管理员权限 Set adminPermissionPoints = buildAdminPermissionV2(productPermissions, saasRoles); - Set noAuthPermissionPoints = buildNoAuthPermission(productPermissions); + Set noAuthPermissionPoints = buildNoAuthPermission(productPermissions, allFeatures); Set normalPermissionPoints = buildNormalPermissionV2(productPermissions, saasRoles, rolePermissions); + //组装返回值 //是否超管 boolean superAdmin = saasRoles.stream() @@ -1470,12 +1534,28 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { allPermissionPoints.addAll(adminPermissionPoints); allPermissionPoints.addAll(noAuthPermissionPoints); allPermissionPoints.addAll(normalPermissionPoints); - // TODO 过滤掉已经删除的权限点 + // 过滤掉已经删除的权限点 + Set effectFeatureIds = allFeatures.stream() + .map(SaasFeatureResourceService.SaasFeatureResourceCache::getFeatureId) + .collect(Collectors.toSet()); - workspacePermission.setPermissionPoint(Lists.newArrayList(allPermissionPoints)); + workspacePermission.setPermissionPoint(allPermissionPoints.stream() + .filter(e -> effectFeatureIds.contains(e.getFeatureId())) + .collect(Collectors.toList())); return workspacePermission; } + private List listSaasFeatureCaches(Set terminals) { + SaasFeatureResourceService.ListSaasFeatureResourceCache listSaasFeatureResourceCache = SaasFeatureResourceService.ListSaasFeatureResourceCache.builder() + .terminals(terminals) + .build(); + return saasFeatureResourceService.listCache(listSaasFeatureResourceCache) + .values() + .stream() + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + private Set buildAdminPermissionV2(List productPermissions, List saasRoles) { //超管和管理员角色 @@ -1506,23 +1586,19 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } - private Set buildNoAuthPermission(List productPermissions) { - // 旧的菜单树免授权的节点很少,所以直接查询,线上只有11个 - Set noAuthSaasFeatureCodes = permissionPointService.queryList(PermissionPointListQueryRequest.builder() - .delegatedType(DelegatedType.NO_NEED.getCode()) - .build()) - .stream() - .map(PermissionPointTreeNode::getCode) + private Set buildNoAuthPermission(List productPermissions, + List allFeatuers) { + Set notAuthFeatureIds = allFeatuers.stream() + .filter(SaasFeatureResourceService.SaasFeatureResourceCache::isNotAuth) + .map(SaasFeatureResourceService.SaasFeatureResourceCache::getFeatureId) .collect(Collectors.toSet()); - // TODO 查询新权限树免授权的权限点 - - if (CollectionUtils.isEmpty(noAuthSaasFeatureCodes)) { + if (CollectionUtils.isEmpty(notAuthFeatureIds)) { return Collections.emptySet(); } return productPermissions.stream() - .filter(productPermission -> noAuthSaasFeatureCodes.contains(productPermission.getFeatureCode())) + .filter(productPermission -> notAuthFeatureIds.contains(productPermission.getFeatureId())) .map(e -> IdentityAuthRes.PermissionPoint.builder() .featureCode(e.getFeatureCode()) .featureId(e.getFeatureId()) From edc5f944f7abe8fec9987779fc7377bb9f37a093 Mon Sep 17 00:00:00 2001 From: lilong Date: Sun, 28 Jul 2024 16:00:26 +0800 Subject: [PATCH 010/112] =?UTF-8?q?feat:(REQ-2720)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E3=80=81=E6=B2=A1=E6=9C=89=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=85=83=E7=B4=A0=E7=9A=84=E6=9D=83=E9=99=90=E7=BC=93=E5=AD=98?= =?UTF-8?q?=EF=BC=8Ckey=E4=BD=BF=E7=94=A8uniCode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inner/CacheProductPermissionHandler.java | 16 +++- .../inner/CacheRolePermissionHandler.java | 16 +++- .../server/job/CacheRolePermissionJob.java | 96 +++++++++++++++---- .../service/impl/TyrSaasAuthServiceImpl.java | 8 +- 4 files changed, 113 insertions(+), 23 deletions(-) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java index 097067ee..28742366 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java @@ -14,6 +14,7 @@ import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductPermissionCacheService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; @@ -25,6 +26,8 @@ import java.util.Collections; 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; @@ -110,10 +113,18 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing .map(relation -> { if (Objects.equals(relation.getType(), NEW_FEATURE)) { SaasFeatureResourceResp featureResource = featureResources.get(relation.getFeatureId()); - if (Objects.isNull(featureResource) || CollectionUtils.isEmpty(featureResource.getFeatureCodes())) { + // 菜单节点是不会关联元素code,所以缓存的featureCode使用菜单编码 + if (Objects.isNull(featureResource)) { return null; } - return featureResource.getFeatureCodes().stream() + Set featureCodes = Optional.ofNullable(featureResource.getFeatureCodes()) + .orElseGet(() -> Sets.newHashSet(featureResource.getUniCode())); + + if (CollectionUtils.isEmpty(featureCodes)) { + return null; + } + + return featureCodes.stream() .map(featureCode -> ProductPermissionCacheService.PermissionDTO.builder() .featureId(featureResource.getId()) .featureCode(featureCode) @@ -137,6 +148,7 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing .cooperateType(relation.getDictCode()) .build()); }) + .filter(Objects::nonNull) .flatMap(Collection::stream) .collect(Collectors.toList()); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java index 24e1a6c1..8f115601 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java @@ -14,6 +14,7 @@ import cn.axzo.tyr.server.service.RolePermissionCacheService; import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; @@ -25,6 +26,8 @@ import java.util.Collections; 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; @@ -100,13 +103,22 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea } List permissions = e.getPermissionRelations().stream() + .distinct() .map(permissionRelation -> { if (Objects.equals(permissionRelation.getType(), NEW_FEATURE)) { SaasFeatureResourceResp featureResource = featureResources.get(permissionRelation.getFeatureId()); - if (Objects.isNull(featureResource) || CollectionUtils.isEmpty(featureResource.getFeatureCodes())) { + // 菜单节点是不会关联元素code,所以缓存的featureCode使用菜单编码 + if (Objects.isNull(featureResource)) { return null; } - return featureResource.getFeatureCodes().stream() + Set featureCodes = Optional.ofNullable(featureResource.getFeatureCodes()) + .orElseGet(() -> Sets.newHashSet(featureResource.getUniCode())); + + if (CollectionUtils.isEmpty(featureCodes)) { + return null; + } + + return featureCodes.stream() .map(featureCode -> RolePermissionCacheService.PermissionDTO.builder() .featureId(featureResource.getId()) .featureCode(featureCode) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java index 5e464316..2d5556c1 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java @@ -1,11 +1,15 @@ package cn.axzo.tyr.server.job; import cn.axzo.foundation.page.PageResp; -import cn.axzo.framework.rocketmq.Event; +import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; import cn.axzo.tyr.client.model.res.SaasRoleRes; import cn.axzo.tyr.server.event.inner.CacheRolePermissionHandler; -import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; +import cn.axzo.tyr.server.repository.dao.SaasPgroupRoleRelationDao; +import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation; +import cn.axzo.tyr.server.repository.entity.SaasPgroupRoleRelation; +import cn.axzo.tyr.server.service.RolePermissionCacheService; import cn.axzo.tyr.server.service.RoleService; +import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService; import com.alibaba.fastjson.JSONObject; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; @@ -13,7 +17,12 @@ import com.xxl.job.core.handler.annotation.XxlJob; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -26,8 +35,14 @@ public class CacheRolePermissionJob extends IJobHandler { private CacheRolePermissionHandler cacheRolePermissionHandler; @Autowired private RoleService roleService; + @Autowired + private SaasPgroupPermissionRelationService saasPgroupPermissionRelationService; + @Autowired + private SaasPgroupRoleRelationDao saasPgroupRoleRelationDao; + @Autowired + private RolePermissionCacheService rolePermissionCacheService; - private static final Integer DEFAULT_PAGE_SIZE = 1000; + private static final Integer DEFAULT_PAGE_SIZE = 2000; @Override @XxlJob("CacheRolePermissionJob") @@ -38,25 +53,16 @@ public class CacheRolePermissionJob extends IJobHandler { .map(e -> JSONObject.parseObject(e, RoleService.PageSaasRoleParam.class)) .orElseGet(() -> RoleService.PageSaasRoleParam.builder().build()); + // 因为角色权限集是重复使用,通过角色找权限集数据量太大,直接查询所有权限集的权限,比较快 + Map> permissionRelations = listPgroupPermissionRelation(); + Integer pageNumber = 1; while (true) { pageSaasRoleParam.setPage(pageNumber++); pageSaasRoleParam.setPageSize(DEFAULT_PAGE_SIZE); - PageResp page = roleService.page(pageSaasRoleParam); - Set roleIds = page.getData().stream() - .map(SaasRoleRes::getId) - .collect(Collectors.toSet()); - RolePermissionCreatedPayload payload = RolePermissionCreatedPayload.builder() - .roleIds(roleIds) - .build(); - - Event event = Event.builder() - .data(payload) - .build(); - - cacheRolePermissionHandler.onEvent(event, null); + store(page.getData(), permissionRelations); if (!page.hasNext()) { break; @@ -65,4 +71,62 @@ public class CacheRolePermissionJob extends IJobHandler { return ReturnT.SUCCESS; } + + private Map> listPgroupPermissionRelation() { + return saasPgroupPermissionRelationService.list().stream() + .collect(Collectors.groupingBy(SaasPgroupPermissionRelation::getGroupId, + Collectors.mapping(e -> SaasPermissionRelationRes.builder() + .featureId(e.getFeatureId()) + .featureType(e.getFeatureType()) + .type(e.getType()) + .build(), Collectors.toList()))); + + } + + private Map> listPermissionGroup(List roleIds) { + + return saasPgroupRoleRelationDao.findByRoleIds(roleIds).stream() + .collect(Collectors.groupingBy(SaasPgroupRoleRelation::getRoleId, + Collectors.mapping(SaasPgroupRoleRelation::getGroupId, Collectors.toSet()))); + } + + private void store(List roles, + Map> permissionRelations) { + + if (CollectionUtils.isEmpty(roles)) { + return; + } + + List roleIds = roles.stream() + .map(SaasRoleRes::getId) + .collect(Collectors.toList()); + Map> roleGroupMap = listPermissionGroup(roleIds); + + roles.forEach(e -> { + Set groupIds = roleGroupMap.get(e.getId()); + if (CollectionUtils.isEmpty(groupIds)) { + return; + } + + List rolePermissions = groupIds.stream() + .map(permissionRelations::get) + .filter(f -> !CollectionUtils.isEmpty(f)) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + + e.setPermissionRelations(rolePermissions); + }); + + List rolePermissions = cacheRolePermissionHandler.resolveRolePermission(roles); + + if (CollectionUtils.isEmpty(rolePermissions)) { + return; + } + + RolePermissionCacheService.StoreRolePermissionParam storeRolePermissionParam = RolePermissionCacheService.StoreRolePermissionParam.builder() + .rolePermissions(rolePermissions) + .build(); + rolePermissionCacheService.store(storeRolePermissionParam); + } } 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 eddcdd13..ea2a8a87 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 @@ -1526,8 +1526,10 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { //组装返回值 //是否超管 - boolean superAdmin = saasRoles.stream() - .anyMatch(e -> RoleTypeEnum.SUPER_ADMIN.getValue().equals(e.getRoleType())); + boolean superAdmin = Optional.ofNullable(saasRoles) + .map(e -> e.stream() + .anyMatch(f -> RoleTypeEnum.SUPER_ADMIN.getValue().equals(f.getRoleType()))) + .orElse(false); workspacePermission.setSuperAdmin(superAdmin); Set allPermissionPoints = Sets.newHashSet(); @@ -1636,7 +1638,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } return productPermissions.stream() - .filter(productPermission -> Objects.equals(productPermission.getCooperateType(), role.getProductUnitType())) + .filter(productPermission -> Objects.equals(productPermission.getCooperateType(), String.valueOf(role.getProductUnitType()))) .filter(productPermission -> rolePermissionFeatureCodes.contains(productPermission.getFeatureCode())) .map(e -> IdentityAuthRes.PermissionPoint.builder() .featureCode(e.getFeatureCode()) From 5e847bea8bc35308b17c540c87d4940e5eafe774 Mon Sep 17 00:00:00 2001 From: lilong Date: Mon, 29 Jul 2024 16:45:48 +0800 Subject: [PATCH 011/112] =?UTF-8?q?feat:(REQ-2720)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E3=80=81=E6=B2=A1=E6=9C=89=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=85=83=E7=B4=A0=E7=9A=84=E6=9D=83=E9=99=90=E7=BC=93=E5=AD=98?= =?UTF-8?q?=EF=BC=8Ckey=E4=BD=BF=E7=94=A8uniCode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/model/req/IdentityAuthReq.java | 16 -- .../model/req/ListSaasRoleGroupParam.java | 1 - .../req/PageProductFeatureRelationReq.java | 7 + .../server/controller/PrivateController.java | 18 ++ ...acheProductSaasFeatureResourceHandler.java | 155 ++++++++++++++ .../CacheRoleSaasFeatureResourceHandler.java | 154 ++++++++++++++ .../job/CacheProductFeatureResourceJob.java | 54 +++++ .../job/CacheRoleFeatureResourceJob.java | 131 ++++++++++++ .../server/job/CacheRolePermissionJob.java | 1 - ...roductSaasFeatureResourceCacheService.java | 66 ++++++ .../RoleSaasFeatureResourceCacheService.java | 67 ++++++ .../service/WorkspaceProductService.java | 45 ++++ .../impl/PermissionQueryServiceImpl.java | 198 ++++++++++-------- ...ctSaasFeatureResourceCacheServiceImpl.java | 174 +++++++++++++++ ...leSaasFeatureResourceCacheServiceImpl.java | 180 ++++++++++++++++ .../impl/WorkspaceProductServiceImpl.java | 45 ++++ 16 files changed, 1207 insertions(+), 105 deletions(-) create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductFeatureResourceJob.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRoleFeatureResourceJob.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductSaasFeatureResourceCacheService.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleSaasFeatureResourceCacheService.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.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 ab35eee3..375dd262 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 @@ -64,22 +64,6 @@ public class IdentityAuthReq { /** 是否使用缓存 - 默认true **/ @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)) { diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListSaasRoleGroupParam.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListSaasRoleGroupParam.java index d343583b..9523c09e 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListSaasRoleGroupParam.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListSaasRoleGroupParam.java @@ -25,5 +25,4 @@ public class ListSaasRoleGroupParam { @CriteriaField(ignore = true) private Boolean needRole; - } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageProductFeatureRelationReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageProductFeatureRelationReq.java index 08a360dd..9bc50bc5 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageProductFeatureRelationReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageProductFeatureRelationReq.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; @@ -40,4 +41,10 @@ public class PageProductFeatureRelationReq implements IPageReq { @CriteriaField(field = "type", operator = Operator.EQ) private Integer type; + + /** + * 查询菜单树节点类型 + */ + @CriteriaField(field = "featureType", operator = Operator.IN) + private List featureResourceTypes; } 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 94b47359..63c0e5dc 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 @@ -22,7 +22,9 @@ import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO; import cn.axzo.tyr.client.model.vo.SaveOrUpdateRoleVO; import cn.axzo.tyr.server.event.outer.CacheWorkspaceProductHandler; import cn.axzo.tyr.server.event.payload.ServicePkgProductCreatedPayload; +import cn.axzo.tyr.server.job.CacheProductFeatureResourceJob; import cn.axzo.tyr.server.job.CacheProductPermissionJob; +import cn.axzo.tyr.server.job.CacheRoleFeatureResourceJob; import cn.axzo.tyr.server.job.CacheRolePermissionJob; import cn.axzo.tyr.server.job.CacheSaasFeatureJob; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; @@ -133,6 +135,10 @@ public class PrivateController { private CacheRolePermissionJob cacheRolePermissionJob; @Autowired private CacheSaasFeatureJob cacheSaasFeatureJob; + @Autowired + private CacheProductFeatureResourceJob cacheProductFeatureResourceJob; + @Autowired + private CacheRoleFeatureResourceJob cacheRoleFeatureResourceJob; /** * 统一层级的roleGroup按照id升序,sort从1递增 @@ -673,6 +679,18 @@ public class PrivateController { return "ok"; } + @PostMapping("/api/private/productSaasFeature/store") + public Object storeProductSaasFeature(@RequestBody ProductSearchListReq request) throws Exception { + cacheProductFeatureResourceJob.execute(JSON.toJSONString(request)); + return "ok"; + } + + @PostMapping("/api/private/roleSaasFeature/store") + public Object storeRoleSaasFeature(@RequestBody RoleService.PageSaasRoleParam request) throws Exception { + cacheRoleFeatureResourceJob.execute(JSON.toJSONString(request)); + return "ok"; + } + @Data @Builder @NoArgsConstructor diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java new file mode 100644 index 00000000..25ea200b --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java @@ -0,0 +1,155 @@ +package cn.axzo.tyr.server.event.inner; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.framework.rocketmq.EventHandler; +import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; +import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload; +import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; +import cn.axzo.tyr.server.service.ProductFeatureRelationService; +import cn.axzo.tyr.server.service.ProductSaasFeatureResourceCacheService; +import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +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 +@Component +public class CacheProductSaasFeatureResourceHandler implements EventHandler, InitializingBean { + + @Autowired + private EventConsumer eventConsumer; + @Autowired + private ProductFeatureRelationService productFeatureRelationService; + @Autowired + private ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService; + @Autowired + private SaasFeatureResourceService saasFeatureResourceService; + + @Override + public void onEvent(Event event, EventConsumer.Context context) { + log.info("begin cached product featureResource handler rocketmq event: {}", event); + ProductPermissionCreatedPayload payload = event.normalizedData(ProductPermissionCreatedPayload.class); + + if (CollectionUtils.isEmpty(payload.getProductModuleIds())) { + return; + } + + PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() + .productModuleIds(payload.getProductModuleIds()) + .type(NEW_FEATURE) + .featureResourceTypes(Lists.newArrayList(FeatureResourceType.MENU.getCode(), + FeatureResourceType.PAGE.getCode(), + FeatureResourceType.MENU_PARTITION_GROUP.getCode(), + FeatureResourceType.GROUP.getCode(), + FeatureResourceType.APP_ENTRY.getCode())) + .build(); + List productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq); + + if (CollectionUtils.isEmpty(productFeatures)) { + return; + } + + List productFeatureResources = resolveProductFeatureResources(productFeatures); + + if (CollectionUtils.isEmpty(productFeatureResources)) { + return; + } + + ProductSaasFeatureResourceCacheService.StoreProductFeatureResourceParam storeProductFeatureResourceParam = ProductSaasFeatureResourceCacheService.StoreProductFeatureResourceParam.builder() + .productFeatureResources(productFeatureResources) + .build(); + productSaasFeatureResourceCacheService.store(storeProductFeatureResourceParam); + + log.info("end cached product featureResource handler rocketmq event: {}", event); + } + + @Override + public void afterPropertiesSet() throws Exception { + eventConsumer.registerHandler(EventTypeEnum.PRODUCT_PERMISSION_CREATED.getEventCode(), this); + } + + public List resolveProductFeatureResources(List productPermissions) { + if (CollectionUtils.isEmpty(productPermissions)) { + return Collections.emptyList(); + } + + Map featureResources = listSaasFeatureResource(productPermissions); + + return productPermissions.stream() + .collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId)) + .entrySet() + .stream() + .map(e -> { + List productFeatureRelations = e.getValue(); + + if (CollectionUtils.isEmpty(productFeatureRelations)) { + return null; + } + + List productFeatureResources = productFeatureRelations.stream() + .map(relation -> { + SaasFeatureResourceResp featureResource = featureResources.get(relation.getFeatureId()); + if (Objects.isNull(featureResource) || StringUtils.isBlank(featureResource.getUniCode())) { + return null; + } + return ProductSaasFeatureResourceCacheService.FeatureResourceDTO.builder() + .featureId(featureResource.getId()) + .featureType(featureResource.getFeatureType()) + .terminal(featureResource.getTerminal()) + .uniCode(featureResource.getUniCode()) + .cooperateType(relation.getDictCode()) + .build(); + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(productFeatureResources)) { + return null; + } + + return ProductSaasFeatureResourceCacheService.ProductFeatureResource.builder() + .productId(e.getKey()) + .featureResources(productFeatureResources) + .build(); + + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + + private Map listSaasFeatureResource(List productPermissions) { + + List featureIds = productPermissions.stream() + .map(SaasProductModuleFeatureRelation::getFeatureId) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyMap(); + } + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(featureIds) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity())); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java new file mode 100644 index 00000000..6b3dcebb --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java @@ -0,0 +1,154 @@ +package cn.axzo.tyr.server.event.inner; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.framework.rocketmq.EventHandler; +import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; +import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; +import cn.axzo.tyr.client.model.res.SaasRoleRes; +import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; +import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService; +import cn.axzo.tyr.server.service.RoleService; +import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +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; + +/** + * 因为菜单树不一定有权限code + * 登录时需要查询菜单树,所以把菜单树缓存起来 + */ +@Slf4j +@Component +public class CacheRoleSaasFeatureResourceHandler implements EventHandler, InitializingBean { + + @Autowired + private EventConsumer eventConsumer; + @Autowired + private RoleService roleService; + @Autowired + private SaasFeatureResourceService saasFeatureResourceService; + @Autowired + private RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService; + + @Override + public void onEvent(Event event, EventConsumer.Context context) { + log.info("begin cached role saasFeatureResource handler rocketmq event: {}", event); + RolePermissionCreatedPayload payload = event.normalizedData(RolePermissionCreatedPayload.class); + + if (CollectionUtils.isEmpty(payload.getRoleIds())) { + return; + } + + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .roleIds(Lists.newArrayList(payload.getRoleIds())) + .needPermissionRelation(true) + .type(NEW_FEATURE) + .featureResourceTypes(Lists.newArrayList(FeatureResourceType.MENU, + FeatureResourceType.PAGE, + FeatureResourceType.MENU_PARTITION_GROUP, + FeatureResourceType.GROUP, + FeatureResourceType.APP_ENTRY)) + .build(); + List roles = roleService.list(listSaasRoleParam); + + if (CollectionUtils.isEmpty(roles)) { + return; + } + + List rolePermissions = resolveRoleFeatureResource(roles); + + if (CollectionUtils.isEmpty(rolePermissions)) { + return; + } + + RoleSaasFeatureResourceCacheService.StoreRoleSaasFeatureResourceParam storeRoleFeatureResourceParam = RoleSaasFeatureResourceCacheService.StoreRoleSaasFeatureResourceParam.builder() + .roleSaasFeatureResources(rolePermissions) + .build(); + roleSaasFeatureResourceCacheService.store(storeRoleFeatureResourceParam); + log.info("end cached role saasFeatureResource handler rocketmq event: {}", event); + } + + @Override + public void afterPropertiesSet() throws Exception { + eventConsumer.registerHandler(EventTypeEnum.ROLE_PERMISSION_CREATED.getEventCode(), this); + } + + public List resolveRoleFeatureResource(List roles) { + + Map featureResources = listSaasFeatureResource(roles); + + return roles.stream() + .map(e -> { + if (CollectionUtils.isEmpty(e.getPermissionRelations())) { + return null; + } + + List permissions = e.getPermissionRelations().stream() + .distinct() + .map(permissionRelation -> { + SaasFeatureResourceResp featureResource = featureResources.get(permissionRelation.getFeatureId()); + if (Objects.isNull(featureResource) || StringUtils.isBlank(featureResource.getUniCode())) { + return null; + } + return RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO.builder() + .featureId(featureResource.getId()) + .featureType(featureResource.getFeatureType()) + .terminal(featureResource.getTerminal()) + .uniCode(featureResource.getUniCode()) + .build(); + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(permissions)) { + return null; + } + + return RoleSaasFeatureResourceCacheService.RoleFeatureResource.builder() + .roleId(e.getId()) + .saasFeatureResources(permissions) + .build(); + + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + private Map listSaasFeatureResource(List roles) { + + List featureIds = roles.stream() + .filter(e -> !CollectionUtils.isEmpty(e.getPermissionRelations())) + .map(SaasRoleRes::getPermissionRelations) + .flatMap(Collection::stream) + .map(SaasPermissionRelationRes::getFeatureId) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyMap(); + } + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(featureIds) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity())); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductFeatureResourceJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductFeatureResourceJob.java new file mode 100644 index 00000000..e70074f7 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductFeatureResourceJob.java @@ -0,0 +1,54 @@ +package cn.axzo.tyr.server.job; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.tyr.client.model.product.ProductSearchListReq; +import cn.axzo.tyr.client.model.product.ProductVO; +import cn.axzo.tyr.server.event.inner.CacheProductSaasFeatureResourceHandler; +import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload; +import cn.axzo.tyr.server.service.ProductService; +import com.alibaba.fastjson.JSONObject; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.IJobHandler; +import com.xxl.job.core.handler.annotation.XxlJob; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +@Component +public class CacheProductFeatureResourceJob extends IJobHandler { + + @Autowired + private CacheProductSaasFeatureResourceHandler cacheProductSaasFeatureResourceHandler; + @Autowired + private ProductService productService; + + @Override + @XxlJob("CacheProductFeatureResourceJob") + public ReturnT execute(String s) throws Exception { + + log.info("start CacheProductFeatureResourceJob, s:{}", s); + ProductSearchListReq productSearchListReq = Optional.ofNullable(s) + .map(e -> JSONObject.parseObject(e, ProductSearchListReq.class)) + .orElseGet(ProductSearchListReq::new); + + Set productIds = productService.list(productSearchListReq).getData() + .stream() + .map(ProductVO::getId) + .collect(Collectors.toSet()); + + ProductPermissionCreatedPayload payload = ProductPermissionCreatedPayload.builder() + .productModuleIds(productIds) + .build(); + + Event event = Event.builder() + .data(payload) + .build(); + cacheProductSaasFeatureResourceHandler.onEvent(event, null); + return ReturnT.SUCCESS; + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRoleFeatureResourceJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRoleFeatureResourceJob.java new file mode 100644 index 00000000..d1eb092c --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRoleFeatureResourceJob.java @@ -0,0 +1,131 @@ +package cn.axzo.tyr.server.job; + +import cn.axzo.foundation.page.PageResp; +import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; +import cn.axzo.tyr.client.model.res.SaasRoleRes; +import cn.axzo.tyr.server.event.inner.CacheRoleSaasFeatureResourceHandler; +import cn.axzo.tyr.server.repository.dao.SaasPgroupRoleRelationDao; +import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation; +import cn.axzo.tyr.server.repository.entity.SaasPgroupRoleRelation; +import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService; +import cn.axzo.tyr.server.service.RoleService; +import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService; +import com.alibaba.fastjson.JSONObject; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.IJobHandler; +import com.xxl.job.core.handler.annotation.XxlJob; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +@Component +public class CacheRoleFeatureResourceJob extends IJobHandler { + + @Autowired + private CacheRoleSaasFeatureResourceHandler cacheRoleSaasFeatureResourceHandler; + @Autowired + private RoleService roleService; + @Autowired + private SaasPgroupPermissionRelationService saasPgroupPermissionRelationService; + @Autowired + private SaasPgroupRoleRelationDao saasPgroupRoleRelationDao; + @Autowired + private RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService; + + private static final Integer DEFAULT_PAGE_SIZE = 2000; + + @Override + @XxlJob("CacheRoleFeatureResourceJob") + public ReturnT execute(String s) throws Exception { + + log.info("start CacheRoleFeatureResourceJob, s:{}", s); + RoleService.PageSaasRoleParam pageSaasRoleParam = Optional.ofNullable(s) + .map(e -> JSONObject.parseObject(e, RoleService.PageSaasRoleParam.class)) + .orElseGet(() -> RoleService.PageSaasRoleParam.builder().build()); + + // 因为角色权限集是重复使用,通过角色找权限集数据量太大,直接查询所有权限集的权限,比较快 + Map> permissionRelations = listPgroupPermissionRelation(); + + Integer pageNumber = 1; + while (true) { + pageSaasRoleParam.setPage(pageNumber++); + pageSaasRoleParam.setPageSize(DEFAULT_PAGE_SIZE); + PageResp page = roleService.page(pageSaasRoleParam); + + store(page.getData(), permissionRelations); + + if (!page.hasNext()) { + break; + } + } + + return ReturnT.SUCCESS; + } + + private Map> listPgroupPermissionRelation() { + return saasPgroupPermissionRelationService.list().stream() + .collect(Collectors.groupingBy(SaasPgroupPermissionRelation::getGroupId, + Collectors.mapping(e -> SaasPermissionRelationRes.builder() + .featureId(e.getFeatureId()) + .featureType(e.getFeatureType()) + .type(e.getType()) + .build(), Collectors.toList()))); + + } + + private Map> listPermissionGroup(List roleIds) { + + return saasPgroupRoleRelationDao.findByRoleIds(roleIds).stream() + .collect(Collectors.groupingBy(SaasPgroupRoleRelation::getRoleId, + Collectors.mapping(SaasPgroupRoleRelation::getGroupId, Collectors.toSet()))); + } + + private void store(List roles, + Map> permissionRelations) { + + if (CollectionUtils.isEmpty(roles)) { + return; + } + + List roleIds = roles.stream() + .map(SaasRoleRes::getId) + .collect(Collectors.toList()); + Map> roleGroupMap = listPermissionGroup(roleIds); + + roles.forEach(e -> { + Set groupIds = roleGroupMap.get(e.getId()); + if (CollectionUtils.isEmpty(groupIds)) { + return; + } + + List rolePermissions = groupIds.stream() + .map(permissionRelations::get) + .filter(f -> !CollectionUtils.isEmpty(f)) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + + e.setPermissionRelations(rolePermissions); + }); + + List roleFeatureResources = cacheRoleSaasFeatureResourceHandler.resolveRoleFeatureResource(roles); + + if (CollectionUtils.isEmpty(roleFeatureResources)) { + return; + } + + RoleSaasFeatureResourceCacheService.StoreRoleSaasFeatureResourceParam storeRolePermissionParam = RoleSaasFeatureResourceCacheService.StoreRoleSaasFeatureResourceParam.builder() + .roleSaasFeatureResources(roleFeatureResources) + .build(); + roleSaasFeatureResourceCacheService.store(storeRolePermissionParam); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java index 2d5556c1..3b0d3bea 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java @@ -22,7 +22,6 @@ import org.springframework.util.CollectionUtils; import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductSaasFeatureResourceCacheService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductSaasFeatureResourceCacheService.java new file mode 100644 index 00000000..71ddb527 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductSaasFeatureResourceCacheService.java @@ -0,0 +1,66 @@ +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.Map; +import java.util.Set; + +public interface ProductSaasFeatureResourceCacheService { + + Map> list(ListProductFeatureResourceParam param); + + void store(StoreProductFeatureResourceParam param); + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class StoreProductFeatureResourceParam { + private List productFeatureResources; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ProductFeatureResource { + private Long productId; + + private List featureResources; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ListProductFeatureResourceParam { + private Set productIds; + + private Set uniCodes; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class FeatureResourceDTO { + + /** + * 协同关系类型 + * 原saas_product_module_feature_relation.dictCode + */ + private String cooperateType; + + private Long featureId; + + private String uniCode; + + private String terminal; + + private Integer featureType; + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleSaasFeatureResourceCacheService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleSaasFeatureResourceCacheService.java new file mode 100644 index 00000000..f5a95828 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleSaasFeatureResourceCacheService.java @@ -0,0 +1,67 @@ +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.Map; +import java.util.Set; + +public interface RoleSaasFeatureResourceCacheService { + + Map> list(ListRoleSaasFeatureResourceParam param); + + void store(StoreRoleSaasFeatureResourceParam param); + + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class StoreRoleSaasFeatureResourceParam { + private List roleSaasFeatureResources; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class RoleFeatureResource { + private Long roleId; + + private List saasFeatureResources; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ListRoleSaasFeatureResourceParam { + private Set roleIds; + + private Set uniCodes; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class SaasFeatureResourceDTO { + + private Long featureId; + + /** + * 资源所属端 + */ + private String terminal; + + /** + * 菜单资源类型1-菜单 2-页面 3-应用入口 4-组件 5-root节点 6-分组 + */ + private Integer featureType; + + private String uniCode; + } +} 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 b5f0441c..494b8098 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 @@ -36,6 +36,26 @@ public interface WorkspaceProductService { */ List listWorkspaceProductPermissionCached(ListWorkspaceProductPermissionCacheParam param); + /** + * 从缓存中查询项目的产品及产品的菜单信息 + * @param param + * @return + */ + List listWorkspaceProductFeatureResourceCached(ListWorkspaceProductFeatureSourceCacheParam param); + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ListWorkspaceProductFeatureSourceCacheParam { + /** + * 项目id + */ + private Set workspaceIds; + + private Set uniCodes; + } + @Data @Builder @NoArgsConstructor @@ -155,5 +175,30 @@ public interface WorkspaceProductService { */ private Set workspaceIds; } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class WorkspaceProductFeatureSource { + + /** + * 项目id + */ + private Long workspaceId; + + private List productFeatureSources; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ProductFeatureSource { + + private Long productId; + + private List featureResources; + } } 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 a508ddf8..2f736f99 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 @@ -21,7 +21,6 @@ import cn.axzo.tyr.client.model.enums.IdentityType; import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO; import cn.axzo.tyr.client.model.req.IdentityAuthReq; import cn.axzo.tyr.client.model.req.NavTreeReq; -import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq; import cn.axzo.tyr.client.model.req.PagePermissionReq; import cn.axzo.tyr.client.model.req.PagePermissionResp; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; @@ -33,7 +32,6 @@ 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; import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam; @@ -47,14 +45,13 @@ 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.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.ProductSaasFeatureResourceCacheService; +import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService; 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.SaasRoleUserRelationService; import cn.axzo.tyr.server.service.TyrSaasAuthService; import cn.axzo.tyr.server.service.WorkspaceProductService; @@ -117,7 +114,8 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { private final SaasFeatureResourceService saasFeatureResourceService; private final SaasRoleUserRelationService saasRoleUserRelationService; private final WorkspaceProductService workspaceProductService; - private final SaasPageElementFeatureResourceRelationService saasPageElementFeatureResourceRelationService; + private final RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService; + private final ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService; @Qualifier("authExecutor") @Autowired @@ -655,39 +653,15 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { private Set listUserPermissionFeatureIds(TreePermissionReq treePermissionReq) { - Set featureCodes = resolveFeatureCodes(treePermissionReq); + List saasRoleUserV2DTOS = listUserPermission(treePermissionReq); - if (StringUtils.isNotBlank(treePermissionReq.getUniCode()) && CollectionUtils.isEmpty(featureCodes)) { - return Collections.emptySet(); - } + List workspaceProductFeatureSources = listWorkspaceProducts(treePermissionReq); + //免授权 + List authFreeFeatureIds = listNotAuthFeatures(treePermissionReq); - IdentityAuthReq identityAuthReq = IdentityAuthReq.builder() - .personId(treePermissionReq.getPersonId()) - .terminal(Lists.newArrayList(treePermissionReq.getTerminal())) - .workspaceOusPairs(treePermissionReq.getWorkspaceOUPairs().stream() - .map(e -> IdentityAuthReq.WorkspaceOuPair.builder() - .ouId(e.getOuId()) - .workspaceId(e.getWorkspaceId()) - .build()) - .collect(Collectors.toList())) - .featureCode(featureCodes) - .build(); - - Set featureTypes = Optional.ofNullable(treePermissionReq.getFeatureResourceTypes()) - .map(e -> e.stream() - .map(FeatureResourceType::getCode) - .collect(Collectors.toSet())) - .orElse(null); - - return saasAuthService.findIdentityAuthMix(identityAuthReq).getPermissions().stream() - .map(IdentityAuthRes.WorkspacePermission::getPermissionPoint) - .flatMap(Collection::stream) - .filter(e -> CollectionUtils.isEmpty(featureTypes) - || featureTypes.contains(e.getFeatureType())) - .map(IdentityAuthRes.PermissionPoint::getFeatureId) - .collect(Collectors.toSet()); - + //取交集确定权限 + return mixFeatureIds(saasRoleUserV2DTOS, workspaceProductFeatureSources, authFreeFeatureIds, treePermissionReq); } private List listNotAuthFeatures(TreePermissionReq treePermissionReq) { @@ -700,22 +674,24 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .collect(Collectors.toList()); } - private List listWorkspaceProducts(TreePermissionReq treePermissionReq, - Set featureCodes) { + private List listWorkspaceProducts(TreePermissionReq treePermissionReq) { //查询租户产品权限点 Set workspaceIds = treePermissionReq.getWorkspaceOUPairs().stream() .map(WorkspaceOUPair::getWorkspaceId) .collect(Collectors.toSet()); - WorkspaceProductService.ListWorkspaceProductPermissionCacheParam listWorkspaceProductPermissionCacheParam = WorkspaceProductService.ListWorkspaceProductPermissionCacheParam + WorkspaceProductService.ListWorkspaceProductFeatureSourceCacheParam listWorkspaceProductFeatureSourceCacheParam = WorkspaceProductService.ListWorkspaceProductFeatureSourceCacheParam .builder() .workspaceIds(workspaceIds) - .featureCodes(featureCodes) + .uniCodes(Optional.ofNullable(treePermissionReq.getUniCode()) + .map(Sets::newHashSet) + .orElseGet(Sets::newHashSet)) .build(); - return workspaceProductService.listWorkspaceProductPermissionCached(listWorkspaceProductPermissionCacheParam); + + return workspaceProductService.listWorkspaceProductFeatureResourceCached(listWorkspaceProductFeatureSourceCacheParam); } - private List listUserPermission(TreePermissionReq treePermissionReq, Set featureCodes) { + private List listUserPermission(TreePermissionReq treePermissionReq) { List workspaceOuPairs = treePermissionReq.getWorkspaceOUPairs().stream() .map(e -> ListRoleUserRelationParam.WorkspaceOuPair.builder() .workspaceId(e.getWorkspaceId()) @@ -727,82 +703,130 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .personId(treePermissionReq.getPersonId()) .workspaceOuPairs(Lists.newArrayList(workspaceOuPairs)) .needRole(true) - .terminal(treePermissionReq.getTerminal()) .build(); return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream() .filter(e -> e.getSaasRole() != null) .collect(Collectors.toList()); } - private Set resolveFeatureCodes(TreePermissionReq treePermissionReq) { - if (StringUtils.isBlank(treePermissionReq.getUniCode())) { - return Collections.emptySet(); + private Map> listRoleFeatureResource(List saasRoleUsers, + TreePermissionReq treePermissionReq) { + + Set roleIds = saasRoleUsers.stream() + .map(SaasRoleUserV2DTO::getRoleId) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(roleIds)) { + return Collections.emptyMap(); } - PageElementFeatureResourceRelationReq pageElementFeatureResourceRelationReq = PageElementFeatureResourceRelationReq.builder() - .featureResourceUniCodes(Sets.newHashSet(treePermissionReq.getUniCode())) + RoleSaasFeatureResourceCacheService.ListRoleSaasFeatureResourceParam listRoleSaasFeatureResourceParam = RoleSaasFeatureResourceCacheService.ListRoleSaasFeatureResourceParam.builder() + .roleIds(roleIds) + .uniCodes(Optional.ofNullable(treePermissionReq.getUniCode()) + .map(Sets::newHashSet) + .orElseGet(Sets::newHashSet)) .build(); - return saasPageElementFeatureResourceRelationService.list(pageElementFeatureResourceRelationReq) - .stream() - .map(SaasPageElementFeatureResourceRelation::getPageElementCode) - .collect(Collectors.toSet()); + return roleSaasFeatureResourceCacheService.list(listRoleSaasFeatureResourceParam); } private Set mixFeatureIds(List saasRoleUsers, - List workspaceProducts, - List authFreeFeatureIds) { + List workspaceProducts, + List authFreeFeatureIds, + TreePermissionReq treePermissionReq) { - Map workspaceProductMap = workspaceProducts.stream() - .collect(Collectors.toMap(WorkspaceProductService.WorkspaceProduct::getWorkspaceId, Function.identity())); + Map> workspaceProductMap = workspaceProducts.stream() + .collect(Collectors.toMap(WorkspaceProductService.WorkspaceProductFeatureSource::getWorkspaceId, WorkspaceProductService.WorkspaceProductFeatureSource::getProductFeatureSources)); + + Map> roleFeatureResourceMap = listRoleFeatureResource(saasRoleUsers, treePermissionReq); + + Set featureTypes = Optional.ofNullable(treePermissionReq.getFeatureResourceTypes()) + .map(e -> e.stream().map(FeatureResourceType::getCode).collect(Collectors.toSet())) + .orElseGet(Sets::newHashSet); 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()); + List productFeatureSources = workspaceProductMap.get(roleUser.getSaasRoleUser().getWorkspaceId()) + .stream() + .map(WorkspaceProductService.ProductFeatureSource::getFeatureResources) + .flatMap(Collection::stream) + .filter(e -> StringUtils.isBlank(treePermissionReq.getTerminal()) + || Objects.equals(e.getTerminal(), treePermissionReq.getTerminal())) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(productFeatureSources)) { + return null; + } SaasRoleUserV2DTO.SaasRole saasRole = roleUser.getSaasRole(); - if (RoleTypeEnum.isAdmin(saasRole.getRoleType())) { - return resolveAdminRole(workspaceProduct, saasRole); - } - return resolveNormalRole(workspaceProduct, saasRole, authFreeFeatureIds); + + Set adminFeatureIds = resolveAdminRole(productFeatureSources, saasRole); + Set notAuthFeatureIds = resolveNotAuthFeatureIds(productFeatureSources, authFreeFeatureIds); + + List roleFeatureResources = roleFeatureResourceMap.get(saasRole.getId()).stream() + .filter(e -> StringUtils.isBlank(treePermissionReq.getTerminal()) + || Objects.equals(e.getTerminal(), treePermissionReq.getTerminal())) + .filter(e -> CollectionUtils.isEmpty(featureTypes) || featureTypes.contains(e.getFeatureType())) + .collect(Collectors.toList()); + + Set normalFeatureIds = resolveNormalRole(productFeatureSources, saasRole, roleFeatureResources); + + Set allFeatureIds = Sets.newHashSet(); + allFeatureIds.addAll(adminFeatureIds); + allFeatureIds.addAll(notAuthFeatureIds); + allFeatureIds.addAll(normalFeatureIds); + + return allFeatureIds; }) + .filter(Objects::nonNull) .flatMap(Collection::stream) .collect(Collectors.toSet()); } - private List resolveAdminRole(WorkspaceProductService.WorkspaceProduct workspaceProduct, + private Set resolveAdminRole(List productFeatureSources, SaasRoleUserV2DTO.SaasRole saasRole) { + if (!RoleTypeEnum.isAdmin(saasRole.getRoleType())) { + return Collections.emptySet(); + } + //超管和管理员 直接取和角色类型匹配的租户产品权限 - return workspaceProduct.getSaasProductModuleFeatureRelations().stream() - .filter(f -> Objects.equals(f.getDictCode(), saasRole.getProductUnitType().toString()) + return productFeatureSources.stream() + .filter(e -> Objects.equals(e.getCooperateType(), saasRole.getProductUnitType().toString()) || !NumberUtil.isPositiveNumber(saasRole.getProductUnitType())) - .map(SaasProductModuleFeatureRelation::getFeatureId) - .collect(Collectors.toList()); + .map(ProductSaasFeatureResourceCacheService.FeatureResourceDTO::getFeatureId) + .collect(Collectors.toSet()); } - private List resolveNormalRole(WorkspaceProductService.WorkspaceProduct workspaceProduct, + private Set resolveNormalRole(List 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); + List roleFeatureResources) { - return workspaceProduct.getSaasProductModuleFeatureRelations().stream() - .filter(f -> Objects.equals(f.getDictCode(), saasRole.getProductUnitType().toString()) + if (CollectionUtils.isEmpty(roleFeatureResources)) { + return Collections.emptySet(); + } + + Set roleFeatureIds = roleFeatureResources.stream() + .map(RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO::getFeatureId) + .collect(Collectors.toSet()); + + return workspaceProduct.stream() + .filter(e -> Objects.equals(e.getCooperateType(), saasRole.getProductUnitType().toString()) || !NumberUtil.isPositiveNumber(saasRole.getProductUnitType())) - .map(SaasProductModuleFeatureRelation::getFeatureId) - .filter(id -> roleFeatureIds.contains(id) || authFreeFeatureIds.contains(id)) - .collect(Collectors.toList()); + .map(ProductSaasFeatureResourceCacheService.FeatureResourceDTO::getFeatureId) + .filter(roleFeatureIds::contains) + .collect(Collectors.toSet()); + } + + private Set resolveNotAuthFeatureIds(List workspaceProduct, + List authFreeFeatureIds) { + + if (CollectionUtils.isEmpty(authFreeFeatureIds)) { + return Collections.emptySet(); + } + + return workspaceProduct.stream() + .map(ProductSaasFeatureResourceCacheService.FeatureResourceDTO::getFeatureId) + .filter(authFreeFeatureIds::contains) + .collect(Collectors.toSet()); } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java new file mode 100644 index 00000000..59c233ee --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java @@ -0,0 +1,174 @@ +package cn.axzo.tyr.server.service.impl; + +import cn.axzo.foundation.exception.Axssert; +import cn.axzo.pokonyan.config.redis.RedisClient; +import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq; +import cn.axzo.tyr.server.event.inner.CacheProductSaasFeatureResourceHandler; +import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; +import cn.axzo.tyr.server.service.ProductFeatureRelationService; +import cn.axzo.tyr.server.service.ProductSaasFeatureResourceCacheService; +import cn.hutool.core.lang.Pair; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +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.dao.DataAccessException; +import org.springframework.data.redis.core.RedisOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.SessionCallback; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static cn.axzo.tyr.server.config.exception.BizResultCode.REDIS_PRODUCT_NOT_NULL; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; + +@Slf4j +@Service +public class ProductSaasFeatureResourceCacheServiceImpl implements ProductSaasFeatureResourceCacheService { + + private static final String PRODUCT_SAAS_FEATURE_RESOURCE_KEY = "product:feature:resource:%s"; + + @Autowired + private RedisTemplate redisTemplate; + @Autowired + private ProductFeatureRelationService productFeatureRelationService; + @Autowired + private CacheProductSaasFeatureResourceHandler cacheProductSaasFeatureResourceHandler; + + @Value("${product.feature.resouce.expire:180}") + private Long expireInDays; + + @Override + public Map> list(ListProductFeatureResourceParam param) { + if (CollectionUtils.isEmpty(param.getProductIds())) { + return Collections.emptyMap(); + } + Map> featureResourceCached = listProductFeatureResourceCached(param); + + fillCacheProductFeatureResource(param, featureResourceCached); + + return featureResourceCached; + } + + @Override + public void store(StoreProductFeatureResourceParam param) { + Axssert.check(param.getProductFeatureResources().stream().allMatch(e -> Objects.nonNull(e.getProductId())), REDIS_PRODUCT_NOT_NULL); + + redisTemplate.executePipelined(new SessionCallback() { + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + + for (ProductFeatureResource productFeatureResource : param.getProductFeatureResources()) { + String redisKey = getKey(productFeatureResource.getProductId()); + + Map redisValues = productFeatureResource.getFeatureResources().stream() + .collect(Collectors.groupingBy(FeatureResourceDTO::getUniCode)) + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); + + RedisClient.HashOps.hPutAll(redisKey, redisValues); + redisTemplate.expire(redisKey, expireInDays, TimeUnit.DAYS); + log.info("succeed to store product featureResource: redisKey:{} value:{}", redisKey, redisValues); + } + return null; + } + }); + } + + private Map> listProductFeatureResourceCached(ListProductFeatureResourceParam param) { + + List redisValues = redisTemplate.executePipelined(new SessionCallback() { + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + + for (Long productId : param.getProductIds()) { + String redisKey = getKey(productId); + + if (CollectionUtils.isEmpty(param.getUniCodes())) { + RedisClient.HashOps.hGetAll(redisKey); + } else { + RedisClient.HashOps.hMultiGet(redisKey, Lists.newArrayList(param.getUniCodes())); + } + + } + return null; + } + }); + + return Streams.zip(param.getProductIds().stream(), + redisValues.stream(), + (productId, redisValue) -> { + + if (Objects.isNull(redisValue)) { + return null; + } + + if (CollectionUtils.isEmpty(param.getUniCodes())) { + List featureResources = (List) ((Map) redisValue).values().stream() + .flatMap(e -> JSONArray.parseArray(JSONArray.toJSONString(e), FeatureResourceDTO.class).stream()) + .collect(Collectors.toList()); + + return Pair.of(productId, featureResources); + } + + List featureResources = (List) ((List) redisValue).stream() + .filter(Objects::nonNull) + .flatMap(e -> JSONArray.parseArray((String) e, FeatureResourceDTO.class).stream()) + .collect(Collectors.toList()); + + return Pair.of(productId, featureResources); + + }) + .filter(Objects::nonNull) + .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); + } + + private void fillCacheProductFeatureResource(ListProductFeatureResourceParam param, + Map> featureResourceCached) { + + Sets.SetView difference = Sets.difference(param.getProductIds(), featureResourceCached.keySet()); + if (difference.isEmpty()) { + return; + } + + PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() + .productModuleIds(difference) + .type(NEW_FEATURE) + .featureResourceTypes(Lists.newArrayList(FeatureResourceType.MENU.getCode(), + FeatureResourceType.PAGE.getCode(), + FeatureResourceType.MENU_PARTITION_GROUP.getCode(), + FeatureResourceType.GROUP.getCode(), + FeatureResourceType.APP_ENTRY.getCode())) + .build(); + List productPermissions = productFeatureRelationService.list(pageProductFeatureRelationReq); + + List productFeatureResources = cacheProductSaasFeatureResourceHandler.resolveProductFeatureResources(productPermissions); + if (CollectionUtils.isEmpty(productFeatureResources)) return; + + StoreProductFeatureResourceParam storeProductFeatureResourceParam = StoreProductFeatureResourceParam.builder() + .productFeatureResources(productFeatureResources) + .build(); + store(storeProductFeatureResourceParam); + + Map> productFeatureResourceMap = productFeatureResources.stream() + .collect(Collectors.toMap(ProductFeatureResource::getProductId, ProductFeatureResource::getFeatureResources)); + featureResourceCached.putAll(productFeatureResourceMap); + } + + private String getKey(Object... params) { + return String.format(PRODUCT_SAAS_FEATURE_RESOURCE_KEY, params); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java new file mode 100644 index 00000000..019d85e8 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java @@ -0,0 +1,180 @@ +package cn.axzo.tyr.server.service.impl; + +import cn.axzo.foundation.exception.Axssert; +import cn.axzo.pokonyan.config.redis.RedisClient; +import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.client.model.res.SaasRoleRes; +import cn.axzo.tyr.server.event.inner.CacheRoleSaasFeatureResourceHandler; +import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService; +import cn.axzo.tyr.server.service.RoleService; +import cn.hutool.core.lang.Pair; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +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.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.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static cn.axzo.tyr.server.config.exception.BizResultCode.REDIS_ROLE_NOT_NULL; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; + +@Slf4j +@Service +public class RoleSaasFeatureResourceCacheServiceImpl implements RoleSaasFeatureResourceCacheService { + + private static final String ROLE_SAAS_FEATURE_RESOURCE_KEY = "role:feature:resource:%s"; + + @Autowired + protected StringRedisTemplate redisTemplate; + @Autowired + private RoleService roleService; + @Autowired + private CacheRoleSaasFeatureResourceHandler cacheRoleSaasFeatureResourceHandler; + + + /** 角色菜单缓存过期时间 **/ + @Value("${role.feature.resource.expire:180}") + private Long expireInDays; + + @Override + public Map> list(ListRoleSaasFeatureResourceParam param) { + if (CollectionUtils.isEmpty(param.getRoleIds())) { + return Collections.emptyMap(); + } + + Map> featureResources = listRoleSaasFeatureResourceCached(param); + + fillCacheRoleFeatureResources(param, featureResources); + return featureResources; + } + + @Override + public void store(StoreRoleSaasFeatureResourceParam param) { + Axssert.check(param.getRoleSaasFeatureResources().stream().allMatch(e -> Objects.nonNull(e.getRoleId())), REDIS_ROLE_NOT_NULL); + + redisTemplate.executePipelined((RedisCallback) connection -> { + + connection.openPipeline(); + + for (RoleFeatureResource roleFeatureResource : param.getRoleSaasFeatureResources()) { + String redisKey = getKey(roleFeatureResource.getRoleId()); + + Map redisValues = roleFeatureResource.getSaasFeatureResources().stream() + .collect(Collectors.groupingBy(SaasFeatureResourceDTO::getUniCode)) + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); + + RedisClient.HashOps.hPutAll(redisKey, redisValues); + redisTemplate.expire(redisKey, expireInDays, TimeUnit.DAYS); + log.info("succeed to store role featureResource: redisKey:{} value:{}", redisKey, redisValues); + } + return null; + }); + } + + private Map> listRoleSaasFeatureResourceCached(ListRoleSaasFeatureResourceParam param) { + + List redisValues = redisTemplate.executePipelined(new SessionCallback() { + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + + for (Long roleId : param.getRoleIds()) { + String redisKey = getKey(roleId); + if (CollectionUtils.isEmpty(param.getUniCodes())) { + RedisClient.HashOps.hGetAll(redisKey); + } else { + RedisClient.HashOps.hMultiGet(redisKey, Lists.newArrayList(param.getUniCodes())); + } + } + return null; + } + }); + + return Streams.zip(param.getRoleIds().stream(), + redisValues.stream(), + (roleId, redisValue) -> { + + if (Objects.isNull(redisValue)) { + return null; + } + + if (CollectionUtils.isEmpty(param.getUniCodes())) { + + List featureResources = (List) ((Map) redisValue).values().stream() + .flatMap(e -> JSONArray.parseArray(JSONArray.toJSONString(e), SaasFeatureResourceDTO.class).stream()) + .collect(Collectors.toList()); + return Pair.of(roleId, featureResources); + } + + List featureResources = (List) ((List) redisValue).stream() + .filter(Objects::nonNull) + .flatMap(e -> JSONArray.parseArray((String) e, SaasFeatureResourceDTO.class).stream()) + .collect(Collectors.toList()); + return Pair.of(roleId, featureResources); + + }) + .filter(Objects::nonNull) + .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); + } + + private void fillCacheRoleFeatureResources(ListRoleSaasFeatureResourceParam param, + Map> featureResources) { + + Sets.SetView difference = Sets.difference(param.getRoleIds(), featureResources.keySet()); + if (difference.isEmpty()) { + return; + } + + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .roleIds(Lists.newArrayList(difference)) + .needPermissionRelation(true) + .type(NEW_FEATURE) + .featureResourceTypes(Lists.newArrayList(FeatureResourceType.MENU, + FeatureResourceType.PAGE, + FeatureResourceType.MENU_PARTITION_GROUP, + FeatureResourceType.GROUP, + FeatureResourceType.APP_ENTRY)) + .build(); + List roles = roleService.list(listSaasRoleParam); + + if (CollectionUtils.isEmpty(roles)) { + return; + } + + List roleFeatureResources = cacheRoleSaasFeatureResourceHandler.resolveRoleFeatureResource(roles); + + if (CollectionUtils.isEmpty(roleFeatureResources)) { + return; + } + + StoreRoleSaasFeatureResourceParam storeRolePermissionParam = StoreRoleSaasFeatureResourceParam.builder() + .roleSaasFeatureResources(roleFeatureResources) + .build(); + store(storeRolePermissionParam); + + Map> rolePermissionMap = roleFeatureResources.stream() + .collect(Collectors.toMap(RoleSaasFeatureResourceCacheService.RoleFeatureResource::getRoleId, RoleSaasFeatureResourceCacheService.RoleFeatureResource::getSaasFeatureResources)); + featureResources.putAll(rolePermissionMap); + } + + private String getKey(Object... params) { + return String.format(ROLE_SAAS_FEATURE_RESOURCE_KEY, params); + } +} 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 b8cdf79a..3ce49afd 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 @@ -11,6 +11,7 @@ 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.ProductPermissionCacheService; +import cn.axzo.tyr.server.service.ProductSaasFeatureResourceCacheService; import cn.axzo.tyr.server.service.WorkspaceProductService; import cn.axzo.tyr.server.utils.RpcInternalUtil; import cn.hutool.core.collection.CollectionUtil; @@ -56,6 +57,8 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { private StringRedisTemplate redisTemplate; @Autowired private ProductPermissionCacheService productPermissionCacheService; + @Autowired + private ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService; /** 授权缓存过期时间 **/ @@ -351,4 +354,46 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { return workspaceProducts; } + + @Override + public List listWorkspaceProductFeatureResourceCached(ListWorkspaceProductFeatureSourceCacheParam param) { + Map> workspaceProducts = listWorkspaceProduct(param.getWorkspaceIds()); + + Set productIds = workspaceProducts.values().stream() + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(productIds)) { + return Collections.emptyList(); + } + + ProductSaasFeatureResourceCacheService.ListProductFeatureResourceParam listProductFeatureResourceParam = ProductSaasFeatureResourceCacheService.ListProductFeatureResourceParam.builder() + .productIds(productIds) + .uniCodes(param.getUniCodes()) + .build(); + Map> productFeatureResourceMap = productSaasFeatureResourceCacheService.list(listProductFeatureResourceParam); + + return workspaceProducts.entrySet().stream() + .filter(e -> CollectionUtils.isNotEmpty(e.getValue())) + .map(e -> { + List productFeatureSources = e.getValue().stream() + .map(productId -> { + List featureResources = productFeatureResourceMap.get(productId); + if (CollectionUtils.isEmpty(featureResources)) { + return null; + } + return ProductFeatureSource.builder() + .productId(productId) + .featureResources(featureResources) + .build(); + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + return WorkspaceProductFeatureSource.builder() + .workspaceId(e.getKey()) + .productFeatureSources(productFeatureSources) + .build(); + }) + .collect(Collectors.toList()); + } } From 8d4f04359de8ca228fe650f5822690bc5a5648d2 Mon Sep 17 00:00:00 2001 From: lilong Date: Mon, 29 Jul 2024 17:41:07 +0800 Subject: [PATCH 012/112] =?UTF-8?q?feat:(REQ-2720)=20=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E4=BA=BA=E5=91=98=E4=BF=A1=E6=81=AF=E5=A2=9E=E5=8A=A0=E8=BA=AB?= =?UTF-8?q?=E4=BB=BDid=E8=BF=94=E5=9B=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/service/impl/SaasRoleUserRelationServiceImpl.java | 2 ++ .../cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) 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 c16cb012..d207802d 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 @@ -209,6 +209,8 @@ public class SaasRoleUserRelationServiceImpl extends ServiceImpl Date: Mon, 29 Jul 2024 18:31:13 +0800 Subject: [PATCH 013/112] =?UTF-8?q?feat:(REQ-2720)=20=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E6=A0=91=E6=97=B6=EF=BC=8C=E5=8F=AF=E4=BB=A5?= =?UTF-8?q?=E5=A2=9E=E9=87=8F=E4=BF=AE=E8=A1=A5=E7=AB=AF=E7=9A=84=E8=8F=9C?= =?UTF-8?q?=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/req/PageSaasFeatureResourceReq.java | 3 + .../server/controller/PrivateController.java | 8 ++ .../event/inner/CacheSaasFeatureHandler.java | 10 +- .../CacheSaasFeatureResourceHandler.java | 6 +- .../tyr/server/job/CacheSaasFeatureJob.java | 36 ++++--- .../service/SaasFeatureResourceService.java | 8 ++ .../impl/SaasFeatureResourceServiceImpl.java | 98 ++++++++++++++++++- 7 files changed, 148 insertions(+), 21 deletions(-) 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 02de287b..c2f809bd 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 @@ -70,6 +70,9 @@ public class PageSaasFeatureResourceReq implements IPageReq { @CriteriaField(ignore = true) private Set paths; + @CriteriaField(field = "terminal", operator = Operator.IN) + private Set terminals; + public PageResp toEmpty() { return PageResp.builder() .current(this.getPage()) 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 63c0e5dc..e14851e0 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 @@ -46,6 +46,7 @@ import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductPermissionCacheService; 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; @@ -139,6 +140,8 @@ public class PrivateController { private CacheProductFeatureResourceJob cacheProductFeatureResourceJob; @Autowired private CacheRoleFeatureResourceJob cacheRoleFeatureResourceJob; + @Autowired + private SaasFeatureResourceService saasFeatureResourceService; /** * 统一层级的roleGroup按照id升序,sort从1递增 @@ -691,6 +694,11 @@ public class PrivateController { return "ok"; } + @PostMapping("/api/private/saasFeature/list") + public Object listSaasFeature(@RequestBody SaasFeatureResourceService.ListSaasFeatureResourceCache request) throws Exception { + return saasFeatureResourceService.listCache(request); + } + @Data @Builder @NoArgsConstructor diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java index 6980f956..65e7174a 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java @@ -8,7 +8,7 @@ import cn.axzo.tyr.server.event.payload.SaasFeatureUpsertPayload; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.entity.SaasFeature; import cn.axzo.tyr.server.service.SaasFeatureResourceService; -import cn.axzo.tyr.server.service.SaasFeatureService; +import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; @@ -45,17 +45,19 @@ public class CacheSaasFeatureHandler implements EventHandler, InitializingBean { .eq(SaasFeature::getTerminal, payload.getTerminal()) .list() .stream() - .map(e -> SaasFeatureResourceService.SaasFeatureResourceCache - .builder() + .map(e -> SaasFeatureResourceService.SaasFeatureResourceCache.builder() .featureId(e.getId()) .notAuth(DelegatedType.notAuth(e.getDelegatedType())) .build()) .collect(Collectors.toList()); - SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() + SaasFeatureResourceService.SaasFeatureResourceDTO saasFeatureResourceDTO = SaasFeatureResourceService.SaasFeatureResourceDTO.builder() .terminal(payload.getTerminal()) .features(saasFeatures) .build(); + SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() + .saasFeatureResources(Lists.newArrayList(saasFeatureResourceDTO)) + .build(); saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java index 9bfc9489..0f2779aa 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java @@ -7,6 +7,7 @@ import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; @@ -50,10 +51,13 @@ public class CacheSaasFeatureResourceHandler implements EventHandler, Initializi .build()) .collect(Collectors.toList()); - SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() + SaasFeatureResourceService.SaasFeatureResourceDTO saasFeatureResourceDTO = SaasFeatureResourceService.SaasFeatureResourceDTO.builder() .terminal(payload.getTerminal()) .features(saasFeatures) .build(); + SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() + .saasFeatureResources(Lists.newArrayList(saasFeatureResourceDTO)) + .build(); saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); log.info("end cached saasFeatureResource handler rocketmq event: {}", event); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java index b0d0c165..89895be7 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java @@ -52,13 +52,17 @@ public class CacheSaasFeatureJob extends IJobHandler { .notAuth(DelegatedType.notAuth(e.getDelegatedType())) .build(), Collectors.toList()))); - saasFeatures.entrySet().forEach(e -> { - SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() - .terminal(e.getKey()) - .features(e.getValue()) - .build(); - saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); - }); + List saasFeatureResources = saasFeatures.entrySet().stream() + .map(e -> SaasFeatureResourceService.SaasFeatureResourceDTO.builder() + .terminal(e.getKey()) + .features(e.getValue()) + .build()) + .collect(Collectors.toList()); + + SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() + .saasFeatureResources(saasFeatureResources) + .build(); + saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); } private void cacheSaasFeatureResource(String terminal) { @@ -75,12 +79,16 @@ public class CacheSaasFeatureJob extends IJobHandler { .notAuth(SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) .build(), Collectors.toList()))); - saasFeatureResources.entrySet().forEach(e -> { - SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() - .terminal(e.getKey()) - .features(e.getValue()) - .build(); - saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); - }); + List featureResources = saasFeatureResources.entrySet().stream() + .map(e -> SaasFeatureResourceService.SaasFeatureResourceDTO.builder() + .terminal(e.getKey()) + .features(e.getValue()) + .build()) + .collect(Collectors.toList()); + + SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() + .saasFeatureResources(featureResources) + .build(); + saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); } } 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 0ca7f997..8a3fcc7d 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 @@ -74,6 +74,14 @@ public interface SaasFeatureResourceService extends IService saasFeatureResources; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class SaasFeatureResourceDTO { private String terminal; private List features; 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 d9bf13de..7c114ed7 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 @@ -15,6 +15,7 @@ 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.common.enums.PageElementFeatureResourceRelationTypeEnum; +import cn.axzo.tyr.client.model.enums.DelegatedType; import cn.axzo.tyr.client.model.req.DeleteFeatureResourceReq; import cn.axzo.tyr.client.model.req.FeatureComponentSaveReq; import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; @@ -33,7 +34,9 @@ import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; 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.SaasFeatureDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; +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; @@ -106,6 +109,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl redisTemplate; @@ -704,12 +708,38 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl() { + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + + for (SaasFeatureResourceDTO saasFeatureResource : param.getSaasFeatureResources()) { + String redisKey = getKey(saasFeatureResource.getTerminal()); + String redisValue = JSONObject.toJSONString(saasFeatureResource.getFeatures()); + RedisClient.StringOps.setEx(redisKey, redisValue, + expireInDays, TimeUnit.DAYS); + log.info("succeed to store featureResource: redisKey:{} value:{}", redisKey, redisValue); + } + return null; + } + }); } @Override public Map> listCache(ListSaasFeatureResourceCache param) { + if (org.springframework.util.CollectionUtils.isEmpty(param.getTerminals())) { + return Collections.emptyMap(); + } + Map> featureSourceCached = listFeatureSourceCached(param); + + fillCacheFeatureSources(param, featureSourceCached); + + return featureSourceCached; + + } + + private Map> listFeatureSourceCached(ListSaasFeatureResourceCache param) { + List redisValues = redisTemplate.executePipelined(new SessionCallback() { @Override public Object execute(RedisOperations operations) throws DataAccessException { @@ -737,6 +767,70 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl> featureSourceCached) { + + Sets.SetView difference = Sets.difference(param.getTerminals(), featureSourceCached.keySet()); + if (difference.isEmpty()) { + return; + } + + List saasFeatureResources = resolveSaasFeature(difference); + + SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() + .saasFeatureResources(saasFeatureResources) + .build(); + storeCache(storeSaasFeatureResourceCache); + + Map> featureSourceMap = saasFeatureResources.stream() + .collect(Collectors.toMap(SaasFeatureResourceDTO::getTerminal, SaasFeatureResourceDTO::getFeatures)); + featureSourceCached.putAll(featureSourceMap); + } + + private List resolveSaasFeature(Set terminals) { + Map> saasFeatures = saasFeatureDao.lambdaQuery() + .in(SaasFeature::getTerminal, terminals) + .list() + .stream() + .collect(Collectors.groupingBy(SaasFeature::getTerminal, + Collectors.mapping(e -> SaasFeatureResourceService.SaasFeatureResourceCache + .builder() + .featureId(e.getId()) + .notAuth(DelegatedType.notAuth(e.getDelegatedType())) + .build(), Collectors.toList()))); + + List allFeatureResources = Lists.newArrayList(); + List featureResources = saasFeatures.entrySet().stream() + .map(e -> SaasFeatureResourceDTO.builder() + .terminal(e.getKey()) + .features(e.getValue()) + .build()) + .collect(Collectors.toList()); + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .terminals(terminals) + .build(); + + List saasFeatureResources = list(pageSaasFeatureResourceReq) + .stream() + .collect(Collectors.groupingBy(SaasFeatureResourceResp::getTerminal, + Collectors.mapping(e -> SaasFeatureResourceService.SaasFeatureResourceCache + .builder() + .featureId(e.getId()) + .notAuth(SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) + .build(), Collectors.toList()))) + .entrySet().stream() + .map(e -> SaasFeatureResourceDTO.builder() + .terminal(e.getKey()) + .features(e.getValue()) + .build()) + .collect(Collectors.toList()); + + allFeatureResources.addAll(featureResources); + allFeatureResources.addAll(saasFeatureResources); + return allFeatureResources; + } + private String getKey(Object... params) { return String.format(SAAS_FEATURE_RESOURCE_KEY, params); } From 4ad6bd73061a034e52ede0f10867179d0d19e196 Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 30 Jul 2024 13:50:42 +0800 Subject: [PATCH 014/112] =?UTF-8?q?feat:(REQ-2720)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E6=9F=A5=E8=AF=A2=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProductFeatureRelationServiceImpl.java | 2 ++ .../server/service/impl/RoleServiceImpl.java | 36 +++++++++++++++++++ .../service/impl/TyrSaasAuthServiceImpl.java | 3 +- 3 files changed, 40 insertions(+), 1 deletion(-) 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 072cc28d..8e0f0258 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 @@ -106,6 +106,8 @@ public class ProductFeatureRelationServiceImpl extends ServiceImpl @Value("${groupLeader.code:projectTeamGPLeader}") private String groupLeaderCode; + @Autowired + private final MqProducer mqProducer; + + private static final String TARGET_TYPE = "saasFeatureResourceId"; + @Override public List queryByIdentityIdType(Long identityId, Integer identityType, Long workspaceId, Long ouId, Boolean includePermissionGroup) { // 查询人关联的角色id @@ -1335,6 +1347,30 @@ public class RoleServiceImpl extends ServiceImpl } } } + + if (CollectionUtils.isEmpty(req)) { + return; + } + // 入参的terminal不是必填,所以根据第一个id查询terminal,目前不会是所有端一起更新 + PageSaasFeatureResourceReq listSaasFeatureResourceParam = PageSaasFeatureResourceReq.builder() + .ids(Lists.newArrayList(req.get(0).getFeatureId())) + .build(); + String terminal = saasFeatureResourceService.list(listSaasFeatureResourceParam).stream() + .findFirst() + .map(SaasFeatureResourceResp::getTerminal) + .orElse(null); + if (StringUtils.isBlank(terminal)) { + return; + } + + Event event = Event.builder() + .targetType(TARGET_TYPE) + .eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode()) + .data(SaasFeatureResourceUpsertPayload.builder() + .terminal(terminal) + .build()) + .build(); + mqProducer.send(event); } @Override 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 82b83c43..ce43f82e 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 @@ -1572,8 +1572,9 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } //聚合超管和管理员的权限点: 直接取角色标签和产品标签相匹配的权限点 - Set productUnitTypes = adminRoles.stream() + Set productUnitTypes = adminRoles.stream() .map(SaasRoleUserV2DTO.SaasRole::getProductUnitType) + .map(String::valueOf) .collect(Collectors.toSet()); return productPermissions.stream() From 0a00c2fb39c8bc0121724a197a1f2d559bb2c8cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Tue, 30 Jul 2024 14:15:56 +0800 Subject: [PATCH 015/112] =?UTF-8?q?fix(REQ-2300):=20=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E8=A7=92=E8=89=B2code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/data/object/DataObjectRuleBO.java | 12 ++++++++ .../entity/DataObjectRuleScope.java | 4 +++ .../service/impl/DataObjectServiceImpl.java | 28 +++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/data/object/DataObjectRuleBO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/data/object/DataObjectRuleBO.java index fc5e43ba..f09eddd7 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/data/object/DataObjectRuleBO.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/data/object/DataObjectRuleBO.java @@ -39,6 +39,10 @@ public class DataObjectRuleBO { * 岗位/角色id */ private List relationId; + /** + * 岗位列表 + */ + private List jobs; /** * 行级数据权限(单选) 1:仅本人数据 2:本人及下属数据 3:仅本部门数据 4:本部门及以下数据 @@ -51,4 +55,12 @@ public class DataObjectRuleBO { */ private List attributePermissionBOList; + @Data + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class JobInfo{ + private Long id; + private String code; + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/DataObjectRuleScope.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/DataObjectRuleScope.java index 03e4673b..5b35d9e4 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/DataObjectRuleScope.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/DataObjectRuleScope.java @@ -36,4 +36,8 @@ public class DataObjectRuleScope extends BaseOperatorEntity * 岗位id/角色id */ private Long relationId; + /** + * 岗位编码 + */ + private String relationCode; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java index e60bcdea..dd52c28f 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java @@ -36,6 +36,7 @@ import cn.hutool.core.collection.CollUtil; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.metadata.IPage; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import groovy.lang.Tuple2; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -92,6 +93,7 @@ public class DataObjectServiceImpl implements DataObjectService { } List dataObjectRules = DataObjectMapper.INSTANCE.ruleBOs2Rules(req.getDataObjectRuleBOList()); + handleJobs(dataObjectRules, req.getDataObjectRuleBOList()); int size = (CollUtil.isNotEmpty(defaultDataObjectRules) ? defaultDataObjectRules.size() : 0) + (CollUtil.isNotEmpty(dataObjectRules) ? dataObjectRules.size() : 0); @@ -200,6 +202,7 @@ public class DataObjectServiceImpl implements DataObjectService { } List dataObjectRules = DataObjectMapper.INSTANCE.ruleBOs2Rules(req.getDataObjectRuleBOList()); + handleJobs(dataObjectRules, req.getDataObjectRuleBOList()); int size = (CollUtil.isNotEmpty(defaultDataObjectRules) ? defaultDataObjectRules.size() : 0) + (CollUtil.isNotEmpty(dataObjectRules) ? dataObjectRules.size() : 0); List generalObjectRuleList = new ArrayList<>(size); @@ -451,4 +454,29 @@ public class DataObjectServiceImpl implements DataObjectService { return res; } + + private void handleJobs(List dataObjectRules, List dataObjectRuleBOList) { + if (CollectionUtils.isEmpty(dataObjectRules) || CollectionUtils.isEmpty(dataObjectRuleBOList)) { + return; + } + + Map jobInfoMap = Maps.newHashMap(); + for (DataObjectRuleBO ruleBO : dataObjectRuleBOList) { + if (1 == ruleBO.getRuleScopeType() && CollectionUtils.isNotEmpty(ruleBO.getJobs())) { + ruleBO.getJobs().forEach(e -> { + jobInfoMap.put(e.getId(), e); + }); + } + } + + for (DataObjectRule rule : dataObjectRules) { + if (1 == rule.getRuleScopeType() && CollectionUtils.isNotEmpty(rule.getDataObjectRuleScopeList())) { + rule.getDataObjectRuleScopeList().forEach(e -> { + if (Objects.nonNull(e.getRelationId()) && jobInfoMap.containsKey(e.getRelationId())) { + e.setRelationCode(jobInfoMap.get(e.getRelationId()).getCode()); + } + }); + } + } + } } From 934609e657c7c1ffe26a77ed2dd2c2fc0725f938 Mon Sep 17 00:00:00 2001 From: luofu Date: Tue, 30 Jul 2024 14:23:15 +0800 Subject: [PATCH 016/112] =?UTF-8?q?feat(REQ-2488):=20=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E6=8E=A5=E5=8F=A3=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/tyr/client/model/req/ListRoleReq.java | 7 +++++++ .../java/cn/axzo/tyr/server/service/RoleService.java | 8 ++++++++ .../axzo/tyr/server/service/impl/RoleServiceImpl.java | 11 ++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListRoleReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListRoleReq.java index 20688036..5021f8dc 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListRoleReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListRoleReq.java @@ -1,5 +1,6 @@ package cn.axzo.tyr.client.model.req; +import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -72,4 +73,10 @@ public class ListRoleReq { * 是否需要角色对应的用户信息 */ private Boolean needRoleUser; + + /** + * workspaceId和ouId配对查询 + * 例如:((workspaceId = ## and ouId = ##) or (workspaceId = ## and ouId = ##)) + */ + private List workspaceOuPairs; } 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 bf464d0d..144d613d 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 @@ -19,6 +19,7 @@ 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.SaasRoleRes; +import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam; import cn.axzo.tyr.client.model.vo.DeleteRoleVO; import cn.axzo.tyr.client.model.vo.SaasRoleAndGroupVO; import cn.axzo.tyr.client.model.vo.SaasRoleCategoryVO; @@ -183,6 +184,13 @@ public interface RoleService extends IService { */ @CriteriaField(ignore = true) private String terminal; + + /** + * workspaceId和ouId配对查询 + * 例如:((workspaceId = ## and ouId = ##) or (workspaceId = ## and ouId = ##)) + */ + @CriteriaField(ignore = true) + private List workspaceOuPairs; } @SuperBuilder 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 15860b22..7784312a 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 @@ -1137,7 +1137,16 @@ public class RoleServiceImpl extends ServiceImpl public cn.axzo.foundation.page.PageResp page(PageSaasRoleParam param) { QueryWrapper wrapper = QueryWrapperHelper.fromBean(param, SaasRole.class); wrapper.eq("is_delete", 0); - + if (CollectionUtils.isNotEmpty(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, SaasRole.class), wrapper); Map> saasRoleGroups = listRoleGroups(param, page.getRecords()); From ef36265460fd5469724d2c8663317fa99fe4aa2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Tue, 30 Jul 2024 14:25:58 +0800 Subject: [PATCH 017/112] =?UTF-8?q?fix(REQ-2300):=20=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E8=A7=92=E8=89=B2code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/client/model/data/object/DataObjectRuleBO.java | 4 ++++ .../axzo/tyr/server/service/impl/DataObjectServiceImpl.java | 1 + 2 files changed, 5 insertions(+) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/data/object/DataObjectRuleBO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/data/object/DataObjectRuleBO.java index f09eddd7..1688ebc9 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/data/object/DataObjectRuleBO.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/data/object/DataObjectRuleBO.java @@ -39,6 +39,10 @@ public class DataObjectRuleBO { * 岗位/角色id */ private List relationId; + /** + * 岗位code + */ + private List relationCodes; /** * 岗位列表 */ diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java index dd52c28f..8eee2943 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java @@ -447,6 +447,7 @@ public class DataObjectServiceImpl implements DataObjectService { if (CollUtil.isNotEmpty(scopeList1)) { List relationIdList = scopeList1.stream().map(DataObjectRuleScope::getRelationId).collect(Collectors.toList()); e.setRelationId(relationIdList); + e.setRelationCodes(scopeList1.stream().map(DataObjectRuleScope::getRelationCode).filter(StringUtils::isNotBlank).collect(Collectors.toList())); } }); } From 3998210c6ff92276777cddeae1c2b38d34025a98 Mon Sep 17 00:00:00 2001 From: luofu Date: Tue, 30 Jul 2024 16:28:18 +0800 Subject: [PATCH 018/112] =?UTF-8?q?feat(REQ-2488):=20=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E6=8E=A5=E5=8F=A3=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/client/model/req/ListRoleReq.java | 4 ++++ .../cn/axzo/tyr/server/service/RoleService.java | 6 ++++++ .../tyr/server/service/impl/RoleServiceImpl.java | 16 ++++++++++++++-- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListRoleReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListRoleReq.java index 5021f8dc..5817a704 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListRoleReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListRoleReq.java @@ -73,6 +73,10 @@ public class ListRoleReq { * 是否需要角色对应的用户信息 */ private Boolean needRoleUser; + /** + * 是否需要预设角色,因为预设角色的workspaceId和ouId为-1 + */ + private Boolean needPresetRole; /** * workspaceId和ouId配对查询 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 144d613d..7e1f5c7b 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 @@ -167,6 +167,12 @@ public interface RoleService extends IService { @CriteriaField(ignore = true) private Boolean needPermissionRelation; + /** + * 是否需要预设角色,因为预设角色的workspaceId和ouId为-1 + */ + @CriteriaField(ignore = true) + private Boolean needPresetRole; + /** * 查询菜单树节点类型 */ 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 7784312a..8f8f0a7a 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 @@ -110,6 +110,11 @@ import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation. public class RoleServiceImpl extends ServiceImpl implements RoleService { + private static final ListRoleUserRelationParam.WorkspaceOuPair PRESET_WORKSPACE_OU_PAIR = ListRoleUserRelationParam.WorkspaceOuPair.builder() + .ouId(-1L) + .workspaceId(-1L) + .build(); + @Autowired SaasRoleUserRelationDao roleUserRelationDao; @Autowired @@ -1137,9 +1142,16 @@ public class RoleServiceImpl extends ServiceImpl public cn.axzo.foundation.page.PageResp page(PageSaasRoleParam param) { QueryWrapper wrapper = QueryWrapperHelper.fromBean(param, SaasRole.class); wrapper.eq("is_delete", 0); - if (CollectionUtils.isNotEmpty(param.getWorkspaceOuPairs())) { + List workspaceOuPairs = Lists.newArrayList(); + if (Boolean.TRUE.equals(param.getNeedPresetRole())) { + workspaceOuPairs.add(PRESET_WORKSPACE_OU_PAIR); + } + CollectionUtils.addAll(workspaceOuPairs, Optional.ofNullable(param.getWorkspaceOuPairs()) + .map(List::listIterator) + .orElseGet(Collections::emptyListIterator)); + if (CollectionUtils.isNotEmpty(workspaceOuPairs)) { wrapper.and(j -> { - for (ListRoleUserRelationParam.WorkspaceOuPair workspaceOuPair : param.getWorkspaceOuPairs()) { + for (ListRoleUserRelationParam.WorkspaceOuPair workspaceOuPair : workspaceOuPairs) { j.or(k -> { k.eq(Objects.nonNull(workspaceOuPair.getOuId()), "ou_id", workspaceOuPair.getOuId()); k.eq(Objects.nonNull(workspaceOuPair.getWorkspaceId()), "workspace_id", workspaceOuPair.getWorkspaceId()); From 7aa3615cc39989118a4558b5cd8048bed55d5371 Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 30 Jul 2024 18:45:02 +0800 Subject: [PATCH 019/112] =?UTF-8?q?feat:(REQ-2720)=20=E6=9D=83=E9=99=90?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=81=9A=E9=99=8D=E7=BA=A7=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/model/req/IdentityAuthReq.java | 17 + .../impl/PermissionQueryServiceImpl.java | 155 ++++- .../service/impl/TyrSaasAuthServiceImpl.java | 615 +++++++++++++++++- 3 files changed, 762 insertions(+), 25 deletions(-) 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 375dd262..81e917a7 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,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-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 2f736f99..07bb8e99 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 @@ -19,6 +19,7 @@ import cn.axzo.tyr.client.model.base.FeatureResourceExtraDO; import cn.axzo.tyr.client.model.base.WorkspaceOUPair; import cn.axzo.tyr.client.model.enums.IdentityType; import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO; +import cn.axzo.tyr.client.model.req.FeatureIdPair; import cn.axzo.tyr.client.model.req.IdentityAuthReq; import cn.axzo.tyr.client.model.req.NavTreeReq; import cn.axzo.tyr.client.model.req.PagePermissionReq; @@ -32,6 +33,7 @@ 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; import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam; @@ -45,6 +47,7 @@ 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.entity.SaasFeatureResource; +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; @@ -89,7 +92,7 @@ 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; /** * 权限查询服务实现 * @@ -117,6 +120,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { private final RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService; private final ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService; + @Qualifier("authExecutor") @Autowired private Executor executor; @@ -320,11 +324,129 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { } + private List resolveFeatureIds(TreePermissionReq treePermissionReq) { + if (StringUtils.isBlank(treePermissionReq.getUniCode())) { + return Collections.emptyList(); + } + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .uniCodes(Sets.newHashSet(treePermissionReq.getUniCode())) + .build(); + return featureResourceService.list(pageSaasFeatureResourceReq).stream() + .map(SaasFeatureResourceResp::getId) + .collect(Collectors.toList()); + } + + private List listUserPermission(TreePermissionReq treePermissionReq, List featureIds) { + 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()) + .featureIds(featureIds) + .build(); + return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream() + .filter(e -> e.getSaasRole() != null) + .collect(Collectors.toList()); + } + + private Set listUserPermissionFeatureIdsFromDB(TreePermissionReq treePermissionReq) { + + List featureIds = resolveFeatureIds(treePermissionReq); + + if (StringUtils.isNotBlank(treePermissionReq.getUniCode()) && CollectionUtils.isEmpty(featureIds)) { + return Collections.emptySet(); + } + + List saasRoleUserV2DTOS = listUserPermission(treePermissionReq, featureIds); + + // 用户可能没有角色 + if (CollectionUtils.isEmpty(saasRoleUserV2DTOS)) { + return Collections.emptySet(); + } + + List workspaceProducts = listWorkspaceProducts(treePermissionReq, featureIds); + + //免授权 + List authFreeFeatureIds = listNotAuthFeatures(treePermissionReq); + + //取交集确定权限 + 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 listWorkspaceProducts(TreePermissionReq treePermissionReq, + List featureIds) { + //查询租户产品权限点 + 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(); + + if (CollectionUtils.isNotEmpty(featureIds)) { + workspaceProductParam.setFeatureIdPairs(Lists.newArrayList(FeatureIdPair.builder() + .featureIds(Sets.newHashSet(featureIds)) + .type(NEW_FEATURE) + .build())); + } + return workspaceProductService.listWorkspaceProduct(workspaceProductParam); + } + @Override public List treePermission(TreePermissionReq req) { Set allFeatureIds = Sets.newHashSet(); - Set featureIds = listUserPermissionFeatureIds(req); + Set featureIds; + try { + featureIds = listUserPermissionFeatureIds(req); + } catch (Exception ex) { + log.error("查询权限异常,执行降级处理"); + featureIds = listUserPermissionFeatureIdsFromDB(req); + } Set defaultFeatureIds = listNotAuthFeatureIds(); allFeatureIds.addAll(featureIds); @@ -829,4 +951,33 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .filter(authFreeFeatureIds::contains) .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/TyrSaasAuthServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/TyrSaasAuthServiceImpl.java index ce43f82e..db6bb867 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,10 +7,12 @@ 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; 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.CheckIdentityPermissionReq; @@ -25,6 +27,7 @@ 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; import cn.axzo.tyr.client.model.req.QuerySaasRoleReq; import cn.axzo.tyr.client.model.req.WorkspacePermissionIdentityReq; import cn.axzo.tyr.client.model.res.IdentityAuthRes; @@ -33,6 +36,7 @@ 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; import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam; import cn.axzo.tyr.client.model.vo.SaasPermissionGroupVO; @@ -76,6 +80,7 @@ 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.BooleanUtil; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; @@ -520,7 +525,15 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { @Override public ListIdentityFromPermissionResp listIdentityFromPermission(ListIdentityFromPermissionReq req) { + try { + return listIdentityFromPermissionResp(req); + } catch (Exception ex) { + log.error("查询权限异常,执行降级处理"); + return listIdentityFromPermissionFromDB(req); + } + } + private ListIdentityFromPermissionResp listIdentityFromPermissionResp(ListIdentityFromPermissionReq req) { Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCode())); ListPermissionUser listPermissionUser = ListPermissionUser.builder() .featureCodes(newFeatureCodes) @@ -781,7 +794,12 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } private List findIdentityPermission(IdentityAuthReq req) { - return findIdentityAuthV2(req).getPermissions(); + try { + return findIdentityAuthV2(req).getPermissions(); + } catch (Exception ex) { + log.error("查询权限异常,执行降级处理"); + return findIdentityAuth(req).getPermissions(); + } } private List findIdentityPermissionFromCache(IdentityAuthReq req) { @@ -960,32 +978,37 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { @Override public List listWorkspacePermissionIdentity(WorkspacePermissionIdentityReq req) { - Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCodes())); + try { + Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCodes())); - Set featureCodes = Sets.newHashSet(req.getFeatureCodes()); - featureCodes.addAll(newFeatureCodes); + Set featureCodes = Sets.newHashSet(req.getFeatureCodes()); + featureCodes.addAll(newFeatureCodes); - ListPermissionUser listPermissionUser = ListPermissionUser.builder() - .featureCodes(featureCodes) - .workspaceId(req.getWorkspaceId()) - .build(); - List users = listPermissionUser(listPermissionUser); - - if (CollectionUtil.isEmpty(users)) { - return Collections.emptyList(); - } - //按ou分组返回 - List result = new ArrayList<>(); - Map> userMap = users.stream() - .collect(Collectors.groupingBy(ListIdentityFromPermissionResp.UserVO::getOuId)); - for (Map.Entry> entry : userMap.entrySet()) { - result.add(ListIdentityFromPermissionResp.builder() + ListPermissionUser listPermissionUser = ListPermissionUser.builder() + .featureCodes(featureCodes) .workspaceId(req.getWorkspaceId()) - .ouId(entry.getKey()) - .users(entry.getValue()) - .build()); + .build(); + List users = listPermissionUser(listPermissionUser); + + if (CollectionUtil.isEmpty(users)) { + return Collections.emptyList(); + } + //按ou分组返回 + List result = new ArrayList<>(); + Map> userMap = users.stream() + .collect(Collectors.groupingBy(ListIdentityFromPermissionResp.UserVO::getOuId)); + for (Map.Entry> entry : userMap.entrySet()) { + result.add(ListIdentityFromPermissionResp.builder() + .workspaceId(req.getWorkspaceId()) + .ouId(entry.getKey()) + .users(entry.getValue()) + .build()); + } + return result; + } catch (Exception ex) { + log.error("查询权限异常,执行降级处理"); + return listWorkspacePermissionIdentityFromDB(req); } - return result; } private List listFeatureRoles(Set featureIds, Integer type) { @@ -1685,4 +1708,550 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .build(); return rolePermissionCacheService.list(listRolePermissionParam); } + + 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 + CompletableFuture> workspacePermissionPointFuture = CompletableFuture + .supplyAsync(TraceSupplier.create(() -> { + WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() + .workspaceIds(realWorkspaceId) + .build(); + return workspaceProductService.listWorkspaceProduct(workspaceProductParam); + }), executor); + //查询工作台下授予的角色和权限 + List owRoles = listRolesWithPermission(saasRoleUserRelations, identityAuthReq); + + Map workspaceProductPermissionMap = workspacePermissionPointFuture.join().stream() + .collect(Collectors.toMap(WorkspaceProductService.WorkspaceProduct::getWorkspaceId, Function.identity())); + + List> futureList = new ArrayList<>(); + for (OUWRoleInfo owRoleInfo : owRoles) { + // 工作台的产品权限点 + WorkspaceProductService.WorkspaceProduct workspaceProduct = workspaceProductPermissionMap.get(owRoleInfo.getWorkspaceId()); + //构建每个工作台的实际权限点 + futureList.add(CompletableFuture.supplyAsync(TraceSupplier.create(() -> buildPermissions(owRoleInfo, workspaceProduct)), executor) + .exceptionally(t -> { + LogUtil.error("获取角色对应权限失败", t); + throw new ServiceException(t); + })); + } + + //汇总结果 + IdentityAuthRes result = new IdentityAuthRes(); + result.setIdentity(identityAuthReq.getIdentityId()); + result.setIdentityType(identityAuthReq.getIdentityType()); + result.setPersonId(identityAuthReq.getPersonId()); + for (CompletableFuture future : futureList) { + result.getPermissions().add(future.join()); + } + return result; + } + + private List listRoleUserRelations(IdentityAuthReq identityAuthReq) { + if (CollectionUtil.isNotEmpty(identityAuthReq.getSpecifyRoleIds())) { + //指定了角色 则不需要去查用户角色关系 + log.info("mock specify roles relation"); + return mockRoleUserRelation(identityAuthReq); + } + //查询人员角色关系 + Set workspaceIds = new HashSet<>(); + Set ouIds = new HashSet<>(); + Set owKeys = new HashSet<>(); + identityAuthReq.getWorkspaceOusPairs().forEach(ow -> { + workspaceIds.add(ow.getWorkspaceId()); + ouIds.add(ow.getOuId()); + owKeys.add(KeyUtil.buildKeyBySeparator(ow.getWorkspaceId(), ow.getOuId())); + }); + List relations = roleUserService.queryByWorkspaceIdOrOu(identityAuthReq.getPersonId(), + identityAuthReq.getIdentityId(), identityAuthReq.getIdentityType(), workspaceIds, ouIds); + if (CollectionUtil.isEmpty(relations)) { + log.warn("no user role relations found"); + return relations; + } + //工作台和单位需成对查询, 对结果二次过滤 + return relations.stream() + .filter(roleUserService -> owKeys.contains( + KeyUtil.buildKeyBySeparator(roleUserService.getWorkspaceId(), roleUserService.getOuId()))) + .collect(Collectors.toList()); + } + + private List mockRoleUserRelation(IdentityAuthReq identityAuthReq) { + final List relations = new ArrayList<>(); + // mock 看做已有指定的角色 + for (IdentityAuthReq.WorkspaceOuPair ow : identityAuthReq.getWorkspaceOusPairs()) { + List mockRelations = identityAuthReq.getSpecifyRoleIds().stream().map(id -> { + SaasRoleUserRelation relation = new SaasRoleUserRelation(); + relation.setRoleId(id); + relation.setOuId(ow.getOuId()); + relation.setWorkspaceId(ow.getWorkspaceId()); + relation.setIdentityId(identityAuthReq.getIdentityId()); + relation.setIdentityType(identityAuthReq.getIdentityType().getCode()); + // 使用角色ID替代,不需要在查询一次 + relation.setId(id); + return relation; + }).collect(Collectors.toList()); + relations.addAll(mockRelations); + } + return relations; + } + + @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) { + + //拼装参数 + Set roleIds = new HashSet<>(); + //按ow分组角色ID: workspaceId-ouId --> roleIds + Map> owRoleIdMap = new HashMap<>(); + for (SaasRoleUserRelation relation : roleUserRelations) { + roleIds.add(relation.getRoleId()); + String key = KeyUtil.buildKeyBySeparator(relation.getWorkspaceId(), relation.getOuId()); + Set owRoleIds = owRoleIdMap.getOrDefault(key, new HashSet<>()); + owRoleIds.add(relation.getRoleId()); + owRoleIdMap.put(key, owRoleIds); + } + //获取角色和关联权限信息 + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .roleIds(Lists.newArrayList(roleIds)) + .needPermissionRelation(true) + .build(); + Map saasRoleRes = roleService.list(listSaasRoleParam).stream() + .collect(Collectors.toMap(SaasRoleRes::getId, Function.identity())); + + //按ow组装拥有的角色 + List owRoleMap = new ArrayList<>(); + for (IdentityAuthReq.WorkspaceOuPair ow : identityAuthReq.getWorkspaceOusPairs()) { + OUWRoleInfo owRoleInfo = OUWRoleInfo.builder() + .workspaceId(ow.getWorkspaceId()) + .ouId(ow.getOuId()) + .build(); + String key = KeyUtil.buildKeyBySeparator(ow.getWorkspaceId(), ow.getOuId()); + Set owRoleIds = owRoleIdMap.get(key); + if (CollectionUtil.isEmpty(owRoleIds)) { + log.info("no roles found for ow:{}", key); + owRoleInfo.setRoles(Collections.emptySet()); + } else { + owRoleInfo.setRoles(owRoleIds.stream() + .map(saasRoleRes::get) + // 有saas_role_user_relation有记录,但是对应的saas_role不存在的情况 + .filter(Objects::nonNull) + .collect(Collectors.toSet())); + } + owRoleMap.add(owRoleInfo); + } + + return owRoleMap; + } + + private IdentityAuthRes.WorkspacePermission buildPermissions(OUWRoleInfo ouwRoleInfo, WorkspaceProductService.WorkspaceProduct workspaceProduct) { + + IdentityAuthRes.WorkspacePermission resultPermission = IdentityAuthRes.WorkspacePermission.builder() + .workspaceId(ouwRoleInfo.getWorkspaceId()) + .ouId(ouwRoleInfo.getOuId()) + .build(); + + if (Objects.isNull(workspaceProduct) || CollectionUtil.isEmpty(workspaceProduct.getSaasProductModuleFeatureRelations())) { + log.warn("no product features found for workspace :{}", ouwRoleInfo.getWorkspaceId()); + return resultPermission; + } + + Set roles = ouwRoleInfo.getRoles(); + if (CollectionUtil.isEmpty(roles)) { + log.warn("no roles for ou:{} workspace:{}", ouwRoleInfo.getOuId(), ouwRoleInfo.getWorkspaceId()); + return resultPermission; + } + + List productFeatures = workspaceProduct.getSaasProductModuleFeatureRelations(); + // 因为存在同时有saas_feature和saas_feature_resource的权限,所以要返回type,根据type解析code + //超管和管理员权限 + Pair> adminPermissions = buildAdminPermission(ouwRoleInfo, productFeatures); + //标准角和自定义角色权限 + Set normalPermissions = buildNormalPermission(ouwRoleInfo, productFeatures); + Set allPermissions = Sets.newHashSet(); + allPermissions.addAll(adminPermissions.getValue()); + allPermissions.addAll(normalPermissions); + + //查询权限点及父级权限点 + List allOldPermissionPoint = listOldFeatures(allPermissions); + + List newPermissionPoints = listNewFeatures(allPermissions); + + //组装返回值 + //是否超管 + resultPermission.setSuperAdmin(BooleanUtil.isTrue(adminPermissions.getKey())); + //权限数据 + resultPermission.getPermissionPoint().addAll(allOldPermissionPoint.stream() + .map(permissionPointTreeNode -> IdentityAuthRes.PermissionPoint.builder() + .featureCode(permissionPointTreeNode.getCode()) + .featureId(permissionPointTreeNode.getId()) + .terminal(permissionPointTreeNode.getTerminal()) + .build()) + .collect(Collectors.toList())); + + resultPermission.getPermissionPoint().addAll(newPermissionPoints); + return resultPermission; + } + + private Pair> buildAdminPermission(OUWRoleInfo userRoleInfoMap, List productFeatures) { + Boolean superAdmin = false; + //超管和管理员角色 + List adminRoles = userRoleInfoMap.getRoles().stream() + .filter(r -> RoleTypeEnum.isAdmin(r.getRoleType())) + .collect(Collectors.toList()); + if (CollectionUtil.isEmpty(adminRoles)) { + log.info("no admin roles"); + return Pair.of(superAdmin, Collections.emptySet()); + } + + log.info("build admin permission for ou:{}, workspace:{}", userRoleInfoMap.getOuId(), userRoleInfoMap.getWorkspaceId()); + + //聚合超管和管理员的权限点: 直接取角色标签和产品标签相匹配的权限点 + Set permissions = Sets.newHashSet(); + for (SaasRoleRes adminRole : adminRoles) { + //超管:查询工作台对应产品,获取权限点, ( 权限点通过单位类型过滤) + if (RoleTypeEnum.SUPER_ADMIN.getValue().equals(adminRole.getRoleType())) { + superAdmin = true; + } + //角色标签类型匹配产品标签类型 + Set permission = productFeatures.stream() + .filter(productFeatureRelationVO -> Objects.equals(productFeatureRelationVO.getDictCode(), + String.valueOf(adminRole.getProductUnitType()))) + .map(e -> FeatureWrapper.builder() + .featureId(e.getFeatureId()) + .type(e.getType()) + .build()) + .collect(Collectors.toSet()); + + if (CollectionUtil.isEmpty(permission)) { + log.warn("empty permission for admin role:{}", adminRole.getId()); + continue; + } + log.info("add all permissions for role:{}", adminRole.getId()); + permissions.addAll(permission); + } + + return Pair.of(superAdmin, permissions); + } + + private Set buildNormalPermission(OUWRoleInfo userRoleInfoMap, List productFeatures) { + + log.info("build permission for ou:{}, workspace:{}", userRoleInfoMap.getOuId(), userRoleInfoMap.getWorkspaceId()); + Set allMatchedProductFeatures = new HashSet<>(); + Set allAuthFeatures = new HashSet<>(); + + //聚合实际授权的权限:角色权限和产品权限交集 + 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 rolePermissions = Optional.ofNullable(role.getPermissionRelations()) + .map(e -> e.stream() + .filter(Objects::nonNull) + .map(f -> FeatureWrapper.builder() + .featureId(f.getFeatureId()) + .type(f.getType()) + .build()) + .collect(Collectors.toSet())) + .orElseGet(Sets::newHashSet); + //角色标签类型匹配产品标签类型 + Set productPermissions = productFeatures.stream() + .filter(productFeatureRelationVO -> Objects.equals(productFeatureRelationVO.getDictCode(), String.valueOf(role.getProductUnitType()))) + .map(e -> FeatureWrapper.builder() + .featureId(e.getFeatureId()) + .type(e.getType()) + .build()) + .collect(Collectors.toSet()); + allMatchedProductFeatures.addAll(productPermissions); + // 产品对应权限点 与 角色权限点 取交集 + Collection resultHashAuthPointId = CollectionUtil.intersection(productPermissions, rolePermissions); + if (CollectionUtil.isNotEmpty(resultHashAuthPointId)) { + log.info("add auth permission for role:{}", role.getId()); + allAuthFeatures.addAll(resultHashAuthPointId); + } + } + if (CollectionUtil.isEmpty(allMatchedProductFeatures)) { + log.info("no normal roles found"); + return allAuthFeatures; + } + + Set newFeatureNoAuth = listNoAuthFeatureResources(allMatchedProductFeatures); + + Set oldFeatureNoAuth = listNoAuthFeatures(allMatchedProductFeatures); + allAuthFeatures.addAll(newFeatureNoAuth); + allAuthFeatures.addAll(oldFeatureNoAuth); + return allAuthFeatures; + } + + 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 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()); + } + + public ListIdentityFromPermissionResp listIdentityFromPermissionFromDB(ListIdentityFromPermissionReq req) { + ListIdentityFromPermissionResp result = new ListIdentityFromPermissionResp(); + result.setOuId(req.getOuId()); + result.setWorkspaceId(req.getWorkspaceId()); + + Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCode())); + + //code查询权限点信息 + List features = permissionPointService.listNodeWithChildrenByCodes(Lists.newArrayList(newFeatureCodes), req.getTerminal()); + + // 兼容新老版本,需要通过featureCode查询新版本的features,原逻辑是查询当前菜单资源的所有子数据 + ListSaasFeatureResourceParam listSaasFeatureResourceParam = ListSaasFeatureResourceParam.builder() + .featureCodes(newFeatureCodes) + .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; + } + //是否免授权权限点 + Optional freeFeature = features.stream() + .filter(f -> DelegatedType.NO_NEED.sameCode(f.getDelegatedType())) + .findAny(); + + 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()); + Set newFeatureIds = saasFeatureResources.stream().map(SaasFeatureResourceResp::getId).collect(Collectors.toSet()); + + List featureIdPairs = Lists.newArrayList(); + if (!CollectionUtils.isEmpty(featureIds)) { + featureIdPairs.add(FeatureIdPair.builder().featureIds(featureIds).type(OLD_FEATURE).build()); + } + + if (!CollectionUtils.isEmpty(newFeatureIds)) { + featureIdPairs.add(FeatureIdPair.builder().featureIds(newFeatureIds).type(NEW_FEATURE).build()); + } + WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() + .workspaceIds(Sets.newHashSet(req.getWorkspaceId())) + .featureIdPairs(featureIdPairs) + .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(), workspaceProducts); + if (CollectionUtil.isEmpty(matchedUsers)) { + return result; + } + result.setUsers(matchedUsers); + return result; + } + + public List listWorkspacePermissionIdentityFromDB(WorkspacePermissionIdentityReq req) { + + Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCodes())); + req.setFeatureCodes(Lists.newArrayList(newFeatureCodes)); + + //code查询权限点信息 + List features = permissionPointService.listNodeWithChildrenByCodes(req.getFeatureCodes(), null); + + // 兼容新老版本,需要通过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()); + Set newFeatureIds = saasFeatureResources.stream().map(SaasFeatureResourceResp::getId).collect(Collectors.toSet()); + List featureIdPairs = Lists.newArrayList(); + + if (!CollectionUtils.isEmpty(featureIds)) { + featureIdPairs.add(FeatureIdPair.builder().featureIds(featureIds).type(OLD_FEATURE).build()); + } + + if (!CollectionUtils.isEmpty(newFeatureIds)) { + featureIdPairs.add(FeatureIdPair.builder().featureIds(newFeatureIds).type(NEW_FEATURE).build()); + } + WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder() + .workspaceIds(Sets.newHashSet(req.getWorkspaceId())) + .featureIdPairs(featureIdPairs) + .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 matchedOldFeatureIds = workspaceProducts.stream() + .filter(e -> Objects.equals(OLD_FEATURE, e.getType())) + .map(SaasProductModuleFeatureRelation::getFeatureId) + .collect(Collectors.toSet()); + Optional freeFeature = features.stream() + .filter(f -> matchedOldFeatureIds.contains(f.getId())) + .filter(f -> DelegatedType.NO_NEED.sameCode(f.getDelegatedType())) + .findAny(); + + 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, workspaceProducts); + if (CollectionUtil.isEmpty(users)) { + return Collections.emptyList(); + } + //按ou分组返回 + List result = new ArrayList<>(); + Map> userMap = users.stream() + .collect(Collectors.groupingBy(ListIdentityFromPermissionResp.UserVO::getOuId)); + for (Map.Entry> entry : userMap.entrySet()) { + result.add(ListIdentityFromPermissionResp.builder() + .workspaceId(req.getWorkspaceId()) + .ouId(entry.getKey()) + .users(entry.getValue()) + .build()); + } + return result; + } } From e51cb3cf2f6e02c62bbe7070cd295edf650c2f5f Mon Sep 17 00:00:00 2001 From: luofu Date: Wed, 31 Jul 2024 10:41:56 +0800 Subject: [PATCH 020/112] =?UTF-8?q?feat(REQ-2488):=20=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E6=8E=A5=E5=8F=A3=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8f8f0a7a..1cca8a90 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 @@ -1153,7 +1153,7 @@ public class RoleServiceImpl extends ServiceImpl wrapper.and(j -> { for (ListRoleUserRelationParam.WorkspaceOuPair workspaceOuPair : workspaceOuPairs) { j.or(k -> { - k.eq(Objects.nonNull(workspaceOuPair.getOuId()), "ou_id", workspaceOuPair.getOuId()); + k.eq(Objects.nonNull(workspaceOuPair.getOuId()), "owner_ou_id", workspaceOuPair.getOuId()); k.eq(Objects.nonNull(workspaceOuPair.getWorkspaceId()), "workspace_id", workspaceOuPair.getWorkspaceId()); }); } From 9e49be1100c7a22eb958d8d386bab8d14fe0f5f4 Mon Sep 17 00:00:00 2001 From: lilong Date: Wed, 31 Jul 2024 11:11:16 +0800 Subject: [PATCH 021/112] =?UTF-8?q?feat:(REQ-2720)=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=B6=88=E8=B4=B9apiSix=E6=93=8D=E4=BD=9C=E6=97=A7=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E6=A0=91=E7=9A=84=E4=BA=8B=E4=BB=B6=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/RocketMQEventConfiguration.java | 18 ++++ .../outer/CacheSaasFeatureOldHandler.java | 85 +++++++++++++++++++ .../tyr/server/event/outer/EventTypeEnum.java | 2 + .../payload/SaasFeatureDeletedPayload.java | 19 +++++ 4 files changed, 124 insertions(+) create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/outer/CacheSaasFeatureOldHandler.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureDeletedPayload.java diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/config/RocketMQEventConfiguration.java b/tyr-server/src/main/java/cn/axzo/tyr/server/config/RocketMQEventConfiguration.java index 71f60031..86ff70f1 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/config/RocketMQEventConfiguration.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/config/RocketMQEventConfiguration.java @@ -99,6 +99,24 @@ public class RocketMQEventConfiguration { } } + @Slf4j + @Component + @RocketMQMessageListener(topic = "topic_apisix_plat_${spring.profiles.active}", + consumerGroup = "GID_topic_apisix_plat_${spring.application.name}_${spring.profiles.active}", + consumeMode = ConsumeMode.ORDERLY, + nameServer = "${rocketmq.name-server}" + ) + public static class ApiSixPlatListener extends BaseListener implements RocketMQListener { + + @Autowired + private EventConsumer eventConsumer; + + @Override + public void onMessage(MessageExt message) { + super.onEvent(message, eventConsumer); + } + } + @Bean EventHandlerRepository eventHandlerRepository() { return new EventHandlerRepository((ex, logText) -> { diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/outer/CacheSaasFeatureOldHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/outer/CacheSaasFeatureOldHandler.java new file mode 100644 index 00000000..5ed9a699 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/outer/CacheSaasFeatureOldHandler.java @@ -0,0 +1,85 @@ +package cn.axzo.tyr.server.event.outer; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.tyr.client.model.enums.DelegatedType; +import cn.axzo.tyr.server.event.payload.SaasFeatureDeletedPayload; +import cn.axzo.tyr.server.event.payload.SaasFeatureUpsertPayload; +import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; +import cn.axzo.tyr.server.repository.entity.SaasFeature; +import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * 缓存全量权限点,因为鉴权等逻辑,需要查询免授权和权限点是否存在,数据量大,数据库压力大 + */ +@Slf4j +@Component +public class CacheSaasFeatureOldHandler implements InitializingBean { + + @Autowired + private EventConsumer eventConsumer; + @Autowired + private SaasFeatureDao saasFeatureDao; + @Autowired + private SaasFeatureResourceService saasFeatureResourceService; + + public void onSaasFeatureUpserted(Event event, EventConsumer.Context context) { + log.info("begin cached saasFeature handler rocketmq event: {}", event); + SaasFeatureUpsertPayload payload = event.normalizedData(SaasFeatureUpsertPayload.class); + + if (StringUtils.isBlank(payload.getTerminal())) { + return; + } + cacheFeature(payload.getTerminal()); + log.info("end cached saasFeature handler rocketmq event: {}", event); + } + + public void onSaasFeatureDeleted(Event event, EventConsumer.Context context) { + log.info("begin cached saasFeature handler rocketmq event: {}", event); + SaasFeatureDeletedPayload payload = event.normalizedData(SaasFeatureDeletedPayload.class); + + if (StringUtils.isBlank(payload.getTerminal())) { + return; + } + + cacheFeature(payload.getTerminal()); + + log.info("end cached saasFeature handler rocketmq event: {}", event); + } + + private void cacheFeature(String terminal) { + List saasFeatures = saasFeatureDao.lambdaQuery() + .eq(SaasFeature::getTerminal, terminal) + .list() + .stream() + .map(e -> SaasFeatureResourceService.SaasFeatureResourceCache.builder() + .featureId(e.getId()) + .notAuth(DelegatedType.notAuth(e.getDelegatedType())) + .build()) + .collect(Collectors.toList()); + + SaasFeatureResourceService.SaasFeatureResourceDTO saasFeatureResourceDTO = SaasFeatureResourceService.SaasFeatureResourceDTO.builder() + .terminal(terminal) + .features(saasFeatures) + .build(); + SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() + .saasFeatureResources(Lists.newArrayList(saasFeatureResourceDTO)) + .build(); + saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); + } + + @Override + public void afterPropertiesSet() throws Exception { + eventConsumer.registerHandler(EventTypeEnum.SAAS_FEATURE_UPSERT.getEventCode(), this::onSaasFeatureUpserted); + eventConsumer.registerHandler(EventTypeEnum.SAAS_FEATURE_DELETED.getEventCode(), this::onSaasFeatureDeleted); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/outer/EventTypeEnum.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/outer/EventTypeEnum.java index 0eec0401..d5091acc 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/outer/EventTypeEnum.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/outer/EventTypeEnum.java @@ -12,6 +12,8 @@ import lombok.Getter; public enum EventTypeEnum { SERVICE_PKG_PRODUCT_CREATED("service-pkg-product", "service-pkg-product-created", "创建服务包的产品"), + SAAS_FEATURE_UPSERT("saas-feature", "saas-feature-upsert", "旧菜单树更新"), + SAAS_FEATURE_DELETED("saas-feature", "saas-feature-deleted", "旧菜单树删除"), ; EventTypeEnum(String model, String name, String desc) { diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureDeletedPayload.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureDeletedPayload.java new file mode 100644 index 00000000..45746e72 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureDeletedPayload.java @@ -0,0 +1,19 @@ +package cn.axzo.tyr.server.event.payload; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaasFeatureDeletedPayload implements Serializable { + + private Long id; + + private String terminal; +} From 98f76501b99e70e38c058cdcc51747b7f78a0992 Mon Sep 17 00:00:00 2001 From: lilong Date: Thu, 1 Aug 2024 10:42:24 +0800 Subject: [PATCH 022/112] =?UTF-8?q?feat:(REQ-2720)=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=9D=83=E9=99=90=E6=9F=A5=E8=AF=A2db=E7=9A=84=E5=BC=80?= =?UTF-8?q?=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/service/TyrSaasAuthService.java | 6 +++++ .../impl/PermissionQueryServiceImpl.java | 25 +++++++++++++------ .../service/impl/TyrSaasAuthServiceImpl.java | 23 +++++++++++++++++ 3 files changed, 47 insertions(+), 7 deletions(-) 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 81ccc0b3..36f8a2b1 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 @@ -66,4 +66,10 @@ public interface TyrSaasAuthService { * @return */ boolean authNewPermission(PermissionCheckReq req); + + /** + * 增加统一的开关:权限是否从数据库查询 + * @return + */ + boolean permissionFromDB(); } 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 07bb8e99..477cfd3a 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 @@ -119,6 +119,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { private final WorkspaceProductService workspaceProductService; private final RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService; private final ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService; + private final TyrSaasAuthService tyrSaasAuthService; @Qualifier("authExecutor") @@ -436,17 +437,13 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { return workspaceProductService.listWorkspaceProduct(workspaceProductParam); } + + @Override public List treePermission(TreePermissionReq req) { Set allFeatureIds = Sets.newHashSet(); - Set featureIds; - try { - featureIds = listUserPermissionFeatureIds(req); - } catch (Exception ex) { - log.error("查询权限异常,执行降级处理"); - featureIds = listUserPermissionFeatureIdsFromDB(req); - } + Set featureIds = resovlePermission(req); Set defaultFeatureIds = listNotAuthFeatureIds(); allFeatureIds.addAll(featureIds); @@ -506,6 +503,20 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { return result; } + private Set resovlePermission(TreePermissionReq req) { + + if (tyrSaasAuthService.permissionFromDB()) { + return listUserPermissionFeatureIdsFromDB(req); + } + + try { + return listUserPermissionFeatureIds(req); + } catch (Exception ex) { + log.error("查询权限异常,执行降级处理"); + return listUserPermissionFeatureIdsFromDB(req); + } + } + private List filterFeature(List saasFeatureResources) { if (CollectionUtils.isEmpty(saasFeatureResources)) { return Collections.emptyList(); 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 db6bb867..dc26b899 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 @@ -97,6 +97,7 @@ 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.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -156,6 +157,14 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { private final RolePermissionCacheService rolePermissionCacheService; private final SaasRoleUserRelationMapper saasRoleUserRelationMapper; + @Value("${permission:from:db:false}") + private boolean PERMISSION_FROM_DB; + + @Override + public boolean permissionFromDB() { + return BooleanUtil.isTrue(PERMISSION_FROM_DB); + } + /** * 通过身份查询人员权限 * @@ -525,6 +534,11 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { @Override public ListIdentityFromPermissionResp listIdentityFromPermission(ListIdentityFromPermissionReq req) { + + if (this.permissionFromDB()) { + return listIdentityFromPermissionFromDB(req); + } + try { return listIdentityFromPermissionResp(req); } catch (Exception ex) { @@ -794,6 +808,11 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } private List findIdentityPermission(IdentityAuthReq req) { + + if (this.permissionFromDB()) { + return findIdentityAuth(req).getPermissions(); + } + try { return findIdentityAuthV2(req).getPermissions(); } catch (Exception ex) { @@ -978,6 +997,10 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { @Override public List listWorkspacePermissionIdentity(WorkspacePermissionIdentityReq req) { + if (this.permissionFromDB()) { + return listWorkspacePermissionIdentityFromDB(req); + } + try { Set newFeatureCodes = featureCodeUtil.resolveFeatureCode(Sets.newHashSet(req.getFeatureCodes())); From c2ef3337011981ad6a791b70917ddf3843362f60 Mon Sep 17 00:00:00 2001 From: lilong Date: Thu, 1 Aug 2024 11:37:26 +0800 Subject: [PATCH 023/112] =?UTF-8?q?feat:(REQ-2720)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=BC=80=E5=85=B3=E9=85=8D=E7=BD=AE?= 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, 1 insertion(+), 1 deletion(-) 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 dc26b899..0a406194 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 @@ -157,7 +157,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { private final RolePermissionCacheService rolePermissionCacheService; private final SaasRoleUserRelationMapper saasRoleUserRelationMapper; - @Value("${permission:from:db:false}") + @Value("${permission.from.db:false}") private boolean PERMISSION_FROM_DB; @Override From e06cb5d126d0374b7239581662feb329a283a19d Mon Sep 17 00:00:00 2001 From: lilong Date: Thu, 1 Aug 2024 14:39:16 +0800 Subject: [PATCH 024/112] =?UTF-8?q?feat:(REQ-2720)=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=97=A5=E5=BF=97=EF=BC=8C=E5=A2=9E=E5=8A=A0=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E4=BA=A7=E5=93=81=E6=9D=83=E9=99=90=E3=80=81=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E6=9D=83=E9=99=90=E7=9A=84=E7=A7=81=E6=9C=89=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/controller/PrivateController.java | 13 +++++++++++++ .../server/service/impl/TyrSaasAuthServiceImpl.java | 12 ++++++++++++ 2 files changed, 25 insertions(+) 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 e14851e0..0a89d1ca 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 @@ -44,6 +44,7 @@ import cn.axzo.tyr.server.repository.entity.SaasRoleGroup; import cn.axzo.tyr.server.repository.entity.SaasRoleGroupRelation; import cn.axzo.tyr.server.service.ProductFeatureRelationService; 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; @@ -142,6 +143,8 @@ public class PrivateController { private CacheRoleFeatureResourceJob cacheRoleFeatureResourceJob; @Autowired private SaasFeatureResourceService saasFeatureResourceService; + @Autowired + private RolePermissionCacheService rolePermissionCacheService; /** * 统一层级的roleGroup按照id升序,sort从1递增 @@ -699,6 +702,16 @@ public class PrivateController { return saasFeatureResourceService.listCache(request); } + @PostMapping("/api/private/workspaceProductCached/list") + public Object workspaceProductCached(@RequestBody WorkspaceProductService.ListWorkspaceProductPermissionCacheParam request) { + return workspaceProductService.listWorkspaceProductPermissionCached(request); + } + + @PostMapping("/api/private/rolePermissionCache/list") + public Object rolePermissionCache(@RequestBody RolePermissionCacheService.ListRolePermissionParam request) { + return rolePermissionCacheService.list(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 0a406194..005759b9 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 @@ -2,6 +2,7 @@ package cn.axzo.tyr.server.service.impl; import cn.axzo.apollo.workspace.common.enums.TableIsDeleteEnum; import cn.axzo.basics.common.BeanMapper; +import cn.axzo.basics.common.util.StopWatchUtil; import cn.axzo.framework.domain.ServiceException; import cn.axzo.pokonyan.util.TraceSupplier; import cn.axzo.thrones.client.saas.ServicePkgClient; @@ -1502,10 +1503,21 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { */ private IdentityAuthRes findIdentityAuthV2(IdentityAuthReq identityAuthReq) { + StopWatchUtil watch = StopWatchUtil.createStarted("redis:"); + watch.start("query workspaceProductPermission"); Map> workspaceProductPermissions = listWorkspaceProductPermission(identityAuthReq); + watch.stop(); + log.info("redis:workspaceProductPermission:", JSON.toJSONString(workspaceProductPermissions)); + watch.start("query userRole"); List saasRoleUsers = listRoleUserRelationsV2(identityAuthReq); + log.info("redis:saasRoleUsers:", JSON.toJSONString(saasRoleUsers)); + watch.stop(); + + watch.start("query rolePermission"); Map> rolePermissions = listRolePermission(identityAuthReq, saasRoleUsers); + log.info("redis:rolePermissions:", JSON.toJSONString(rolePermissions)); + watch.stop(); Map> workspaceRoles = saasRoleUsers.stream() .collect(Collectors.groupingBy(e -> e.getSaasRoleUser().buildOuWorkspaceKey(), From 4f3daf8adff218792d3ae1ef2b3a9c9357a4142e Mon Sep 17 00:00:00 2001 From: luofu Date: Thu, 1 Aug 2024 14:54:14 +0800 Subject: [PATCH 025/112] =?UTF-8?q?feat(REQ-2488):=20=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E8=A7=92=E8=89=B2=E6=8E=A5=E5=8F=A3=E8=B0=83?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roleuser/req/ListRoleUserRelationParam.java | 12 ++++++++++++ .../impl/SaasRoleUserRelationServiceImpl.java | 2 ++ 2 files changed, 14 insertions(+) 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 d901dd58..3c7ba434 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 @@ -27,6 +27,18 @@ public class ListRoleUserRelationParam { @CriteriaField(field = "ouId", operator = Operator.EQ) private Long ouId; + /** + * 是否显示 + */ + @CriteriaField(ignore = true) + private Boolean isDisplay; + + /** + * 是否启用 + */ + @CriteriaField(ignore = true) + private Boolean enabled; + /** * 身份类型 1:工人 2:从业人员 3:班组长 4:运营人员 5:政务人员 */ 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 c16cb012..fdcfb4a2 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 @@ -236,6 +236,8 @@ public class SaasRoleUserRelationServiceImpl extends ServiceImpl Date: Thu, 1 Aug 2024 14:56:26 +0800 Subject: [PATCH 026/112] =?UTF-8?q?feat:(REQ-2720)=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=97=A5=E5=BF=97=EF=BC=8C=E5=A2=9E=E5=8A=A0=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E4=BA=A7=E5=93=81=E6=9D=83=E9=99=90=E3=80=81=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E6=9D=83=E9=99=90=E7=9A=84=E7=A7=81=E6=9C=89=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/service/impl/TyrSaasAuthServiceImpl.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 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 005759b9..d5177650 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 @@ -85,6 +85,7 @@ import cn.hutool.core.lang.Pair; import cn.hutool.core.util.BooleanUtil; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -1502,12 +1503,11 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { * @return */ private IdentityAuthRes findIdentityAuthV2(IdentityAuthReq identityAuthReq) { - - StopWatchUtil watch = StopWatchUtil.createStarted("redis:"); + StopWatch watch = StopWatch.create("redis:"); watch.start("query workspaceProductPermission"); Map> workspaceProductPermissions = listWorkspaceProductPermission(identityAuthReq); watch.stop(); - log.info("redis:workspaceProductPermission:", JSON.toJSONString(workspaceProductPermissions)); + log.info("redis:workspaceProductPermission:{}", JSON.toJSONString(workspaceProductPermissions)); watch.start("query userRole"); List saasRoleUsers = listRoleUserRelationsV2(identityAuthReq); @@ -1516,13 +1516,14 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { watch.start("query rolePermission"); Map> rolePermissions = listRolePermission(identityAuthReq, saasRoleUsers); - log.info("redis:rolePermissions:", JSON.toJSONString(rolePermissions)); + log.info("redis:rolePermissions:{}", JSON.toJSONString(rolePermissions)); watch.stop(); Map> workspaceRoles = saasRoleUsers.stream() .collect(Collectors.groupingBy(e -> e.getSaasRoleUser().buildOuWorkspaceKey(), Collectors.mapping(SaasRoleUserV2DTO::getSaasRole, Collectors.toList()))); + watch.start("resolve permission"); List permissions = identityAuthReq.getWorkspaceOusPairs().stream() .map(workspaceOuPair -> { List productPermissions = Optional.ofNullable(workspaceProductPermissions.get(workspaceOuPair.getWorkspaceId())) @@ -1545,6 +1546,10 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return buildPermissionsV2(workspaceOuPair, productPermissions, saasRoles, rolePermissions); }) .collect(Collectors.toList()); + watch.stop(); + watch.prettyPrint(TimeUnit.MILLISECONDS); + + log.info("redis:Permissions:{}", JSON.toJSONString(permissions)); IdentityAuthRes result = new IdentityAuthRes(); result.setIdentity(identityAuthReq.getIdentityId()); From 6e45898d3b8fd471179eeb51344d7e4ed8aeb463 Mon Sep 17 00:00:00 2001 From: lilong Date: Thu, 1 Aug 2024 16:11:52 +0800 Subject: [PATCH 027/112] =?UTF-8?q?feat:(REQ-2720)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E6=97=A7=E8=8F=9C=E5=8D=95=E6=A0=91=E7=BC=93=E5=AD=98=EF=BC=8C?= =?UTF-8?q?=E5=9B=A0=E4=B8=BA=E6=B2=A1=E6=9C=89=E6=8A=8A=E7=88=B6=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E7=9A=84=E6=9D=83=E9=99=90=E5=AD=98=E5=82=A8=E8=B5=B7?= =?UTF-8?q?=E6=9D=A5=EF=BC=8C=E4=BD=86=E6=98=AF=E5=AE=9E=E9=99=85=E6=9C=89?= =?UTF-8?q?=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/res/SimplePermissionPointResp.java | 5 +++ .../inner/CacheProductPermissionHandler.java | 31 ++++++++++++------- .../inner/CacheRolePermissionHandler.java | 29 ++++++++++------- .../impl/PermissionPointServiceImpl.java | 4 ++- .../service/impl/TyrSaasAuthServiceImpl.java | 2 +- 5 files changed, 45 insertions(+), 26 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SimplePermissionPointResp.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SimplePermissionPointResp.java index afe9bd03..bb57fc9f 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SimplePermissionPointResp.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SimplePermissionPointResp.java @@ -37,6 +37,11 @@ public class SimplePermissionPointResp implements IBaseTree children; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java index 28742366..22813a94 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java @@ -5,11 +5,12 @@ import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.client.model.req.QueryPermissionByIdsReq; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; +import cn.axzo.tyr.client.model.res.SimplePermissionPointResp; import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload; -import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; -import cn.axzo.tyr.server.repository.entity.SaasFeature; import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; +import cn.axzo.tyr.server.service.PermissionPointService; import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductPermissionCacheService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; @@ -50,7 +51,7 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing @Autowired private SaasFeatureResourceService saasFeatureResourceService; @Autowired - private SaasFeatureDao saasFeatureDao; + private PermissionPointService permissionPointService; @Override public void onEvent(Event event, EventConsumer.Context context) { @@ -94,9 +95,11 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing return Collections.emptyList(); } + // 新的菜单树是是把有权限点的父节点也存进去了,所以直接解析 Map featureResources = listSaasFeatureResource(productPermissions); - Map saasFeatures = listSaasFeature(productPermissions); + // 旧的菜单树只存储了权限点信息,没有把父节点存进去,需要解析父节点进行存储 + Map saasFeatures = listSaasFeature(productPermissions); return productPermissions.stream() .collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId)) @@ -135,14 +138,14 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing .collect(Collectors.toList()); } - SaasFeature saasFeature = saasFeatures.get(relation.getFeatureId()); + SimplePermissionPointResp saasFeature = saasFeatures.get(relation.getFeatureId()); if (Objects.isNull(saasFeature)) { return null; } return Lists.newArrayList(ProductPermissionCacheService.PermissionDTO.builder() .featureId(saasFeature.getId()) - .featureCode(saasFeature.getFeatureCode()) + .featureCode(saasFeature.getCode()) .featureType(saasFeature.getFeatureType()) .terminal(saasFeature.getTerminal()) .cooperateType(relation.getDictCode()) @@ -187,19 +190,23 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity())); } - private Map listSaasFeature(List productPermissions) { + private Map listSaasFeature(List productPermissions) { - List featureIds = productPermissions.stream() + Set featureIds = productPermissions.stream() .filter(e -> Objects.equals(e.getType(), OLD_FEATURE)) .map(SaasProductModuleFeatureRelation::getFeatureId) - .distinct() - .collect(Collectors.toList()); + .collect(Collectors.toSet()); if (CollectionUtils.isEmpty(featureIds)) { return Collections.emptyMap(); } - return saasFeatureDao.listByIds(featureIds).stream() - .collect(Collectors.toMap(SaasFeature::getId, Function.identity())); + return permissionPointService.listPermissionByIds( + QueryPermissionByIdsReq.builder() + .ids(featureIds) + .includeParent(true) + .build()) + .stream() + .collect(Collectors.toMap(SimplePermissionPointResp::getId, Function.identity())); } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java index 8f115601..c2b24650 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java @@ -4,12 +4,13 @@ import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.client.model.req.QueryPermissionByIdsReq; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; import cn.axzo.tyr.client.model.res.SaasRoleRes; +import cn.axzo.tyr.client.model.res.SimplePermissionPointResp; import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; -import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; -import cn.axzo.tyr.server.repository.entity.SaasFeature; +import cn.axzo.tyr.server.service.PermissionPointService; import cn.axzo.tyr.server.service.RolePermissionCacheService; import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; @@ -50,7 +51,7 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea @Autowired private SaasFeatureResourceService saasFeatureResourceService; @Autowired - private SaasFeatureDao saasFeatureDao; + private PermissionPointService permissionPointService; @Override public void onEvent(Event event, EventConsumer.Context context) { @@ -94,7 +95,7 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea Map featureResources = listSaasFeatureResource(roles); - Map saasFeatures = listSaasFeature(roles); + Map saasFeatures = listSaasFeature(roles); return roles.stream() .map(e -> { @@ -127,13 +128,13 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea .build()) .collect(Collectors.toList()); } - SaasFeature saasFeature = saasFeatures.get(permissionRelation.getFeatureId()); + SimplePermissionPointResp saasFeature = saasFeatures.get(permissionRelation.getFeatureId()); if (Objects.isNull(saasFeature)) { return null; } return Lists.newArrayList(RolePermissionCacheService.PermissionDTO.builder() .featureId(saasFeature.getId()) - .featureCode(saasFeature.getFeatureCode()) + .featureCode(saasFeature.getCode()) .featureType(saasFeature.getFeatureType()) .terminal(saasFeature.getTerminal()) .build()); @@ -180,22 +181,26 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity())); } - private Map listSaasFeature(List roles) { + private Map listSaasFeature(List roles) { - List featureIds = roles.stream() + Set featureIds = roles.stream() .filter(e -> !CollectionUtils.isEmpty(e.getPermissionRelations())) .map(SaasRoleRes::getPermissionRelations) .flatMap(Collection::stream) .filter(e -> Objects.equals(e.getType(), OLD_FEATURE)) .map(SaasPermissionRelationRes::getFeatureId) - .distinct() - .collect(Collectors.toList()); + .collect(Collectors.toSet()); if (CollectionUtils.isEmpty(featureIds)) { return Collections.emptyMap(); } - return saasFeatureDao.listByIds(featureIds).stream() - .collect(Collectors.toMap(SaasFeature::getId, Function.identity())); + return permissionPointService.listPermissionByIds( + QueryPermissionByIdsReq.builder() + .ids(featureIds) + .includeParent(true) + .build()) + .stream() + .collect(Collectors.toMap(SimplePermissionPointResp::getId, Function.identity())); } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionPointServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionPointServiceImpl.java index 86c81b8d..31b42688 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionPointServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionPointServiceImpl.java @@ -634,7 +634,8 @@ public class PermissionPointServiceImpl implements PermissionPointService { SaasFeature::getFeatureName, SaasFeature::getParentId, SaasFeature::getPath, - SaasFeature::getTerminal)); + SaasFeature::getTerminal, + SaasFeature::getFeatureType)); Set parentIds = new HashSet<>(); for (SaasFeature permission : allPermissions) { @@ -672,6 +673,7 @@ public class PermissionPointServiceImpl implements PermissionPointService { .name(permission.getFeatureName()) .parentId(permission.getParentId()) .terminal(permission.getTerminal()) + .featureType(permission.getFeatureType()) .build(); } 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 d5177650..1f87811b 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 @@ -159,7 +159,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { private final RolePermissionCacheService rolePermissionCacheService; private final SaasRoleUserRelationMapper saasRoleUserRelationMapper; - @Value("${permission.from.db:false}") + @Value("${permission.from.db:true}") private boolean PERMISSION_FROM_DB; @Override From 9dc6319aea2ae5452f20515caa078c3c8714e0e7 Mon Sep 17 00:00:00 2001 From: lilong Date: Thu, 1 Aug 2024 16:42:41 +0800 Subject: [PATCH 028/112] =?UTF-8?q?feat:(REQ-2720)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E6=97=A7=E8=8F=9C=E5=8D=95=E6=A0=91=E7=BC=93=E5=AD=98=EF=BC=8C?= =?UTF-8?q?=E5=9B=A0=E4=B8=BA=E6=B2=A1=E6=9C=89=E6=8A=8A=E7=88=B6=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E7=9A=84=E6=9D=83=E9=99=90=E5=AD=98=E5=82=A8=E8=B5=B7?= =?UTF-8?q?=E6=9D=A5=EF=BC=8C=E4=BD=86=E6=98=AF=E5=AE=9E=E9=99=85=E6=9C=89?= =?UTF-8?q?=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inner/CacheProductPermissionHandler.java | 29 +++++++++++-- ...acheProductSaasFeatureResourceHandler.java | 42 +++++++++++++++---- .../inner/CacheRolePermissionHandler.java | 29 +++++++++++-- .../CacheRoleSaasFeatureResourceHandler.java | 29 ++++++++++++- 4 files changed, 113 insertions(+), 16 deletions(-) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java index 22813a94..bd879908 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java @@ -17,11 +17,13 @@ import cn.axzo.tyr.server.service.SaasFeatureResourceService; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -182,12 +184,33 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing return Collections.emptyMap(); } + // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() .ids(featureIds) .needFeatureCodes(true) .build(); - return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() - .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity())); + List features = saasFeatureResourceService.list(pageSaasFeatureResourceReq); + + if (CollectionUtils.isEmpty(features)) { + return Collections.emptyMap(); + } + + List parentIds = features.stream() + .map(SaasFeatureResourceResp::getPath) + .flatMap(path -> Arrays.stream(path.split(","))) + .filter(StringUtils::isNotBlank) + .map(Long::valueOf) + .distinct() + .collect(Collectors.toList()); + + List parentFeatures = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() + .ids(parentIds) + .needFeatureCodes(true) + .build()); + features.addAll(parentFeatures); + + return features.stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); } private Map listSaasFeature(List productPermissions) { @@ -207,6 +230,6 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing .includeParent(true) .build()) .stream() - .collect(Collectors.toMap(SimplePermissionPointResp::getId, Function.identity())); + .collect(Collectors.toMap(SimplePermissionPointResp::getId, Function.identity(), (f, s) -> s)); } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java index 25ea200b..92ca8765 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java @@ -12,7 +12,7 @@ import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductSaasFeatureResourceCacheService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; -import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; @@ -20,10 +20,12 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import java.util.Arrays; import java.util.Collections; 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; @@ -42,6 +44,12 @@ public class CacheProductSaasFeatureResourceHandler implements EventHandler, Ini @Autowired private SaasFeatureResourceService saasFeatureResourceService; + public static final Set FEATURE_RESOURCE_TYPES = Sets.newHashSet(FeatureResourceType.MENU.getCode(), + FeatureResourceType.PAGE.getCode(), + FeatureResourceType.MENU_PARTITION_GROUP.getCode(), + FeatureResourceType.GROUP.getCode(), + FeatureResourceType.APP_ENTRY.getCode()); + @Override public void onEvent(Event event, EventConsumer.Context context) { log.info("begin cached product featureResource handler rocketmq event: {}", event); @@ -54,11 +62,6 @@ public class CacheProductSaasFeatureResourceHandler implements EventHandler, Ini PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() .productModuleIds(payload.getProductModuleIds()) .type(NEW_FEATURE) - .featureResourceTypes(Lists.newArrayList(FeatureResourceType.MENU.getCode(), - FeatureResourceType.PAGE.getCode(), - FeatureResourceType.MENU_PARTITION_GROUP.getCode(), - FeatureResourceType.GROUP.getCode(), - FeatureResourceType.APP_ENTRY.getCode())) .build(); List productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq); @@ -146,10 +149,33 @@ public class CacheProductSaasFeatureResourceHandler implements EventHandler, Ini return Collections.emptyMap(); } + // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() .ids(featureIds) + .needFeatureCodes(true) .build(); - return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() - .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity())); + List features = saasFeatureResourceService.list(pageSaasFeatureResourceReq); + + if (CollectionUtils.isEmpty(features)) { + return Collections.emptyMap(); + } + + List parentIds = features.stream() + .map(SaasFeatureResourceResp::getPath) + .flatMap(path -> Arrays.stream(path.split(","))) + .filter(StringUtils::isNotBlank) + .map(Long::valueOf) + .distinct() + .collect(Collectors.toList()); + + List parentFeatures = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() + .ids(parentIds) + .needFeatureCodes(true) + .build()); + features.addAll(parentFeatures); + + return features.stream() + .filter(e -> FEATURE_RESOURCE_TYPES.contains(e.getFeatureType())) + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java index c2b24650..135d2304 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java @@ -17,11 +17,13 @@ import cn.axzo.tyr.server.service.SaasFeatureResourceService; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -173,12 +175,33 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea return Collections.emptyMap(); } + // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() .ids(featureIds) .needFeatureCodes(true) .build(); - return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() - .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity())); + List features = saasFeatureResourceService.list(pageSaasFeatureResourceReq); + + if (CollectionUtils.isEmpty(features)) { + return Collections.emptyMap(); + } + + List parentIds = features.stream() + .map(SaasFeatureResourceResp::getPath) + .flatMap(path -> Arrays.stream(path.split(","))) + .filter(StringUtils::isNotBlank) + .map(Long::valueOf) + .distinct() + .collect(Collectors.toList()); + + List parentFeatures = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() + .ids(parentIds) + .needFeatureCodes(true) + .build()); + features.addAll(parentFeatures); + + return features.stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); } private Map listSaasFeature(List roles) { @@ -201,6 +224,6 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea .includeParent(true) .build()) .stream() - .collect(Collectors.toMap(SimplePermissionPointResp::getId, Function.identity())); + .collect(Collectors.toMap(SimplePermissionPointResp::getId, Function.identity(), (f, s) -> s)); } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java index 6b3dcebb..1ab27c2e 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java @@ -20,6 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -28,6 +29,7 @@ import java.util.Objects; import java.util.function.Function; import java.util.stream.Collectors; +import static cn.axzo.tyr.server.event.inner.CacheProductSaasFeatureResourceHandler.FEATURE_RESOURCE_TYPES; import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; /** @@ -145,10 +147,33 @@ public class CacheRoleSaasFeatureResourceHandler implements EventHandler, Initia return Collections.emptyMap(); } + // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() .ids(featureIds) + .needFeatureCodes(true) .build(); - return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() - .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity())); + List features = saasFeatureResourceService.list(pageSaasFeatureResourceReq); + + if (CollectionUtils.isEmpty(features)) { + return Collections.emptyMap(); + } + + List parentIds = features.stream() + .map(SaasFeatureResourceResp::getPath) + .flatMap(path -> Arrays.stream(path.split(","))) + .filter(StringUtils::isNotBlank) + .map(Long::valueOf) + .distinct() + .collect(Collectors.toList()); + + List parentFeatures = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() + .ids(parentIds) + .needFeatureCodes(true) + .build()); + features.addAll(parentFeatures); + + return features.stream() + .filter(e -> FEATURE_RESOURCE_TYPES.contains(e.getFeatureType())) + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); } } From 2cee917948c115f28f61ffb63fadf49aa40b390a Mon Sep 17 00:00:00 2001 From: lilong Date: Thu, 1 Aug 2024 16:43:56 +0800 Subject: [PATCH 029/112] =?UTF-8?q?feat:(REQ-2720)=20=E5=8E=BB=E6=8E=89red?= =?UTF-8?q?is=E7=9A=84=E8=BF=94=E5=9B=9E=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/service/impl/TyrSaasAuthServiceImpl.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 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 1f87811b..9eee508e 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 @@ -1504,26 +1504,24 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { */ private IdentityAuthRes findIdentityAuthV2(IdentityAuthReq identityAuthReq) { StopWatch watch = StopWatch.create("redis:"); - watch.start("query workspaceProductPermission"); + watch.start("redis:query workspaceProductPermission"); Map> workspaceProductPermissions = listWorkspaceProductPermission(identityAuthReq); watch.stop(); - log.info("redis:workspaceProductPermission:{}", JSON.toJSONString(workspaceProductPermissions)); - watch.start("query userRole"); + watch.start("redis:query userRole"); List saasRoleUsers = listRoleUserRelationsV2(identityAuthReq); log.info("redis:saasRoleUsers:", JSON.toJSONString(saasRoleUsers)); watch.stop(); - watch.start("query rolePermission"); + watch.start("redis:query rolePermission"); Map> rolePermissions = listRolePermission(identityAuthReq, saasRoleUsers); - log.info("redis:rolePermissions:{}", JSON.toJSONString(rolePermissions)); watch.stop(); Map> workspaceRoles = saasRoleUsers.stream() .collect(Collectors.groupingBy(e -> e.getSaasRoleUser().buildOuWorkspaceKey(), Collectors.mapping(SaasRoleUserV2DTO::getSaasRole, Collectors.toList()))); - watch.start("resolve permission"); + watch.start("redis:resolve permission"); List permissions = identityAuthReq.getWorkspaceOusPairs().stream() .map(workspaceOuPair -> { List productPermissions = Optional.ofNullable(workspaceProductPermissions.get(workspaceOuPair.getWorkspaceId())) @@ -1549,8 +1547,6 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { watch.stop(); watch.prettyPrint(TimeUnit.MILLISECONDS); - log.info("redis:Permissions:{}", JSON.toJSONString(permissions)); - IdentityAuthRes result = new IdentityAuthRes(); result.setIdentity(identityAuthReq.getIdentityId()); result.setIdentityType(identityAuthReq.getIdentityType()); From 9e85790cc79f71a5393c3228db3adeca8fdc6994 Mon Sep 17 00:00:00 2001 From: lilong Date: Thu, 1 Aug 2024 18:57:26 +0800 Subject: [PATCH 030/112] =?UTF-8?q?feat:(REQ-2720)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E3=80=81=E4=BA=A7=E5=93=81=E7=9A=84=E6=9D=83?= =?UTF-8?q?=E9=99=90=E5=8C=85=E6=8B=AC=E7=88=B6=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/res/SaasFeatureResourceResp.java | 11 + .../inner/CacheProductPermissionHandler.java | 208 ++++++++++++------ ...acheProductSaasFeatureResourceHandler.java | 64 ++++-- .../inner/CacheRolePermissionHandler.java | 203 +++++++++++------ .../CacheRoleSaasFeatureResourceHandler.java | 62 ++++-- 5 files changed, 377 insertions(+), 171 deletions(-) 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 index d8905e45..4f067e36 100644 --- 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 @@ -3,13 +3,18 @@ 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 com.google.common.collect.Lists; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.util.Arrays; import java.util.Date; +import java.util.List; +import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; @Data @Builder @@ -143,4 +148,10 @@ public class SaasFeatureResourceResp { * 唯一编码,用于pre环境菜单同步 */ private String uniCode; + + public List resolvePath() { + return Optional.ofNullable(this.getPath()) + .map(e -> Arrays.stream(e.split(",")).map(Long::valueOf).collect(Collectors.toList())) + .orElseGet(Lists::newArrayList); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java index bd879908..c6f33fa8 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java @@ -5,25 +5,22 @@ import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; -import cn.axzo.tyr.client.model.req.QueryPermissionByIdsReq; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; -import cn.axzo.tyr.client.model.res.SimplePermissionPointResp; import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload; +import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; +import cn.axzo.tyr.server.repository.entity.SaasFeature; import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; -import cn.axzo.tyr.server.service.PermissionPointService; import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductPermissionCacheService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -53,7 +50,7 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing @Autowired private SaasFeatureResourceService saasFeatureResourceService; @Autowired - private PermissionPointService permissionPointService; + private SaasFeatureDao saasFeatureDao; @Override public void onEvent(Event event, EventConsumer.Context context) { @@ -100,8 +97,12 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing // 新的菜单树是是把有权限点的父节点也存进去了,所以直接解析 Map featureResources = listSaasFeatureResource(productPermissions); + Map parentFeatureResources = listParentSaasFeatureResource(featureResources); + // 旧的菜单树只存储了权限点信息,没有把父节点存进去,需要解析父节点进行存储 - Map saasFeatures = listSaasFeature(productPermissions); + Map saasFeatures = listSaasFeature(productPermissions); + + Map parentSaasFeatures = listParentSaasFeature(saasFeatures); return productPermissions.stream() .collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId)) @@ -117,44 +118,14 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing List permissions = productFeatureRelations.stream() .map(relation -> { if (Objects.equals(relation.getType(), NEW_FEATURE)) { - SaasFeatureResourceResp featureResource = featureResources.get(relation.getFeatureId()); - // 菜单节点是不会关联元素code,所以缓存的featureCode使用菜单编码 - if (Objects.isNull(featureResource)) { - return null; - } - Set featureCodes = Optional.ofNullable(featureResource.getFeatureCodes()) - .orElseGet(() -> Sets.newHashSet(featureResource.getUniCode())); - - if (CollectionUtils.isEmpty(featureCodes)) { - return null; - } - - return featureCodes.stream() - .map(featureCode -> ProductPermissionCacheService.PermissionDTO.builder() - .featureId(featureResource.getId()) - .featureCode(featureCode) - .featureType(featureResource.getFeatureType()) - .terminal(featureResource.getTerminal()) - .cooperateType(relation.getDictCode()) - .build()) - .collect(Collectors.toList()); + return resolveFeatureResourcePermission(relation, featureResources, parentFeatureResources); } - SimplePermissionPointResp saasFeature = saasFeatures.get(relation.getFeatureId()); - if (Objects.isNull(saasFeature)) { - return null; - } - - return Lists.newArrayList(ProductPermissionCacheService.PermissionDTO.builder() - .featureId(saasFeature.getId()) - .featureCode(saasFeature.getCode()) - .featureType(saasFeature.getFeatureType()) - .terminal(saasFeature.getTerminal()) - .cooperateType(relation.getDictCode()) - .build()); + return resolveFeaturePermission(relation, saasFeatures, parentSaasFeatures); }) .filter(Objects::nonNull) .flatMap(Collection::stream) + .distinct() .collect(Collectors.toList()); if (CollectionUtils.isEmpty(permissions)) { @@ -171,6 +142,88 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing .collect(Collectors.toList()); } + private List resolveFeaturePermission(SaasProductModuleFeatureRelation relation, Map saasFeatures, Map parentSaasFeatures) { + SaasFeature saasFeature = saasFeatures.get(relation.getFeatureId()); + if (Objects.isNull(saasFeature)) { + return null; + } + + List permissionDTOS = Lists.newArrayList(ProductPermissionCacheService.PermissionDTO.builder() + .featureId(saasFeature.getId()) + .featureCode(saasFeature.getFeatureCode()) + .featureType(saasFeature.getFeatureType()) + .terminal(saasFeature.getTerminal()) + .cooperateType(relation.getDictCode()) + .build()); + + List parentPermissions = saasFeature.splitPath().stream() + .map(parentSaasFeatures::get) + .filter(Objects::nonNull) + .map(f -> ProductPermissionCacheService.PermissionDTO.builder() + .featureId(f.getId()) + .featureCode(f.getFeatureCode()) + .featureType(f.getFeatureType()) + .terminal(f.getTerminal()) + .cooperateType(relation.getDictCode()) + .build()) + .collect(Collectors.toList()); + + permissionDTOS.addAll(parentPermissions); + return permissionDTOS; + } + + private List resolveFeatureResourcePermission(SaasProductModuleFeatureRelation relation, Map featureResources, Map parentFeatureResources) { + SaasFeatureResourceResp featureResource = featureResources.get(relation.getFeatureId()); + // 菜单节点是不会关联元素code,所以缓存的featureCode使用菜单编码 + if (Objects.isNull(featureResource)) { + return null; + } + Set featureCodes = Optional.ofNullable(featureResource.getFeatureCodes()) + .orElseGet(() -> Sets.newHashSet(featureResource.getUniCode())); + + if (CollectionUtils.isEmpty(featureCodes)) { + return null; + } + + List permissionDTOS = featureCodes.stream() + .map(featureCode -> ProductPermissionCacheService.PermissionDTO.builder() + .featureId(featureResource.getId()) + .featureCode(featureCode) + .featureType(featureResource.getFeatureType()) + .terminal(featureResource.getTerminal()) + .cooperateType(relation.getDictCode()) + .build()) + .collect(Collectors.toList()); + + List parentPermissions = featureResource.resolvePath().stream() + .map(parentFeatureResources::get) + .filter(Objects::nonNull) + .map(f -> { + + Set parentFeatureCodes = Optional.ofNullable(f.getFeatureCodes()) + .orElseGet(() -> Sets.newHashSet(f.getUniCode())); + if (CollectionUtils.isEmpty(parentFeatureCodes)) { + return null; + } + + return parentFeatureCodes.stream() + .map(featureCode -> ProductPermissionCacheService.PermissionDTO.builder() + .featureId(featureResource.getId()) + .featureCode(featureCode) + .featureType(featureResource.getFeatureType()) + .terminal(featureResource.getTerminal()) + .cooperateType(relation.getDictCode()) + .build()) + .collect(Collectors.toList()); + }) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + permissionDTOS.addAll(parentPermissions); + return permissionDTOS; + } + private Map listSaasFeatureResource(List productPermissions) { @@ -184,36 +237,36 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing return Collections.emptyMap(); } - // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() .ids(featureIds) .needFeatureCodes(true) .build(); - List features = saasFeatureResourceService.list(pageSaasFeatureResourceReq); - - if (CollectionUtils.isEmpty(features)) { - return Collections.emptyMap(); - } - - List parentIds = features.stream() - .map(SaasFeatureResourceResp::getPath) - .flatMap(path -> Arrays.stream(path.split(","))) - .filter(StringUtils::isNotBlank) - .map(Long::valueOf) - .distinct() - .collect(Collectors.toList()); - - List parentFeatures = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() - .ids(parentIds) - .needFeatureCodes(true) - .build()); - features.addAll(parentFeatures); - - return features.stream() + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); } - private Map listSaasFeature(List productPermissions) { + private Map listParentSaasFeatureResource(Map productPermissions) { + + List parentIds = productPermissions.values().stream() + .map(SaasFeatureResourceResp::resolvePath) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(parentIds)) { + return Collections.emptyMap(); + } + + // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(parentIds) + .needFeatureCodes(true) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); + } + + private Map listSaasFeature(List productPermissions) { Set featureIds = productPermissions.stream() .filter(e -> Objects.equals(e.getType(), OLD_FEATURE)) @@ -224,12 +277,27 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing return Collections.emptyMap(); } - return permissionPointService.listPermissionByIds( - QueryPermissionByIdsReq.builder() - .ids(featureIds) - .includeParent(true) - .build()) - .stream() - .collect(Collectors.toMap(SimplePermissionPointResp::getId, Function.identity(), (f, s) -> s)); + return saasFeatureDao.listByIds(featureIds).stream() + .collect(Collectors.toMap(SaasFeature::getId, Function.identity())); + } + + private Map listParentSaasFeature(Map saasFeatures) { + + if (CollectionUtils.isEmpty(saasFeatures)) { + return Collections.emptyMap(); + } + + List parentIds = saasFeatures.values().stream() + .map(SaasFeature::splitPath) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(parentIds)) { + return Collections.emptyMap(); + } + + return saasFeatureDao.listByIds(parentIds).stream() + .collect(Collectors.toMap(SaasFeature::getId, Function.identity())); } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java index 92ca8765..6fe8b0dc 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java @@ -12,6 +12,7 @@ import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductSaasFeatureResourceCacheService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import com.google.common.collect.Lists; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -21,6 +22,7 @@ import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -95,6 +97,8 @@ public class CacheProductSaasFeatureResourceHandler implements EventHandler, Ini Map featureResources = listSaasFeatureResource(productPermissions); + Map parentFeatureResources = listParentSaasFeatureResource(featureResources); + return productPermissions.stream() .collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId)) .entrySet() @@ -112,15 +116,41 @@ public class CacheProductSaasFeatureResourceHandler implements EventHandler, Ini if (Objects.isNull(featureResource) || StringUtils.isBlank(featureResource.getUniCode())) { return null; } - return ProductSaasFeatureResourceCacheService.FeatureResourceDTO.builder() + + List featureResourceDTOS = Lists.newArrayList(ProductSaasFeatureResourceCacheService.FeatureResourceDTO.builder() .featureId(featureResource.getId()) .featureType(featureResource.getFeatureType()) .terminal(featureResource.getTerminal()) .uniCode(featureResource.getUniCode()) .cooperateType(relation.getDictCode()) - .build(); + .build()); + List parentPermissions = featureResource.resolvePath().stream() + .map(parentFeatureResources::get) + .filter(Objects::nonNull) + .map(f -> { + + if (StringUtils.isBlank(f.getUniCode())) { + return null; + } + + return ProductSaasFeatureResourceCacheService.FeatureResourceDTO.builder() + .featureId(featureResource.getId()) + .featureType(featureResource.getFeatureType()) + .terminal(featureResource.getTerminal()) + .uniCode(featureResource.getUniCode()) + .cooperateType(relation.getDictCode()) + .build(); + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + featureResourceDTOS.addAll(parentPermissions); + + return featureResourceDTOS; }) .filter(Objects::nonNull) + .flatMap(Collection::stream) + .distinct() + .filter(f -> FEATURE_RESOURCE_TYPES.contains(f.getFeatureType())) .collect(Collectors.toList()); if (CollectionUtils.isEmpty(productFeatureResources)) { @@ -154,28 +184,28 @@ public class CacheProductSaasFeatureResourceHandler implements EventHandler, Ini .ids(featureIds) .needFeatureCodes(true) .build(); - List features = saasFeatureResourceService.list(pageSaasFeatureResourceReq); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); + } - if (CollectionUtils.isEmpty(features)) { - return Collections.emptyMap(); - } + private Map listParentSaasFeatureResource(Map productPermissions) { - List parentIds = features.stream() - .map(SaasFeatureResourceResp::getPath) - .flatMap(path -> Arrays.stream(path.split(","))) - .filter(StringUtils::isNotBlank) - .map(Long::valueOf) + List parentIds = productPermissions.values().stream() + .map(SaasFeatureResourceResp::resolvePath) + .flatMap(Collection::stream) .distinct() .collect(Collectors.toList()); - List parentFeatures = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() + if (CollectionUtils.isEmpty(parentIds)) { + return Collections.emptyMap(); + } + + // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() .ids(parentIds) .needFeatureCodes(true) - .build()); - features.addAll(parentFeatures); - - return features.stream() - .filter(e -> FEATURE_RESOURCE_TYPES.contains(e.getFeatureType())) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java index 135d2304..d3e4d17e 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java @@ -4,26 +4,23 @@ import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; -import cn.axzo.tyr.client.model.req.QueryPermissionByIdsReq; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; import cn.axzo.tyr.client.model.res.SaasRoleRes; -import cn.axzo.tyr.client.model.res.SimplePermissionPointResp; import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; -import cn.axzo.tyr.server.service.PermissionPointService; +import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; +import cn.axzo.tyr.server.repository.entity.SaasFeature; import cn.axzo.tyr.server.service.RolePermissionCacheService; import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -53,7 +50,7 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea @Autowired private SaasFeatureResourceService saasFeatureResourceService; @Autowired - private PermissionPointService permissionPointService; + private SaasFeatureDao saasFeatureDao; @Override public void onEvent(Event event, EventConsumer.Context context) { @@ -97,7 +94,12 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea Map featureResources = listSaasFeatureResource(roles); - Map saasFeatures = listSaasFeature(roles); + Map parentFeatureResources = listParentSaasFeatureResource(featureResources); + + Map saasFeatures = listSaasFeature(roles); + + Map parentSaasFeatures = listParentSaasFeature(saasFeatures); + return roles.stream() .map(e -> { @@ -109,40 +111,13 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea .distinct() .map(permissionRelation -> { if (Objects.equals(permissionRelation.getType(), NEW_FEATURE)) { - SaasFeatureResourceResp featureResource = featureResources.get(permissionRelation.getFeatureId()); - // 菜单节点是不会关联元素code,所以缓存的featureCode使用菜单编码 - if (Objects.isNull(featureResource)) { - return null; - } - Set featureCodes = Optional.ofNullable(featureResource.getFeatureCodes()) - .orElseGet(() -> Sets.newHashSet(featureResource.getUniCode())); - - if (CollectionUtils.isEmpty(featureCodes)) { - return null; - } - - return featureCodes.stream() - .map(featureCode -> RolePermissionCacheService.PermissionDTO.builder() - .featureId(featureResource.getId()) - .featureCode(featureCode) - .featureType(featureResource.getFeatureType()) - .terminal(featureResource.getTerminal()) - .build()) - .collect(Collectors.toList()); + return resolveFeatureResourcePermission(permissionRelation, featureResources, parentFeatureResources); } - SimplePermissionPointResp saasFeature = saasFeatures.get(permissionRelation.getFeatureId()); - if (Objects.isNull(saasFeature)) { - return null; - } - return Lists.newArrayList(RolePermissionCacheService.PermissionDTO.builder() - .featureId(saasFeature.getId()) - .featureCode(saasFeature.getCode()) - .featureType(saasFeature.getFeatureType()) - .terminal(saasFeature.getTerminal()) - .build()); + return resolveFeaturePermission(permissionRelation, saasFeatures, parentSaasFeatures); }) .filter(Objects::nonNull) .flatMap(Collection::stream) + .distinct() .collect(Collectors.toList()); if (CollectionUtils.isEmpty(permissions)) { @@ -159,6 +134,85 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea .collect(Collectors.toList()); } + private static List resolveFeaturePermission(SaasPermissionRelationRes permissionRelation, Map saasFeatures, Map parentSaasFeatures) { + SaasFeature saasFeature = saasFeatures.get(permissionRelation.getFeatureId()); + if (Objects.isNull(saasFeature)) { + return null; + } + + List permissionDTOS = Lists.newArrayList(RolePermissionCacheService.PermissionDTO.builder() + .featureId(saasFeature.getId()) + .featureCode(saasFeature.getFeatureCode()) + .featureType(saasFeature.getFeatureType()) + .terminal(saasFeature.getTerminal()) + .build()); + + List parentPermissions = saasFeature.splitPath().stream() + .map(parentSaasFeatures::get) + .filter(Objects::nonNull) + .map(f -> RolePermissionCacheService.PermissionDTO.builder() + .featureId(saasFeature.getId()) + .featureCode(saasFeature.getFeatureCode()) + .featureType(saasFeature.getFeatureType()) + .terminal(saasFeature.getTerminal()) + .build()) + .collect(Collectors.toList()); + + permissionDTOS.addAll(parentPermissions); + return permissionDTOS; + } + + private static List resolveFeatureResourcePermission(SaasPermissionRelationRes permissionRelation, Map featureResources, Map parentFeatureResources) { + SaasFeatureResourceResp featureResource = featureResources.get(permissionRelation.getFeatureId()); + // 菜单节点是不会关联元素code,所以缓存的featureCode使用菜单编码 + if (Objects.isNull(featureResource)) { + return null; + } + Set featureCodes = Optional.ofNullable(featureResource.getFeatureCodes()) + .orElseGet(() -> Sets.newHashSet(featureResource.getUniCode())); + + if (CollectionUtils.isEmpty(featureCodes)) { + return null; + } + + List permissionDTOS = featureCodes.stream() + .map(featureCode -> RolePermissionCacheService.PermissionDTO.builder() + .featureId(featureResource.getId()) + .featureCode(featureCode) + .featureType(featureResource.getFeatureType()) + .terminal(featureResource.getTerminal()) + .build()) + .collect(Collectors.toList()); + + List parentPermissions = featureResource.resolvePath().stream() + .map(parentFeatureResources::get) + .filter(Objects::nonNull) + .map(f -> { + + Set parentFeatureCodes = Optional.ofNullable(f.getFeatureCodes()) + .orElseGet(() -> Sets.newHashSet(f.getUniCode())); + if (CollectionUtils.isEmpty(parentFeatureCodes)) { + return null; + } + + return parentFeatureCodes.stream() + .map(featureCode -> RolePermissionCacheService.PermissionDTO.builder() + .featureId(featureResource.getId()) + .featureCode(featureCode) + .featureType(featureResource.getFeatureType()) + .terminal(featureResource.getTerminal()) + .build()) + .collect(Collectors.toList()); + }) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + permissionDTOS.addAll(parentPermissions); + + return permissionDTOS; + } + private Map listSaasFeatureResource(List roles) { @@ -175,36 +229,37 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea return Collections.emptyMap(); } - // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() .ids(featureIds) .needFeatureCodes(true) .build(); - List features = saasFeatureResourceService.list(pageSaasFeatureResourceReq); - - if (CollectionUtils.isEmpty(features)) { - return Collections.emptyMap(); - } - - List parentIds = features.stream() - .map(SaasFeatureResourceResp::getPath) - .flatMap(path -> Arrays.stream(path.split(","))) - .filter(StringUtils::isNotBlank) - .map(Long::valueOf) - .distinct() - .collect(Collectors.toList()); - - List parentFeatures = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() - .ids(parentIds) - .needFeatureCodes(true) - .build()); - features.addAll(parentFeatures); - - return features.stream() + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); } - private Map listSaasFeature(List roles) { + private Map listParentSaasFeatureResource(Map productPermissions) { + + List parentIds = productPermissions.values().stream() + .map(SaasFeatureResourceResp::resolvePath) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(parentIds)) { + return Collections.emptyMap(); + } + + // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(parentIds) + .needFeatureCodes(true) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); + } + + private Map listSaasFeature(List roles) { Set featureIds = roles.stream() .filter(e -> !CollectionUtils.isEmpty(e.getPermissionRelations())) @@ -218,12 +273,28 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea return Collections.emptyMap(); } - return permissionPointService.listPermissionByIds( - QueryPermissionByIdsReq.builder() - .ids(featureIds) - .includeParent(true) - .build()) + return saasFeatureDao.listByIds(featureIds) .stream() - .collect(Collectors.toMap(SimplePermissionPointResp::getId, Function.identity(), (f, s) -> s)); + .collect(Collectors.toMap(SaasFeature::getId, Function.identity(), (f, s) -> s)); + } + + private Map listParentSaasFeature(Map saasFeatures) { + + if (CollectionUtils.isEmpty(saasFeatures)) { + return Collections.emptyMap(); + } + + List parentIds = saasFeatures.values().stream() + .map(SaasFeature::splitPath) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(parentIds)) { + return Collections.emptyMap(); + } + + return saasFeatureDao.listByIds(parentIds).stream() + .collect(Collectors.toMap(SaasFeature::getId, Function.identity())); } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java index 1ab27c2e..e55aaeee 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java @@ -20,7 +20,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -96,6 +95,8 @@ public class CacheRoleSaasFeatureResourceHandler implements EventHandler, Initia Map featureResources = listSaasFeatureResource(roles); + Map parentFeatureResources = listParentSaasFeatureResource(featureResources); + return roles.stream() .map(e -> { if (CollectionUtils.isEmpty(e.getPermissionRelations())) { @@ -109,14 +110,39 @@ public class CacheRoleSaasFeatureResourceHandler implements EventHandler, Initia if (Objects.isNull(featureResource) || StringUtils.isBlank(featureResource.getUniCode())) { return null; } - return RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO.builder() + + List featureResourceDTOS = Lists.newArrayList(RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO.builder() .featureId(featureResource.getId()) .featureType(featureResource.getFeatureType()) .terminal(featureResource.getTerminal()) .uniCode(featureResource.getUniCode()) - .build(); + .build()); + List parentPermissions = featureResource.resolvePath().stream() + .map(parentFeatureResources::get) + .filter(Objects::nonNull) + .map(f -> { + + if (StringUtils.isBlank(f.getUniCode())) { + return null; + } + + return RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO.builder() + .featureId(featureResource.getId()) + .featureType(featureResource.getFeatureType()) + .terminal(featureResource.getTerminal()) + .uniCode(featureResource.getUniCode()) + .build(); + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + featureResourceDTOS.addAll(parentPermissions); + + return featureResourceDTOS; }) .filter(Objects::nonNull) + .flatMap(Collection::stream) + .distinct() + .filter(f -> FEATURE_RESOURCE_TYPES.contains(f.getFeatureType())) .collect(Collectors.toList()); if (CollectionUtils.isEmpty(permissions)) { @@ -152,28 +178,28 @@ public class CacheRoleSaasFeatureResourceHandler implements EventHandler, Initia .ids(featureIds) .needFeatureCodes(true) .build(); - List features = saasFeatureResourceService.list(pageSaasFeatureResourceReq); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); + } - if (CollectionUtils.isEmpty(features)) { - return Collections.emptyMap(); - } + private Map listParentSaasFeatureResource(Map productPermissions) { - List parentIds = features.stream() - .map(SaasFeatureResourceResp::getPath) - .flatMap(path -> Arrays.stream(path.split(","))) - .filter(StringUtils::isNotBlank) - .map(Long::valueOf) + List parentIds = productPermissions.values().stream() + .map(SaasFeatureResourceResp::resolvePath) + .flatMap(Collection::stream) .distinct() .collect(Collectors.toList()); - List parentFeatures = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() + if (CollectionUtils.isEmpty(parentIds)) { + return Collections.emptyMap(); + } + + // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() .ids(parentIds) .needFeatureCodes(true) - .build()); - features.addAll(parentFeatures); - - return features.stream() - .filter(e -> FEATURE_RESOURCE_TYPES.contains(e.getFeatureType())) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); } } From a023d3960796d264ea3dc58614bbe1ff4fda1a90 Mon Sep 17 00:00:00 2001 From: lilong Date: Fri, 2 Aug 2024 14:36:02 +0800 Subject: [PATCH 031/112] =?UTF-8?q?feat:(REQ-2720)=20=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=85=83=E7=B4=A0=E7=BB=91=E5=AE=9A=E5=85=B3=E7=B3=BB=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=90=8E=EF=BC=8C=E8=A7=A6=E5=8F=91=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E4=BA=A7=E5=93=81=E3=80=81=E8=A7=92=E8=89=B2=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inner/CacheProductPermissionHandler.java | 57 ++++++++++----- ...acheProductSaasFeatureResourceHandler.java | 64 +++++++++++------ .../inner/CacheRolePermissionHandler.java | 69 ++++++++++++------ .../CacheRoleSaasFeatureResourceHandler.java | 72 +++++++++++-------- .../tyr/server/event/inner/EventTypeEnum.java | 1 + ...geElementFeatureResourceUpsertPayload.java | 19 +++++ .../job/CacheProductFeatureResourceJob.java | 2 +- .../server/job/CacheProductPermissionJob.java | 2 +- .../impl/SaasPageElementServiceImpl.java | 52 ++++++++++---- 9 files changed, 234 insertions(+), 104 deletions(-) create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/PageElementFeatureResourceUpsertPayload.java diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java index c6f33fa8..35df0b47 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java @@ -2,10 +2,10 @@ package cn.axzo.tyr.server.event.inner; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; -import cn.axzo.framework.rocketmq.EventHandler; import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; +import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.entity.SaasFeature; @@ -39,7 +39,7 @@ import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation. */ @Slf4j @Component -public class CacheProductPermissionHandler implements EventHandler, InitializingBean { +public class CacheProductPermissionHandler implements InitializingBean { @Autowired private EventConsumer eventConsumer; @@ -52,19 +52,7 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing @Autowired private SaasFeatureDao saasFeatureDao; - @Override - public void onEvent(Event event, EventConsumer.Context context) { - log.info("begin cached product permission handler rocketmq event: {}", event); - ProductPermissionCreatedPayload payload = event.normalizedData(ProductPermissionCreatedPayload.class); - - if (CollectionUtils.isEmpty(payload.getProductModuleIds())) { - return; - } - - PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() - .productModuleIds(payload.getProductModuleIds()) - .build(); - List productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq); + private void storeProductPermission(List productFeatures) { if (CollectionUtils.isEmpty(productFeatures)) { return; @@ -80,13 +68,44 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing .productPermissions(productPermissions) .build(); productPermissionCacheService.store(storeProductPermissionParam); + } + public void onProductPermissionUpsert(Event event, EventConsumer.Context context) { + log.info("begin cached product permission handler rocketmq event: {}", event); + ProductPermissionCreatedPayload payload = event.normalizedData(ProductPermissionCreatedPayload.class); + + if (CollectionUtils.isEmpty(payload.getProductModuleIds())) { + return; + } + PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() + .productModuleIds(payload.getProductModuleIds()) + .build(); + List productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq); + + storeProductPermission(productFeatures); + log.info("end cached product permission handler rocketmq event: {}", event); + } + + public void onPageElementFeatureResourceUpsert(Event event, EventConsumer.Context context) { + log.info("begin cached product permission handler rocketmq event: {}", event); + PageElementFeatureResourceUpsertPayload payload = event.normalizedData(PageElementFeatureResourceUpsertPayload.class); + + if (CollectionUtils.isEmpty(payload.getRelations())) { + return; + } + + PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() + .build(); + List productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq); + + storeProductPermission(productFeatures); log.info("end cached product permission handler rocketmq event: {}", event); } @Override public void afterPropertiesSet() throws Exception { - eventConsumer.registerHandler(EventTypeEnum.PRODUCT_PERMISSION_CREATED.getEventCode(), this); + eventConsumer.registerHandler(EventTypeEnum.PRODUCT_PERMISSION_CREATED.getEventCode(), this::onProductPermissionUpsert); + eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert); } public List resolveProductPermissions(List productPermissions) { @@ -208,10 +227,10 @@ public class CacheProductPermissionHandler implements EventHandler, Initializing return parentFeatureCodes.stream() .map(featureCode -> ProductPermissionCacheService.PermissionDTO.builder() - .featureId(featureResource.getId()) + .featureId(f.getId()) .featureCode(featureCode) - .featureType(featureResource.getFeatureType()) - .terminal(featureResource.getTerminal()) + .featureType(f.getFeatureType()) + .terminal(f.getTerminal()) .cooperateType(relation.getDictCode()) .build()) .collect(Collectors.toList()); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java index 6fe8b0dc..8e6a65fc 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java @@ -7,6 +7,7 @@ import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; +import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload; import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; import cn.axzo.tyr.server.service.ProductFeatureRelationService; @@ -35,7 +36,7 @@ import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation. @Slf4j @Component -public class CacheProductSaasFeatureResourceHandler implements EventHandler, InitializingBean { +public class CacheProductSaasFeatureResourceHandler implements InitializingBean { @Autowired private EventConsumer eventConsumer; @@ -52,20 +53,7 @@ public class CacheProductSaasFeatureResourceHandler implements EventHandler, Ini FeatureResourceType.GROUP.getCode(), FeatureResourceType.APP_ENTRY.getCode()); - @Override - public void onEvent(Event event, EventConsumer.Context context) { - log.info("begin cached product featureResource handler rocketmq event: {}", event); - ProductPermissionCreatedPayload payload = event.normalizedData(ProductPermissionCreatedPayload.class); - - if (CollectionUtils.isEmpty(payload.getProductModuleIds())) { - return; - } - - PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() - .productModuleIds(payload.getProductModuleIds()) - .type(NEW_FEATURE) - .build(); - List productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq); + private void storeProductFeatureResource(List productFeatures) { if (CollectionUtils.isEmpty(productFeatures)) { return; @@ -82,12 +70,48 @@ public class CacheProductSaasFeatureResourceHandler implements EventHandler, Ini .build(); productSaasFeatureResourceCacheService.store(storeProductFeatureResourceParam); + } + + public void onProductPermissionUpsert(Event event, EventConsumer.Context context) { + log.info("begin cached product featureResource handler rocketmq event: {}", event); + ProductPermissionCreatedPayload payload = event.normalizedData(ProductPermissionCreatedPayload.class); + + if (CollectionUtils.isEmpty(payload.getProductModuleIds())) { + return; + } + + PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() + .productModuleIds(payload.getProductModuleIds()) + .type(NEW_FEATURE) + .build(); + List productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq); + + storeProductFeatureResource(productFeatures); + log.info("end cached product featureResource handler rocketmq event: {}", event); + } + + public void onPageElementFeatureResourceUpsert(Event event, EventConsumer.Context context) { + log.info("begin cached product featureResource handler rocketmq event: {}", event); + PageElementFeatureResourceUpsertPayload payload = event.normalizedData(PageElementFeatureResourceUpsertPayload.class); + + if (CollectionUtils.isEmpty(payload.getRelations())) { + return; + } + + PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() + .type(NEW_FEATURE) + .build(); + List productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq); + + storeProductFeatureResource(productFeatures); log.info("end cached product featureResource handler rocketmq event: {}", event); } @Override public void afterPropertiesSet() throws Exception { - eventConsumer.registerHandler(EventTypeEnum.PRODUCT_PERMISSION_CREATED.getEventCode(), this); + eventConsumer.registerHandler(EventTypeEnum.PRODUCT_PERMISSION_CREATED.getEventCode(), this::onProductPermissionUpsert); + eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert); + } public List resolveProductFeatureResources(List productPermissions) { @@ -134,10 +158,10 @@ public class CacheProductSaasFeatureResourceHandler implements EventHandler, Ini } return ProductSaasFeatureResourceCacheService.FeatureResourceDTO.builder() - .featureId(featureResource.getId()) - .featureType(featureResource.getFeatureType()) - .terminal(featureResource.getTerminal()) - .uniCode(featureResource.getUniCode()) + .featureId(f.getId()) + .featureType(f.getFeatureType()) + .terminal(f.getTerminal()) + .uniCode(f.getUniCode()) .cooperateType(relation.getDictCode()) .build(); }) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java index d3e4d17e..70703d25 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java @@ -3,13 +3,16 @@ package cn.axzo.tyr.server.event.inner; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; +import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; import cn.axzo.tyr.client.model.res.SaasRoleRes; +import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.entity.SaasFeature; +import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; import cn.axzo.tyr.server.service.RolePermissionCacheService; import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; @@ -39,7 +42,7 @@ import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation. */ @Slf4j @Component -public class CacheRolePermissionHandler implements EventHandler, InitializingBean { +public class CacheRolePermissionHandler implements InitializingBean { @Autowired private EventConsumer eventConsumer; @@ -52,20 +55,7 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea @Autowired private SaasFeatureDao saasFeatureDao; - @Override - public void onEvent(Event event, EventConsumer.Context context) { - log.info("begin cached role permission handler rocketmq event: {}", event); - RolePermissionCreatedPayload payload = event.normalizedData(RolePermissionCreatedPayload.class); - - if (CollectionUtils.isEmpty(payload.getRoleIds())) { - return; - } - - RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() - .roleIds(Lists.newArrayList(payload.getRoleIds())) - .needPermissionRelation(true) - .build(); - List roles = roleService.list(listSaasRoleParam); + private void storeRolePermission(List roles) { if (CollectionUtils.isEmpty(roles)) { return; @@ -81,12 +71,45 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea .rolePermissions(rolePermissions) .build(); rolePermissionCacheService.store(storeRolePermissionParam); + } + + public void onRolePermissionUpsert(Event event, EventConsumer.Context context) { + log.info("begin cached role permission handler rocketmq event: {}", event); + RolePermissionCreatedPayload payload = event.normalizedData(RolePermissionCreatedPayload.class); + + if (CollectionUtils.isEmpty(payload.getRoleIds())) { + return; + } + + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .roleIds(Lists.newArrayList(payload.getRoleIds())) + .needPermissionRelation(true) + .build(); + List roles = roleService.list(listSaasRoleParam); + + storeRolePermission(roles); log.info("end cached role permission handler rocketmq event: {}", event); } + public void onPageElementFeatureResourceUpsert(Event event, EventConsumer.Context context) { + PageElementFeatureResourceUpsertPayload payload = event.normalizedData(PageElementFeatureResourceUpsertPayload.class); + + if (CollectionUtils.isEmpty(payload.getRelations())) { + return; + } + + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .needPermissionRelation(true) + .build(); + List roles = roleService.list(listSaasRoleParam); + + storeRolePermission(roles); + } + @Override public void afterPropertiesSet() throws Exception { - eventConsumer.registerHandler(EventTypeEnum.ROLE_PERMISSION_CREATED.getEventCode(), this); + eventConsumer.registerHandler(EventTypeEnum.ROLE_PERMISSION_CREATED.getEventCode(), this::onRolePermissionUpsert); + eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert); } public List resolveRolePermission(List roles) { @@ -151,10 +174,10 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea .map(parentSaasFeatures::get) .filter(Objects::nonNull) .map(f -> RolePermissionCacheService.PermissionDTO.builder() - .featureId(saasFeature.getId()) - .featureCode(saasFeature.getFeatureCode()) - .featureType(saasFeature.getFeatureType()) - .terminal(saasFeature.getTerminal()) + .featureId(f.getId()) + .featureCode(f.getFeatureCode()) + .featureType(f.getFeatureType()) + .terminal(f.getTerminal()) .build()) .collect(Collectors.toList()); @@ -197,10 +220,10 @@ public class CacheRolePermissionHandler implements EventHandler, InitializingBea return parentFeatureCodes.stream() .map(featureCode -> RolePermissionCacheService.PermissionDTO.builder() - .featureId(featureResource.getId()) + .featureId(f.getId()) .featureCode(featureCode) - .featureType(featureResource.getFeatureType()) - .terminal(featureResource.getTerminal()) + .featureType(f.getFeatureType()) + .terminal(f.getTerminal()) .build()) .collect(Collectors.toList()); }) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java index e55aaeee..ca7c4fc1 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java @@ -2,12 +2,11 @@ package cn.axzo.tyr.server.event.inner; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; -import cn.axzo.framework.rocketmq.EventHandler; -import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; import cn.axzo.tyr.client.model.res.SaasRoleRes; +import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService; import cn.axzo.tyr.server.service.RoleService; @@ -37,7 +36,7 @@ import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation. */ @Slf4j @Component -public class CacheRoleSaasFeatureResourceHandler implements EventHandler, InitializingBean { +public class CacheRoleSaasFeatureResourceHandler implements InitializingBean { @Autowired private EventConsumer eventConsumer; @@ -48,26 +47,7 @@ public class CacheRoleSaasFeatureResourceHandler implements EventHandler, Initia @Autowired private RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService; - @Override - public void onEvent(Event event, EventConsumer.Context context) { - log.info("begin cached role saasFeatureResource handler rocketmq event: {}", event); - RolePermissionCreatedPayload payload = event.normalizedData(RolePermissionCreatedPayload.class); - - if (CollectionUtils.isEmpty(payload.getRoleIds())) { - return; - } - - RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() - .roleIds(Lists.newArrayList(payload.getRoleIds())) - .needPermissionRelation(true) - .type(NEW_FEATURE) - .featureResourceTypes(Lists.newArrayList(FeatureResourceType.MENU, - FeatureResourceType.PAGE, - FeatureResourceType.MENU_PARTITION_GROUP, - FeatureResourceType.GROUP, - FeatureResourceType.APP_ENTRY)) - .build(); - List roles = roleService.list(listSaasRoleParam); + private void storeRoleFeatureResource(List roles) { if (CollectionUtils.isEmpty(roles)) { return; @@ -83,12 +63,48 @@ public class CacheRoleSaasFeatureResourceHandler implements EventHandler, Initia .roleSaasFeatureResources(rolePermissions) .build(); roleSaasFeatureResourceCacheService.store(storeRoleFeatureResourceParam); + } + public void onRolePermissionUpsert(Event event, EventConsumer.Context context) { + log.info("begin cached role saasFeatureResource handler rocketmq event: {}", event); + RolePermissionCreatedPayload payload = event.normalizedData(RolePermissionCreatedPayload.class); + + if (CollectionUtils.isEmpty(payload.getRoleIds())) { + return; + } + + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .roleIds(Lists.newArrayList(payload.getRoleIds())) + .needPermissionRelation(true) + .type(NEW_FEATURE) + .build(); + List roles = roleService.list(listSaasRoleParam); + + storeRoleFeatureResource(roles); + log.info("end cached role saasFeatureResource handler rocketmq event: {}", event); } + public void onPageElementFeatureResourceUpsert(Event event, EventConsumer.Context context) { + PageElementFeatureResourceUpsertPayload payload = event.normalizedData(PageElementFeatureResourceUpsertPayload.class); + + if (CollectionUtils.isEmpty(payload.getRelations())) { + return; + } + + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .needPermissionRelation(true) + .type(NEW_FEATURE) + .build(); + List roles = roleService.list(listSaasRoleParam); + + storeRoleFeatureResource(roles); + } + @Override public void afterPropertiesSet() throws Exception { - eventConsumer.registerHandler(EventTypeEnum.ROLE_PERMISSION_CREATED.getEventCode(), this); + eventConsumer.registerHandler(EventTypeEnum.ROLE_PERMISSION_CREATED.getEventCode(), this::onRolePermissionUpsert); + eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert); + } public List resolveRoleFeatureResource(List roles) { @@ -127,10 +143,10 @@ public class CacheRoleSaasFeatureResourceHandler implements EventHandler, Initia } return RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO.builder() - .featureId(featureResource.getId()) - .featureType(featureResource.getFeatureType()) - .terminal(featureResource.getTerminal()) - .uniCode(featureResource.getUniCode()) + .featureId(f.getId()) + .featureType(f.getFeatureType()) + .terminal(f.getTerminal()) + .uniCode(f.getUniCode()) .build(); }) .filter(Objects::nonNull) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/EventTypeEnum.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/EventTypeEnum.java index b6074238..3883080e 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/EventTypeEnum.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/EventTypeEnum.java @@ -10,6 +10,7 @@ public enum EventTypeEnum { ROLE_PERMISSION_CREATED("role-permission", "role-permission-created", "角色权限添加"), SAAS_FEATURE_UPSERT("saas-feature", "saas-feature-upsert", "旧菜单树更新"), SAAS_FEATURE_RESOURCE_UPSERT("saas-feature-resource", "saas-feature-resource-upsert", "新菜单树更新"), + PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT("page-element-feature-resource", "page-element-feature-resource-upsert", "菜单-页面元素绑定关系更新"), ; EventTypeEnum(String model, String name, String desc) { diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/PageElementFeatureResourceUpsertPayload.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/PageElementFeatureResourceUpsertPayload.java new file mode 100644 index 00000000..78332c19 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/PageElementFeatureResourceUpsertPayload.java @@ -0,0 +1,19 @@ +package cn.axzo.tyr.server.event.payload; + +import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PageElementFeatureResourceUpsertPayload implements Serializable { + + private List relations; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductFeatureResourceJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductFeatureResourceJob.java index e70074f7..2a4c602e 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductFeatureResourceJob.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductFeatureResourceJob.java @@ -48,7 +48,7 @@ public class CacheProductFeatureResourceJob extends IJobHandler { Event event = Event.builder() .data(payload) .build(); - cacheProductSaasFeatureResourceHandler.onEvent(event, null); + cacheProductSaasFeatureResourceHandler.onProductPermissionUpsert(event, null); return ReturnT.SUCCESS; } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductPermissionJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductPermissionJob.java index 299f47f3..b05d63a3 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductPermissionJob.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductPermissionJob.java @@ -48,7 +48,7 @@ public class CacheProductPermissionJob extends IJobHandler { Event event = Event.builder() .data(payload) .build(); - cacheProductPermissionHandler.onEvent(event, null); + cacheProductPermissionHandler.onProductPermissionUpsert(event, null); return ReturnT.SUCCESS; } } 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 6d32e0d7..4471eafe 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 @@ -4,22 +4,29 @@ 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.framework.rocketmq.Event; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum; import cn.axzo.tyr.client.common.enums.PageElementTypeEnum; -import cn.axzo.tyr.client.model.req.*; +import cn.axzo.tyr.client.model.req.GetPageElementReq; +import cn.axzo.tyr.client.model.req.GetUserHasPermissionPageElementReq; +import cn.axzo.tyr.client.model.req.IdentityAuthReq; +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.GetUserHasPermissionPageElementResp; import cn.axzo.tyr.client.model.res.IdentityAuthRes; import cn.axzo.tyr.client.model.res.PageElementBasicDTO; import cn.axzo.tyr.client.model.res.PageElementResp; +import cn.axzo.tyr.server.config.MqProducer; +import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; 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.TyrSaasAuthService; import cn.hutool.json.JSONUtil; @@ -38,12 +45,18 @@ import org.springframework.cloud.context.config.annotation.RefreshScope; 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.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.function.Function; import java.util.stream.Collectors; +import static cn.axzo.tyr.server.event.inner.EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT; + /** * @author likunpeng * @version 1.0 @@ -59,6 +72,7 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { private final SaasPageElementFeatureResourceRelationDao saasPageElementFeatureResourceRelationDao; private final SaasFeatureResourceDao saasFeatureResourceDao; private final TyrSaasAuthService tyrSaasAuthService; + private final MqProducer mqProducer; @Qualifier("asyncExecutor") @Autowired @@ -66,6 +80,8 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { @Value("${not.auth.featureCodes:}") private Set notAuthFeatureCodes; + private static final String TARGET_TYPE = "pageElementFeatureResourceId"; + @Override @Transactional(rollbackFor = Exception.class) public void report(PageElementReportReq request) { @@ -153,16 +169,28 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { Lists.newArrayList(modifyPageElementRelation.getFeatureResourceUniCode()), Lists.newArrayList(modifyPageElementRelation.getRelationType()), modifyPageElementRelation.getOperatorId()); // 保存新的绑定关系 - if (CollectionUtils.isNotEmpty(modifyPageElementRelation.getPageElementCodes())) { - List relations = modifyPageElementRelation.getPageElementCodes().stream().map(e -> SaasPageElementFeatureResourceRelation.builder() - .pageElementCode(e) - .featureResourceUniCode(modifyPageElementRelation.getFeatureResourceUniCode()) - .terminal(modifyPageElementRelation.getTerminal()) - .type(modifyPageElementRelation.getRelationType()) - .createBy(modifyPageElementRelation.getOperatorId()) - .build()).collect(Collectors.toList()); - saasPageElementFeatureResourceRelationDao.saveBatch(relations); + if (CollectionUtils.isEmpty(modifyPageElementRelation.getPageElementCodes())) { + return; } + + // 保存新的绑定关系 + List relations = modifyPageElementRelation.getPageElementCodes().stream().map(e -> SaasPageElementFeatureResourceRelation.builder() + .pageElementCode(e) + .featureResourceUniCode(modifyPageElementRelation.getFeatureResourceUniCode()) + .terminal(modifyPageElementRelation.getTerminal()) + .type(modifyPageElementRelation.getRelationType()) + .createBy(modifyPageElementRelation.getOperatorId()) + .build()).collect(Collectors.toList()); + saasPageElementFeatureResourceRelationDao.saveBatch(relations); + + Event event = Event.builder() + .targetType(TARGET_TYPE) + .eventCode(PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode()) + .data(PageElementFeatureResourceUpsertPayload.builder() + .relations(relations) + .build()) + .build(); + mqProducer.send(event); } @Override From bdf274a33d2f1d3159a7eee748d6b31dda0cef8b Mon Sep 17 00:00:00 2001 From: lilong Date: Fri, 2 Aug 2024 14:48:26 +0800 Subject: [PATCH 032/112] =?UTF-8?q?feat:(REQ-2720)=20=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E8=B7=9F=E5=85=83=E7=B4=A0=E7=BB=91=E5=AE=9A?= =?UTF-8?q?=E5=85=B3=E7=B3=BB=E6=9B=B4=E6=96=B0=E5=90=8E=EF=BC=8C=E6=A0=B9?= =?UTF-8?q?=E6=8D=AE=E4=BF=AE=E6=94=B9=E5=8F=91=E9=80=81mq=E7=9A=84payload?= =?UTF-8?q?=EF=BC=8C=E5=87=8F=E5=B0=91=E6=97=A5=E5=AD=90=E5=A4=A7=E5=B0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../req/PageProductFeatureRelationReq.java | 3 +++ .../inner/CacheProductPermissionHandler.java | 10 ++++++++- ...acheProductSaasFeatureResourceHandler.java | 5 ++++- .../inner/CacheRolePermissionHandler.java | 3 ++- .../CacheRoleSaasFeatureResourceHandler.java | 2 +- ...geElementFeatureResourceUpsertPayload.java | 2 +- .../impl/SaasPageElementServiceImpl.java | 22 +++++++++---------- 7 files changed, 30 insertions(+), 17 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageProductFeatureRelationReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageProductFeatureRelationReq.java index 9bc50bc5..a06f6cb6 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageProductFeatureRelationReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageProductFeatureRelationReq.java @@ -47,4 +47,7 @@ public class PageProductFeatureRelationReq implements IPageReq { */ @CriteriaField(field = "featureType", operator = Operator.IN) private List featureResourceTypes; + + @CriteriaField(field = "terminal", operator = Operator.EQ) + private String terminal; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java index 35df0b47..4e1dc0f1 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java @@ -16,6 +16,7 @@ import cn.axzo.tyr.server.service.SaasFeatureResourceService; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -82,6 +83,10 @@ public class CacheProductPermissionHandler implements InitializingBean { .build(); List productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq); + if (CollectionUtils.isEmpty(productFeatures)) { + return; + } + storeProductPermission(productFeatures); log.info("end cached product permission handler rocketmq event: {}", event); } @@ -90,7 +95,7 @@ public class CacheProductPermissionHandler implements InitializingBean { log.info("begin cached product permission handler rocketmq event: {}", event); PageElementFeatureResourceUpsertPayload payload = event.normalizedData(PageElementFeatureResourceUpsertPayload.class); - if (CollectionUtils.isEmpty(payload.getRelations())) { + if (StringUtils.isBlank(payload.getTerminal())) { return; } @@ -98,6 +103,9 @@ public class CacheProductPermissionHandler implements InitializingBean { .build(); List productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq); + if (CollectionUtils.isEmpty(productFeatures)) { + return; + } storeProductPermission(productFeatures); log.info("end cached product permission handler rocketmq event: {}", event); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java index 8e6a65fc..0a8fa2ef 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java @@ -94,7 +94,7 @@ public class CacheProductSaasFeatureResourceHandler implements InitializingBean log.info("begin cached product featureResource handler rocketmq event: {}", event); PageElementFeatureResourceUpsertPayload payload = event.normalizedData(PageElementFeatureResourceUpsertPayload.class); - if (CollectionUtils.isEmpty(payload.getRelations())) { + if (StringUtils.isBlank(payload.getTerminal())) { return; } @@ -103,6 +103,9 @@ public class CacheProductSaasFeatureResourceHandler implements InitializingBean .build(); List productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq); + if (CollectionUtils.isEmpty(productFeatures)) { + return; + } storeProductFeatureResource(productFeatures); log.info("end cached product featureResource handler rocketmq event: {}", event); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java index 70703d25..12ce3db5 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java @@ -19,6 +19,7 @@ import cn.axzo.tyr.server.service.SaasFeatureResourceService; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -94,7 +95,7 @@ public class CacheRolePermissionHandler implements InitializingBean { public void onPageElementFeatureResourceUpsert(Event event, EventConsumer.Context context) { PageElementFeatureResourceUpsertPayload payload = event.normalizedData(PageElementFeatureResourceUpsertPayload.class); - if (CollectionUtils.isEmpty(payload.getRelations())) { + if (StringUtils.isBlank(payload.getTerminal())) { return; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java index ca7c4fc1..be92484b 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java @@ -87,7 +87,7 @@ public class CacheRoleSaasFeatureResourceHandler implements InitializingBean { public void onPageElementFeatureResourceUpsert(Event event, EventConsumer.Context context) { PageElementFeatureResourceUpsertPayload payload = event.normalizedData(PageElementFeatureResourceUpsertPayload.class); - if (CollectionUtils.isEmpty(payload.getRelations())) { + if (StringUtils.isBlank(payload.getTerminal())) { return; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/PageElementFeatureResourceUpsertPayload.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/PageElementFeatureResourceUpsertPayload.java index 78332c19..f0c6b420 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/PageElementFeatureResourceUpsertPayload.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/PageElementFeatureResourceUpsertPayload.java @@ -15,5 +15,5 @@ import java.util.List; @AllArgsConstructor public class PageElementFeatureResourceUpsertPayload implements Serializable { - private List relations; + private String terminal; } 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 4471eafe..655451d5 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 @@ -169,25 +169,23 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { Lists.newArrayList(modifyPageElementRelation.getFeatureResourceUniCode()), Lists.newArrayList(modifyPageElementRelation.getRelationType()), modifyPageElementRelation.getOperatorId()); // 保存新的绑定关系 - if (CollectionUtils.isEmpty(modifyPageElementRelation.getPageElementCodes())) { - return; + if (CollectionUtils.isNotEmpty(modifyPageElementRelation.getPageElementCodes())) { + List relations = modifyPageElementRelation.getPageElementCodes().stream().map(e -> SaasPageElementFeatureResourceRelation.builder() + .pageElementCode(e) + .featureResourceUniCode(modifyPageElementRelation.getFeatureResourceUniCode()) + .terminal(modifyPageElementRelation.getTerminal()) + .type(modifyPageElementRelation.getRelationType()) + .createBy(modifyPageElementRelation.getOperatorId()) + .build()).collect(Collectors.toList()); + saasPageElementFeatureResourceRelationDao.saveBatch(relations); } - // 保存新的绑定关系 - List relations = modifyPageElementRelation.getPageElementCodes().stream().map(e -> SaasPageElementFeatureResourceRelation.builder() - .pageElementCode(e) - .featureResourceUniCode(modifyPageElementRelation.getFeatureResourceUniCode()) - .terminal(modifyPageElementRelation.getTerminal()) - .type(modifyPageElementRelation.getRelationType()) - .createBy(modifyPageElementRelation.getOperatorId()) - .build()).collect(Collectors.toList()); - saasPageElementFeatureResourceRelationDao.saveBatch(relations); Event event = Event.builder() .targetType(TARGET_TYPE) .eventCode(PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode()) .data(PageElementFeatureResourceUpsertPayload.builder() - .relations(relations) + .terminal(modifyPageElementRelation.getTerminal()) .build()) .build(); mqProducer.send(event); From 36d949fdd787d13af5f96c871cd3ff8bb3ba7dd2 Mon Sep 17 00:00:00 2001 From: lilong Date: Fri, 2 Aug 2024 18:04:37 +0800 Subject: [PATCH 033/112] =?UTF-8?q?feat:(REQ-2720)=20=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E5=AD=90=E8=8A=82=E7=82=B9=E6=98=AF=E5=85=8D=E6=8E=88=E6=9D=83?= =?UTF-8?q?=EF=BC=8C=E9=9C=80=E8=A6=81=E8=BF=94=E5=9B=9E=E7=88=B6=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E6=9D=83=E9=99=90=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/model/res/IdentityAuthRes.java | 2 +- .../model/res/SaasFeatureResourceResp.java | 9 +++--- .../event/inner/CacheSaasFeatureHandler.java | 1 + .../CacheSaasFeatureResourceHandler.java | 1 + .../service/SaasFeatureResourceService.java | 2 ++ .../service/impl/TyrSaasAuthServiceImpl.java | 31 +++++++++++++------ 6 files changed, 31 insertions(+), 15 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/IdentityAuthRes.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/IdentityAuthRes.java index fa3a9a2b..fd8946a4 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/IdentityAuthRes.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/IdentityAuthRes.java @@ -56,7 +56,7 @@ public class IdentityAuthRes { public static class PermissionPoint { private Long featureId; - private String featureCode; + private String featureCode; private Integer featureType; 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 index 4f067e36..b5d3484c 100644 --- 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 @@ -3,7 +3,7 @@ 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 com.google.common.collect.Lists; +import com.google.common.collect.Sets; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -11,7 +11,6 @@ import lombok.NoArgsConstructor; import java.util.Arrays; import java.util.Date; -import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -149,9 +148,9 @@ public class SaasFeatureResourceResp { */ private String uniCode; - public List resolvePath() { + public Set resolvePath() { return Optional.ofNullable(this.getPath()) - .map(e -> Arrays.stream(e.split(",")).map(Long::valueOf).collect(Collectors.toList())) - .orElseGet(Lists::newArrayList); + .map(e -> Arrays.stream(e.split(",")).map(Long::valueOf).collect(Collectors.toSet())) + .orElseGet(Sets::newHashSet); } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java index 65e7174a..888b5893 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java @@ -48,6 +48,7 @@ public class CacheSaasFeatureHandler implements EventHandler, InitializingBean { .map(e -> SaasFeatureResourceService.SaasFeatureResourceCache.builder() .featureId(e.getId()) .notAuth(DelegatedType.notAuth(e.getDelegatedType())) + .parentIds(e.splitPath()) .build()) .collect(Collectors.toList()); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java index 0f2779aa..69c213a2 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java @@ -48,6 +48,7 @@ public class CacheSaasFeatureResourceHandler implements EventHandler, Initializi .map(e -> SaasFeatureResourceService.SaasFeatureResourceCache.builder() .featureId(e.getId()) .notAuth(SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) + .parentIds(e.resolvePath()) .build()) .collect(Collectors.toList()); 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 8a3fcc7d..56ff3b82 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 @@ -105,5 +105,7 @@ public interface SaasFeatureResourceService extends IService parentIds; } } 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 9eee508e..ab46a710 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 @@ -1521,6 +1521,15 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .collect(Collectors.groupingBy(e -> e.getSaasRoleUser().buildOuWorkspaceKey(), Collectors.mapping(SaasRoleUserV2DTO::getSaasRole, Collectors.toList()))); + Set terminals = workspaceProductPermissions.values().stream() + .flatMap(Collection::stream) + .map(WorkspaceProductService.ProductPermission::getPermissions) + .flatMap(Collection::stream) + .map(ProductPermissionCacheService.PermissionDTO::getTerminal) + .collect(Collectors.toSet()); + // CMP、CMS新旧菜单树id不会重复 + List allFeatures = listSaasFeatureCaches(terminals); + watch.start("redis:resolve permission"); List permissions = identityAuthReq.getWorkspaceOusPairs().stream() .map(workspaceOuPair -> { @@ -1541,7 +1550,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { List saasRoles = workspaceRoles.get(workspaceOuPair.buildOuWorkspaceKey()); - return buildPermissionsV2(workspaceOuPair, productPermissions, saasRoles, rolePermissions); + return buildPermissionsV2(workspaceOuPair, productPermissions, saasRoles, rolePermissions, allFeatures); }) .collect(Collectors.toList()); watch.stop(); @@ -1560,19 +1569,14 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { private IdentityAuthRes.WorkspacePermission buildPermissionsV2(IdentityAuthReq.WorkspaceOuPair workspaceOuPair, List productPermissions, List saasRoles, - Map> rolePermissions) { + Map> rolePermissions, + List allFeatures) { IdentityAuthRes.WorkspacePermission workspacePermission = IdentityAuthRes.WorkspacePermission.builder() .workspaceId(workspaceOuPair.getWorkspaceId()) .ouId(workspaceOuPair.getOuId()) .build(); - // 根据项目的产品找到对应端的所有权限点,因为可能存在某些权限点被删除或者是免授权,虽然有两颗权限点树,但是id不会重复,新的权限点从100000开始,历史的后续不会再使用 - Set terminals = productPermissions.stream() - .map(ProductPermissionCacheService.PermissionDTO::getTerminal) - .collect(Collectors.toSet()); - List allFeatures = listSaasFeatureCaches(terminals); - if (CollectionUtils.isEmpty(allFeatures)) { return workspacePermission; } @@ -1650,15 +1654,24 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { private Set buildNoAuthPermission(List productPermissions, List allFeatuers) { + + // 因为有权授权权限的权限点,就需要有所有上层权限点的权限 Set notAuthFeatureIds = allFeatuers.stream() .filter(SaasFeatureResourceService.SaasFeatureResourceCache::isNotAuth) - .map(SaasFeatureResourceService.SaasFeatureResourceCache::getFeatureId) + .map(e -> Optional.ofNullable(e.getParentIds()) + .map(f -> { + f.add(e.getFeatureId()); + return f; + }) + .orElseGet(() -> Sets.newHashSet(e.getFeatureId()))) + .flatMap(Collection::stream) .collect(Collectors.toSet()); if (CollectionUtils.isEmpty(notAuthFeatureIds)) { return Collections.emptySet(); } + return productPermissions.stream() .filter(productPermission -> notAuthFeatureIds.contains(productPermission.getFeatureId())) .map(e -> IdentityAuthRes.PermissionPoint.builder() From 756cb227fe554d9834548472e1e1fb4cd5a1d16a Mon Sep 17 00:00:00 2001 From: lilong Date: Fri, 2 Aug 2024 18:21:20 +0800 Subject: [PATCH 034/112] =?UTF-8?q?feat:(REQ-2720)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E7=BC=93=E5=AD=98=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java index 89895be7..0d299ed9 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java @@ -50,6 +50,7 @@ public class CacheSaasFeatureJob extends IJobHandler { .builder() .featureId(e.getId()) .notAuth(DelegatedType.notAuth(e.getDelegatedType())) + .parentIds(e.splitPath()) .build(), Collectors.toList()))); List saasFeatureResources = saasFeatures.entrySet().stream() @@ -77,6 +78,7 @@ public class CacheSaasFeatureJob extends IJobHandler { .builder() .featureId(e.getId()) .notAuth(SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) + .parentIds(e.resolvePath()) .build(), Collectors.toList()))); List featureResources = saasFeatureResources.entrySet().stream() From 46505e3243aed8927db7fc2605e4e8db475bcdc9 Mon Sep 17 00:00:00 2001 From: lilong Date: Fri, 2 Aug 2024 19:15:16 +0800 Subject: [PATCH 035/112] =?UTF-8?q?feat:(REQ-2720)=20=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E6=9D=83=E9=99=90=E8=A7=A6=E5=8F=91mq?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/service/impl/RoleServiceImpl.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) 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 3f7baa25..4384446d 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 @@ -41,6 +41,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.config.MqProducer; +import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; import cn.axzo.tyr.server.model.ResourcePermission; import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO; @@ -99,7 +100,6 @@ import org.springframework.beans.BeanUtils; 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.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -117,6 +117,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; +import static cn.axzo.tyr.server.event.inner.EventTypeEnum.ROLE_PERMISSION_CREATED; import static cn.axzo.tyr.server.event.inner.EventTypeEnum.SAAS_FEATURE_RESOURCE_UPSERT; import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE; @@ -387,6 +388,15 @@ public class RoleServiceImpl extends ServiceImpl // 保存新的菜单资源树权限 saveSaasFeatureResourcePermission(saveOrUpdateRole, saasFeatureResources, saasPermissionGroup); + + Event event = Event.builder() + .targetType(TARGET_TYPE) + .eventCode(ROLE_PERMISSION_CREATED.getEventCode()) + .data(RolePermissionCreatedPayload.builder() + .roleIds(Sets.newHashSet(saasRole.getId())) + .build()) + .build(); + mqProducer.send(event); return saasRole.getId(); } From 8b54388a9618009314751ee2dc4818449d0f3830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Mon, 5 Aug 2024 15:21:23 +0800 Subject: [PATCH 036/112] =?UTF-8?q?feat(REQ-2699):=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=85=83=E7=B4=A0=E5=A2=9E=E5=8A=A0=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/common/enums/PageElementTypeEnum.java | 1 + .../axzo/tyr/client/model/res/PageElementResp.java | 10 ++++++++++ .../server/repository/entity/SaasPageElement.java | 12 ++++++++++++ 3 files changed, 23 insertions(+) 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 index d51b9070..eb1c0305 100644 --- 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 @@ -14,6 +14,7 @@ public enum PageElementTypeEnum { PAGE("PAGE", "页面"), COMPONENT("COMPONENT", "组件"), + APP_ENTRY("APP_ENTRY", "应用入口"), ; 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 c32c9411..5096c267 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 @@ -48,6 +48,16 @@ public class PageElementResp { */ private String linkUrl; + /** + * app类型(APP:原生,H5:h5页面) + */ + private String appType; + + /** + * 客户端版本号 + */ + private Integer version; + /** * 是否已勾选 */ 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 index f5327ea1..2b475092 100644 --- 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 @@ -61,4 +61,16 @@ public class SaasPageElement extends BaseEntity { */ @TableField("create_name") private String createName; + + /** + * app类型(APP:原生,H5:h5页面) + */ + @TableField("app_type") + private String appType; + + /** + * 客户端版本号 + */ + @TableField("version") + private Integer version; } From fd86f41f38b1ae235c5a3ed207f69265da49f1e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Tue, 6 Aug 2024 14:08:28 +0800 Subject: [PATCH 037/112] =?UTF-8?q?feat(REQ-2699):=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=A2=9E=E5=8A=A0=E5=A4=9A=E5=B7=A5=E4=BD=9C?= =?UTF-8?q?=E5=8F=B0=E7=B1=BB=E5=9E=8B=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/req/FeatureResourceTreeSaveReq.java | 5 +++++ .../client/model/res/FeatureResourceDTO.java | 5 +++++ .../repository/entity/SaasFeatureResource.java | 5 +++++ .../repository/entity/SaasPageElement.java | 6 ++++++ .../impl/SaasFeatureResourceServiceImpl.java | 17 +++++++++++------ 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureResourceTreeSaveReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureResourceTreeSaveReq.java index 58e84c8b..f5c00c4a 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureResourceTreeSaveReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureResourceTreeSaveReq.java @@ -39,6 +39,11 @@ public class FeatureResourceTreeSaveReq extends BaseFeatureResourceDO { */ private Long workspaceType; + /** + * 应用范围(租户类型):1:企业工作台 2;项目工作台 以英文逗号分隔 + */ + private String workspaceTypes; + /** * 最低版本序列,主要支持版本灰度策略 */ 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 7d01dc64..7582eadf 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 @@ -144,6 +144,11 @@ public class FeatureResourceDTO implements Serializable { */ private Long workspaceType; + /** + * 应用范围(租户类型):1:企业工作台 2;项目工作台 以英文逗号分隔 + */ + private String workspaceTypes; + /** * 最低版本序列,主要支持版本灰度策略 */ 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 526e5dc7..448a4146 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 @@ -162,6 +162,11 @@ public class SaasFeatureResource extends BaseEntity { */ private Long workspaceType; + /** + * 应用范围(租户类型):1:企业工作台 2;项目工作台 以英文逗号分隔 cmp的应用可以配置支持多工作台类型 + */ + private String workspaceTypes; + /** * 最低版本序列,主要支持版本灰度策略 */ 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 index 2b475092..63e0166c 100644 --- 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 @@ -68,6 +68,12 @@ public class SaasPageElement extends BaseEntity { @TableField("app_type") private String appType; + /** + * 项目code(H5会拉取项目下所有的元素) + */ + @TableField("item_code") + private String itemCode; + /** * 客户端版本号 */ 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 28297274..1c6b2f11 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 @@ -55,12 +55,7 @@ import org.springframework.cache.annotation.CacheEvict; import org.springframework.stereotype.Service; 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.*; import java.util.stream.Collectors; import static cn.axzo.tyr.server.config.exception.BizResultCode.FEATURE_RESOURCE_NOT_FOUND; @@ -172,6 +167,12 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl dbWorkspaceTypes = Arrays.stream(e.getWorkspaceTypes().split(",")).collect(Collectors.toList()); + return dbWorkspaceTypes.contains(req.getWorkspaceType().toString()); + } + // 数据库默认值为0 if (Objects.equals(e.getWorkspaceType(), DEFAULT_WORKSPACE_TYPE)) { return true; @@ -205,6 +206,10 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl 0) { + req.setWorkspaceTypes(req.getWorkspaceType().toString()); + } SaasFeatureResource baseResource = BeanMapper.copyBean(req, SaasFeatureResource.class); baseResource.setUpdateBy(req.getOperatorId()); // 新增时候 From 2f8c8ad0514eef931a9ef6af7936dd37a83627bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Tue, 6 Aug 2024 14:43:01 +0800 Subject: [PATCH 038/112] =?UTF-8?q?feat(REQ-2699):=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=A2=9E=E5=8A=A0=E5=A4=9A=E5=B7=A5=E4=BD=9C?= =?UTF-8?q?=E5=8F=B0=E7=B1=BB=E5=9E=8B=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/service/impl/SaasFeatureResourceServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 1c6b2f11..25e3f14c 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 @@ -169,7 +169,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl dbWorkspaceTypes = Arrays.stream(e.getWorkspaceTypes().split(",")).collect(Collectors.toList()); + List dbWorkspaceTypes = Arrays.stream(e.getWorkspaceTypes().split(",")).filter(StringUtils::isNotBlank).collect(Collectors.toList()); return dbWorkspaceTypes.contains(req.getWorkspaceType().toString()); } From 4f7e8aa518051c041b01539def900a9b441d6e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Wed, 7 Aug 2024 09:58:31 +0800 Subject: [PATCH 039/112] =?UTF-8?q?feat(REQ-2699):=E5=85=83=E7=B4=A0?= =?UTF-8?q?=E8=A1=A8=E5=A2=9E=E5=8A=A0=E8=B7=AF=E7=94=B1=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/server/repository/entity/SaasPageElement.java | 5 +++++ 1 file changed, 5 insertions(+) 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 index 63e0166c..a8be5edc 100644 --- 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 @@ -50,6 +50,11 @@ public class SaasPageElement extends BaseEntity { @TableField("link_url") private String linkUrl; + /** + * APP适配参数 + */ + private String linkExt; + /** * 所属端 */ From a0de50cfb5e725aea7dd151c6365beb715ae80fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Wed, 7 Aug 2024 13:54:11 +0800 Subject: [PATCH 040/112] =?UTF-8?q?feat(REQ-2699):=E5=85=83=E7=B4=A0?= =?UTF-8?q?=E8=A1=A8=E5=A2=9E=E5=8A=A0=E8=B7=AF=E7=94=B1=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/service/impl/SaasPageElementServiceImpl.java | 2 ++ 1 file changed, 2 insertions(+) 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 80c7e091..10523ff2 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 @@ -337,6 +337,7 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { .type(e.getType()) .selected(selectedIds.contains(e.getId())) .children(Lists.newArrayList()) + .version(e.getVersion()) .build()).collect(Collectors.toList()); if (CollectionUtils.isEmpty(pageTypeElements)) { return Collections.emptyList(); @@ -352,6 +353,7 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { .name(e.getName()) .type(e.getType()) .selected(selectedIds.contains(e.getId())) + .version(e.getVersion()) .build()); } }); From 3aa0886f8da5a0ad2725c8d7390e27e535620cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Wed, 7 Aug 2024 14:28:53 +0800 Subject: [PATCH 041/112] =?UTF-8?q?feat(REQ-2699):=E5=85=83=E7=B4=A0?= =?UTF-8?q?=E8=A1=A8=E5=A2=9E=E5=8A=A0=E8=B7=AF=E7=94=B1=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/repository/entity/SaasPageElement.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) 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 index a8be5edc..eb60d3d4 100644 --- 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 @@ -20,6 +20,11 @@ import lombok.*; @TableName("saas_page_element") public class SaasPageElement extends BaseEntity { + /** + * 客户端版本号 + */ + private Integer version; + /** * 元素的组编码 */ @@ -78,10 +83,4 @@ public class SaasPageElement extends BaseEntity { */ @TableField("item_code") private String itemCode; - - /** - * 客户端版本号 - */ - @TableField("version") - private Integer version; } From 41ab01c8c2933385e05bb6b0ea3e5ab4bd61bdb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Wed, 7 Aug 2024 15:04:57 +0800 Subject: [PATCH 042/112] =?UTF-8?q?feat(REQ-2699):=E5=85=83=E7=B4=A0?= =?UTF-8?q?=E8=A1=A8=E5=A2=9E=E5=8A=A0=E8=B7=AF=E7=94=B1=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/service/impl/SaasFeatureResourceServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 25e3f14c..d23c19c5 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 @@ -239,7 +239,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl Date: Wed, 7 Aug 2024 16:12:14 +0800 Subject: [PATCH 043/112] =?UTF-8?q?feat(REQ-2699):=E5=85=83=E7=B4=A0?= =?UTF-8?q?=E8=A1=A8=E5=A2=9E=E5=8A=A0=E8=B7=AF=E7=94=B1=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 9c09c7bf..b54f22e2 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 @@ -32,7 +32,8 @@ public class SaasFeatureResourceDao extends ServiceImpl Date: Wed, 7 Aug 2024 17:20:43 +0800 Subject: [PATCH 044/112] =?UTF-8?q?feat(REQ-2699):=E5=85=83=E7=B4=A0?= =?UTF-8?q?=E8=A1=A8=E5=A2=9E=E5=8A=A0=E8=B7=AF=E7=94=B1=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/service/impl/SaasFeatureResourceServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 d23c19c5..02307fef 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 @@ -632,7 +632,8 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl Date: Thu, 8 Aug 2024 10:33:10 +0800 Subject: [PATCH 045/112] =?UTF-8?q?feat(REQ-2300):=20=E5=86=99=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E5=A2=9E=E5=8A=A0=E4=BA=8B=E5=8A=A1=E6=B3=A8=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/server/service/impl/DataObjectServiceImpl.java | 4 ++++ .../tyr/server/service/impl/DataResourceServiceImpl.java | 5 +++++ .../server/service/impl/FeatureResourceSyncServiceImpl.java | 2 ++ .../tyr/server/service/impl/PermissionPointServiceImpl.java | 2 ++ .../cn/axzo/tyr/server/service/impl/ProductServiceImpl.java | 4 ++++ .../cn/axzo/tyr/server/service/impl/RoleUserService.java | 2 ++ .../tyr/server/service/impl/SaasBasicDictServiceImpl.java | 4 ++++ .../server/service/impl/SaasFeatureResourceServiceImpl.java | 1 + .../tyr/server/service/impl/SaasRoleGroupServiceImpl.java | 3 +++ 9 files changed, 27 insertions(+) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java index 8eee2943..c9d27339 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataObjectServiceImpl.java @@ -43,6 +43,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionTemplate; import javax.annotation.Resource; @@ -69,6 +70,7 @@ public class DataObjectServiceImpl implements DataObjectService { private TransactionTemplate transactionTemplate; @Override + @Transactional(rollbackFor = Exception.class) public Long createDataObject(CreateDataObjectReq req) { // 校验 // objectName、objectCode不能重复 @@ -173,6 +175,7 @@ public class DataObjectServiceImpl implements DataObjectService { } @Override + @Transactional(rollbackFor = Exception.class) public void editDataObject(EditDataObjectReq req) { // 对象属性名和code不能重复 checkObjectAttrNameOrCodeUnique(req.getAttrs()); @@ -242,6 +245,7 @@ public class DataObjectServiceImpl implements DataObjectService { } @Override + @Transactional(rollbackFor = Exception.class) public void deleteDataObject(Long dataObjectId, Long updateBy) { List idList = Collections.singletonList(dataObjectId); transactionTemplate.executeWithoutResult(status -> { diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataResourceServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataResourceServiceImpl.java index 0273bd77..e7ceeb53 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataResourceServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/DataResourceServiceImpl.java @@ -30,6 +30,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Objects; @@ -48,6 +49,7 @@ public class DataResourceServiceImpl implements DataResourceService { private final SaasFeatureDao saasFeatureDao; private final SaasFeatureDataResourceDao saasFeatureDataResourceDao; @Override + @Transactional(rollbackFor = Exception.class) public void create(CreateDataResourceParam param) { DataResource existDataResource = dataResourceDao.lambdaQuery() .eq(DataResource::getResourceCode, param.getResourceCode()) @@ -72,6 +74,7 @@ public class DataResourceServiceImpl implements DataResourceService { } @Override + @Transactional(rollbackFor = Exception.class) public boolean delete(DeleteDataResourceParam param) { DataResource dataResource = dataResourceDao.getById(param.getId()); if (Objects.nonNull(dataResource)) { @@ -109,6 +112,7 @@ public class DataResourceServiceImpl implements DataResourceService { } @Override + @Transactional(rollbackFor = Exception.class) public boolean update(UpdateDataResourceParam param) { DataResource dataResource = new DataResource(); BeanUtils.copyProperties(param, dataResource); @@ -116,6 +120,7 @@ public class DataResourceServiceImpl implements DataResourceService { } @Override + @Transactional(rollbackFor = Exception.class) public void createDataResourceSaasFeature(DataResourceSaasFeatureParam param) { DataResource existDataResource = dataResourceDao.lambdaQuery() .eq(DataResource::getResourceCode, param.getResourceCode()) 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 41a24b09..a6da2b19 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 @@ -18,6 +18,7 @@ import lombok.extern.slf4j.Slf4j; 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.Collections; import java.util.List; @@ -75,6 +76,7 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic } @Override + @Transactional(rollbackFor = Exception.class) public void syncFromBase(ResourceSyncReq req) { if (req.getIds().size() > 1) { //超过一个异步处理 diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionPointServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionPointServiceImpl.java index 51feb1b6..f51c9716 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionPointServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/PermissionPointServiceImpl.java @@ -314,6 +314,7 @@ public class PermissionPointServiceImpl implements PermissionPointService { } @Override + @Transactional(rollbackFor = Exception.class) public PermissionPointDTO save(PermissionPointDTO dto) { if (dto.getId() == null) { return doInsert(dto); @@ -431,6 +432,7 @@ public class PermissionPointServiceImpl implements PermissionPointService { @Override + @Transactional(rollbackFor = Exception.class) public void move(PermissionPointMoveRequest request) { SaasFeature feature = getAndCheck(request.getPermissionId()); changeParent(feature, request); 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 5fb9196a..003d502c 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 @@ -22,6 +22,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.util.Integers; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -92,6 +93,7 @@ public class ProductServiceImpl implements ProductService { } @Override + @Transactional(rollbackFor = Exception.class) public ApiResult add(ProductAddReq req) { Optional optProduct = productModuleDao.lambdaQuery() .eq(ProductModule::getProductName, req.getProductName()) @@ -108,6 +110,7 @@ public class ProductServiceImpl implements ProductService { } @Override + @Transactional(rollbackFor = Exception.class) public ApiResult update(ProductUpdateReq req) { Optional optProduct = productModuleDao.lambdaQuery() .eq(ProductModule::getProductName, req.getProductName()) @@ -125,6 +128,7 @@ public class ProductServiceImpl implements ProductService { } @Override + @Transactional(rollbackFor = Exception.class) public ApiResult delete(Long id) { ProductModule productModule = productModuleDao.getById(id); AssertUtil.isTrue(Objects.nonNull(productModule), "产品不存在"); 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 3853fb91..4d2bec03 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 @@ -351,12 +351,14 @@ public class RoleUserService implements SaasRoleUserService { } @Override + @Transactional(rollbackFor = Exception.class) public void removeWorkspaceOuAllUserRole(Long workspaceId, Long ouId) { saasRoleDao.removeWorkspaceOuAllRole(workspaceId, ouId); roleUserRelationDao.removeWorkspaceOuAllUserRole(workspaceId, ouId); } @Override + @Transactional(rollbackFor = Exception.class) public void grantOrUngrantWorkerLeader(GantOrUnGantaWorkerLeaderRoleReq req) { Boolean grant = req.getGrant(); // 授权 diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasBasicDictServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasBasicDictServiceImpl.java index d99c244b..192e223f 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasBasicDictServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasBasicDictServiceImpl.java @@ -15,6 +15,7 @@ import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.*; import java.util.stream.Collectors; @@ -103,6 +104,7 @@ public class SaasBasicDictServiceImpl implements SaasBasicDictService { * @return */ @Override + @Transactional(rollbackFor = Exception.class) public Long create(BasicDictCreateReq req) { SaasBasicDict parent = saasBasicDictDao.getById(req.getParentId()); if (Objects.isNull(parent)) { @@ -145,6 +147,7 @@ public class SaasBasicDictServiceImpl implements SaasBasicDictService { } @Override + @Transactional(rollbackFor = Exception.class) public Boolean update(BasicDictUpdateReq req) { BasicDictNodeResp currentNode = getById(req.getId()); if (Objects.isNull(currentNode)) { @@ -166,6 +169,7 @@ public class SaasBasicDictServiceImpl implements SaasBasicDictService { } @Override + @Transactional(rollbackFor = Exception.class) public Boolean updateStauts(BasicDictUpdateStatusReq req) { return saasBasicDictDao.updateStatus(req); } 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 0e0e7fb9..a52f3449 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 @@ -220,6 +220,7 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic } @Override + @Transactional(rollbackFor = Exception.class) @CacheEvict(value = SaasFeatureResourceCacheService.CACHE_FEATURE_RESOURCE_TREE,allEntries = true) public void updateFeatureAuthType(Long featureId, Integer authType) { if (featureId != null && authType != null) { diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java index 921b37f2..cffa57b4 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java @@ -18,6 +18,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.Arrays; @@ -104,6 +105,7 @@ public class SaasRoleGroupServiceImpl extends ServiceImpl ids) { if (CollectionUtils.isEmpty(ids)) { return; From a217422ab47712de3d7a39ecb109dff1d53dbb86 Mon Sep 17 00:00:00 2001 From: lilong Date: Thu, 8 Aug 2024 11:23:57 +0800 Subject: [PATCH 046/112] =?UTF-8?q?feat:(REQ-2720)=20hash=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E6=97=B6=EF=BC=8C=E5=85=88=E6=8A=8Aredis=E7=9A=84key?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=8E=89=EF=BC=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/service/impl/ProductPermissionCacheServiceImpl.java | 2 ++ .../impl/ProductSaasFeatureResourceCacheServiceImpl.java | 2 ++ .../tyr/server/service/impl/RolePermissionCacheServiceImpl.java | 2 ++ .../service/impl/RoleSaasFeatureResourceCacheServiceImpl.java | 2 ++ 4 files changed, 8 insertions(+) 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 index 3dddf88d..ba3d97bb 100644 --- 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 @@ -133,6 +133,8 @@ public class ProductPermissionCacheServiceImpl implements ProductPermissionCache .stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); + // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 + redisTemplate.delete(redisKey); RedisClient.HashOps.hPutAll(redisKey, redisValues); redisTemplate.expire(redisKey, expireInDays, TimeUnit.DAYS); log.info("succeed to store product permission: redisKey:{} value:{}", redisKey, redisValues); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java index 59c233ee..9bad1442 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java @@ -79,6 +79,8 @@ public class ProductSaasFeatureResourceCacheServiceImpl implements ProductSaasFe .stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); + // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 + redisTemplate.delete(redisKey); RedisClient.HashOps.hPutAll(redisKey, redisValues); redisTemplate.expire(redisKey, expireInDays, TimeUnit.DAYS); log.info("succeed to store product featureResource: redisKey:{} value:{}", redisKey, redisValues); 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 index b4471f17..a237d7f9 100644 --- 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 @@ -128,6 +128,8 @@ public class RolePermissionCacheServiceImpl implements RolePermissionCacheServic .stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); + // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 + redisTemplate.delete(redisKey); RedisClient.HashOps.hPutAll(redisKey, redisValues); redisTemplate.expire(redisKey, expireInDays, TimeUnit.DAYS); log.info("succeed to store role permission: redisKey:{} value:{}", redisKey, redisValues); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java index 019d85e8..3d150979 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java @@ -81,6 +81,8 @@ public class RoleSaasFeatureResourceCacheServiceImpl implements RoleSaasFeatureR .stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); + // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 + redisTemplate.delete(redisKey); RedisClient.HashOps.hPutAll(redisKey, redisValues); redisTemplate.expire(redisKey, expireInDays, TimeUnit.DAYS); log.info("succeed to store role featureResource: redisKey:{} value:{}", redisKey, redisValues); From 202d0797dcaad4c052267cd70b6ddda24744e854 Mon Sep 17 00:00:00 2001 From: lilong Date: Fri, 9 Aug 2024 10:43:38 +0800 Subject: [PATCH 047/112] =?UTF-8?q?feat:(REQ-2699)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E4=BA=A7=E5=93=81=E6=9D=83=E9=99=90=E7=BC=93=E5=AD=98=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=89=88=E6=9C=AC=EF=BC=8C=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/model/req/IdentityAuthReq.java | 15 ++++++ .../tyr/client/model/req/PageElementReq.java | 34 +++++++++++++ .../model/req/PageSaasFeatureResourceReq.java | 3 ++ .../tyr/client/model/res/PageElementResp.java | 2 + .../model/res/SaasFeatureResourceResp.java | 6 +++ .../server/controller/PrivateController.java | 5 ++ .../inner/CacheProductPermissionHandler.java | 34 ++++++------- .../inner/CacheRolePermissionHandler.java | 29 ++++------- .../ProductPermissionCacheService.java | 15 ++++++ .../service/SaasPageElementService.java | 12 ++++- .../impl/SaasFeatureResourceServiceImpl.java | 51 +++++++++++++++++-- .../impl/SaasPageElementServiceImpl.java | 10 ++++ .../service/impl/TyrSaasAuthServiceImpl.java | 19 +++---- 13 files changed, 181 insertions(+), 54 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementReq.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 81e917a7..13da1cae 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,21 @@ public class IdentityAuthReq { @Builder.Default private boolean useCache = true; + /** + * app类型(APP:原生,H5:h5页面) + */ + private String appType; + + /** + * 项目code(H5会拉取项目下所有的元素) + */ + private String itemCode; + + /** + * 客户端版本号 + */ + private Integer versionMax; + 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/PageElementReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementReq.java new file mode 100644 index 00000000..83f429fa --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementReq.java @@ -0,0 +1,34 @@ +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; +import java.util.Set; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PageElementReq implements IPageReq { + + @CriteriaField(ignore = true) + Integer page; + + @CriteriaField(ignore = true) + Integer pageSize; + + /** + * 排序:使用示例,createTime__DESC + */ + @CriteriaField(ignore = true) + List sort; + + @CriteriaField(field = "code", operator = Operator.IN) + private Set codes; +} \ No newline at end of file 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 c2f809bd..0db07770 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 @@ -73,6 +73,9 @@ public class PageSaasFeatureResourceReq implements IPageReq { @CriteriaField(field = "terminal", operator = Operator.IN) private Set terminals; + @CriteriaField(ignore = true) + private Boolean needPageElement; + public PageResp toEmpty() { return PageResp.builder() .current(this.getPage()) 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 5096c267..e90e5d94 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 @@ -63,6 +63,8 @@ public class PageElementResp { */ private Boolean selected; + private String itemCode; + /** * 子元素(只包含一级) */ 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 index b5d3484c..3a812a46 100644 --- 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 @@ -11,6 +11,7 @@ import lombok.NoArgsConstructor; import java.util.Arrays; import java.util.Date; +import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -148,6 +149,11 @@ public class SaasFeatureResourceResp { */ private String uniCode; + /** + * 页面元素信息 + */ + private List saasPageElements; + public Set resolvePath() { return Optional.ofNullable(this.getPath()) .map(e -> Arrays.stream(e.split(",")).map(Long::valueOf).collect(Collectors.toSet())) 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 0a89d1ca..ceabd520 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 @@ -712,6 +712,11 @@ public class PrivateController { return rolePermissionCacheService.list(request); } + @PostMapping("/api/private/productPermissionCached/list") + public Object productPermissionCached(@RequestBody ProductPermissionCacheService.ListProductPermissionParam request) { + return productPermissionCacheService.list(request); + } + @Data @Builder @NoArgsConstructor diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java index 4e1dc0f1..a39257d2 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java @@ -14,7 +14,6 @@ import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductPermissionCacheService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; @@ -27,7 +26,6 @@ import java.util.Collections; 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; @@ -205,20 +203,21 @@ public class CacheProductPermissionHandler implements InitializingBean { if (Objects.isNull(featureResource)) { return null; } - Set featureCodes = Optional.ofNullable(featureResource.getFeatureCodes()) - .orElseGet(() -> Sets.newHashSet(featureResource.getUniCode())); - if (CollectionUtils.isEmpty(featureCodes)) { + if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) { return null; } - List permissionDTOS = featureCodes.stream() - .map(featureCode -> ProductPermissionCacheService.PermissionDTO.builder() + List permissionDTOS = featureResource.getSaasPageElements().stream() + .map(pageElement -> ProductPermissionCacheService.PermissionDTO.builder() .featureId(featureResource.getId()) - .featureCode(featureCode) + .featureCode(pageElement.getCode()) .featureType(featureResource.getFeatureType()) .terminal(featureResource.getTerminal()) .cooperateType(relation.getDictCode()) + .itemCode(pageElement.getItemCode()) + .version(pageElement.getVersion()) + .appType(pageElement.getAppType()) .build()) .collect(Collectors.toList()); @@ -226,20 +225,20 @@ public class CacheProductPermissionHandler implements InitializingBean { .map(parentFeatureResources::get) .filter(Objects::nonNull) .map(f -> { - - Set parentFeatureCodes = Optional.ofNullable(f.getFeatureCodes()) - .orElseGet(() -> Sets.newHashSet(f.getUniCode())); - if (CollectionUtils.isEmpty(parentFeatureCodes)) { + if (CollectionUtils.isEmpty(f.getSaasPageElements())) { return null; } - return parentFeatureCodes.stream() - .map(featureCode -> ProductPermissionCacheService.PermissionDTO.builder() + return f.getSaasPageElements().stream() + .map(pageElement -> ProductPermissionCacheService.PermissionDTO.builder() .featureId(f.getId()) - .featureCode(featureCode) + .featureCode(pageElement.getCode()) .featureType(f.getFeatureType()) .terminal(f.getTerminal()) .cooperateType(relation.getDictCode()) + .itemCode(pageElement.getItemCode()) + .version(pageElement.getVersion()) + .appType(pageElement.getAppType()) .build()) .collect(Collectors.toList()); }) @@ -266,7 +265,7 @@ public class CacheProductPermissionHandler implements InitializingBean { PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() .ids(featureIds) - .needFeatureCodes(true) + .needPageElement(true) .build(); return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); @@ -284,10 +283,9 @@ public class CacheProductPermissionHandler implements InitializingBean { return Collections.emptyMap(); } - // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() .ids(parentIds) - .needFeatureCodes(true) + .needPageElement(true) .build(); return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java index 12ce3db5..093166c1 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java @@ -2,8 +2,6 @@ package cn.axzo.tyr.server.event.inner; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; -import cn.axzo.framework.rocketmq.EventHandler; -import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; @@ -12,12 +10,10 @@ import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.entity.SaasFeature; -import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; import cn.axzo.tyr.server.service.RolePermissionCacheService; import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; @@ -30,7 +26,6 @@ import java.util.Collections; 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; @@ -192,17 +187,15 @@ public class CacheRolePermissionHandler implements InitializingBean { if (Objects.isNull(featureResource)) { return null; } - Set featureCodes = Optional.ofNullable(featureResource.getFeatureCodes()) - .orElseGet(() -> Sets.newHashSet(featureResource.getUniCode())); - if (CollectionUtils.isEmpty(featureCodes)) { + if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) { return null; } - List permissionDTOS = featureCodes.stream() - .map(featureCode -> RolePermissionCacheService.PermissionDTO.builder() + List permissionDTOS = featureResource.getSaasPageElements().stream() + .map(pageElement -> RolePermissionCacheService.PermissionDTO.builder() .featureId(featureResource.getId()) - .featureCode(featureCode) + .featureCode(pageElement.getCode()) .featureType(featureResource.getFeatureType()) .terminal(featureResource.getTerminal()) .build()) @@ -213,16 +206,14 @@ public class CacheRolePermissionHandler implements InitializingBean { .filter(Objects::nonNull) .map(f -> { - Set parentFeatureCodes = Optional.ofNullable(f.getFeatureCodes()) - .orElseGet(() -> Sets.newHashSet(f.getUniCode())); - if (CollectionUtils.isEmpty(parentFeatureCodes)) { + if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) { return null; } - return parentFeatureCodes.stream() - .map(featureCode -> RolePermissionCacheService.PermissionDTO.builder() + return featureResource.getSaasPageElements().stream() + .map(pageElement -> RolePermissionCacheService.PermissionDTO.builder() .featureId(f.getId()) - .featureCode(featureCode) + .featureCode(pageElement.getCode()) .featureType(f.getFeatureType()) .terminal(f.getTerminal()) .build()) @@ -256,7 +247,7 @@ public class CacheRolePermissionHandler implements InitializingBean { PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() .ids(featureIds) - .needFeatureCodes(true) + .needPageElement(true) .build(); return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); @@ -277,7 +268,7 @@ public class CacheRolePermissionHandler implements InitializingBean { // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() .ids(parentIds) - .needFeatureCodes(true) + .needPageElement(true) .build(); return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); 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 index 7ae8a81f..d222620d 100644 --- 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 @@ -86,5 +86,20 @@ public interface ProductPermissionCacheService { private String terminal; private Integer featureType; + + /** + * app类型(APP:原生,H5:h5页面) + */ + private String appType; + + /** + * 项目code(H5会拉取项目下所有的元素) + */ + private String itemCode; + + /** + * 客户端版本号 + */ + private Integer version; } } \ No newline at end of file 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 3c31fc6d..8d23aac1 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,7 +1,12 @@ package cn.axzo.tyr.server.service; import cn.axzo.framework.domain.page.PageResp; -import cn.axzo.tyr.client.model.req.*; +import cn.axzo.tyr.client.model.req.GetPageElementReq; +import cn.axzo.tyr.client.model.req.GetUserHasPermissionPageElementReq; +import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; +import cn.axzo.tyr.client.model.req.PageElementReportReq; +import cn.axzo.tyr.client.model.req.PageElementReq; +import cn.axzo.tyr.client.model.req.PageQueryElementReq; import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; import cn.axzo.tyr.client.model.res.PageElementBasicDTO; import cn.axzo.tyr.client.model.res.PageElementResp; @@ -70,4 +75,9 @@ public interface SaasPageElementService { * @return */ GetUserHasPermissionPageElementResp getUserHasPermissionPageElement(GetUserHasPermissionPageElementReq request); + + + List list(PageElementReq param); + + cn.axzo.foundation.page.PageResp page(PageElementReq param); } 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 234be947..581561a4 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 @@ -22,11 +22,13 @@ 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.PageElementReq; 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.PageElementResp; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.server.common.util.Throws; import cn.axzo.tyr.server.config.MqProducer; @@ -73,7 +75,7 @@ import org.springframework.data.redis.core.SessionCallback; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.*; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -81,6 +83,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.stream.Collectors; import static cn.axzo.tyr.server.config.exception.BizResultCode.FEATURE_RESOURCE_NOT_FOUND; @@ -588,15 +591,22 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl> uniCodeFeatureCodeMap = listFeatureCodes(param, page.getRecords()); - return PageConverter.toResp(page, e -> from(e, uniCodeFeatureCodeMap)); + Map> pageElements = listPageElements(param, page.getRecords()); + + return PageConverter.toResp(page, e -> from(e, + uniCodeFeatureCodeMap, + pageElements)); } private SaasFeatureResourceResp from(SaasFeatureResource featureResource, - Map> uniCodeFeatureCodeMap) { + Map> uniCodeFeatureCodeMap, + Map> pageElements) { SaasFeatureResourceResp saasFeatureResourceResp = SaasFeatureResourceResp.builder().build(); BeanUtils.copyProperties(featureResource, saasFeatureResourceResp); saasFeatureResourceResp.setFeatureCodes(uniCodeFeatureCodeMap.get(featureResource.getUniCode())); + + saasFeatureResourceResp.setSaasPageElements(pageElements.get(saasFeatureResourceResp.getUniCode())); return saasFeatureResourceResp; } @@ -617,6 +627,41 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl> listPageElements(PageSaasFeatureResourceReq param, + List saasFeatureResources) { + + if (CollectionUtils.isEmpty(saasFeatureResources) || BooleanUtils.isNotTrue(param.getNeedPageElement())) { + return Collections.emptyMap(); + } + + Set uniCodes = saasFeatureResources.stream() + .map(SaasFeatureResource::getUniCode) + .collect(Collectors.toSet()); + PageElementFeatureResourceRelationReq pageElementFeatureResourceRelationReq = PageElementFeatureResourceRelationReq.builder() + .featureResourceUniCodes(uniCodes) + .build(); + + List pageElementFeatureResourceRelations = saasPageElementFeatureResourceRelationService.list(pageElementFeatureResourceRelationReq); + + if (CollectionUtils.isEmpty(pageElementFeatureResourceRelations)) { + return Collections.emptyMap(); + } + + Set elementCodes = pageElementFeatureResourceRelations.stream() + .map(SaasPageElementFeatureResourceRelation::getPageElementCode) + .collect(Collectors.toSet()); + + PageElementReq pageElementReq = PageElementReq.builder() + .codes(elementCodes) + .build(); + Map elementMap = saasPageElementService.list(pageElementReq).stream() + .collect(Collectors.toMap(PageElementResp::getCode, Function.identity())); + + return pageElementFeatureResourceRelations.stream() + .collect(Collectors.groupingBy(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode, + Collectors.mapping(e -> elementMap.get(e.getPageElementCode()), Collectors.toList()))); } 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 8b38d33c..bed51ab0 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 @@ -466,4 +466,14 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { saasPgroupPermissionRelationOperateLogService.batchSave(Lists.newArrayList(operateLog)); } + + @Override + public List list(PageElementReq param) { + return null; + } + + @Override + public cn.axzo.foundation.page.PageResp page(PageElementReq param) { + return null; + } } 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 ab46a710..7cc6408d 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 @@ -2,7 +2,6 @@ package cn.axzo.tyr.server.service.impl; import cn.axzo.apollo.workspace.common.enums.TableIsDeleteEnum; import cn.axzo.basics.common.BeanMapper; -import cn.axzo.basics.common.util.StopWatchUtil; import cn.axzo.framework.domain.ServiceException; import cn.axzo.pokonyan.util.TraceSupplier; import cn.axzo.thrones.client.saas.ServicePkgClient; @@ -85,7 +84,6 @@ import cn.hutool.core.lang.Pair; import cn.hutool.core.util.BooleanUtil; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; -import com.alibaba.fastjson.JSON; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -1503,19 +1501,11 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { * @return */ private IdentityAuthRes findIdentityAuthV2(IdentityAuthReq identityAuthReq) { - StopWatch watch = StopWatch.create("redis:"); - watch.start("redis:query workspaceProductPermission"); Map> workspaceProductPermissions = listWorkspaceProductPermission(identityAuthReq); - watch.stop(); - watch.start("redis:query userRole"); List saasRoleUsers = listRoleUserRelationsV2(identityAuthReq); - log.info("redis:saasRoleUsers:", JSON.toJSONString(saasRoleUsers)); - watch.stop(); - watch.start("redis:query rolePermission"); Map> rolePermissions = listRolePermission(identityAuthReq, saasRoleUsers); - watch.stop(); Map> workspaceRoles = saasRoleUsers.stream() .collect(Collectors.groupingBy(e -> e.getSaasRoleUser().buildOuWorkspaceKey(), @@ -1530,7 +1520,6 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { // CMP、CMS新旧菜单树id不会重复 List allFeatures = listSaasFeatureCaches(terminals); - watch.start("redis:resolve permission"); List permissions = identityAuthReq.getWorkspaceOusPairs().stream() .map(workspaceOuPair -> { List productPermissions = Optional.ofNullable(workspaceProductPermissions.get(workspaceOuPair.getWorkspaceId())) @@ -1538,6 +1527,12 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .map(WorkspaceProductService.ProductPermission::getPermissions) .filter(f -> !CollectionUtils.isEmpty(f)) .flatMap(Collection::stream) + .filter(f -> StringUtils.isBlank(identityAuthReq.getItemCode()) + || Objects.equals(identityAuthReq.getItemCode(), f.getItemCode())) + .filter(f -> StringUtils.isBlank(identityAuthReq.getAppType()) + || Objects.equals(identityAuthReq.getAppType(), f.getAppType())) + .filter(f -> Objects.isNull(identityAuthReq.getVersionMax()) + || identityAuthReq.getVersionMax().compareTo(f.getVersion()) < 1) .collect(Collectors.toList())) .orElse(null); @@ -1553,8 +1548,6 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return buildPermissionsV2(workspaceOuPair, productPermissions, saasRoles, rolePermissions, allFeatures); }) .collect(Collectors.toList()); - watch.stop(); - watch.prettyPrint(TimeUnit.MILLISECONDS); IdentityAuthRes result = new IdentityAuthRes(); result.setIdentity(identityAuthReq.getIdentityId()); From 5ea15447ad24e42720f03bd93d8e727c04bbf51b Mon Sep 17 00:00:00 2001 From: lilong Date: Fri, 9 Aug 2024 13:32:24 +0800 Subject: [PATCH 048/112] =?UTF-8?q?feat:(REQ-2699)=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E8=84=8F=E6=95=B0=E6=8D=AE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/SaasPageElementService.java | 4 ++- .../impl/SaasFeatureResourceServiceImpl.java | 1 + .../impl/SaasPageElementServiceImpl.java | 36 +++++++++++++++---- 3 files changed, 34 insertions(+), 7 deletions(-) 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 8d23aac1..9ea72575 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 @@ -10,6 +10,8 @@ import cn.axzo.tyr.client.model.req.PageQueryElementReq; import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; import cn.axzo.tyr.client.model.res.PageElementBasicDTO; import cn.axzo.tyr.client.model.res.PageElementResp; +import cn.axzo.tyr.server.repository.entity.SaasPageElement; +import com.baomidou.mybatisplus.extension.service.IService; import java.util.List; @@ -18,7 +20,7 @@ import java.util.List; * @version 1.0 * @date 2024/6/18 */ -public interface SaasPageElementService { +public interface SaasPageElementService extends IService { /** * 页面元素上报 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 581561a4..e979db36 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 @@ -660,6 +660,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl elementMap.get(e.getPageElementCode()) != null) .collect(Collectors.groupingBy(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode, Collectors.mapping(e -> elementMap.get(e.getPageElementCode()), Collectors.toList()))); 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 bed51ab0..c792e503 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 @@ -5,6 +5,8 @@ import cn.axzo.basics.common.util.AssertUtil; import cn.axzo.basics.common.util.StopWatchUtil; import cn.axzo.basics.profiles.api.UserProfileServiceApi; import cn.axzo.basics.profiles.dto.basic.PersonProfileDto; +import cn.axzo.foundation.dao.support.converter.PageConverter; +import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper; import cn.axzo.foundation.exception.BusinessException; import cn.axzo.framework.domain.page.PageResp; import cn.axzo.framework.rocketmq.Event; @@ -13,27 +15,28 @@ import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum; import cn.axzo.tyr.client.common.enums.PageElementTypeEnum; import cn.axzo.tyr.client.common.enums.PermissionRelationOperateLogSceneEnum; -import cn.axzo.tyr.client.model.req.*; import cn.axzo.tyr.client.model.req.GetPageElementReq; import cn.axzo.tyr.client.model.req.GetUserHasPermissionPageElementReq; import cn.axzo.tyr.client.model.req.IdentityAuthReq; import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; import cn.axzo.tyr.client.model.req.PageElementReportReq; +import cn.axzo.tyr.client.model.req.PageElementReq; import cn.axzo.tyr.client.model.req.PageQueryElementReq; import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; import cn.axzo.tyr.client.model.res.IdentityAuthRes; import cn.axzo.tyr.client.model.res.PageElementBasicDTO; import cn.axzo.tyr.client.model.res.PageElementResp; -import cn.axzo.tyr.server.model.RelationOperateLogResourceBindElementDO; import cn.axzo.tyr.server.config.MqProducer; import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; +import cn.axzo.tyr.server.model.RelationOperateLogResourceBindElementDO; 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.*; 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.SaasPgroupPermissionRelationOperateLog; +import cn.axzo.tyr.server.repository.mapper.SaasPageElementMapper; import cn.axzo.tyr.server.service.SaasPageElementService; import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationOperateLogService; import cn.axzo.tyr.server.service.TyrSaasAuthService; @@ -41,8 +44,10 @@ import cn.axzo.tyr.server.util.RpcInternalUtil; import cn.azxo.framework.common.constatns.Constants; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import lombok.RequiredArgsConstructor; @@ -50,6 +55,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.MDC; +import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; @@ -78,7 +84,9 @@ import static cn.axzo.tyr.server.event.inner.EventTypeEnum.PAGE_ELEMENT_FEATURE_ @Slf4j @Service @RequiredArgsConstructor -public class SaasPageElementServiceImpl implements SaasPageElementService { +public class SaasPageElementServiceImpl + extends ServiceImpl + implements SaasPageElementService { private final SaasPageElementDao saasPageElementDao; private final SaasPageElementFeatureResourceRelationDao saasPageElementFeatureResourceRelationDao; @@ -469,11 +477,27 @@ public class SaasPageElementServiceImpl implements SaasPageElementService { @Override public List list(PageElementReq param) { - return null; + return PageConverter.drainAll(pageNumber -> { + param.setPage(pageNumber); + param.setPageSize(1000); + return page(param); + }); } @Override public cn.axzo.foundation.page.PageResp page(PageElementReq param) { - return null; + QueryWrapper wrapper = QueryWrapperHelper.fromBean(param, SaasPageElement.class); + wrapper.eq("is_delete", 0); + + IPage page = this.page(PageConverter.toMybatis(param, SaasPageElement.class), wrapper); + + return PageConverter.toResp(page, this::from); + } + + private PageElementResp from(SaasPageElement saasPageElement) { + PageElementResp pageElementResp = PageElementResp.builder().build(); + + BeanUtils.copyProperties(saasPageElement, pageElementResp); + return pageElementResp; } } From fc0f60e4679d7afb67659a92762c0b87663ded50 Mon Sep 17 00:00:00 2001 From: lilong Date: Fri, 9 Aug 2024 14:02:04 +0800 Subject: [PATCH 049/112] =?UTF-8?q?feat:(REQ-2699)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E6=9D=83=E9=99=90=E7=82=B9=E7=89=88=E6=9C=AC=E8=BF=87=E6=BB=A4?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6?= 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, 1 insertion(+), 1 deletion(-) 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 7cc6408d..d5eea5c0 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 @@ -1532,7 +1532,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { .filter(f -> StringUtils.isBlank(identityAuthReq.getAppType()) || Objects.equals(identityAuthReq.getAppType(), f.getAppType())) .filter(f -> Objects.isNull(identityAuthReq.getVersionMax()) - || identityAuthReq.getVersionMax().compareTo(f.getVersion()) < 1) + || identityAuthReq.getVersionMax().compareTo(f.getVersion()) > -1) .collect(Collectors.toList())) .orElse(null); From 836090d12918f977f6e2bb83f9d613e716cd82f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Fri, 9 Aug 2024 14:18:22 +0800 Subject: [PATCH 050/112] =?UTF-8?q?feat(REQ-2699):=20=E5=88=B7=E6=96=B0cmp?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E8=B7=AF=E7=94=B1=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/PrivateController.java | 91 ++++++++++++++----- 1 file changed, 70 insertions(+), 21 deletions(-) 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 ceabd520..42a021de 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 @@ -4,16 +4,14 @@ 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.foundation.page.PageResp; +import cn.axzo.framework.auth.domain.TerminalInfo; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.framework.rocketmq.Event; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; +import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum; import cn.axzo.tyr.client.model.product.ProductSearchListReq; -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.PageProductFeatureRelationReq; -import cn.axzo.tyr.client.model.req.PermissionCheckReq; -import cn.axzo.tyr.client.model.req.QuerySaasRoleGroupReq; +import cn.axzo.tyr.client.model.req.*; import cn.axzo.tyr.client.model.res.CommonDictResp; import cn.axzo.tyr.client.model.res.FeatureResourceDTO; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; @@ -27,21 +25,8 @@ import cn.axzo.tyr.server.job.CacheProductPermissionJob; import cn.axzo.tyr.server.job.CacheRoleFeatureResourceJob; import cn.axzo.tyr.server.job.CacheRolePermissionJob; import cn.axzo.tyr.server.job.CacheSaasFeatureJob; -import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; -import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; -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.dao.SaasRoleGroupDao; -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.SaasPgroupRoleRelation; -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.dao.*; +import cn.axzo.tyr.server.repository.entity.*; import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductPermissionCacheService; import cn.axzo.tyr.server.service.RolePermissionCacheService; @@ -54,6 +39,7 @@ import cn.axzo.tyr.server.service.TyrSaasAuthService; import cn.axzo.tyr.server.service.WorkspaceProductService; import cn.axzo.tyr.server.service.impl.SaasFeatureResourceCacheService; import cn.axzo.tyr.server.util.FeatureCodeUtil; +import cn.azxo.framework.common.utils.StringUtils; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.fastjson.JSON; @@ -145,6 +131,10 @@ public class PrivateController { private SaasFeatureResourceService saasFeatureResourceService; @Autowired private RolePermissionCacheService rolePermissionCacheService; + @Autowired + private SaasPageElementDao saasPageElementDao; + @Autowired + private SaasPageElementFeatureResourceRelationDao saasPageElementFeatureResourceRelationDao; /** * 统一层级的roleGroup按照id升序,sort从1递增 @@ -717,6 +707,56 @@ public class PrivateController { return productPermissionCacheService.list(request); } + @PostMapping("/api/private/saasPageElement/refreshCmpFeatureResourceLinkUrl") + public ApiResult refreshCmpFeatureResourceLinkUrl(@RequestBody RefreshFeatureResourceLinkUrlParam request) { + Long startId = 0L; + while (true) { + List saasPageElements = saasPageElementDao.lambdaQuery() + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) + .eq(SaasPageElement::getTerminal, TerminalInfo.NT_CMP_APP_GENERAL) + .ne(SaasPageElement::getLinkUrl, StringUtils.EMPTY) + .gt(BaseEntity::getId, startId) + .orderByAsc(BaseEntity::getId) + .last("LIMIT " + request.getPageSize()) + .list(); + if (CollectionUtils.isEmpty(saasPageElements)) { + return ApiResult.ok(); + } + + for (SaasPageElement pageElement : saasPageElements) { + if (org.apache.commons.lang3.StringUtils.isBlank(pageElement.getLinkUrl())) { + continue; + } + List relations = saasPageElementFeatureResourceRelationDao.listByPageElementCode(pageElement.getCode(), TerminalInfo.NT_CMP_APP_GENERAL, Lists.newArrayList(PageElementFeatureResourceRelationTypeEnum.PAGE_ROUTE.getValue())); + if (org.apache.commons.collections4.CollectionUtils.isEmpty(relations)) { + continue; + } + List saasFeatureResources = saasFeatureResourceDao.lambdaQuery() + .eq(SaasFeatureResource::getUniCode, relations.get(0).getFeatureResourceUniCode()) + .eq(SaasFeatureResource::getTerminal, TerminalInfo.NT_CMP_APP_GENERAL) + .list(); + if (org.apache.commons.collections4.CollectionUtils.isEmpty(saasFeatureResources)) { + continue; + } + SaasFeatureResource saasFeatureResource = saasFeatureResources.get(0); + if (!FeatureResourceType.APP_ENTRY.getCode().equals(saasFeatureResource.getFeatureType()) + || pageElement.getLinkUrl().equals(saasFeatureResource.getLinkUrl())) { + continue; + } + saasFeatureResourceDao.lambdaUpdate() + .eq(BaseEntity::getId, saasFeatureResource.getId()) + .set(SaasFeatureResource::getLinkUrl, pageElement.getLinkUrl()) + .update(); + log.info("refreshCmpFeatureResourceLinkUrl SaasFeatureResourceId:{}", saasFeatureResource.getId()); + } + + + startId = saasPageElements.get(saasPageElements.size() - 1).getId(); + } + +// return ApiResult.ok(); + } + @Data @Builder @NoArgsConstructor @@ -796,4 +836,13 @@ public class PrivateController { private List ids; } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class RefreshFeatureResourceLinkUrlParam { + @Builder.Default + private Integer pageSize = 10; + } } From 604839f711f7b660067cea5119358de76c344fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Fri, 9 Aug 2024 16:26:07 +0800 Subject: [PATCH 051/112] =?UTF-8?q?feat(REQ-2699):=20=E5=85=83=E7=B4=A0pag?= =?UTF-8?q?e=E6=8E=A5=E5=8F=A3=E8=BF=94=E5=9B=9ElinkExt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/tyr/client/model/res/PageElementResp.java | 2 ++ 1 file changed, 2 insertions(+) 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 e90e5d94..c624ef86 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 @@ -65,6 +65,8 @@ public class PageElementResp { private String itemCode; + private String linkExt; + /** * 子元素(只包含一级) */ From dfec87ee3b5809b2884c869948972a38f50c9994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Fri, 9 Aug 2024 17:55:27 +0800 Subject: [PATCH 052/112] =?UTF-8?q?feat(REQ-2699):=20=E5=85=83=E7=B4=A0pag?= =?UTF-8?q?e=E6=8E=A5=E5=8F=A3=E8=BF=94=E5=9B=9ElinkExt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/controller/PrivateController.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) 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 42a021de..923c58e1 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 @@ -714,7 +714,9 @@ public class PrivateController { List saasPageElements = saasPageElementDao.lambdaQuery() .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) .eq(SaasPageElement::getTerminal, TerminalInfo.NT_CMP_APP_GENERAL) - .ne(SaasPageElement::getLinkUrl, StringUtils.EMPTY) + .and(wrapper -> wrapper.ne(SaasPageElement::getLinkUrl, StringUtils.EMPTY) + .or() + .ne(SaasPageElement::getLinkExt, StringUtils.EMPTY)) .gt(BaseEntity::getId, startId) .orderByAsc(BaseEntity::getId) .last("LIMIT " + request.getPageSize()) @@ -739,13 +741,17 @@ public class PrivateController { continue; } SaasFeatureResource saasFeatureResource = saasFeatureResources.get(0); - if (!FeatureResourceType.APP_ENTRY.getCode().equals(saasFeatureResource.getFeatureType()) - || pageElement.getLinkUrl().equals(saasFeatureResource.getLinkUrl())) { + if (!FeatureResourceType.APP_ENTRY.getCode().equals(saasFeatureResource.getFeatureType())) { + continue; + } + if (pageElement.getLinkUrl().equals(saasFeatureResource.getLinkUrl()) + && pageElement.getLinkExt().equals(saasFeatureResource.getLinkExt())) { continue; } saasFeatureResourceDao.lambdaUpdate() .eq(BaseEntity::getId, saasFeatureResource.getId()) - .set(SaasFeatureResource::getLinkUrl, pageElement.getLinkUrl()) + .set(StringUtils.isNotBlank(pageElement.getLinkUrl()), SaasFeatureResource::getLinkUrl, pageElement.getLinkUrl()) + .set(StringUtils.isNotBlank(pageElement.getLinkExt()), SaasFeatureResource::getLinkExt, pageElement.getLinkExt()) .update(); log.info("refreshCmpFeatureResourceLinkUrl SaasFeatureResourceId:{}", saasFeatureResource.getId()); } From 2b3d7e5219776e3848e53cb8d0cb0735fc06dce9 Mon Sep 17 00:00:00 2001 From: lilong Date: Sat, 10 Aug 2024 09:51:47 +0800 Subject: [PATCH 053/112] =?UTF-8?q?feat:(REQ-2699)=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E9=A1=B5=E9=9D=A2=E5=85=83=E7=B4=A0=E6=97=B6?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E8=8F=9C=E5=8D=95=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/client/feign/PageElementApi.java | 4 ++ .../tyr/client/model/req/PageElementReq.java | 3 + .../tyr/client/model/res/PageElementResp.java | 5 ++ .../permission/PageElementController.java | 12 +++- .../impl/SaasPageElementServiceImpl.java | 57 +++++++++++++++++-- 5 files changed, 76 insertions(+), 5 deletions(-) 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 76373ffd..87e5015a 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,5 +1,6 @@ package cn.axzo.tyr.client.feign; +import cn.axzo.framework.domain.page.Page; import cn.axzo.framework.domain.web.result.ApiPageResult; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.tyr.client.model.req.*; @@ -41,4 +42,7 @@ public interface PageElementApi { /** 根据用户传入的页面code,查询用户有权限的元素code **/ @PostMapping("/api/pageElement/getUserHasPermissionPageElement") ApiResult getUserHasPermissionPageElement(@RequestBody @Valid GetUserHasPermissionPageElementReq req); + + @PostMapping("/api/pageElement/list") + ApiResult> list(PageElementReq param); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementReq.java index 83f429fa..072622f9 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementReq.java @@ -31,4 +31,7 @@ public class PageElementReq implements IPageReq { @CriteriaField(field = "code", operator = Operator.IN) private Set codes; + + @CriteriaField(ignore = true) + private Boolean needFeatureSource; } \ No newline at end of file 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 c624ef86..4ecfa89e 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 @@ -71,4 +71,9 @@ public class PageElementResp { * 子元素(只包含一级) */ private List children; + + /** + * 元素对应的菜单信息,可能会存在多个 + */ + private List featureResources; } 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 7fc95122..bf9e5191 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,7 +3,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.*; +import cn.axzo.tyr.client.model.req.GetPageElementReq; +import cn.axzo.tyr.client.model.req.GetUserHasPermissionPageElementReq; +import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; +import cn.axzo.tyr.client.model.req.PageElementReportReq; +import cn.axzo.tyr.client.model.req.PageElementReq; +import cn.axzo.tyr.client.model.req.PageQueryElementReq; import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; import cn.axzo.tyr.client.model.res.PageElementResp; import cn.axzo.tyr.server.service.SaasPageElementService; @@ -51,4 +56,9 @@ public class PageElementController implements PageElementApi { public ApiResult getUserHasPermissionPageElement(GetUserHasPermissionPageElementReq req) { return ApiResult.ok(saasPageElementService.getUserHasPermissionPageElement(req)); } + + @Override + public ApiResult> list(PageElementReq param) { + return ApiResult.ok(saasPageElementService.list(param)); + } } 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 c792e503..45440782 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 @@ -19,13 +19,16 @@ import cn.axzo.tyr.client.model.req.GetPageElementReq; import cn.axzo.tyr.client.model.req.GetUserHasPermissionPageElementReq; import cn.axzo.tyr.client.model.req.IdentityAuthReq; import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; +import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq; import cn.axzo.tyr.client.model.req.PageElementReportReq; import cn.axzo.tyr.client.model.req.PageElementReq; import cn.axzo.tyr.client.model.req.PageQueryElementReq; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; import cn.axzo.tyr.client.model.res.IdentityAuthRes; import cn.axzo.tyr.client.model.res.PageElementBasicDTO; import cn.axzo.tyr.client.model.res.PageElementResp; +import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.server.config.MqProducer; import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.model.RelationOperateLogResourceBindElementDO; @@ -37,6 +40,8 @@ import cn.axzo.tyr.server.repository.entity.SaasPageElement; import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelationOperateLog; import cn.axzo.tyr.server.repository.mapper.SaasPageElementMapper; +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.SaasPgroupPermissionRelationOperateLogService; import cn.axzo.tyr.server.service.TyrSaasAuthService; @@ -53,6 +58,7 @@ import com.google.common.collect.Maps; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.MDC; import org.springframework.beans.BeanUtils; @@ -84,8 +90,7 @@ import static cn.axzo.tyr.server.event.inner.EventTypeEnum.PAGE_ELEMENT_FEATURE_ @Slf4j @Service @RequiredArgsConstructor -public class SaasPageElementServiceImpl - extends ServiceImpl +public class SaasPageElementServiceImpl extends ServiceImpl implements SaasPageElementService { private final SaasPageElementDao saasPageElementDao; @@ -95,6 +100,8 @@ public class SaasPageElementServiceImpl private final SaasPgroupPermissionRelationOperateLogService saasPgroupPermissionRelationOperateLogService; private final UserProfileServiceApi userProfileServiceApi; private final MqProducer mqProducer; + private final SaasFeatureResourceService saasFeatureResourceService; + private final SaasPageElementFeatureResourceRelationService saasPageElementFeatureResourceRelationService; @Qualifier("asyncExecutor") @Autowired @@ -491,13 +498,55 @@ public class SaasPageElementServiceImpl IPage page = this.page(PageConverter.toMybatis(param, SaasPageElement.class), wrapper); - return PageConverter.toResp(page, this::from); + Map> featureResources = listFeatureResource(page.getRecords(), param); + + return PageConverter.toResp(page, e -> from(e, featureResources)); } - private PageElementResp from(SaasPageElement saasPageElement) { + private PageElementResp from(SaasPageElement saasPageElement, + Map> featureResources) { PageElementResp pageElementResp = PageElementResp.builder().build(); BeanUtils.copyProperties(saasPageElement, pageElementResp); + pageElementResp.setFeatureResources(featureResources.get(saasPageElement.getCode())); return pageElementResp; } + + private Map> listFeatureResource(List pageElements, + PageElementReq param) { + + if (CollectionUtils.isEmpty(pageElements) || BooleanUtils.isNotTrue(param.getNeedFeatureSource())) { + return Collections.emptyMap(); + } + + Set pageElementCodes = pageElements.stream() + .map(SaasPageElement::getCode) + .collect(Collectors.toSet()); + + + PageElementFeatureResourceRelationReq elementFeatureResourceRelationReq = PageElementFeatureResourceRelationReq + .builder() + .pageElementCodes(pageElementCodes) + .build(); + List elementFeatureResourceRelations = saasPageElementFeatureResourceRelationService.list(elementFeatureResourceRelationReq); + + Set uniCodes = elementFeatureResourceRelations.stream() + .map(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(uniCodes)) { + return Collections.emptyMap(); + } + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq + .builder() + .uniCodes(uniCodes) + .build(); + Map featureResources = saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getUniCode, Function.identity())); + + return elementFeatureResourceRelations.stream() + .collect(Collectors.groupingBy(SaasPageElementFeatureResourceRelation::getPageElementCode, + Collectors.mapping(e -> featureResources.get(e.getFeatureResourceUniCode()), Collectors.toList()))); + } } From 35b20166624167bdd33fab53a6f86fc68cc5cf84 Mon Sep 17 00:00:00 2001 From: lilong Date: Sat, 10 Aug 2024 11:21:16 +0800 Subject: [PATCH 054/112] =?UTF-8?q?feat:(REQ-2699)=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E8=8F=9C=E5=8D=95=E6=9D=83=E9=99=90=E5=88=97?= =?UTF-8?q?=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/feign/PermissionQueryApi.java | 10 ++++ .../model/req/ListPermissionFeatureReq.java | 47 +++++++++++++++++++ ...PageElementFeatureResourceRelationReq.java | 4 ++ .../model/req/PageSaasFeatureResourceReq.java | 7 +++ .../client/model/req/TreePermissionReq.java | 13 +++-- .../model/res/ListPermissionFeatureResp.java | 35 ++++++++++++++ .../tyr/client/model/res/PageElementResp.java | 37 +++++++++++++++ .../permission/PermissionQueryController.java | 8 ++++ .../service/PermissionQueryService.java | 4 ++ .../impl/PermissionQueryServiceImpl.java | 47 +++++++++++++++---- .../impl/SaasFeatureResourceServiceImpl.java | 1 + ...entFeatureResourceRelationServiceImpl.java | 7 +++ 12 files changed, 205 insertions(+), 15 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListPermissionFeatureReq.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/res/ListPermissionFeatureResp.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 3c77b8ff..f6bd0aa6 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 @@ -1,6 +1,7 @@ package cn.axzo.tyr.client.feign; import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.tyr.client.model.req.ListPermissionFeatureReq; import cn.axzo.tyr.client.model.req.NavTreeReq; import cn.axzo.tyr.client.model.req.PagePermissionReq; import cn.axzo.tyr.client.model.req.PagePermissionResp; @@ -8,6 +9,7 @@ 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.ListPermissionFeatureResp; import cn.axzo.tyr.client.model.res.NavTreeResp; import cn.axzo.tyr.client.model.res.ProductFeatureResourceResp; import cn.axzo.tyr.client.model.res.TreePermissionResp; @@ -67,4 +69,12 @@ public interface PermissionQueryApi { */ @PostMapping(value = "/api/v3/permission/featureResource/tree") ApiResult> treePermission(@RequestBody @Validated TreePermissionReq req); + + /** + * 查询有权限的菜单树节点 + * @param req + * @return + */ + @PostMapping(value = "/api/v3/permission/featureResource/list") + ApiResult> listPermission(@RequestBody @Validated ListPermissionFeatureReq req); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListPermissionFeatureReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListPermissionFeatureReq.java new file mode 100644 index 00000000..b2e42bf0 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListPermissionFeatureReq.java @@ -0,0 +1,47 @@ +package cn.axzo.tyr.client.model.req; + +import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum; +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; +import java.util.Set; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ListPermissionFeatureReq { + + @NotNull(message = "人员ID不能为空") + private Long personId; + + /** + * 端 + */ + @NotNull(message = "端不能为空") + private String terminal; + + /** + * 项目与企业 + */ + @NotEmpty(message = "项目与企业对不能为空") + private List workspaceOUPairs; + + /** + * 菜单节点的uniCode + */ + private Set uniCodes; + + private Boolean needPageElement; + + /** + * 菜单跟页面元素绑定的类型 + */ + private Set pageElementTypes; +} 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 e41f144f..64270bed 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 @@ -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.PageElementFeatureResourceRelationTypeEnum; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -37,4 +38,7 @@ public class PageElementFeatureResourceRelationReq implements IPageReq { @CriteriaField(field = "terminal", operator = Operator.EQ) private String terminal; + + @CriteriaField(ignore = true) + private Set types; } 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 0db07770..45593a09 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 @@ -5,6 +5,7 @@ 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 cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -76,6 +77,12 @@ public class PageSaasFeatureResourceReq implements IPageReq { @CriteriaField(ignore = true) private Boolean needPageElement; + /** + * 菜单跟页面元素绑定的类型 + */ + @CriteriaField(ignore = true) + private Set pageElementTypes; + public PageResp toEmpty() { return PageResp.builder() .current(this.getPage()) 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 index 72c00f79..cad451ba 100644 --- 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 @@ -6,10 +6,13 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import java.util.List; +import java.util.Optional; +import java.util.Set; @Data @Builder @@ -37,13 +40,13 @@ public class TreePermissionReq { */ private List featureResourceTypes; - /** - * 菜单节点的uniCode - */ - private String uniCode; - /** * 是否需要返回权限码 */ private boolean needFeatureCodes; + + /** + * 菜单节点的uniCode + */ + private Set uniCodes; } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/ListPermissionFeatureResp.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/ListPermissionFeatureResp.java new file mode 100644 index 00000000..37b1d8f6 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/ListPermissionFeatureResp.java @@ -0,0 +1,35 @@ +package cn.axzo.tyr.client.model.res; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ListPermissionFeatureResp { + + /** + * 菜单树节点id + */ + private Long featureId; + + /** + * 菜单树节点名字 + */ + private String featureName; + + /** 图标 **/ + private String icon; + + /** + * 菜单页面编码,端唯一 + */ + private String uniCode; + + private List saasPageElements; +} 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 4ecfa89e..9a697094 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 @@ -1,11 +1,15 @@ package cn.axzo.tyr.client.model.res; +import com.alibaba.fastjson.JSONArray; +import com.google.common.collect.Lists; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; +import java.util.Objects; +import java.util.Optional; /** * @author likunpeng @@ -76,4 +80,37 @@ public class PageElementResp { * 元素对应的菜单信息,可能会存在多个 */ private List featureResources; + + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class LinkExt { + private String system; + + private String routerUrl; + } + + public List resolveLinkExt() { + return Optional.ofNullable(this.getLinkExt()) + .map(e -> JSONArray.parseArray(this.getLinkExt(), LinkExt.class)) + .orElseGet(Lists::newArrayList); + } + + public String resolveIosRouterUrl() { + return resolveLinkExt().stream() + .filter(e -> Objects.equals(e.getSystem(), "ios")) + .findFirst() + .map(LinkExt::getRouterUrl) + .orElse(null); + } + + public String resolveAndroidRouterUrl() { + return resolveLinkExt().stream() + .filter(e -> Objects.equals(e.getSystem(), "android")) + .findFirst() + .map(LinkExt::getRouterUrl) + .orElse(null); + } } 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 70c389f1..01c7b990 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 @@ -2,6 +2,7 @@ package cn.axzo.tyr.server.controller.permission; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.tyr.client.feign.PermissionQueryApi; +import cn.axzo.tyr.client.model.req.ListPermissionFeatureReq; import cn.axzo.tyr.client.model.req.NavTreeReq; import cn.axzo.tyr.client.model.req.PagePermissionReq; import cn.axzo.tyr.client.model.req.PagePermissionResp; @@ -9,6 +10,7 @@ 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.ListPermissionFeatureResp; import cn.axzo.tyr.client.model.res.NavTreeResp; import cn.axzo.tyr.client.model.res.ProductFeatureResourceResp; import cn.axzo.tyr.client.model.res.TreePermissionResp; @@ -62,4 +64,10 @@ public class PermissionQueryController implements PermissionQueryApi { public ApiResult> treePermission(TreePermissionReq req) { return ApiResult.ok(permissionService.treePermission(req)); } + + @Override + public ApiResult> listPermission(ListPermissionFeatureReq req) { + + return ApiResult.ok(permissionService.listPermission(req)); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/PermissionQueryService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/PermissionQueryService.java index 82dfa740..ffc52aa2 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/PermissionQueryService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/PermissionQueryService.java @@ -1,5 +1,6 @@ package cn.axzo.tyr.server.service; +import cn.axzo.tyr.client.model.req.ListPermissionFeatureReq; import cn.axzo.tyr.client.model.req.NavTreeReq; import cn.axzo.tyr.client.model.req.PagePermissionReq; import cn.axzo.tyr.client.model.req.PagePermissionResp; @@ -7,6 +8,7 @@ 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.ListPermissionFeatureResp; import cn.axzo.tyr.client.model.res.NavTreeResp; import cn.axzo.tyr.client.model.res.ProductFeatureResourceResp; import cn.axzo.tyr.client.model.res.TreePermissionResp; @@ -51,4 +53,6 @@ public interface PermissionQueryService { * @return */ List treePermission(TreePermissionReq req); + + List listPermission(ListPermissionFeatureReq req); } 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 477cfd3a..cf69f302 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 @@ -21,6 +21,7 @@ import cn.axzo.tyr.client.model.enums.IdentityType; import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO; import cn.axzo.tyr.client.model.req.FeatureIdPair; import cn.axzo.tyr.client.model.req.IdentityAuthReq; +import cn.axzo.tyr.client.model.req.ListPermissionFeatureReq; import cn.axzo.tyr.client.model.req.NavTreeReq; import cn.axzo.tyr.client.model.req.PagePermissionReq; import cn.axzo.tyr.client.model.req.PagePermissionResp; @@ -30,6 +31,7 @@ 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.ListPermissionFeatureResp; import cn.axzo.tyr.client.model.res.NavTreeResp; import cn.axzo.tyr.client.model.res.ProductFeatureResourceResp; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; @@ -326,12 +328,12 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { } private List resolveFeatureIds(TreePermissionReq treePermissionReq) { - if (StringUtils.isBlank(treePermissionReq.getUniCode())) { + if (CollectionUtils.isEmpty(treePermissionReq.getUniCodes())) { return Collections.emptyList(); } PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() - .uniCodes(Sets.newHashSet(treePermissionReq.getUniCode())) + .uniCodes(treePermissionReq.getUniCodes()) .build(); return featureResourceService.list(pageSaasFeatureResourceReq).stream() .map(SaasFeatureResourceResp::getId) @@ -365,7 +367,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { List featureIds = resolveFeatureIds(treePermissionReq); - if (StringUtils.isNotBlank(treePermissionReq.getUniCode()) && CollectionUtils.isEmpty(featureIds)) { + if (CollectionUtils.isNotEmpty(treePermissionReq.getUniCodes()) && CollectionUtils.isEmpty(featureIds)) { return Collections.emptySet(); } @@ -461,7 +463,8 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .build()); // 有可能存在资源树被删除的情况 // 因为会存在用户只有菜单权限,下面没有节点,这种需要过滤掉 - if (StringUtils.isBlank(req.getUniCode())) { + // 如果指定查询某个节点的tree,就不需要过滤,因为CMS在项目没有项目菜单权限时,会查询企业所有项目是否有项目菜单权限,能让用户进入项目菜单切换项目 + if (CollectionUtils.isEmpty(req.getUniCodes())) { saasFeatureResources = filterFeature(saasFeatureResources); } if (CollectionUtils.isEmpty(saasFeatureResources)) { @@ -503,6 +506,34 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { return result; } + @Override + public List listPermission(ListPermissionFeatureReq req) { + + TreePermissionReq treePermissionReq = TreePermissionReq.builder() + .workspaceOUPairs(req.getWorkspaceOUPairs()) + .personId(req.getPersonId()) + .terminal(req.getTerminal()) + .uniCodes(req.getUniCodes()) + .build(); + Set featureIds = listUserPermissionFeatureIds(treePermissionReq); + + + List saasFeatureResources = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() + .ids(Lists.newArrayList(featureIds)) + .needPageElement(req.getNeedPageElement()) + .pageElementTypes(req.getPageElementTypes()) + .build()); + + return saasFeatureResources.stream() + .map(e -> { + ListPermissionFeatureResp result = ListPermissionFeatureResp.builder().build(); + BeanUtils.copyProperties(e, result); + result.setFeatureId(e.getId()); + return result; + }) + .collect(Collectors.toList()); + } + private Set resovlePermission(TreePermissionReq req) { if (tyrSaasAuthService.permissionFromDB()) { @@ -816,9 +847,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { WorkspaceProductService.ListWorkspaceProductFeatureSourceCacheParam listWorkspaceProductFeatureSourceCacheParam = WorkspaceProductService.ListWorkspaceProductFeatureSourceCacheParam .builder() .workspaceIds(workspaceIds) - .uniCodes(Optional.ofNullable(treePermissionReq.getUniCode()) - .map(Sets::newHashSet) - .orElseGet(Sets::newHashSet)) + .uniCodes(treePermissionReq.getUniCodes()) .build(); return workspaceProductService.listWorkspaceProductFeatureResourceCached(listWorkspaceProductFeatureSourceCacheParam); @@ -855,9 +884,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { RoleSaasFeatureResourceCacheService.ListRoleSaasFeatureResourceParam listRoleSaasFeatureResourceParam = RoleSaasFeatureResourceCacheService.ListRoleSaasFeatureResourceParam.builder() .roleIds(roleIds) - .uniCodes(Optional.ofNullable(treePermissionReq.getUniCode()) - .map(Sets::newHashSet) - .orElseGet(Sets::newHashSet)) + .uniCodes(treePermissionReq.getUniCodes()) .build(); return roleSaasFeatureResourceCacheService.list(listRoleSaasFeatureResourceParam); } 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 e979db36..cf961c9f 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 @@ -641,6 +641,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl pageElementFeatureResourceRelations = saasPageElementFeatureResourceRelationService.list(pageElementFeatureResourceRelationReq); 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 index c9f18b6b..0beda527 100644 --- 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 @@ -3,6 +3,7 @@ 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.common.enums.PageElementFeatureResourceRelationTypeEnum; import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq; import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; import cn.axzo.tyr.server.repository.mapper.SaasPageElementFeatureResourceRelationMapper; @@ -11,10 +12,12 @@ 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.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Service; import java.util.List; import java.util.function.Function; +import java.util.stream.Collectors; @Slf4j @Service @@ -36,6 +39,10 @@ public class SaasPageElementFeatureResourceRelationServiceImpl extends ServiceIm QueryWrapper wrapper = QueryWrapperHelper.fromBean(param, SaasPageElementFeatureResourceRelation.class); wrapper.eq("is_delete", 0); + if (CollectionUtils.isNotEmpty(param.getTypes())) { + wrapper.in("type", param.getTypes().stream().map(PageElementFeatureResourceRelationTypeEnum::getValue).collect(Collectors.toSet())); + } + IPage page = this.page(PageConverter.toMybatis(param, SaasPageElementFeatureResourceRelation.class), wrapper); return PageConverter.toResp(page, Function.identity()); From 1db9878f272965b82feb0647a1adeaa894d92850 Mon Sep 17 00:00:00 2001 From: lilong Date: Sat, 10 Aug 2024 13:27:02 +0800 Subject: [PATCH 055/112] =?UTF-8?q?feat:(REQ-2699)=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E6=9C=AA=E6=9F=A5=E5=88=B0=E6=9D=83=E9=99=90=E6=97=B6=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/service/impl/PermissionQueryServiceImpl.java | 3 +++ 1 file changed, 3 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 cf69f302..8776af59 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 @@ -517,6 +517,9 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .build(); Set featureIds = listUserPermissionFeatureIds(treePermissionReq); + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyList(); + } List saasFeatureResources = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() .ids(Lists.newArrayList(featureIds)) From 3e3f219818ad41f7c7fdd4cdd67793533a695b2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Mon, 12 Aug 2024 17:47:05 +0800 Subject: [PATCH 056/112] feat(REQ-2300): merge master to 2300 --- .../cn/axzo/tyr/server/service/impl/ProductServiceImpl.java | 2 -- 1 file changed, 2 deletions(-) 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 9c3c5fe1..c4d76d41 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 @@ -55,8 +55,6 @@ import org.apache.commons.collections4.CollectionUtils; import org.slf4j.MDC; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.CollectionUtils; -import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.util.ArrayList; From a85354c677d5ebe31719079d01c0bc53e3cc48d6 Mon Sep 17 00:00:00 2001 From: lilong Date: Mon, 12 Aug 2024 17:56:22 +0800 Subject: [PATCH 057/112] =?UTF-8?q?feat:(REQ-2699)=20=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E6=9D=83=E9=99=90=E6=94=AF=E6=8C=81=E7=89=88=E6=9C=AC=E5=8F=B7?= =?UTF-8?q?=E5=92=8C=E7=88=B6=E7=BB=84=E4=BB=B6code=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/req/ListPermissionFeatureReq.java | 17 ++++ .../client/model/req/TreePermissionReq.java | 11 +++ ...acheProductSaasFeatureResourceHandler.java | 35 ++++--- .../event/inner/CacheSaasFeatureHandler.java | 36 +------- .../CacheSaasFeatureResourceHandler.java | 33 +------ .../tyr/server/job/CacheSaasFeatureJob.java | 19 +++- .../service/SaasFeatureResourceService.java | 8 ++ .../impl/PermissionQueryServiceImpl.java | 92 ++++++++++++++----- 8 files changed, 146 insertions(+), 105 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListPermissionFeatureReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListPermissionFeatureReq.java index b2e42bf0..5d524012 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListPermissionFeatureReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListPermissionFeatureReq.java @@ -1,5 +1,6 @@ package cn.axzo.tyr.client.model.req; +import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum; import cn.axzo.tyr.client.model.base.WorkspaceOUPair; import lombok.AllArgsConstructor; @@ -35,6 +36,7 @@ public class ListPermissionFeatureReq { /** * 菜单节点的uniCode + * 查询指定组件code集合里有权限的组件code */ private Set uniCodes; @@ -44,4 +46,19 @@ public class ListPermissionFeatureReq { * 菜单跟页面元素绑定的类型 */ private Set pageElementTypes; + + /** + * 客户端版本号 + */ + private Integer versionMax; + + /** + * 查询菜单树节点类型 + */ + private List featureResourceTypes; + + /** + * 查询父组件code下的有权限的uniCode + */ + private String parentUniCode; } 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 index cad451ba..08fb70ae 100644 --- 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 @@ -47,6 +47,17 @@ public class TreePermissionReq { /** * 菜单节点的uniCode + * 查询指定组件code集合里有权限的组件code */ private Set uniCodes; + + /** + * 客户端版本号 + */ + private Integer versionMax; + + /** + * 查询父组件code下的有权限的uniCode + */ + private String parentUniCode; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java index 0a8fa2ef..113ca793 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java @@ -2,10 +2,11 @@ package cn.axzo.tyr.server.event.inner; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; -import cn.axzo.framework.rocketmq.EventHandler; import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum; import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.client.model.res.PageElementResp; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload; @@ -22,12 +23,12 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; 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; @@ -144,13 +145,9 @@ public class CacheProductSaasFeatureResourceHandler implements InitializingBean return null; } - List featureResourceDTOS = Lists.newArrayList(ProductSaasFeatureResourceCacheService.FeatureResourceDTO.builder() - .featureId(featureResource.getId()) - .featureType(featureResource.getFeatureType()) - .terminal(featureResource.getTerminal()) - .uniCode(featureResource.getUniCode()) - .cooperateType(relation.getDictCode()) - .build()); + ProductSaasFeatureResourceCacheService.FeatureResourceDTO featureResourceDTO = from(featureResource, relation); + List featureResourceDTOS = Lists.newArrayList(featureResourceDTO); + List parentPermissions = featureResource.resolvePath().stream() .map(parentFeatureResources::get) .filter(Objects::nonNull) @@ -160,13 +157,7 @@ public class CacheProductSaasFeatureResourceHandler implements InitializingBean return null; } - return ProductSaasFeatureResourceCacheService.FeatureResourceDTO.builder() - .featureId(f.getId()) - .featureType(f.getFeatureType()) - .terminal(f.getTerminal()) - .uniCode(f.getUniCode()) - .cooperateType(relation.getDictCode()) - .build(); + return from(featureResource, relation); }) .filter(Objects::nonNull) .collect(Collectors.toList()); @@ -194,6 +185,16 @@ public class CacheProductSaasFeatureResourceHandler implements InitializingBean .collect(Collectors.toList()); } + private ProductSaasFeatureResourceCacheService.FeatureResourceDTO from(SaasFeatureResourceResp featureResource, + SaasProductModuleFeatureRelation relation) { + return ProductSaasFeatureResourceCacheService.FeatureResourceDTO.builder() + .featureId(featureResource.getId()) + .featureType(featureResource.getFeatureType()) + .terminal(featureResource.getTerminal()) + .uniCode(featureResource.getUniCode()) + .cooperateType(relation.getDictCode()) + .build(); + } private Map listSaasFeatureResource(List productPermissions) { @@ -209,7 +210,6 @@ public class CacheProductSaasFeatureResourceHandler implements InitializingBean // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() .ids(featureIds) - .needFeatureCodes(true) .build(); return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); @@ -230,7 +230,6 @@ public class CacheProductSaasFeatureResourceHandler implements InitializingBean // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() .ids(parentIds) - .needFeatureCodes(true) .build(); return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java index 888b5893..8c41f346 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java @@ -3,21 +3,14 @@ package cn.axzo.tyr.server.event.inner; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; -import cn.axzo.tyr.client.model.enums.DelegatedType; import cn.axzo.tyr.server.event.payload.SaasFeatureUpsertPayload; -import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; -import cn.axzo.tyr.server.repository.entity.SaasFeature; -import cn.axzo.tyr.server.service.SaasFeatureResourceService; -import com.google.common.collect.Lists; +import cn.axzo.tyr.server.job.CacheSaasFeatureJob; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.List; -import java.util.stream.Collectors; - /** * 缓存全量权限点,因为鉴权等逻辑,需要查询免授权和权限点是否存在,数据量大,数据库压力大 */ @@ -28,9 +21,7 @@ public class CacheSaasFeatureHandler implements EventHandler, InitializingBean { @Autowired private EventConsumer eventConsumer; @Autowired - private SaasFeatureDao saasFeatureDao; - @Autowired - private SaasFeatureResourceService saasFeatureResourceService; + private CacheSaasFeatureJob cacheSaasFeatureJob; @Override public void onEvent(Event event, EventConsumer.Context context) { @@ -40,28 +31,7 @@ public class CacheSaasFeatureHandler implements EventHandler, InitializingBean { if (StringUtils.isBlank(payload.getTerminal())) { return; } - - List saasFeatures = saasFeatureDao.lambdaQuery() - .eq(SaasFeature::getTerminal, payload.getTerminal()) - .list() - .stream() - .map(e -> SaasFeatureResourceService.SaasFeatureResourceCache.builder() - .featureId(e.getId()) - .notAuth(DelegatedType.notAuth(e.getDelegatedType())) - .parentIds(e.splitPath()) - .build()) - .collect(Collectors.toList()); - - SaasFeatureResourceService.SaasFeatureResourceDTO saasFeatureResourceDTO = SaasFeatureResourceService.SaasFeatureResourceDTO.builder() - .terminal(payload.getTerminal()) - .features(saasFeatures) - .build(); - SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() - .saasFeatureResources(Lists.newArrayList(saasFeatureResourceDTO)) - .build(); - saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); - - + cacheSaasFeatureJob.cacheSaasFeature(payload.getTerminal()); log.info("end cached saasFeature handler rocketmq event: {}", event); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java index 69c213a2..87a197a0 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java @@ -3,20 +3,14 @@ package cn.axzo.tyr.server.event.inner; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; -import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; -import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; -import cn.axzo.tyr.server.service.SaasFeatureResourceService; -import com.google.common.collect.Lists; +import cn.axzo.tyr.server.job.CacheSaasFeatureJob; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.List; -import java.util.stream.Collectors; - /** * 缓存全量权限点,因为鉴权等逻辑,需要查询免授权和权限点是否存在,数据量大,数据库压力大 */ @@ -27,7 +21,7 @@ public class CacheSaasFeatureResourceHandler implements EventHandler, Initializi @Autowired private EventConsumer eventConsumer; @Autowired - private SaasFeatureResourceService saasFeatureResourceService; + private CacheSaasFeatureJob cacheSaasFeatureJob; @Override public void onEvent(Event event, EventConsumer.Context context) { @@ -39,28 +33,7 @@ public class CacheSaasFeatureResourceHandler implements EventHandler, Initializi } // 直接查询缓存所有节点,因为修改的代码不好改 - - PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() - .terminal(payload.getTerminal()) - .build(); - - List saasFeatures = saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() - .map(e -> SaasFeatureResourceService.SaasFeatureResourceCache.builder() - .featureId(e.getId()) - .notAuth(SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) - .parentIds(e.resolvePath()) - .build()) - .collect(Collectors.toList()); - - SaasFeatureResourceService.SaasFeatureResourceDTO saasFeatureResourceDTO = SaasFeatureResourceService.SaasFeatureResourceDTO.builder() - .terminal(payload.getTerminal()) - .features(saasFeatures) - .build(); - SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() - .saasFeatureResources(Lists.newArrayList(saasFeatureResourceDTO)) - .build(); - saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); - + cacheSaasFeatureJob.cacheSaasFeatureResource(payload.getTerminal()); log.info("end cached saasFeatureResource handler rocketmq event: {}", event); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java index 0d299ed9..9269a13a 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java @@ -2,6 +2,7 @@ package cn.axzo.tyr.server.job; import cn.axzo.tyr.client.model.enums.DelegatedType; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.client.model.res.PageElementResp; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.entity.SaasFeature; @@ -17,6 +18,7 @@ import org.springframework.stereotype.Component; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; @Slf4j @@ -28,6 +30,11 @@ public class CacheSaasFeatureJob extends IJobHandler { @Autowired private SaasFeatureResourceService saasFeatureResourceService; + /** + * 分组这些菜单节点没有版本号,默认为0,方便权限过滤 + */ + private static final int DEFAULT_VERSION = 0; + @Override @XxlJob("CacheSaasFeatureJob") public ReturnT execute(String s) throws Exception { @@ -40,7 +47,7 @@ public class CacheSaasFeatureJob extends IJobHandler { return ReturnT.SUCCESS; } - private void cacheSaasFeature(String terminal) { + public void cacheSaasFeature(String terminal) { Map> saasFeatures = saasFeatureDao.lambdaQuery() .eq(StringUtils.isNotBlank(terminal), SaasFeature::getTerminal, terminal) .list() @@ -66,9 +73,10 @@ public class CacheSaasFeatureJob extends IJobHandler { saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); } - private void cacheSaasFeatureResource(String terminal) { + public void cacheSaasFeatureResource(String terminal) { PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() .terminal(terminal) + .needPageElement(true) .build(); Map> saasFeatureResources = saasFeatureResourceService.list(pageSaasFeatureResourceReq) @@ -79,6 +87,13 @@ public class CacheSaasFeatureJob extends IJobHandler { .featureId(e.getId()) .notAuth(SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) .parentIds(e.resolvePath()) + .uniCode(e.getUniCode()) + .version(Optional.ofNullable(e.getSaasPageElements()) + .map(pageElement -> pageElement.stream() + .findFirst() + .map(PageElementResp::getVersion) + .orElse(DEFAULT_VERSION)) + .orElse(DEFAULT_VERSION)) .build(), Collectors.toList()))); List featureResources = saasFeatureResources.entrySet().stream() 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 56ff3b82..f2a94322 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 @@ -107,5 +107,13 @@ public interface SaasFeatureResourceService extends IService parentIds; + + private String uniCode; + + /** + * 客户端版本号 + * 在根据版本号查询菜单树权限的时候需要 + */ + private Integer version; } } 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 8776af59..8003aadb 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 @@ -69,6 +69,7 @@ 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.Autowired; @@ -116,11 +117,9 @@ 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 RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService; - private final ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService; private final TyrSaasAuthService tyrSaasAuthService; @@ -381,7 +380,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { List workspaceProducts = listWorkspaceProducts(treePermissionReq, featureIds); //免授权 - List authFreeFeatureIds = listNotAuthFeatures(treePermissionReq); + Set authFreeFeatureIds = listNotAuthFeatures(treePermissionReq); //取交集确定权限 return mixFeatureIds(saasRoleUserV2DTOS, workspaceProducts, authFreeFeatureIds); @@ -389,7 +388,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { private Set mixFeatureIds(List saasRoleUsers, List workspaceProducts, - List authFreeFeatureIds) { + Set authFreeFeatureIds) { Map workspaceProductMap = workspaceProducts.stream() .collect(Collectors.toMap(WorkspaceProductService.WorkspaceProduct::getWorkspaceId, Function.identity())); @@ -456,7 +455,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { return Collections.emptyList(); } - List saasFeatureResources = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() + List saasFeatureResources = featureResourceService.list(PageSaasFeatureResourceReq.builder() .ids(Lists.newArrayList(allFeatureIds)) .needFeatureCodes(true) .terminal(req.getTerminal()) @@ -514,6 +513,8 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .personId(req.getPersonId()) .terminal(req.getTerminal()) .uniCodes(req.getUniCodes()) + .versionMax(req.getVersionMax()) + .parentUniCode(req.getParentUniCode()) .build(); Set featureIds = listUserPermissionFeatureIds(treePermissionReq); @@ -521,7 +522,8 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { return Collections.emptyList(); } - List saasFeatureResources = saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder() + // 使用方需要名字、icon、routerUrl等信息,放在redis就数据量比较大,后续要做成人维度的权限缓存,所以现在就查询数据库,因为有权限的权限点不多,且是主键查询 + List saasFeatureResources = featureResourceService.list(PageSaasFeatureResourceReq.builder() .ids(Lists.newArrayList(featureIds)) .needPageElement(req.getNeedPageElement()) .pageElementTypes(req.getPageElementTypes()) @@ -818,27 +820,72 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { return relations; } + private List listAllFeatureResources(TreePermissionReq treePermissionReq) { + + List allFeatureResources = featureResourceService.listCache(SaasFeatureResourceService.ListSaasFeatureResourceCache.builder() + .terminals(Sets.newHashSet(treePermissionReq.getTerminal())) + .build()) + .get(treePermissionReq.getTerminal()) + .stream() + .filter(f -> Objects.isNull(treePermissionReq.getVersionMax()) + || treePermissionReq.getVersionMax().compareTo(f.getVersion()) > -1) + .collect(Collectors.toList()); + + if (StringUtils.isBlank(treePermissionReq.getParentUniCode())) { + return allFeatureResources; + } + + Optional parentId = allFeatureResources.stream() + .filter(e -> Objects.equals(e.getUniCode(), treePermissionReq.getParentUniCode())) + .map(SaasFeatureResourceService.SaasFeatureResourceCache::getFeatureId) + .findFirst(); + return parentId.map(aLong -> allFeatureResources.stream() + .filter(e -> e.getParentIds().contains(aLong)) + .collect(Collectors.toList())) + .orElse(Collections.emptyList()); + } + private Set listUserPermissionFeatureIds(TreePermissionReq treePermissionReq) { - List saasRoleUserV2DTOS = listUserPermission(treePermissionReq); + List allFeatureResources = listAllFeatureResources(treePermissionReq); + + if (CollectionUtils.isEmpty(allFeatureResources)) { + return Collections.emptySet(); + } + + List saasRoleUsers = listUserPermission(treePermissionReq); + + Map> roleFeatureResourceMap = listRoleFeatureResource(saasRoleUsers, treePermissionReq); List workspaceProductFeatureSources = listWorkspaceProducts(treePermissionReq); //免授权 - List authFreeFeatureIds = listNotAuthFeatures(treePermissionReq); + Set authFreeFeatureIds = allFeatureResources.stream() + .filter(e -> BooleanUtils.isTrue(e.isNotAuth())) + .map(SaasFeatureResourceService.SaasFeatureResourceCache::getFeatureId) + .collect(Collectors.toSet()); + + Set allFeatureIds = allFeatureResources.stream() + .map(SaasFeatureResourceService.SaasFeatureResourceCache::getFeatureId) + .collect(Collectors.toSet()); //取交集确定权限 - return mixFeatureIds(saasRoleUserV2DTOS, workspaceProductFeatureSources, authFreeFeatureIds, treePermissionReq); + return mixFeatureIds(saasRoleUsers, + workspaceProductFeatureSources, + authFreeFeatureIds, + treePermissionReq, + roleFeatureResourceMap, + allFeatureIds); } - private List listNotAuthFeatures(TreePermissionReq treePermissionReq) { + private Set 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()); + .collect(Collectors.toSet()); } private List listWorkspaceProducts(TreePermissionReq treePermissionReq) { @@ -894,14 +941,14 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { private Set mixFeatureIds(List saasRoleUsers, List workspaceProducts, - List authFreeFeatureIds, - TreePermissionReq treePermissionReq) { + Set authFreeFeatureIds, + TreePermissionReq treePermissionReq, + Map> roleFeatureResourceMap, + Set allFeatureIds) { Map> workspaceProductMap = workspaceProducts.stream() .collect(Collectors.toMap(WorkspaceProductService.WorkspaceProductFeatureSource::getWorkspaceId, WorkspaceProductService.WorkspaceProductFeatureSource::getProductFeatureSources)); - Map> roleFeatureResourceMap = listRoleFeatureResource(saasRoleUsers, treePermissionReq); - Set featureTypes = Optional.ofNullable(treePermissionReq.getFeatureResourceTypes()) .map(e -> e.stream().map(FeatureResourceType::getCode).collect(Collectors.toSet())) .orElseGet(Sets::newHashSet); @@ -914,6 +961,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .flatMap(Collection::stream) .filter(e -> StringUtils.isBlank(treePermissionReq.getTerminal()) || Objects.equals(e.getTerminal(), treePermissionReq.getTerminal())) + .filter(e -> allFeatureIds.contains(e.getFeatureId())) .collect(Collectors.toList()); if (CollectionUtils.isEmpty(productFeatureSources)) { @@ -933,12 +981,12 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { Set normalFeatureIds = resolveNormalRole(productFeatureSources, saasRole, roleFeatureResources); - Set allFeatureIds = Sets.newHashSet(); - allFeatureIds.addAll(adminFeatureIds); - allFeatureIds.addAll(notAuthFeatureIds); - allFeatureIds.addAll(normalFeatureIds); + Set result = Sets.newHashSet(); + result.addAll(adminFeatureIds); + result.addAll(notAuthFeatureIds); + result.addAll(normalFeatureIds); - return allFeatureIds; + return result; }) .filter(Objects::nonNull) .flatMap(Collection::stream) @@ -981,7 +1029,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { } private Set resolveNotAuthFeatureIds(List workspaceProduct, - List authFreeFeatureIds) { + Set authFreeFeatureIds) { if (CollectionUtils.isEmpty(authFreeFeatureIds)) { return Collections.emptySet(); @@ -1006,7 +1054,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { private List resolveNormalRole(WorkspaceProductService.WorkspaceProduct workspaceProduct, SaasRoleUserV2DTO.SaasRole saasRole, - List authFreeFeatureIds) { + Set authFreeFeatureIds) { //普通角色:角色同类型的租户产品权限已分配 且角色上已分配 + 免授权 Set roleFeatureIds = Optional.ofNullable(saasRole.getPermissionRelations()) .map(e -> e.stream() From 494bebc84dd71b9702aa5c6ca22f5d9fff72d509 Mon Sep 17 00:00:00 2001 From: lilong Date: Mon, 12 Aug 2024 19:52:49 +0800 Subject: [PATCH 058/112] =?UTF-8?q?feat:(REQ-2699)=20=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E6=9D=83=E9=99=90=E5=A2=9E=E5=8A=A0=E9=A1=B5=E9=9D=A2=E5=85=83?= =?UTF-8?q?=E7=B4=A0=E6=9F=A5=E8=AF=A2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/tyr/client/model/req/TreePermissionReq.java | 8 ++++++++ .../cn/axzo/tyr/client/model/res/TreePermissionResp.java | 2 ++ .../server/service/impl/PermissionQueryServiceImpl.java | 2 ++ 3 files changed, 12 insertions(+) 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 index 08fb70ae..3ef4a3be 100644 --- 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 @@ -1,6 +1,7 @@ package cn.axzo.tyr.client.model.req; import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum; import cn.axzo.tyr.client.model.base.WorkspaceOUPair; import lombok.AllArgsConstructor; import lombok.Builder; @@ -60,4 +61,11 @@ public class TreePermissionReq { * 查询父组件code下的有权限的uniCode */ private String parentUniCode; + + private Boolean needPageElement; + + /** + * 菜单跟页面元素绑定的类型 + */ + private Set pageElementTypes; } 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 index 198a887e..46d5fb65 100644 --- 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 @@ -80,6 +80,8 @@ public class TreePermissionResp implements IBaseTree { */ private Integer displayOrder; + private List saasPageElements; + /** * 菜单树子节点信息 */ 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 8003aadb..1ccdbd2d 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 @@ -459,6 +459,8 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .ids(Lists.newArrayList(allFeatureIds)) .needFeatureCodes(true) .terminal(req.getTerminal()) + .needPageElement(req.getNeedPageElement()) + .pageElementTypes(req.getPageElementTypes()) .build()); // 有可能存在资源树被删除的情况 // 因为会存在用户只有菜单权限,下面没有节点,这种需要过滤掉 From e7fb5dd8d808bc452d784578d3e48448b983a23f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E6=95=8F?= Date: Tue, 13 Aug 2024 18:14:44 +0800 Subject: [PATCH 059/112] =?UTF-8?q?feat(REQ-2864):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=8D=95=E4=BD=8D=E3=80=81=E9=83=A8=E9=97=A8=E3=80=81=E5=8D=8F?= =?UTF-8?q?=E5=90=8C=E5=85=B3=E7=B3=BB=E3=80=81=E9=83=A8=E9=97=A8=E4=BA=BA?= =?UTF-8?q?=E5=91=98=E6=93=8D=E4=BD=9C=E6=97=A5=E5=BF=97=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E7=9A=84=E6=9E=9A=E4=B8=BE=EF=BC=8C=E6=89=A9=E5=B1=95=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E6=94=AF=E6=8C=81operatorId=E4=B8=BA=E7=A9=BA?= =?UTF-8?q?=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/req/PermissionOperateLogReq.java | 8 ++++++-- .../SaasPgroupPermissionRelationOperateLog.java | 8 +++++++- ...PermissionRelationOperateLogServiceImpl.java | 17 +++++++++++++---- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PermissionOperateLogReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PermissionOperateLogReq.java index dfa5c3a4..1d67e8a5 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PermissionOperateLogReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PermissionOperateLogReq.java @@ -29,10 +29,12 @@ public class PermissionOperateLogReq implements Serializable { @NotBlank(message = "表名不能为空") private String tableName; - @NotNull(message = "操作人ID不能为空") - @Min(value = 1, message = "操作人ID有误") +// @NotNull(message = "操作人ID不能为空") +// @Min(value = 1, message = "操作人ID有误") private Long operatorId; + private String operatorName; + @NotBlank(message = "场景不能为空") private String scene; @@ -41,4 +43,6 @@ public class PermissionOperateLogReq implements Serializable { private Object requestData; private Object operateData; + + private JSONObject ext; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPgroupPermissionRelationOperateLog.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPgroupPermissionRelationOperateLog.java index ddf61fbd..a8feb86e 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPgroupPermissionRelationOperateLog.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPgroupPermissionRelationOperateLog.java @@ -2,7 +2,10 @@ package cn.axzo.tyr.server.repository.entity; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.common.enums.PermissionRelationOperateLogSceneEnum; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; import lombok.*; /** @@ -15,7 +18,7 @@ import lombok.*; @Builder @ToString @EqualsAndHashCode(callSuper = true) -@TableName("saas_pgroup_permission_relation_operate_log") +@TableName(value = "saas_pgroup_permission_relation_operate_log", autoResultMap = true) public class SaasPgroupPermissionRelationOperateLog extends BaseEntity { /** @@ -63,4 +66,7 @@ public class SaasPgroupPermissionRelationOperateLog extends BaseEntity personProfileDtos = RpcInternalUtil.rpcListProcessor(() -> userProfileServiceApi.getPersonProfiles(Lists.newArrayList(req.getOperatorId())), "查询用户信息", req.getOperatorId()).getData(); - PersonProfileDto operator = CollectionUtils.isEmpty(personProfileDtos) ? null : personProfileDtos.get(0); + String realName = req.getOperatorId() == null ? "" : Optional.ofNullable(getPersonProfileDto(req)).map(PersonProfileDto::getRealName).orElse(""); SaasPgroupPermissionRelationOperateLog operateLog = SaasPgroupPermissionRelationOperateLog.builder() .tableName(req.getTableName()) .scene(req.getScene()) .sceneId(req.getSceneId()) - .createBy(req.getOperatorId()) - .createByName(Objects.isNull(operator) ? "" : operator.getRealName()) + .createBy(ObjectUtils.firstNonNull(req.getOperatorId(), 0L)) + .createByName(StringUtils.firstNonBlank(realName, req.getOperatorName(), "")) .traceId(MDC.get(Constants.CTX_LOG_ID_MDC)) .requestData(Objects.nonNull(req.getRequestData()) ? JSONObject.toJSONString(req.getRequestData()) : null) .operateData(Objects.nonNull(req.getOperateData()) ? JSONObject.toJSONString(req.getOperateData()) : null) .createByRole(JSONObject.toJSONString(getPersonBasicRoles(req.getOperatorId()))) + .ext(req.getExt()) .build(); batchSave(Lists.newArrayList(operateLog)); } + + private PersonProfileDto getPersonProfileDto(PermissionOperateLogReq req) { + List personProfileDtos = RpcInternalUtil.rpcListProcessor(() -> userProfileServiceApi.getPersonProfiles(Lists.newArrayList(req.getOperatorId())), "查询用户信息", req.getOperatorId()).getData(); + PersonProfileDto operator = CollectionUtils.isEmpty(personProfileDtos) ? null : personProfileDtos.get(0); + return operator; + } } From 08a1e556fede7977fe659e908eb9132e73ef17c4 Mon Sep 17 00:00:00 2001 From: lilong Date: Wed, 14 Aug 2024 16:53:34 +0800 Subject: [PATCH 060/112] =?UTF-8?q?feat:(REQ-2699)=20=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E6=9D=83=E9=99=90=E6=A0=91tree=E6=8E=A5=E5=8F=A3=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=98=AF=E5=90=A6=E6=8E=92=E9=99=A4=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E6=9D=83=E9=99=90=E7=9A=84=E5=85=A5=E5=8F=82=EF=BC=8C=E5=9B=A0?= =?UTF-8?q?=E4=B8=BA=E4=B8=8D=E6=98=AF=E6=89=80=E6=9C=89=E9=9C=80=E6=B1=82?= =?UTF-8?q?=E9=83=BD=E9=9C=80=E8=A6=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/tyr/client/model/req/TreePermissionReq.java | 5 +++++ .../server/service/impl/PermissionQueryServiceImpl.java | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) 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 index 3ef4a3be..0cf9dfb4 100644 --- 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 @@ -68,4 +68,9 @@ public class TreePermissionReq { * 菜单跟页面元素绑定的类型 */ private Set pageElementTypes; + + /** + * 默认会增加config配置的默认权限,不需要就传true + */ + private Boolean excludeDefaultPermission; } 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 1ccdbd2d..2904f048 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 @@ -312,7 +312,12 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { * 所以做了一个开关可以配置所有用户可以看到的菜单 * @return */ - private Set listNotAuthFeatureIds() { + private Set listNotAuthFeatureIds(TreePermissionReq req) { + + if (BooleanUtils.isTrue(req.getExcludeDefaultPermission())) { + return Collections.emptySet(); + } + if (CollectionUtils.isEmpty(notAuthUniCodes)) { return Collections.emptySet(); } @@ -446,7 +451,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { Set allFeatureIds = Sets.newHashSet(); Set featureIds = resovlePermission(req); - Set defaultFeatureIds = listNotAuthFeatureIds(); + Set defaultFeatureIds = listNotAuthFeatureIds(req); allFeatureIds.addAll(featureIds); allFeatureIds.addAll(defaultFeatureIds); From 61f755d3ee8b210c73553c36828df6080c91613e Mon Sep 17 00:00:00 2001 From: lilong Date: Thu, 15 Aug 2024 16:01:38 +0800 Subject: [PATCH 061/112] =?UTF-8?q?feat:(REQ-2720)=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E8=8F=9C=E5=8D=95=E6=97=B6=E5=8F=91=E9=80=81?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E6=9B=B4=E6=96=B0mq=E5=92=8C=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E6=9D=83=E9=99=90mq=EF=BC=8C=E8=A7=A6=E5=8F=91?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/PrivateController.java | 2 +- .../event/inner/CacheSaasFeatureHandler.java | 28 ++----------- .../CacheSaasFeatureResourceHandler.java | 38 +++-------------- .../outer/CacheSaasFeatureOldHandler.java | 41 +++---------------- .../SaasFeatureResourceUpsertPayload.java | 3 +- .../tyr/server/job/CacheSaasFeatureJob.java | 32 +++++++++++---- .../impl/FeatureResourceSyncServiceImpl.java | 40 ++++++++++++++++++ .../server/service/impl/RoleServiceImpl.java | 2 +- .../impl/SaasFeatureResourceServiceImpl.java | 4 +- 9 files changed, 86 insertions(+), 104 deletions(-) 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 0a89d1ca..82f6daef 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 @@ -681,7 +681,7 @@ public class PrivateController { @PostMapping("/api/private/saasFeature/store") public Object storeSaasFeature(@RequestBody StoreFeatureParam request) throws Exception { - cacheSaasFeatureJob.execute(request.getTerminal()); + cacheSaasFeatureJob.execute(JSON.toJSONString(request)); return "ok"; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java index 888b5893..953399ac 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java @@ -5,10 +5,12 @@ import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; import cn.axzo.tyr.client.model.enums.DelegatedType; import cn.axzo.tyr.server.event.payload.SaasFeatureUpsertPayload; +import cn.axzo.tyr.server.job.CacheSaasFeatureJob; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.entity.SaasFeature; import cn.axzo.tyr.server.service.SaasFeatureResourceService; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; @@ -28,9 +30,7 @@ public class CacheSaasFeatureHandler implements EventHandler, InitializingBean { @Autowired private EventConsumer eventConsumer; @Autowired - private SaasFeatureDao saasFeatureDao; - @Autowired - private SaasFeatureResourceService saasFeatureResourceService; + private CacheSaasFeatureJob cacheSaasFeatureJob; @Override public void onEvent(Event event, EventConsumer.Context context) { @@ -41,27 +41,7 @@ public class CacheSaasFeatureHandler implements EventHandler, InitializingBean { return; } - List saasFeatures = saasFeatureDao.lambdaQuery() - .eq(SaasFeature::getTerminal, payload.getTerminal()) - .list() - .stream() - .map(e -> SaasFeatureResourceService.SaasFeatureResourceCache.builder() - .featureId(e.getId()) - .notAuth(DelegatedType.notAuth(e.getDelegatedType())) - .parentIds(e.splitPath()) - .build()) - .collect(Collectors.toList()); - - SaasFeatureResourceService.SaasFeatureResourceDTO saasFeatureResourceDTO = SaasFeatureResourceService.SaasFeatureResourceDTO.builder() - .terminal(payload.getTerminal()) - .features(saasFeatures) - .build(); - SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() - .saasFeatureResources(Lists.newArrayList(saasFeatureResourceDTO)) - .build(); - saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); - - + cacheSaasFeatureJob.cacheSaasFeature(Sets.newHashSet(payload.getTerminal())); log.info("end cached saasFeature handler rocketmq event: {}", event); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java index 69c213a2..9695a0e0 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java @@ -3,20 +3,14 @@ package cn.axzo.tyr.server.event.inner; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; -import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; -import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; -import cn.axzo.tyr.server.service.SaasFeatureResourceService; -import com.google.common.collect.Lists; +import cn.axzo.tyr.server.job.CacheSaasFeatureJob; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.List; -import java.util.stream.Collectors; - /** * 缓存全量权限点,因为鉴权等逻辑,需要查询免授权和权限点是否存在,数据量大,数据库压力大 */ @@ -27,40 +21,18 @@ public class CacheSaasFeatureResourceHandler implements EventHandler, Initializi @Autowired private EventConsumer eventConsumer; @Autowired - private SaasFeatureResourceService saasFeatureResourceService; + private CacheSaasFeatureJob cacheSaasFeatureJob; @Override public void onEvent(Event event, EventConsumer.Context context) { log.info("begin cached saasFeatureResource handler rocketmq event: {}", event); SaasFeatureResourceUpsertPayload payload = event.normalizedData(SaasFeatureResourceUpsertPayload.class); - if (StringUtils.isBlank(payload.getTerminal())) { + if (CollectionUtils.isEmpty(payload.getTerminals())) { return; } - // 直接查询缓存所有节点,因为修改的代码不好改 - - PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() - .terminal(payload.getTerminal()) - .build(); - - List saasFeatures = saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() - .map(e -> SaasFeatureResourceService.SaasFeatureResourceCache.builder() - .featureId(e.getId()) - .notAuth(SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) - .parentIds(e.resolvePath()) - .build()) - .collect(Collectors.toList()); - - SaasFeatureResourceService.SaasFeatureResourceDTO saasFeatureResourceDTO = SaasFeatureResourceService.SaasFeatureResourceDTO.builder() - .terminal(payload.getTerminal()) - .features(saasFeatures) - .build(); - SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() - .saasFeatureResources(Lists.newArrayList(saasFeatureResourceDTO)) - .build(); - saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); - + cacheSaasFeatureJob.cacheSaasFeatureResource(payload.getTerminals()); log.info("end cached saasFeatureResource handler rocketmq event: {}", event); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/outer/CacheSaasFeatureOldHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/outer/CacheSaasFeatureOldHandler.java index 5ed9a699..014675ec 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/outer/CacheSaasFeatureOldHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/outer/CacheSaasFeatureOldHandler.java @@ -2,22 +2,16 @@ package cn.axzo.tyr.server.event.outer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; -import cn.axzo.tyr.client.model.enums.DelegatedType; import cn.axzo.tyr.server.event.payload.SaasFeatureDeletedPayload; import cn.axzo.tyr.server.event.payload.SaasFeatureUpsertPayload; -import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; -import cn.axzo.tyr.server.repository.entity.SaasFeature; -import cn.axzo.tyr.server.service.SaasFeatureResourceService; -import com.google.common.collect.Lists; +import cn.axzo.tyr.server.job.CacheSaasFeatureJob; +import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.List; -import java.util.stream.Collectors; - /** * 缓存全量权限点,因为鉴权等逻辑,需要查询免授权和权限点是否存在,数据量大,数据库压力大 */ @@ -28,9 +22,7 @@ public class CacheSaasFeatureOldHandler implements InitializingBean { @Autowired private EventConsumer eventConsumer; @Autowired - private SaasFeatureDao saasFeatureDao; - @Autowired - private SaasFeatureResourceService saasFeatureResourceService; + private CacheSaasFeatureJob cacheSaasFeatureJob; public void onSaasFeatureUpserted(Event event, EventConsumer.Context context) { log.info("begin cached saasFeature handler rocketmq event: {}", event); @@ -39,7 +31,8 @@ public class CacheSaasFeatureOldHandler implements InitializingBean { if (StringUtils.isBlank(payload.getTerminal())) { return; } - cacheFeature(payload.getTerminal()); + + cacheSaasFeatureJob.cacheSaasFeature(Sets.newHashSet(payload.getTerminal())); log.info("end cached saasFeature handler rocketmq event: {}", event); } @@ -51,32 +44,10 @@ public class CacheSaasFeatureOldHandler implements InitializingBean { return; } - cacheFeature(payload.getTerminal()); - + cacheSaasFeatureJob.cacheSaasFeature(Sets.newHashSet(payload.getTerminal())); log.info("end cached saasFeature handler rocketmq event: {}", event); } - private void cacheFeature(String terminal) { - List saasFeatures = saasFeatureDao.lambdaQuery() - .eq(SaasFeature::getTerminal, terminal) - .list() - .stream() - .map(e -> SaasFeatureResourceService.SaasFeatureResourceCache.builder() - .featureId(e.getId()) - .notAuth(DelegatedType.notAuth(e.getDelegatedType())) - .build()) - .collect(Collectors.toList()); - - SaasFeatureResourceService.SaasFeatureResourceDTO saasFeatureResourceDTO = SaasFeatureResourceService.SaasFeatureResourceDTO.builder() - .terminal(terminal) - .features(saasFeatures) - .build(); - SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() - .saasFeatureResources(Lists.newArrayList(saasFeatureResourceDTO)) - .build(); - saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); - } - @Override public void afterPropertiesSet() throws Exception { eventConsumer.registerHandler(EventTypeEnum.SAAS_FEATURE_UPSERT.getEventCode(), this::onSaasFeatureUpserted); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java index 648fb7d9..1cdcbafb 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java @@ -6,6 +6,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; +import java.util.Set; @Data @Builder @@ -13,5 +14,5 @@ import java.io.Serializable; @AllArgsConstructor public class SaasFeatureResourceUpsertPayload implements Serializable { - private String terminal; + private Set terminals; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java index 0d299ed9..b6b5d127 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java @@ -7,16 +7,24 @@ import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.entity.SaasFeature; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import com.alibaba.fastjson.JSONObject; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; import com.xxl.job.core.handler.annotation.XxlJob; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; @Slf4j @@ -33,16 +41,18 @@ public class CacheSaasFeatureJob extends IJobHandler { public ReturnT execute(String s) throws Exception { log.info("start CacheSaasFeatureJob, s:{}", s); + StoreSaasFeatureParam req = Optional.ofNullable(s) + .map(e -> JSONObject.parseObject(e, StoreSaasFeatureParam.class)) + .orElseGet(() -> StoreSaasFeatureParam.builder().build()); + cacheSaasFeature(req.getTerminals()); - cacheSaasFeature(s); - - cacheSaasFeatureResource(s); + cacheSaasFeatureResource(req.getTerminals()); return ReturnT.SUCCESS; } - private void cacheSaasFeature(String terminal) { + public void cacheSaasFeature(Set terminals) { Map> saasFeatures = saasFeatureDao.lambdaQuery() - .eq(StringUtils.isNotBlank(terminal), SaasFeature::getTerminal, terminal) + .in(CollectionUtils.isNotEmpty(terminals), SaasFeature::getTerminal, terminals) .list() .stream() .collect(Collectors.groupingBy(SaasFeature::getTerminal, @@ -66,9 +76,9 @@ public class CacheSaasFeatureJob extends IJobHandler { saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); } - private void cacheSaasFeatureResource(String terminal) { + public void cacheSaasFeatureResource(Set terminals) { PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() - .terminal(terminal) + .terminals(terminals) .build(); Map> saasFeatureResources = saasFeatureResourceService.list(pageSaasFeatureResourceReq) @@ -93,4 +103,12 @@ public class CacheSaasFeatureJob extends IJobHandler { .build(); saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class StoreSaasFeatureParam { + private Set terminals; + } } 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 9ebdc0a8..542bea78 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 @@ -3,11 +3,15 @@ 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.framework.rocketmq.Event; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; import cn.axzo.tyr.client.model.req.ResourceSyncReq; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; +import cn.axzo.tyr.server.config.MqProducer; +import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; +import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; import cn.axzo.tyr.server.inner.feign.BaseFeatureResourceApi; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; import cn.axzo.tyr.server.repository.dao.SaasPageElementFeatureResourceRelationDao; @@ -23,6 +27,7 @@ import cn.axzo.tyr.server.service.FeatureResourceSyncService; import cn.axzo.tyr.server.util.RpcInternalUtil; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; @@ -36,12 +41,15 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.function.Function; import java.util.stream.Collectors; +import static cn.axzo.tyr.server.event.inner.EventTypeEnum.ROLE_PERMISSION_CREATED; +import static cn.axzo.tyr.server.event.inner.EventTypeEnum.SAAS_FEATURE_RESOURCE_UPSERT; import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; /** @@ -74,6 +82,13 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic @Autowired private ExecutorService asyncExecutor; + @Autowired + private final MqProducer mqProducer; + + private static final String ROLE_PERMISSION_TARGET_TYPE = "saasFeatureResourceId"; + + private static final String SAAS_FEATURE_RESOURCE_TARGET_TYPE = "saasFeatureResourceId"; + @Override public List getSyncTreeById(Long id) { List allFeatureResourceIds = Lists.newArrayList(id); @@ -123,12 +138,26 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic //处理数据缓存:避免同级节点上级重复处理 - 上级code查询 final Map codeCache = new ConcurrentHashMap<>(); + Set terminals = Sets.newHashSet(); for (Long id : req.getIds()) { //获取基准环境配置数据:同步某个ID的数据 需要同步处理它所有上级及下级组件 List syncList = RpcInternalUtil.rpcProcessor(() -> baseFeatureResourceApi.getSyncTreeById(id), "get base sync tree by id", id).getData(); syncResourceProcess(syncList, codeCache, req.getOperatorId()); + + terminals.addAll(syncList.stream() + .map(FeatureResourceTreeNode::getTerminal) + .collect(Collectors.toSet())); } + + Event event = Event.builder() + .targetType(SAAS_FEATURE_RESOURCE_TARGET_TYPE) + .eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode()) + .data(SaasFeatureResourceUpsertPayload.builder() + .terminals(terminals) + .build()) + .build(); + mqProducer.send(event); } @Override @@ -283,6 +312,17 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic .collect(Collectors.toList()); saasPgroupPermissionRelationDao.saveBatch(insertRelation); } + + Event event = Event.builder() + .targetType(ROLE_PERMISSION_TARGET_TYPE) + .eventCode(ROLE_PERMISSION_CREATED.getEventCode()) + .data(RolePermissionCreatedPayload.builder() + .roleIds(saasRoles.stream() + .map(SaasRole::getId) + .collect(Collectors.toSet())) + .build()) + .build(); + mqProducer.send(event); } private Map> getFeatureResourceRoleCodeMap(List allFeatureResourceIds) { 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 4384446d..c1c4dfb4 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 @@ -1377,7 +1377,7 @@ public class RoleServiceImpl extends ServiceImpl .targetType(TARGET_TYPE) .eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode()) .data(SaasFeatureResourceUpsertPayload.builder() - .terminal(terminal) + .terminals(Sets.newHashSet(terminal)) .build()) .build(); mqProducer.send(event); 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 7c114ed7..a8d7bbbb 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 @@ -292,7 +292,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl Date: Sat, 17 Aug 2024 11:14:45 +0800 Subject: [PATCH 062/112] =?UTF-8?q?feat(REQ-2699):=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=A2=9E=E5=8A=A0=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/repository/entity/SaasPageElement.java | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 index eb60d3d4..95cd1994 100644 --- 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 @@ -83,4 +83,15 @@ public class SaasPageElement extends BaseEntity { */ @TableField("item_code") private String itemCode; + + /** + * 项目名称 + */ + @TableField("item_name") + private String itemName; + + /** + * H5的应用ID + */ + private String appId; } From c4d0c769735f68d468d1c7b83365d1c249fab6fb Mon Sep 17 00:00:00 2001 From: lilong Date: Mon, 19 Aug 2024 16:06:57 +0800 Subject: [PATCH 063/112] =?UTF-8?q?feat:(REQ-2699)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=B2=A1=E8=A7=92=E8=89=B2=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E8=BF=94=E5=9B=9E=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/PrivateController.java | 395 +++++++++++++++++- .../service/impl/TyrSaasAuthServiceImpl.java | 87 ++-- 2 files changed, 434 insertions(+), 48 deletions(-) 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 cee1f2b3..a860ea30 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 @@ -10,12 +10,19 @@ import cn.axzo.framework.rocketmq.Event; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum; +import cn.axzo.tyr.client.common.enums.RoleTypeEnum; import cn.axzo.tyr.client.model.product.ProductSearchListReq; -import cn.axzo.tyr.client.model.req.*; +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.PageProductFeatureRelationReq; +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; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; import cn.axzo.tyr.client.model.res.SaasRoleRes; +import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam; import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO; import cn.axzo.tyr.client.model.vo.SaveOrUpdateRoleVO; import cn.axzo.tyr.server.event.outer.CacheWorkspaceProductHandler; @@ -25,8 +32,26 @@ import cn.axzo.tyr.server.job.CacheProductPermissionJob; import cn.axzo.tyr.server.job.CacheRoleFeatureResourceJob; import cn.axzo.tyr.server.job.CacheRolePermissionJob; import cn.axzo.tyr.server.job.CacheSaasFeatureJob; -import cn.axzo.tyr.server.repository.dao.*; -import cn.axzo.tyr.server.repository.entity.*; +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.SaasPageElementDao; +import cn.axzo.tyr.server.repository.dao.SaasPageElementFeatureResourceRelationDao; +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.dao.SaasRoleGroupDao; +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.SaasPageElement; +import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; +import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation; +import cn.axzo.tyr.server.repository.entity.SaasPgroupRoleRelation; +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.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductPermissionCacheService; import cn.axzo.tyr.server.service.RolePermissionCacheService; @@ -35,6 +60,7 @@ 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.SaasRoleUserRelationService; import cn.axzo.tyr.server.service.TyrSaasAuthService; import cn.axzo.tyr.server.service.WorkspaceProductService; import cn.axzo.tyr.server.service.impl.SaasFeatureResourceCacheService; @@ -44,6 +70,7 @@ import com.alibaba.excel.EasyExcel; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.fastjson.JSON; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -51,6 +78,7 @@ import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; @@ -60,6 +88,7 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import java.io.IOException; import java.util.Collection; @@ -68,6 +97,7 @@ import java.util.Comparator; 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; @@ -135,6 +165,10 @@ public class PrivateController { private SaasPageElementDao saasPageElementDao; @Autowired private SaasPageElementFeatureResourceRelationDao saasPageElementFeatureResourceRelationDao; + @Autowired + private SaasRoleUserRelationService saasRoleUserRelationService; + @Autowired + private ProductModuleDao productModuleDao; /** * 统一层级的roleGroup按照id升序,sort从1递增 @@ -763,6 +797,361 @@ public class PrivateController { // return ApiResult.ok(); } + @PostMapping("/api/private/permission/check") + public ApiResult checkPermission(@RequestBody @Validated CheckPermissionParam request) { + + SaasFeatureResourceService.ListSaasFeatureResourceCache listSaasFeatureResourceCache = SaasFeatureResourceService.ListSaasFeatureResourceCache.builder() + .terminals(Sets.newHashSet(request.getTerminal())) + .build(); + List allFeatures = saasFeatureResourceService.listCache(listSaasFeatureResourceCache).get(request.getTerminal()); + + List roles = listRole(request); + + List productPermissions = listWorkspaceProductPermission(request); + + List products = listProduct(productPermissions); + + Map> rolePermissions = listRolePermission(roles); + + return ApiResult.ok(CheckPermissionDTO.builder() + .products(products) + .roles(roles) + .featureCodeCheckResults(resolveFeatureCode(request, productPermissions, rolePermissions, roles, allFeatures)) + .build()); + } + + private FeatureCodeCheckResult resolveAdminRole(List adminRoles, + List productPermissions) { + if (CollectionUtils.isEmpty(adminRoles)) { + return FeatureCodeCheckResult.builder() + .authPermission(false) + .reasons(Lists.newArrayList("没有管理员角色")) + .build(); + + } + + List reasons = Lists.newArrayList(); + Boolean authPermission = false; + + for (Role adminRole : adminRoles) { + + List adminPermissions = productPermissions.stream() + .filter(e -> Objects.equals(e.getCooperateType(), adminRole.getCooperateType().toString())) + .collect(Collectors.toList()); + + if (CollectionUtils.isNotEmpty(adminPermissions)) { + reasons.add("角色Id:" + adminRole.getRoleId() + + ";角色名字:" + adminRole.getRoleName() + + ";单位类型:" + adminRole.getCooperateType() + ";是管理员角色,有该权限code权限"); + authPermission = true; + } else { + reasons.add("角色Id:" + adminRole.getRoleId() + + ";角色名字:" + adminRole.getRoleName() + + ";单位类型:" + adminRole.getCooperateType() + ";没有该权限code权限"); + } + } + return FeatureCodeCheckResult.builder() + .authPermission(authPermission) + .reasons(reasons) + .build(); + } + + private FeatureCodeCheckResult resolveNormalRole(List normalRoles, + List productPermissions, + Map> rolePermissions, + String featureCode) { + if (CollectionUtils.isEmpty(normalRoles)) { + return FeatureCodeCheckResult.builder() + .authPermission(false) + .reasons(Lists.newArrayList("没有普通角色")) + .build(); + + } + + List reasons = Lists.newArrayList(); + Boolean authPermission = false; + + for (Role normalRole : normalRoles) { + List normalRolepermissions = rolePermissions.getOrDefault(normalRole.getRoleId(), Lists.newArrayList()) + .stream() + .filter(e -> Objects.equals(e.getFeatureCode(), featureCode)) + .collect(Collectors.toList()); + + Set productCooperateTypes = productPermissions.stream() + .map(e -> e.getCooperateType()) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(normalRolepermissions)) { + reasons.add("角色Id:" + normalRole.getRoleId() + + ";角色名字:" + normalRole.getRoleName() + + ";单位类型:" + normalRole.getCooperateType() + ";没有该权限code权限"); + } else if (productCooperateTypes.contains(normalRole.getCooperateType().toString())) { + reasons.add("角色Id:" + normalRole.getRoleId() + + ";角色名字:" + normalRole.getRoleName() + + ";单位类型:" + normalRole.getCooperateType() + ";有该权限code权限;有该权限的产品的单位类型有" + + JSON.toJSONString(productCooperateTypes)); + authPermission = true; + } else { + reasons.add("角色Id:" + normalRole.getRoleId() + + ";角色名字:" + normalRole.getRoleName() + + ";单位类型:" + normalRole.getCooperateType() + ";有该权限code权限;有该权限的产品的单位类型有" + + JSON.toJSONString(productCooperateTypes)); + } + } + return FeatureCodeCheckResult.builder() + .authPermission(authPermission) + .reasons(reasons) + .build(); + } + + private FeatureCodeCheckResult resolveNotAuth(List productPermissions, + String featureCode, + List allFeatures) { + // 直接配置成免授权的权限点 + List notAuthFeatures = allFeatures.stream() + .filter(SaasFeatureResourceService.SaasFeatureResourceCache::isNotAuth) + .collect(Collectors.toList()); + + // 子节点是免授权的权限点 + Set parentNotAuthFeatureIds = notAuthFeatures.stream() + .map(e -> Optional.ofNullable(e.getParentIds()) + .map(f -> { + f.add(e.getFeatureId()); + return f; + }) + .orElseGet(() -> Sets.newHashSet(e.getFeatureId()))) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + Set notAuthFeatureIds = notAuthFeatures.stream() + .map(SaasFeatureResourceService.SaasFeatureResourceCache::getFeatureId) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(parentNotAuthFeatureIds) && CollectionUtils.isEmpty(notAuthFeatureIds)) { + return FeatureCodeCheckResult.builder() + .authPermission(false) + .reasons(Lists.newArrayList("没有免授权权限点")) + .build(); + } + + Set productFeatureIds = productPermissions.stream() + .filter(e -> Objects.equals(e.getFeatureCode(), featureCode)) + .map(ProductPermissionCacheService.PermissionDTO::getFeatureId) + .collect(Collectors.toSet()); + + + + if (!Sets.difference(notAuthFeatureIds, productFeatureIds).isEmpty()) { + return FeatureCodeCheckResult.builder() + .authPermission(true) + .reasons(Lists.newArrayList("权限点是免授权")) + .build(); + } else if (!Sets.difference(parentNotAuthFeatureIds, productFeatureIds).isEmpty()) { + return FeatureCodeCheckResult.builder() + .authPermission(true) + .reasons(Lists.newArrayList("权限点的子节点是免授权")) + .build(); + } else { + return FeatureCodeCheckResult.builder() + .authPermission(false) + .reasons(Lists.newArrayList("权限点不是免授权")) + .build(); + } + } + + private List resolveFeatureCode(CheckPermissionParam checkPermissionParam, + List productPermissions, + Map> rolePermissions, + List roles, + List allFeatures) { + Map> productPermissionMap = productPermissions.stream() + .map(WorkspaceProductService.ProductPermission::getPermissions) + .flatMap(Collection::stream) + .collect(Collectors.groupingBy(ProductPermissionCacheService.PermissionDTO::getFeatureCode)); + List adminRoles = roles.stream() + .filter(e -> RoleTypeEnum.isAdmin(e.getRoleType())) + .collect(Collectors.toList()); + + List normalRoles = roles.stream() + .filter(e -> !RoleTypeEnum.isAdmin(e.getRoleType())) + .collect(Collectors.toList()); + + + return checkPermissionParam.getFeatureCodes().stream() + .map(featureCode -> { + List permissions = productPermissionMap.get(featureCode); + if (CollectionUtils.isEmpty(permissions)) { + return FeatureCodeCheckResult.builder() + .featureCode(featureCode) + .authPermission(false) + .reasons(Lists.newArrayList("项目没有配置产品及权限")) + .build(); + } + + FeatureCodeCheckResult adminRoleCheckResult = resolveAdminRole(adminRoles, permissions); + + FeatureCodeCheckResult normalRoleCheckResult = resolveNormalRole(normalRoles, permissions, rolePermissions, featureCode); + + FeatureCodeCheckResult notAuthCheckResult = resolveNotAuth(permissions, featureCode, allFeatures); + + Boolean authPermission = BooleanUtils.isTrue(adminRoleCheckResult.getAuthPermission()) + || BooleanUtils.isTrue(normalRoleCheckResult.getAuthPermission()) + || BooleanUtils.isTrue(notAuthCheckResult.getAuthPermission()); + + List adminRoleReasons = adminRoleCheckResult.getReasons(); + List normalRoleReasons = adminRoleCheckResult.getReasons(); + List notAuthReasons = notAuthCheckResult.getReasons(); + + adminRoleReasons.addAll(normalRoleReasons); + adminRoleReasons.addAll(notAuthReasons); + + return FeatureCodeCheckResult.builder() + .featureCode(featureCode) + .authPermission(authPermission) + .reasons(adminRoleReasons) + .build(); + }) + .collect(Collectors.toList()); + } + + private Map> listRolePermission(List roles) { + + if (CollectionUtils.isEmpty(roles)) { + return Collections.emptyMap(); + } + + RolePermissionCacheService.ListRolePermissionParam listRolePermissionParam = RolePermissionCacheService.ListRolePermissionParam.builder() + .roleIds(roles.stream().map(Role::getRoleId).collect(Collectors.toSet())) + .build(); + return rolePermissionCacheService.list(listRolePermissionParam); + } + + private List listProduct(List productPermissions) { + + if (CollectionUtils.isEmpty(productPermissions)) { + return Collections.emptyList(); + } + + List productIds = productPermissions.stream() + .map(WorkspaceProductService.ProductPermission::getProductId) + .collect(Collectors.toList()); + + return productModuleDao.listByIds(productIds).stream() + .filter(productModule -> Objects.equals(productModule.getIsDelete(),0L)) + .map(e -> Product.builder() + .productId(e.getId()) + .productName(e.getProductName()) + .build()) + .collect(Collectors.toList()); + } + + private List listWorkspaceProductPermission(CheckPermissionParam request) { + WorkspaceProductService.ListWorkspaceProductPermissionCacheParam listWorkspaceProductPermissionCacheParam = WorkspaceProductService.ListWorkspaceProductPermissionCacheParam + .builder() + .workspaceIds(Sets.newHashSet(request.getWorkspaceId())) + .build(); + return workspaceProductService.listWorkspaceProductPermissionCached(listWorkspaceProductPermissionCacheParam).stream() + .map(WorkspaceProductService.WorkspaceProductPermission::getProductPermissions) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + private List listRole(CheckPermissionParam request) { + ListRoleUserRelationParam listRoleUserRelationParam = ListRoleUserRelationParam.builder() + .personId(request.getPersonId()) + .workspaceOuPairs(Lists.newArrayList(ListRoleUserRelationParam.WorkspaceOuPair.builder() + .workspaceId(request.getWorkspaceId()) + .ouId(request.getOuId()) + .build())) + .needRole(true) + .build(); + + return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream() + .filter(e -> e.getSaasRole() != null) + .collect(Collectors.toList()) + .stream() + .map(e -> Role.builder() + .roleId(e.getRoleId()) + .roleName(e.getSaasRole().getName()) + .cooperateType(e.getSaasRole().getProductUnitType()) + .roleType(e.getSaasRole().getRoleType()) + .build()) + .collect(Collectors.toList()); + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CheckPermissionParam { + + @NotNull(message = "ouId不能为空") + private Long ouId; + + @NotNull(message = "workspaceId不能为空") + private Long workspaceId; + + @NotEmpty(message = "featureCodes不能为空") + private Set featureCodes; + + @NotNull(message = "personId不能为空") + private Long personId; + + @NotBlank(message = "terminal不能为空") + private String terminal; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CheckPermissionDTO { + + private List products; + + private List roles; + + private List featureCodeCheckResults; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Product { + + private Long productId; + + private String productName; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Role { + + private Long roleId; + + private String roleName; + + private String roleType; + + private Integer cooperateType; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class FeatureCodeCheckResult { + private String featureCode; + + private List reasons; + + private Boolean authPermission; + } + @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 d5eea5c0..231c617d 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 @@ -13,8 +13,6 @@ import cn.axzo.tyr.client.common.enums.WorkspaceJoinType; import cn.axzo.tyr.client.model.enums.DelegatedType; 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.CheckIdentityPermissionReq; import cn.axzo.tyr.client.model.req.FeatureIdPair; import cn.axzo.tyr.client.model.req.IdentityAuthReq; @@ -28,7 +26,6 @@ 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; -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; @@ -39,8 +36,6 @@ 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.vo.SaasRoleVO; import cn.axzo.tyr.server.model.FilterRoleAuth; import cn.axzo.tyr.server.model.PermissionCacheKey; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; @@ -75,7 +70,6 @@ import cn.axzo.tyr.server.service.TyrSaasAuthService; import cn.axzo.tyr.server.service.WorkspaceProductService; import cn.axzo.tyr.server.util.FeatureCodeUtil; import cn.axzo.tyr.server.util.KeyUtil; -import cn.axzo.tyr.server.utils.RpcExternalUtil; import cn.azxo.framework.common.model.CommonResponse; import cn.azxo.framework.common.utils.LogUtil; import cn.hutool.core.collection.CollectionUtil; @@ -908,59 +902,52 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { * @return KEY :role Id ; VALUE: feature id ; */ public Map> filterAuthByRoleAndProduct(List filterRoleAuths) { - List roleIds = filterRoleAuths.stream().map(FilterRoleAuth::getRoleId).distinct().collect(Collectors.toList()); + Set roleIds = filterRoleAuths.stream().map(FilterRoleAuth::getRoleId).collect(Collectors.toSet()); + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .roleIds(Lists.newArrayList(roleIds)) + .build(); + Map roles = roleService.list(listSaasRoleParam).stream() + .collect(Collectors.toMap(SaasRoleRes::getId, Function.identity())); + RolePermissionCacheService.ListRolePermissionParam listRolePermissionParam = RolePermissionCacheService.ListRolePermissionParam.builder() + .roleIds(roleIds) + .build(); + Map> rolePermissions = rolePermissionCacheService.list(listRolePermissionParam); - List query = roleService.query(QuerySaasRoleReq.builder() - .ids(roleIds) - .includePermissionGroup(true) - .build()); - Map roleMap = query.stream().collect(Collectors.toMap(SaasRoleVO::getId, Function.identity(), (a, b) -> a)); // find product by workspace Set workspaceId = filterRoleAuths.stream().map(FilterRoleAuth::getWorkspaceId).collect(Collectors.toSet()); - List servicePkgDetailRes = RpcExternalUtil.rpcProcessor(() -> servicePkgClient.getServicePkgDetailBySpaceId(workspaceId), "find product ", workspaceId); - Map> workspaceMap = servicePkgDetailRes.stream().collect(Collectors.toMap(ServicePkgDetailRes::getSpaceId, ServicePkgDetailRes::getProducts, (a, b) -> a)); - // find permission point by product - List productIds = servicePkgDetailRes.stream().map(ServicePkgDetailRes::getProducts).flatMap(List::stream).map(ServicePkgProduct::getProductId).distinct().collect(Collectors.toList()); - List productsDetail = RpcExternalUtil.rpcApiResultProcessor(() -> productFeatureRelationService.featureListByProduct(productIds), " find permission point by product ", productIds); - Map>> productGroup = productsDetail.stream().collect(Collectors.groupingBy(ProductFeatureRelationVO::getProductModuleId, Collectors.groupingBy(ProductFeatureRelationVO::getDictCode))); - - Map featureRelationVoMap = productsDetail.stream().collect(Collectors.toMap(ProductFeatureRelationVO::getFeatureId, Function.identity(), (v1, v2) -> v1)); + WorkspaceProductService.ListWorkspaceProductPermissionCacheParam listWorkspaceProductPermission = WorkspaceProductService.ListWorkspaceProductPermissionCacheParam.builder() + .workspaceIds(workspaceId) + .build(); + Map> workspaceProductPermissions = workspaceProductService.listWorkspaceProductPermissionCached(listWorkspaceProductPermission) + .stream() + .collect(Collectors.toMap(WorkspaceProductService.WorkspaceProductPermission::getWorkspaceId, + WorkspaceProductService.WorkspaceProductPermission::getProductPermissions)); // intersection auth from role and product Map> map = filterRoleAuths.stream().collect(Collectors.toMap(FilterRoleAuth::getRoleId, e -> { Long roleId = e.getRoleId(); - SaasRoleVO saasRole = roleMap.get(e.getRoleId()); + SaasRoleRes saasRole = roles.get(e.getRoleId()); if (null == saasRole) { LogUtil.error(" find role info error,role id:{}", roleId); return Collections.emptySet(); } + Set rolePermissionIds = rolePermissions.get(roleId) + .stream() + .map(RolePermissionCacheService.PermissionDTO::getFeatureId) + .collect(Collectors.toSet()); - List servicePkgProducts = workspaceMap.get(e.getWorkspaceId()); - Set allFeatureIds = servicePkgProducts.stream().map(ServicePkgProduct::getProductId).distinct().map(productId -> - { + Set productPermissionIds = workspaceProductPermissions.get(e.getWorkspaceId()).stream() + .map(WorkspaceProductService.ProductPermission::getPermissions) + .flatMap(Collection::stream) + .filter(productPermission -> Objects.equals(productPermission.getCooperateType(), String.valueOf(saasRole.getProductUnitType()))) + .map(ProductPermissionCacheService.PermissionDTO::getFeatureId) + .collect(Collectors.toSet()); - Map> productUnitMap = productGroup.get(productId); - if (null == productUnitMap) { - return null; - } - List productFeatureRelationVO = productUnitMap.get(String.valueOf(saasRole.getProductUnitType())); - if (CollectionUtil.isEmpty(productFeatureRelationVO)) { - return null; - } - - return productFeatureRelationVO.stream().map(ProductFeatureRelationVO::getFeatureId).collect(Collectors.toSet()); - } - ).filter(Objects::nonNull).flatMap(Set::stream).collect(Collectors.toSet()); - - - List currentPermissionId = saasRole.getPermissionGroup().stream().map(SaasPermissionGroupVO::getFeature).flatMap(List::stream).map(PermissionPointTreeNode::getPermissionPointId).distinct().collect(Collectors.toList()); - - - return new HashSet<>(CollectionUtil.intersection(allFeatureIds, currentPermissionId)); + return new HashSet<>(CollectionUtil.intersection(productPermissionIds, rolePermissionIds)); }, (oldFeatureLists, newFeatureLists) -> { @@ -972,7 +959,10 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { for (Map.Entry> entry : map.entrySet()) { Set featureInfos = org.apache.commons.collections4.CollectionUtils.emptyIfNull(entry.getValue()).stream().map(e -> ListPermissionFromRoleGroupResp.FeatureInfo.builder() .featureId(e) - .relationType(Optional.ofNullable(featureRelationVoMap.get(e)).map(ProductFeatureRelationVO::getType).orElse(null)) + // 因为CMS、CMP端saas_feature_resouce表的id从100000开始自增 + // 不会跟saas_feature有冲突,项企分离后,旧的saas_feature表不会再使用,所以这里直接根据featureId < 100000 + // 来判断relationType是saas_feature还是saas_feature_resource,不增加到缓存里是减少io量 + .relationType(e < 100000 ? OLD_FEATURE : NEW_FEATURE) .build()).collect(Collectors.toSet()); featureMap.put(entry.getKey(), featureInfos); } @@ -1545,6 +1535,13 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { List saasRoles = workspaceRoles.get(workspaceOuPair.buildOuWorkspaceKey()); + if (CollectionUtils.isEmpty(saasRoles)) { + return IdentityAuthRes.WorkspacePermission.builder() + .workspaceId(workspaceOuPair.getWorkspaceId()) + .ouId(workspaceOuPair.getOuId()) + .build(); + } + return buildPermissionsV2(workspaceOuPair, productPermissions, saasRoles, rolePermissions, allFeatures); }) .collect(Collectors.toList()); @@ -1646,10 +1643,10 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { private Set buildNoAuthPermission(List productPermissions, - List allFeatuers) { + List allFeatures) { // 因为有权授权权限的权限点,就需要有所有上层权限点的权限 - Set notAuthFeatureIds = allFeatuers.stream() + Set notAuthFeatureIds = allFeatures.stream() .filter(SaasFeatureResourceService.SaasFeatureResourceCache::isNotAuth) .map(e -> Optional.ofNullable(e.getParentIds()) .map(f -> { From 008cd8c15b725d6f0002edd04b2c77f8430c35d9 Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 20 Aug 2024 16:33:39 +0800 Subject: [PATCH 064/112] =?UTF-8?q?feat:(REQ-2699)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=B2=A1=E8=A7=92=E8=89=B2=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E8=BF=94=E5=9B=9E=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/controller/PrivateController.java | 14 +++++++++++--- .../service/impl/PermissionQueryServiceImpl.java | 11 ++++++----- 2 files changed, 17 insertions(+), 8 deletions(-) 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 a860ea30..a495da22 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 @@ -941,12 +941,12 @@ public class PrivateController { - if (!Sets.difference(notAuthFeatureIds, productFeatureIds).isEmpty()) { + if (!Sets.intersection(notAuthFeatureIds, productFeatureIds).isEmpty()) { return FeatureCodeCheckResult.builder() .authPermission(true) .reasons(Lists.newArrayList("权限点是免授权")) .build(); - } else if (!Sets.difference(parentNotAuthFeatureIds, productFeatureIds).isEmpty()) { + } else if (!Sets.intersection(parentNotAuthFeatureIds, productFeatureIds).isEmpty()) { return FeatureCodeCheckResult.builder() .authPermission(true) .reasons(Lists.newArrayList("权限点的子节点是免授权")) @@ -988,6 +988,14 @@ public class PrivateController { .build(); } + if (CollectionUtils.isEmpty(roles)) { + return FeatureCodeCheckResult.builder() + .featureCode(featureCode) + .authPermission(false) + .reasons(Lists.newArrayList("用户在项目里没有任何角色")) + .build(); + } + FeatureCodeCheckResult adminRoleCheckResult = resolveAdminRole(adminRoles, permissions); FeatureCodeCheckResult normalRoleCheckResult = resolveNormalRole(normalRoles, permissions, rolePermissions, featureCode); @@ -999,7 +1007,7 @@ public class PrivateController { || BooleanUtils.isTrue(notAuthCheckResult.getAuthPermission()); List adminRoleReasons = adminRoleCheckResult.getReasons(); - List normalRoleReasons = adminRoleCheckResult.getReasons(); + List normalRoleReasons = normalRoleCheckResult.getReasons(); List notAuthReasons = notAuthCheckResult.getReasons(); adminRoleReasons.addAll(normalRoleReasons); 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 2904f048..8a332750 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 @@ -188,11 +188,6 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { //这里暂时硬编码-非OMS端鉴权请求 直接转老接口处理 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"); // 为了兼容用户没有在企业中,但是需要看到企业类型的菜单,在调用相关接口时,忽略这些菜单的鉴权 if (CollectionUtils.isNotEmpty(notAuthUniCodes)) { @@ -202,6 +197,12 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { } } + if (USE_OLD_AUTH) { + log.info("user old auth"); + return hasPermissionV2(req); + } + log.info("user new auth"); + List> authFutures = Lists.newArrayList(); authFutures.add(CompletableFuture.supplyAsync(TraceSupplier.create(() -> saasAuthService.authPermission(req)), executor)); authFutures.add(CompletableFuture.supplyAsync(TraceSupplier.create(() -> saasAuthService.authNewPermission(req)), executor)); From 9df330d835f93de0d079a7901946bfb8ec6e2ccf Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 20 Aug 2024 18:02:06 +0800 Subject: [PATCH 065/112] =?UTF-8?q?feat:(REQ-2699)=20featureCode=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E6=88=90=E5=85=A8=E5=B1=80=E5=94=AF=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/service/impl/SaasFeatureResourceServiceImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 940cc68b..afc0f86b 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 @@ -511,14 +511,13 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl Date: Wed, 21 Aug 2024 20:55:04 +0800 Subject: [PATCH 066/112] =?UTF-8?q?feat:(REQ-2699)=20=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E6=9D=83=E9=99=90=E5=A2=9E=E5=8A=A0=E6=94=AF=E6=8C=81=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=98=BE=E7=A4=BA=E7=9A=84=E8=8F=9C=E5=8D=95=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/req/ListPermissionFeatureReq.java | 6 + .../model/req/PageSaasFeatureResourceReq.java | 4 +- .../client/model/req/TreePermissionReq.java | 6 + .../tyr/server/job/CacheSaasFeatureJob.java | 2 + .../service/SaasFeatureResourceService.java | 245 +++++++++--------- .../impl/PermissionQueryServiceImpl.java | 17 +- 6 files changed, 159 insertions(+), 121 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListPermissionFeatureReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListPermissionFeatureReq.java index 5d524012..66c0b1c6 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListPermissionFeatureReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListPermissionFeatureReq.java @@ -1,5 +1,6 @@ package cn.axzo.tyr.client.model.req; +import cn.axzo.tyr.client.common.enums.FeatureResourceStatus; import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum; import cn.axzo.tyr.client.model.base.WorkspaceOUPair; @@ -61,4 +62,9 @@ public class ListPermissionFeatureReq { * 查询父组件code下的有权限的uniCode */ private String parentUniCode; + + /** + * 显示或者隐藏,如果父节点是隐藏,则子节点也会隐藏 + */ + private FeatureResourceStatus status; } 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 45593a09..3740a40f 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 @@ -4,7 +4,6 @@ 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 cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum; import lombok.AllArgsConstructor; import lombok.Builder; @@ -77,6 +76,9 @@ public class PageSaasFeatureResourceReq implements IPageReq { @CriteriaField(ignore = true) private Boolean needPageElement; + @CriteriaField(field = "status", operator = Operator.EQ) + private Integer status; + /** * 菜单跟页面元素绑定的类型 */ 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 index 0cf9dfb4..6f57bed7 100644 --- 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 @@ -1,5 +1,6 @@ package cn.axzo.tyr.client.model.req; +import cn.axzo.tyr.client.common.enums.FeatureResourceStatus; import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum; import cn.axzo.tyr.client.model.base.WorkspaceOUPair; @@ -73,4 +74,9 @@ public class TreePermissionReq { * 默认会增加config配置的默认权限,不需要就传true */ private Boolean excludeDefaultPermission; + + /** + * 显示或者隐藏,如果父节点是隐藏,则子节点也会隐藏 + */ + private FeatureResourceStatus status; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java index 6c48dc91..b667eb0d 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java @@ -1,5 +1,6 @@ package cn.axzo.tyr.server.job; +import cn.axzo.tyr.client.common.enums.FeatureResourceStatus; import cn.axzo.tyr.client.model.enums.DelegatedType; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; import cn.axzo.tyr.client.model.res.PageElementResp; @@ -96,6 +97,7 @@ public class CacheSaasFeatureJob extends IJobHandler { .notAuth(SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) .parentIds(e.resolvePath()) .uniCode(e.getUniCode()) + .status(e.getStatus()) .version(Optional.ofNullable(e.getSaasPageElements()) .map(pageElement -> pageElement.stream() .findFirst() 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 f2a94322..10ec91e5 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,119 +1,126 @@ -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; -import com.baomidou.mybatisplus.extension.service.IService; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * 功能资源服务 - * - * @version V1.0 - * @author: ZhanSiHu - * @date: 2024/4/3 10:17 - */ -public interface SaasFeatureResourceService extends IService { - - Long saveOrUpdateMenu(FeatureResourceTreeSaveReq req); - - void updateFeatureAuthType(Long featureId, Integer authType); - - /**递归的**/ - List batchListDescendant(List featureIds); - - SaasFeatureResource featureResourceById(Long featureId); - - FeatureResourceTreeNode getTreeFeatureDescendant(Long featureId, Integer featureType); - - /**菜单重排序**/ - void reorderMenuFeature(Long featureId, Integer offset); - - /** 根据ID查询导航菜单页面信息 仅可显示 - 限制查询字段 **/ - List listNavByIds(List featureIds, List featureTypes); - - /** 资源权限通用查询 **/ - List permissionQuery(ResourcePermissionQueryDTO param); - - /** 查询资源树 **/ - List getTree(GetFeatureResourceTreeReq req); - - SaasFeatureResource getByCode(String featureCode); - - Set listAuthFree(); - - List listByParentIdAndTerminalAndIds(Long parentId, String terminal, List featureIds); - - List list(PageSaasFeatureResourceReq param); - - PageResp page(PageSaasFeatureResourceReq param); - - void deleteFeatureResource(DeleteFeatureResourceReq param); - - void storeCache(StoreSaasFeatureResourceCache param); - - Map> listCache(ListSaasFeatureResourceCache param); - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - class StoreSaasFeatureResourceCache { - - private List saasFeatureResources; - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - class SaasFeatureResourceDTO { - private String terminal; - - private List features; - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - class ListSaasFeatureResourceCache { - - private Set terminals; - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - class SaasFeatureResourceCache { - - private Long featureId; - - private boolean notAuth; - - private Set parentIds; - - private String uniCode; - - /** - * 客户端版本号 - * 在根据版本号查询菜单树权限的时候需要 - */ - private Integer version; - } -} +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; +import com.baomidou.mybatisplus.extension.service.IService; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 功能资源服务 + * + * @version V1.0 + * @author: ZhanSiHu + * @date: 2024/4/3 10:17 + */ +public interface SaasFeatureResourceService extends IService { + + Long saveOrUpdateMenu(FeatureResourceTreeSaveReq req); + + void updateFeatureAuthType(Long featureId, Integer authType); + + /**递归的**/ + List batchListDescendant(List featureIds); + + SaasFeatureResource featureResourceById(Long featureId); + + FeatureResourceTreeNode getTreeFeatureDescendant(Long featureId, Integer featureType); + + /**菜单重排序**/ + void reorderMenuFeature(Long featureId, Integer offset); + + /** 根据ID查询导航菜单页面信息 仅可显示 - 限制查询字段 **/ + List listNavByIds(List featureIds, List featureTypes); + + /** 资源权限通用查询 **/ + List permissionQuery(ResourcePermissionQueryDTO param); + + /** 查询资源树 **/ + List getTree(GetFeatureResourceTreeReq req); + + SaasFeatureResource getByCode(String featureCode); + + Set listAuthFree(); + + List listByParentIdAndTerminalAndIds(Long parentId, String terminal, List featureIds); + + List list(PageSaasFeatureResourceReq param); + + PageResp page(PageSaasFeatureResourceReq param); + + void deleteFeatureResource(DeleteFeatureResourceReq param); + + void storeCache(StoreSaasFeatureResourceCache param); + + Map> listCache(ListSaasFeatureResourceCache param); + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class StoreSaasFeatureResourceCache { + + private List saasFeatureResources; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class SaasFeatureResourceDTO { + private String terminal; + + private List features; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class ListSaasFeatureResourceCache { + + private Set terminals; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class SaasFeatureResourceCache { + + private Long featureId; + + private boolean notAuth; + + private Set parentIds; + + private String uniCode; + + /** + * 客户端版本号 + * 在根据版本号查询菜单树限的时候需要 + */ + private Integer version; + + /** + * 1、展示 + * 0、隐藏 + * FeatureResourceStatus + */ + private Integer status; + } +} 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 8a332750..ad316568 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 @@ -13,6 +13,7 @@ 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.FeatureResourceStatus; import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.common.enums.RoleTypeEnum; import cn.axzo.tyr.client.model.base.FeatureResourceExtraDO; @@ -523,6 +524,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .uniCodes(req.getUniCodes()) .versionMax(req.getVersionMax()) .parentUniCode(req.getParentUniCode()) + .status(req.getStatus()) .build(); Set featureIds = listUserPermissionFeatureIds(treePermissionReq); @@ -839,6 +841,18 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { || treePermissionReq.getVersionMax().compareTo(f.getVersion()) > -1) .collect(Collectors.toList()); + // 查询显示的菜单,需要过滤掉隐藏的节点,如果父节点隐藏,则下面所有子节点也需要过滤掉 + if (Objects.equals(treePermissionReq.getStatus(), FeatureResourceStatus.NORMAL)) { + Set normalFeatureIds = allFeatureResources.stream() + .filter(e -> Objects.equals(e.getStatus(), FeatureResourceStatus.NORMAL.getCode())) + .map(SaasFeatureResourceService.SaasFeatureResourceCache::getFeatureId) + .collect(Collectors.toSet()); + + allFeatureResources = allFeatureResources.stream() + .filter(e -> normalFeatureIds.contains(e.getFeatureId()) && normalFeatureIds.containsAll(e.getParentIds())) + .collect(Collectors.toList()); + } + if (StringUtils.isBlank(treePermissionReq.getParentUniCode())) { return allFeatureResources; } @@ -847,7 +861,8 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .filter(e -> Objects.equals(e.getUniCode(), treePermissionReq.getParentUniCode())) .map(SaasFeatureResourceService.SaasFeatureResourceCache::getFeatureId) .findFirst(); - return parentId.map(aLong -> allFeatureResources.stream() + final List finalFeatureResources = allFeatureResources; + return parentId.map(aLong -> finalFeatureResources.stream() .filter(e -> e.getParentIds().contains(aLong)) .collect(Collectors.toList())) .orElse(Collections.emptyList()); From 71132842515d9acfb58cce5f3f9aec66ccd9e5cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Thu, 22 Aug 2024 16:14:15 +0800 Subject: [PATCH 067/112] =?UTF-8?q?feat(REQ-2899):=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...PermissionRelationOperateLogSceneEnum.java | 15 ++ .../axzo/tyr/client/feign/PageElementApi.java | 25 +++ .../req/DeletePageElementCategoryReq.java | 31 +++ .../model/req/PageQueryElementV2Req.java | 53 +++++ .../SaveOrUpdatePageElementCategoryReq.java | 40 ++++ .../SaveOrUpdatePageElementComponentReq.java | 42 ++++ .../req/SaveOrUpdatePageElementPageReq.java | 59 ++++++ .../res/ListPageElementCategoryResp.java | 39 ++++ .../tyr/client/model/res/PageElementResp.java | 5 + .../permission/PageElementController.java | 43 +++- .../dao/SaasPageElementCategoryDao.java | 15 ++ .../repository/dao/SaasPageElementDao.java | 40 ++++ ...PageElementFeatureResourceRelationDao.java | 21 ++ .../entity/SaasPageElementCategory.java | 45 ++++ .../mapper/SaasPageElementCategoryMapper.java | 9 + .../SaasPageElementCategoryService.java | 21 ++ .../service/SaasPageElementService.java | 13 +- .../SaasPageElementCategoryServiceImpl.java | 174 ++++++++++++++++ .../impl/SaasPageElementServiceImpl.java | 194 ++++++++++++++++-- 19 files changed, 854 insertions(+), 30 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeletePageElementCategoryReq.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementCategoryReq.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementComponentReq.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementPageReq.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/res/ListPageElementCategoryResp.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementCategoryDao.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElementCategory.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasPageElementCategoryMapper.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementCategoryService.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementCategoryServiceImpl.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/PermissionRelationOperateLogSceneEnum.java b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/PermissionRelationOperateLogSceneEnum.java index 0568aa27..7f04e26e 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/PermissionRelationOperateLogSceneEnum.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/PermissionRelationOperateLogSceneEnum.java @@ -58,6 +58,21 @@ public enum PermissionRelationOperateLogSceneEnum { */ OMS_API_SYNC("OMS_API_SYNC", "oms后台同步API"), + /** + * oms新增、编辑元素类型 + */ + OMS_UPSERT_PAGE_ELEMENT_CATEGORY("OMS_UPSERT_PAGE_ELEMENT_CATEGORY", "oms新增、编辑元素类型"), + + /** + * oms删除元素类型 + */ + OMS_DELETE_PAGE_ELEMENT_CATEGORY("OMS_DELETE_PAGE_ELEMENT_CATEGORY", "oms删除元素类型"), + + /** + * oms新增、编辑页面元素 + */ + OMS_UPSERT_PAGE_ELEMENT("OMS_UPSERT_PAGE_ELEMENT", "oms新增、编辑页面元素"), + ; @EnumValue 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 87e5015a..eefc626d 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 @@ -5,6 +5,7 @@ import cn.axzo.framework.domain.web.result.ApiPageResult; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.tyr.client.model.req.*; import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; +import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp; import cn.axzo.tyr.client.model.res.PageElementResp; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; @@ -45,4 +46,28 @@ public interface PageElementApi { @PostMapping("/api/pageElement/list") ApiResult> list(PageElementReq param); + + /** 查询页面元素类型(按端分组) **/ + @PostMapping("/api/pageElementCategory/list") + ApiResult> listPageElementCategory(); + + /** 新增、编辑页面元素类型 **/ + @PostMapping("/api/pageElementCategory/saveOrUpdate") + ApiResult saveOrUpdateCategory(@RequestBody @Valid SaveOrUpdatePageElementCategoryReq req); + + /** 删除页面元素类型 **/ + @PostMapping("/api/pageElementCategory/delete") + ApiResult deleteCategory(@RequestBody @Valid DeletePageElementCategoryReq req); + + /** 分页查询页面资源V2 **/ + @PostMapping("/api/pageElement/pageV2") + ApiPageResult pageV2(@RequestBody @Valid PageQueryElementV2Req req); + + /** 新增、编辑页面元素类型 **/ + @PostMapping("/api/pageElement/saveOrUpdatePage") + ApiResult saveOrUpdatePage(@RequestBody @Valid SaveOrUpdatePageElementPageReq req); + + /** 新增、编辑页面组件元素类型 **/ + @PostMapping("/api/pageElement/saveOrUpdateComponent") + ApiResult saveOrUpdateComponent(@RequestBody @Valid SaveOrUpdatePageElementComponentReq req); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeletePageElementCategoryReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeletePageElementCategoryReq.java new file mode 100644 index 00000000..274d0938 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeletePageElementCategoryReq.java @@ -0,0 +1,31 @@ +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.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/8/21 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DeletePageElementCategoryReq { + + @NotNull(message = "ID不能为空") + @Min(value = 1, message = "ID有误") + private Long id; + + /** 操作人personId **/ + @NotNull(message = "操作人不能为空") + @Min(value = 1, message = "操作人有误") + private Long operatorId; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java new file mode 100644 index 00000000..8779107e --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java @@ -0,0 +1,53 @@ +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 PageQueryElementV2Req { + + /** + * 端 + */ + private String terminal; + + /** + * 页面元素组件类型 + */ + private List elementTypes; + + /** + * 页面元素名称 + */ + private String pageElementCodeOrName; + + /** + * 页面元素名称 + */ + private String pageElementGroupCodeOrName; + + /** + * 页码 + */ + @Builder.Default + private Long page = 1L; + + /** + * 每页大小 + */ + @Builder.Default + private Long pageSize = 20L; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementCategoryReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementCategoryReq.java new file mode 100644 index 00000000..e274380d --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementCategoryReq.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 javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/8/21 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaveOrUpdatePageElementCategoryReq { + + private Long id; + + /** 项目编码 **/ + private String itemCode; + + /** 项目名称 **/ + @NotBlank(message = "项目名称不能为空") + private String itemName; + + /** 登录端 **/ + @NotBlank(message = "所属端不能为空") + private String terminal; + + /** 操作人personId **/ + @NotNull(message = "操作人不能为空") + @Min(value = 1, message = "操作人有误") + private Long operatorId; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementComponentReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementComponentReq.java new file mode 100644 index 00000000..18843682 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementComponentReq.java @@ -0,0 +1,42 @@ +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.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/8/21 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaveOrUpdatePageElementComponentReq { + + private Long id; + + /** 分组ID **/ + @NotNull(message = "分组ID不能为空") + @Min(value = 1, message = "分组ID有误") + private Long pageId; + + /** 项目编码 **/ + @NotBlank(message = "项目编码不能为空") + private String code; + + /** 元素名称 **/ + @NotBlank(message = "元素名称不能为空") + private String name; + + /** 操作人personId **/ + @NotNull(message = "操作人不能为空") + @Min(value = 1, message = "操作人有误") + private Long operatorId; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementPageReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementPageReq.java new file mode 100644 index 00000000..e4313a01 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementPageReq.java @@ -0,0 +1,59 @@ +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.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/8/21 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaveOrUpdatePageElementPageReq { + + private Long id; + + /** 项目编码 **/ + @NotBlank(message = "项目编码不能为空") + private String itemCode; + + /** 项目编码 **/ + @NotBlank(message = "项目编码不能为空") + private String code; + + /** 元素名称 **/ + @NotBlank(message = "元素名称不能为空") + private String name; + + /** app类型(APP:原生,H5:h5页面, PC:web页面) **/ + private String appType; + + /** H5的appId **/ + private String appId; + + /** pc/h5路由地址 **/ + private String linkUrl; + + /** ios挑战地址 **/ + private String iosRouterUrl; + + /** android挑战地址 **/ + private String androidRouterUrl; + + /** 版本号 **/ + private Integer version; + + /** 操作人personId **/ + @NotNull(message = "操作人不能为空") + @Min(value = 1, message = "操作人有误") + private Long operatorId; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/ListPageElementCategoryResp.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/ListPageElementCategoryResp.java new file mode 100644 index 00000000..0ccf85bd --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/ListPageElementCategoryResp.java @@ -0,0 +1,39 @@ +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/8/20 + */ + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ListPageElementCategoryResp { + + /** 端 **/ + private String terminal; + /** 页面元素类型列表 **/ + private List pageElementCategories; + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class PageElementCategoryDTO { + /** 主键 **/ + private Long id; + /** 项目编码 **/ + private String itemCode; + /** 项目名称 **/ + private String itemName; + } +} 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 9a697094..3b76766b 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 @@ -32,6 +32,11 @@ public class PageElementResp { */ private String groupCode; + /** + * 元素的组编码 + */ + private String groupName; + /** * 元素编码 */ 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 bf9e5191..e1504269 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,14 +3,11 @@ 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.GetUserHasPermissionPageElementReq; -import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; -import cn.axzo.tyr.client.model.req.PageElementReportReq; -import cn.axzo.tyr.client.model.req.PageElementReq; -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.ListPageElementCategoryResp; import cn.axzo.tyr.client.model.res.PageElementResp; +import cn.axzo.tyr.server.service.SaasPageElementCategoryService; import cn.axzo.tyr.server.service.SaasPageElementService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -29,6 +26,7 @@ import java.util.List; public class PageElementController implements PageElementApi { private final SaasPageElementService saasPageElementService; + private final SaasPageElementCategoryService saasPageElementCategoryService; @Override public ApiResult report(PageElementReportReq req) { @@ -61,4 +59,37 @@ public class PageElementController implements PageElementApi { public ApiResult> list(PageElementReq param) { return ApiResult.ok(saasPageElementService.list(param)); } + + @Override + public ApiResult> listPageElementCategory() { + return ApiResult.ok(saasPageElementCategoryService.listGroupByTerminal()); + } + + @Override + public ApiResult saveOrUpdateCategory(SaveOrUpdatePageElementCategoryReq req) { + return ApiResult.ok(saasPageElementCategoryService.saveOrUpdate(req)); + } + + @Override + public ApiResult deleteCategory(DeletePageElementCategoryReq req) { + saasPageElementCategoryService.delete(req); + return ApiResult.ok(); + } + + @Override + public ApiPageResult pageV2(PageQueryElementV2Req req) { + return ApiPageResult.ok(saasPageElementService.pageV2(req)); + } + + @Override + public ApiResult saveOrUpdatePage(SaveOrUpdatePageElementPageReq req) { + saasPageElementService.saveOrUpdatePage(req); + return ApiResult.ok(); + } + + @Override + public ApiResult saveOrUpdateComponent(SaveOrUpdatePageElementComponentReq req) { + saasPageElementService.saveOrUpdateComponent(req); + return ApiResult.ok(); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementCategoryDao.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementCategoryDao.java new file mode 100644 index 00000000..621c047c --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPageElementCategoryDao.java @@ -0,0 +1,15 @@ +package cn.axzo.tyr.server.repository.dao; + +import cn.axzo.tyr.server.repository.entity.SaasPageElementCategory; +import cn.axzo.tyr.server.repository.mapper.SaasPageElementCategoryMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Repository; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/8/20 + */ +@Repository +public class SaasPageElementCategoryDao extends ServiceImpl { +} 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 cefcefed..cb52412f 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 @@ -1,6 +1,8 @@ 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.client.common.enums.PageElementTypeEnum; import cn.axzo.tyr.server.repository.entity.SaasPageElement; import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; import cn.axzo.tyr.server.repository.mapper.SaasPageElementMapper; @@ -41,4 +43,42 @@ public class SaasPageElementDao extends ServiceImpl listByItemCodeAndTerminal(String itemCode, String terminal) { + return lambdaQuery() + .eq(SaasPageElement::getIsDelete, DeleteEnum.NORMAL.getValue()) + .eq(SaasPageElement::getTerminal, terminal) + .eq(SaasPageElement::getItemCode, itemCode) + .list(); + } + + public void deleteIdsByTerminal(List ids, String terminal) { + if (CollectionUtils.isEmpty(ids)) { + return; + } + lambdaUpdate() + .eq(SaasPageElement::getTerminal, terminal) + .in(BaseEntity::getId, ids) + .set(SaasPageElement::getIsDelete, DeleteEnum.DELETE.getValue()) + .update(); + } + + public void updateComponentsGroupCode(String oldGroupCode, String newGroupCode, String terminal) { + lambdaUpdate() + .eq(SaasPageElement::getIsDelete, DeleteEnum.NORMAL.getValue()) + .eq(SaasPageElement::getTerminal, terminal) + .eq(SaasPageElement::getType, PageElementTypeEnum.COMPONENT.getCode()) + .eq(SaasPageElement::getGroupCode, oldGroupCode) + .set(SaasPageElement::getGroupCode, newGroupCode) + .update(); + } } 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 c52bc145..a1b0cacc 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 @@ -2,6 +2,8 @@ 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.client.common.enums.PageElementTypeEnum; +import cn.axzo.tyr.server.repository.entity.SaasPageElement; import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; import cn.axzo.tyr.server.repository.mapper.SaasPageElementFeatureResourceRelationMapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -46,4 +48,23 @@ public class SaasPageElementFeatureResourceRelationDao extends ServiceImpl pageElementCodes, Long operatorId) { + lambdaUpdate() + .eq(SaasPageElementFeatureResourceRelation::getIsDelete, DeleteEnum.NORMAL.getValue()) + .eq(SaasPageElementFeatureResourceRelation::getTerminal, terminal) + .in(SaasPageElementFeatureResourceRelation::getPageElementCode, pageElementCodes) + .set(SaasPageElementFeatureResourceRelation::getIsDelete, DeleteEnum.DELETE.getValue()) + .set(Objects.nonNull(operatorId), SaasPageElementFeatureResourceRelation::getUpdateBy, operatorId) + .update(); + } + + public void updateGroupCode(String oldGroupCode, String newGroupCode, String terminal) { + lambdaUpdate() + .eq(SaasPageElementFeatureResourceRelation::getIsDelete, DeleteEnum.NORMAL.getValue()) + .eq(SaasPageElementFeatureResourceRelation::getTerminal, terminal) + .eq(SaasPageElementFeatureResourceRelation::getPageElementCode, oldGroupCode) + .set(SaasPageElementFeatureResourceRelation::getPageElementCode, newGroupCode) + .update(); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElementCategory.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElementCategory.java new file mode 100644 index 00000000..c4c2ca8d --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElementCategory.java @@ -0,0 +1,45 @@ +package cn.axzo.tyr.server.repository.entity; + +import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; +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(value = "saas_page_element_category", autoResultMap = true) +public class SaasPageElementCategory extends BaseEntity { + /** + * 创建人 + */ + private Long createBy; + + /** + * 更新人 + */ + private Long updateBy; + + /** + * 项目code(H5会拉取项目下所有的元素) + */ + private String itemCode; + + /** + * 项目名称 + */ + private String itemName; + + /** + * 所属端 + */ + private String terminal; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasPageElementCategoryMapper.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasPageElementCategoryMapper.java new file mode 100644 index 00000000..d65ccbd4 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/SaasPageElementCategoryMapper.java @@ -0,0 +1,9 @@ +package cn.axzo.tyr.server.repository.mapper; + +import cn.axzo.tyr.server.repository.entity.SaasPageElementCategory; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +public interface SaasPageElementCategoryMapper extends BaseMapper { + +} + diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementCategoryService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementCategoryService.java new file mode 100644 index 00000000..dc0b35fd --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasPageElementCategoryService.java @@ -0,0 +1,21 @@ +package cn.axzo.tyr.server.service; + +import cn.axzo.tyr.client.model.req.DeletePageElementCategoryReq; +import cn.axzo.tyr.client.model.req.SaveOrUpdatePageElementCategoryReq; +import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp; + +import java.util.List; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/8/20 + */ +public interface SaasPageElementCategoryService { + + List listGroupByTerminal(); + + Long saveOrUpdate(SaveOrUpdatePageElementCategoryReq req); + + void delete(DeletePageElementCategoryReq req); +} 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 9ea72575..d4497533 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,12 +1,7 @@ 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.GetUserHasPermissionPageElementReq; -import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; -import cn.axzo.tyr.client.model.req.PageElementReportReq; -import cn.axzo.tyr.client.model.req.PageElementReq; -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.PageElementBasicDTO; import cn.axzo.tyr.client.model.res.PageElementResp; @@ -82,4 +77,10 @@ public interface SaasPageElementService extends IService { List list(PageElementReq param); cn.axzo.foundation.page.PageResp page(PageElementReq param); + + PageResp pageV2(PageQueryElementV2Req req); + + Long saveOrUpdatePage(SaveOrUpdatePageElementPageReq req); + + Long saveOrUpdateComponent(SaveOrUpdatePageElementComponentReq req); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementCategoryServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementCategoryServiceImpl.java new file mode 100644 index 00000000..3d4c77d6 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementCategoryServiceImpl.java @@ -0,0 +1,174 @@ +package cn.axzo.tyr.server.service.impl; + +import cn.axzo.basics.common.constant.enums.DeleteEnum; +import cn.axzo.basics.common.util.AssertUtil; +import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; +import cn.axzo.tyr.client.common.enums.PermissionRelationOperateLogSceneEnum; +import cn.axzo.tyr.client.model.req.DeletePageElementCategoryReq; +import cn.axzo.tyr.client.model.req.PermissionOperateLogReq; +import cn.axzo.tyr.client.model.req.SaveOrUpdatePageElementCategoryReq; +import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp; +import cn.axzo.tyr.server.repository.dao.SaasPageElementCategoryDao; +import cn.axzo.tyr.server.repository.dao.SaasPageElementDao; +import cn.axzo.tyr.server.repository.dao.SaasPageElementFeatureResourceRelationDao; +import cn.axzo.tyr.server.repository.entity.SaasPageElement; +import cn.axzo.tyr.server.repository.entity.SaasPageElementCategory; +import cn.axzo.tyr.server.service.SaasPageElementCategoryService; +import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationOperateLogService; +import com.google.common.collect.Lists; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/8/20 + */ +@Slf4j +@Service +@AllArgsConstructor +public class SaasPageElementCategoryServiceImpl implements SaasPageElementCategoryService { + + public static final String PAGE_ELEMENT_CATEGORY_TABLE_NAME = "saas_page_element_category"; + + private final SaasPageElementCategoryDao saasPageElementCategoryDao; + private final SaasPageElementDao saasPageElementDao; + private final SaasPageElementFeatureResourceRelationDao saasPageElementFeatureResourceRelationDao; + private final SaasPgroupPermissionRelationOperateLogService saasPgroupPermissionRelationOperateLogService; + + @Override + public List listGroupByTerminal() { + List categoryResps = Lists.newArrayList(); + List categories = saasPageElementCategoryDao.lambdaQuery() + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.value) + .list(); + if (CollectionUtils.isEmpty(categories)) { + return categoryResps; + } + Map> categoryMap = categories.stream().collect(Collectors.groupingBy(SaasPageElementCategory::getTerminal)); + categoryMap.forEach((key, value) -> { + categoryResps.add(ListPageElementCategoryResp.builder().terminal(key) + .pageElementCategories(value.stream().map(c -> ListPageElementCategoryResp.PageElementCategoryDTO + .builder() + .id(c.getId()) + .itemCode(c.getItemCode()) + .itemName(c.getItemName()) + .build()).collect(Collectors.toList())).build()); + }); + return categoryResps; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Long saveOrUpdate(SaveOrUpdatePageElementCategoryReq req) { + SaasPageElementCategory baseCategory = SaasPageElementCategory.builder() + .itemName(req.getItemName()) + .createBy(req.getOperatorId()) + .updateBy(req.getOperatorId()) + .build(); + validItemName(req.getItemName(), req.getId()); + + if (Objects.nonNull(req.getId())) { + // 不允许编辑itemCoe,不然端上查询权限点出问题 + SaasPageElementCategory dbCategory = saasPageElementCategoryDao.getById(req.getId()); + AssertUtil.notNull(dbCategory, "页面元素分类不存在"); + baseCategory.setId(req.getId()); + if (!dbCategory.getItemName().equals(req.getItemName())) { + // 更新saas_page_element的item_name + saasPageElementDao.updateItemNameByItemCode(dbCategory.getItemCode(), req.getItemName(), dbCategory.getTerminal()); + } + saasPageElementCategoryDao.updateById(baseCategory); + } else { + AssertUtil.notEmpty(req.getItemCode(), "项目编码不能为空"); + validItemCode(req.getItemCode()); + baseCategory.setItemCode(req.getItemCode()); + baseCategory.setTerminal(req.getTerminal()); + saasPageElementCategoryDao.save(baseCategory); + } + + try { + saveOrUpdateOperateLog(req, baseCategory); + } catch (Exception e) { + log.warn("save operate log error", e); + } + + return baseCategory.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(DeletePageElementCategoryReq req) { + SaasPageElementCategory dbCategory = saasPageElementCategoryDao.getById(req.getId()); + AssertUtil.notNull(dbCategory, "页面元素分类不存在"); + saasPageElementCategoryDao.lambdaUpdate() + .eq(BaseEntity::getId, req.getId()) + .set(SaasPageElementCategory::getIsDelete, DeleteEnum.DELETE.getValue()) + .set(SaasPageElementCategory::getUpdateBy, req.getOperatorId()) + .update(); + + // 删除页面元素 + List pageElements = saasPageElementDao.listByItemCodeAndTerminal(dbCategory.getItemCode(), dbCategory.getTerminal()); + if (CollectionUtils.isEmpty(pageElements)) { + return; + } + List pageElementIds = pageElements.stream().map(BaseEntity::getId).collect(Collectors.toList()); + saasPageElementDao.deleteIdsByTerminal(pageElementIds, dbCategory.getTerminal()); + + // 删除页面元素绑定关系 + List pageElementCodes = pageElements.stream().map(SaasPageElement::getCode).collect(Collectors.toList()); + saasPageElementFeatureResourceRelationDao.deleteByTerminalAndPageElementCodes(dbCategory.getTerminal(), pageElementCodes, req.getOperatorId()); + + try { + saveDeleteOperateLog(req, dbCategory); + } catch (Exception e) { + log.warn("save operate log error", e); + } + } + + private void validItemCode(String itemCode) { + List categories = saasPageElementCategoryDao.lambdaQuery() + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.value) + .eq(SaasPageElementCategory::getItemCode, itemCode) + .list(); + AssertUtil.isEmpty(categories, "项目编码已存在"); + } + + private void validItemName(String itemName, Long categoryId) { + List categories = saasPageElementCategoryDao.lambdaQuery() + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.value) + .eq(SaasPageElementCategory::getItemName, itemName) + .ne(Objects.nonNull(categoryId), BaseEntity::getId, categoryId) + .list(); + AssertUtil.isEmpty(categories, "项目名称已存在"); + } + + private void saveOrUpdateOperateLog(SaveOrUpdatePageElementCategoryReq req, SaasPageElementCategory baseCategory) { + saasPgroupPermissionRelationOperateLogService.save(PermissionOperateLogReq.builder() + .tableName(PAGE_ELEMENT_CATEGORY_TABLE_NAME) + .operatorId(req.getOperatorId()) + .scene(PermissionRelationOperateLogSceneEnum.OMS_UPSERT_PAGE_ELEMENT_CATEGORY.getValue()) + .sceneId(baseCategory.getId().toString()) + .requestData(req) + .operateData(baseCategory) + .build()); + } + + private void saveDeleteOperateLog(DeletePageElementCategoryReq req, SaasPageElementCategory baseCategory) { + saasPgroupPermissionRelationOperateLogService.save(PermissionOperateLogReq.builder() + .tableName(PAGE_ELEMENT_CATEGORY_TABLE_NAME) + .operatorId(req.getOperatorId()) + .scene(PermissionRelationOperateLogSceneEnum.OMS_DELETE_PAGE_ELEMENT_CATEGORY.getValue()) + .sceneId(baseCategory.getId().toString()) + .requestData(req) + .operateData(baseCategory) + .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 45440782..ecfd952b 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,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.AssertUtil; import cn.axzo.basics.common.util.StopWatchUtil; import cn.axzo.basics.profiles.api.UserProfileServiceApi; @@ -15,15 +16,7 @@ import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum; import cn.axzo.tyr.client.common.enums.PageElementTypeEnum; import cn.axzo.tyr.client.common.enums.PermissionRelationOperateLogSceneEnum; -import cn.axzo.tyr.client.model.req.GetPageElementReq; -import cn.axzo.tyr.client.model.req.GetUserHasPermissionPageElementReq; -import cn.axzo.tyr.client.model.req.IdentityAuthReq; -import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; -import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq; -import cn.axzo.tyr.client.model.req.PageElementReportReq; -import cn.axzo.tyr.client.model.req.PageElementReq; -import cn.axzo.tyr.client.model.req.PageQueryElementReq; -import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.client.model.req.*; import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; import cn.axzo.tyr.client.model.res.IdentityAuthRes; import cn.axzo.tyr.client.model.res.PageElementBasicDTO; @@ -33,12 +26,10 @@ import cn.axzo.tyr.server.config.MqProducer; import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.model.RelationOperateLogResourceBindElementDO; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; +import cn.axzo.tyr.server.repository.dao.SaasPageElementCategoryDao; 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.SaasPgroupPermissionRelationOperateLog; +import cn.axzo.tyr.server.repository.entity.*; import cn.axzo.tyr.server.repository.mapper.SaasPageElementMapper; import cn.axzo.tyr.server.service.SaasFeatureResourceService; import cn.axzo.tyr.server.service.SaasPageElementFeatureResourceRelationService; @@ -53,6 +44,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import lombok.RequiredArgsConstructor; @@ -69,11 +61,7 @@ import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.function.Function; @@ -102,6 +90,7 @@ public class SaasPageElementServiceImpl extends ServiceImpl reportSecretKeys; private static final String TARGET_TYPE = "pageElementFeatureResourceId"; + public static final String PAGE_ELEMENT_TABLE_NAME = "saas_page_element"; @Override @Transactional(rollbackFor = Exception.class) @@ -503,6 +493,123 @@ public class SaasPageElementServiceImpl extends ServiceImpl from(e, featureResources)); } + @Override + public PageResp pageV2(PageQueryElementV2Req request) { + IPage page = saasPageElementDao.lambdaQuery() + .eq(StringUtils.isNotBlank(request.getTerminal()), SaasPageElement::getTerminal, request.getTerminal()) + .in(CollectionUtils.isNotEmpty(request.getElementTypes()), SaasPageElement::getType, request.getElementTypes()) + .and(StringUtils.isNotBlank(request.getPageElementCodeOrName()), w -> w.like(SaasPageElement::getCode, request.getPageElementCodeOrName()) + .or().like(SaasPageElement::getName, request.getPageElementCodeOrName())) + .eq(StringUtils.isNotBlank(request.getPageElementGroupCodeOrName()), SaasPageElement::getType, PageElementTypeEnum.PAGE.getCode()) + .and(StringUtils.isNotBlank(request.getPageElementGroupCodeOrName()), + w -> w.like(SaasPageElement::getGroupCode, request.getPageElementGroupCodeOrName()) + .or().like(SaasPageElement::getName, request.getPageElementGroupCodeOrName())) + .orderByDesc(BaseEntity::getId) + .page(new Page<>(request.getPage(), request.getPageSize())); + List list = BeanMapper.copyList(page.getRecords(), PageElementResp.class); + fillGroupName(list); + return PageResp.list(page.getCurrent(), page.getSize(), page.getTotal(), list); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Long saveOrUpdatePage(SaveOrUpdatePageElementPageReq req) { + List categories = saasPageElementCategoryDao.lambdaQuery() + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) + .eq(SaasPageElementCategory::getItemCode, req.getItemCode()).list(); + AssertUtil.notEmpty(categories, "元素分类不存在。"); + SaasPageElementCategory category = categories.get(0); + + SaasPageElement basePageElement = SaasPageElement.builder() + .version(req.getVersion()) + .groupCode(req.getCode()) + .code(req.getCode()) + .name(req.getName()) + .type(PageElementTypeEnum.PAGE.getCode()) + .linkUrl(req.getLinkUrl()) + .linkExt(getLinkExtStr(req.getIosRouterUrl(), req.getAndroidRouterUrl())) + .terminal(category.getTerminal()) + .appType(req.getAppType()) + .appId(req.getAppId()) + .itemCode(req.getItemCode()) + .itemName(category.getItemName()) + .build(); + + if (Objects.nonNull(req.getId())) { + SaasPageElement dbPageElement = saasPageElementDao.getById(req.getId()); + AssertUtil.notNull(dbPageElement, "页面元素不存在"); + basePageElement.setId(dbPageElement.getId()); + if (!dbPageElement.getCode().equals(basePageElement.getCode())) { + // 校验code唯一 + validCode(basePageElement.getCode()); + // 更新子元素的group_code + saasPageElementDao.updateComponentsGroupCode(dbPageElement.getCode(), basePageElement.getCode(), category.getTerminal()); + // 更新关联关系的page_element_code + saasPageElementFeatureResourceRelationDao.updateGroupCode(dbPageElement.getCode(), basePageElement.getCode(), category.getTerminal()); + } + saasPageElementDao.updateById(basePageElement); + } else { + validCode(basePageElement.getCode()); + saasPageElementDao.save(basePageElement); + } + + // 记录操作日志 + try { + saveOrUpdatePageOperateLog(req, basePageElement); + } catch (Exception e) { + log.warn("save operate log error", e); + } + + return basePageElement.getId(); + } + + @Override + public Long saveOrUpdateComponent(SaveOrUpdatePageElementComponentReq req) { + List pageElements = saasPageElementDao.lambdaQuery() + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) + .eq(SaasPageElement::getId, req.getPageId()).list(); + AssertUtil.notEmpty(pageElements, "父级元素不存在。"); + SaasPageElement pageElement = pageElements.get(0); + + SaasPageElement basePageElement = SaasPageElement.builder() + .version(pageElement.getVersion()) + .groupCode(pageElement.getCode()) + .code(req.getCode()) + .name(req.getName()) + .type(PageElementTypeEnum.COMPONENT.getCode()) + .terminal(pageElement.getTerminal()) + .appType(pageElement.getAppType()) + .appId(pageElement.getAppId()) + .itemCode(pageElement.getItemCode()) + .itemName(pageElement.getItemName()) + .build(); + + if (Objects.nonNull(req.getId())) { + SaasPageElement dbPageElement = saasPageElementDao.getById(req.getId()); + AssertUtil.notNull(dbPageElement, "页面组件元素不存在"); + basePageElement.setId(dbPageElement.getId()); + if (!dbPageElement.getCode().equals(basePageElement.getCode())) { + // 校验code唯一 + validCode(basePageElement.getCode()); + // 更新关联关系的page_element_code + saasPageElementFeatureResourceRelationDao.updateGroupCode(dbPageElement.getCode(), basePageElement.getCode(), pageElement.getTerminal()); + } + saasPageElementDao.updateById(basePageElement); + } else { + validCode(basePageElement.getCode()); + saasPageElementDao.save(basePageElement); + } + + // 记录操作日志 + try { + saveOrUpdateComponentOperateLog(req, basePageElement); + } catch (Exception e) { + log.warn("save operate log error", e); + } + + return basePageElement.getId(); + } + private PageElementResp from(SaasPageElement saasPageElement, Map> featureResources) { PageElementResp pageElementResp = PageElementResp.builder().build(); @@ -549,4 +656,55 @@ public class SaasPageElementServiceImpl extends ServiceImpl featureResources.get(e.getFeatureResourceUniCode()), Collectors.toList()))); } + + private void fillGroupName(List list) { + if (CollectionUtils.isEmpty(list)) { + return; + } + + Map elementMap = saasPageElementDao.lambdaQuery() + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) + .in(SaasPageElement::getCode, list.stream().map(PageElementResp::getGroupCode).distinct().collect(Collectors.toList())) + .list().stream().collect(Collectors.toMap(SaasPageElement::getCode, Function.identity(), (v1, v2) -> v1)); + list.forEach(e -> e.setGroupName(Optional.ofNullable(elementMap.get(e.getGroupCode())).map(SaasPageElement::getName).orElse(StringUtils.EMPTY))); + } + + private void validCode(String code) { + List pageElements = saasPageElementDao.lambdaQuery() + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.value) + .eq(SaasPageElement::getCode, code) + .list(); + AssertUtil.isEmpty(pageElements, "featureCode已存在"); + } + + private String getLinkExtStr(String iosRouterUrl, String androidRouterUrl) { + if (StringUtils.isBlank(iosRouterUrl) && StringUtils.isBlank(androidRouterUrl)) { + return StringUtils.EMPTY; + } + List exts = Lists.newArrayList(PageElementResp.LinkExt.builder().system("ios").routerUrl(Strings.nullToEmpty(iosRouterUrl)).build(), + PageElementResp.LinkExt.builder().system("android").routerUrl(Strings.nullToEmpty(androidRouterUrl)).build()); + return JSONObject.toJSONString(exts); + } + + private void saveOrUpdatePageOperateLog(SaveOrUpdatePageElementPageReq req, SaasPageElement basePageElement) { + saasPgroupPermissionRelationOperateLogService.save(PermissionOperateLogReq.builder() + .tableName(PAGE_ELEMENT_TABLE_NAME) + .operatorId(req.getOperatorId()) + .scene(PermissionRelationOperateLogSceneEnum.OMS_UPSERT_PAGE_ELEMENT.getValue()) + .sceneId(basePageElement.getId().toString()) + .requestData(req) + .operateData(basePageElement) + .build()); + } + + private void saveOrUpdateComponentOperateLog(SaveOrUpdatePageElementComponentReq req, SaasPageElement basePageElement) { + saasPgroupPermissionRelationOperateLogService.save(PermissionOperateLogReq.builder() + .tableName(PAGE_ELEMENT_TABLE_NAME) + .operatorId(req.getOperatorId()) + .scene(PermissionRelationOperateLogSceneEnum.OMS_UPSERT_PAGE_ELEMENT.getValue()) + .sceneId(basePageElement.getId().toString()) + .requestData(req) + .operateData(basePageElement) + .build()); + } } From cc28bb554ab87be8ae0b385d16a916a7cbe25080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Fri, 23 Aug 2024 08:50:33 +0800 Subject: [PATCH 068/112] =?UTF-8?q?feat(REQ-2899):=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E6=96=B0=E5=A2=9E=E3=80=81=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/client/feign/PageElementApi.java | 9 +- .../SaveOrUpdatePageElementComponentReq.java | 42 ------- ...q.java => SaveOrUpdatePageElementReq.java} | 10 +- .../permission/PageElementController.java | 10 +- .../service/SaasPageElementService.java | 4 +- .../impl/SaasPageElementServiceImpl.java | 108 ++++++------------ 6 files changed, 48 insertions(+), 135 deletions(-) delete mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementComponentReq.java rename tyr-api/src/main/java/cn/axzo/tyr/client/model/req/{SaveOrUpdatePageElementPageReq.java => SaveOrUpdatePageElementReq.java} (84%) 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 eefc626d..49867907 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,6 +1,5 @@ package cn.axzo.tyr.client.feign; -import cn.axzo.framework.domain.page.Page; import cn.axzo.framework.domain.web.result.ApiPageResult; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.tyr.client.model.req.*; @@ -64,10 +63,6 @@ public interface PageElementApi { ApiPageResult pageV2(@RequestBody @Valid PageQueryElementV2Req req); /** 新增、编辑页面元素类型 **/ - @PostMapping("/api/pageElement/saveOrUpdatePage") - ApiResult saveOrUpdatePage(@RequestBody @Valid SaveOrUpdatePageElementPageReq req); - - /** 新增、编辑页面组件元素类型 **/ - @PostMapping("/api/pageElement/saveOrUpdateComponent") - ApiResult saveOrUpdateComponent(@RequestBody @Valid SaveOrUpdatePageElementComponentReq req); + @PostMapping("/api/pageElement/saveOrUpdate") + ApiResult saveOrUpdate(@RequestBody @Valid SaveOrUpdatePageElementReq req); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementComponentReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementComponentReq.java deleted file mode 100644 index 18843682..00000000 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementComponentReq.java +++ /dev/null @@ -1,42 +0,0 @@ -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.NotBlank; -import javax.validation.constraints.NotNull; - -/** - * @author likunpeng - * @version 1.0 - * @date 2024/8/21 - */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class SaveOrUpdatePageElementComponentReq { - - private Long id; - - /** 分组ID **/ - @NotNull(message = "分组ID不能为空") - @Min(value = 1, message = "分组ID有误") - private Long pageId; - - /** 项目编码 **/ - @NotBlank(message = "项目编码不能为空") - private String code; - - /** 元素名称 **/ - @NotBlank(message = "元素名称不能为空") - private String name; - - /** 操作人personId **/ - @NotNull(message = "操作人不能为空") - @Min(value = 1, message = "操作人有误") - private Long operatorId; -} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementPageReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementReq.java similarity index 84% rename from tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementPageReq.java rename to tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementReq.java index e4313a01..51f391b0 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementPageReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementReq.java @@ -18,14 +18,20 @@ import javax.validation.constraints.NotNull; @Builder @NoArgsConstructor @AllArgsConstructor -public class SaveOrUpdatePageElementPageReq { +public class SaveOrUpdatePageElementReq { private Long id; /** 项目编码 **/ - @NotBlank(message = "项目编码不能为空") private String itemCode; + /** 分组ID **/ + private Long pageId; + + /** 页面元素类型:PAGE/COMPONENT **/ + @NotBlank(message = "页面元素类型不能为空") + private String type; + /** 项目编码 **/ @NotBlank(message = "项目编码不能为空") private String code; 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 e1504269..5b56d023 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 @@ -82,14 +82,8 @@ public class PageElementController implements PageElementApi { } @Override - public ApiResult saveOrUpdatePage(SaveOrUpdatePageElementPageReq req) { - saasPageElementService.saveOrUpdatePage(req); - return ApiResult.ok(); - } - - @Override - public ApiResult saveOrUpdateComponent(SaveOrUpdatePageElementComponentReq req) { - saasPageElementService.saveOrUpdateComponent(req); + public ApiResult saveOrUpdate(SaveOrUpdatePageElementReq req) { + saasPageElementService.saveOrUpdate(req); return ApiResult.ok(); } } 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 d4497533..8247864a 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 @@ -80,7 +80,5 @@ public interface SaasPageElementService extends IService { PageResp pageV2(PageQueryElementV2Req req); - Long saveOrUpdatePage(SaveOrUpdatePageElementPageReq req); - - Long saveOrUpdateComponent(SaveOrUpdatePageElementComponentReq req); + Long saveOrUpdate(SaveOrUpdatePageElementReq req); } 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 ecfd952b..36d32179 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 @@ -513,26 +513,18 @@ public class SaasPageElementServiceImpl extends ServiceImpl categories = saasPageElementCategoryDao.lambdaQuery() - .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) - .eq(SaasPageElementCategory::getItemCode, req.getItemCode()).list(); - AssertUtil.notEmpty(categories, "元素分类不存在。"); - SaasPageElementCategory category = categories.get(0); - + public Long saveOrUpdate(SaveOrUpdatePageElementReq req) { SaasPageElement basePageElement = SaasPageElement.builder() .version(req.getVersion()) .groupCode(req.getCode()) .code(req.getCode()) .name(req.getName()) - .type(PageElementTypeEnum.PAGE.getCode()) + .type(req.getType()) .linkUrl(req.getLinkUrl()) .linkExt(getLinkExtStr(req.getIosRouterUrl(), req.getAndroidRouterUrl())) - .terminal(category.getTerminal()) .appType(req.getAppType()) .appId(req.getAppId()) .itemCode(req.getItemCode()) - .itemName(category.getItemName()) .build(); if (Objects.nonNull(req.getId())) { @@ -542,67 +534,48 @@ public class SaasPageElementServiceImpl extends ServiceImpl categories = saasPageElementCategoryDao.lambdaQuery() + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) + .eq(SaasPageElementCategory::getItemCode, req.getItemCode()).list(); + AssertUtil.notEmpty(categories, "元素分类不存在。"); + SaasPageElementCategory category = categories.get(0); + basePageElement.setTerminal(category.getTerminal()); + basePageElement.setItemName(category.getItemName()); + } else if (PageElementTypeEnum.COMPONENT.getCode().equals(req.getType())) { + AssertUtil.isTrue(Objects.nonNull(req.getPageId()) && req.getPageId() > 0, "页面元素不存在"); + List pageElements = saasPageElementDao.lambdaQuery() + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) + .eq(SaasPageElement::getId, req.getPageId()).list(); + AssertUtil.notEmpty(pageElements, "父级元素不存在。"); + + SaasPageElement pageElement = pageElements.get(0); + basePageElement.setVersion(pageElement.getVersion()); + basePageElement.setGroupCode(pageElement.getCode()); + basePageElement.setTerminal(pageElement.getTerminal()); + basePageElement.setAppType(pageElement.getAppType()); + basePageElement.setAppId(pageElement.getAppId()); + basePageElement.setItemCode(pageElement.getItemCode()); + basePageElement.setItemName(pageElement.getItemName()); + } + // 校验code唯一 validCode(basePageElement.getCode()); saasPageElementDao.save(basePageElement); } // 记录操作日志 try { - saveOrUpdatePageOperateLog(req, basePageElement); - } catch (Exception e) { - log.warn("save operate log error", e); - } - - return basePageElement.getId(); - } - - @Override - public Long saveOrUpdateComponent(SaveOrUpdatePageElementComponentReq req) { - List pageElements = saasPageElementDao.lambdaQuery() - .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) - .eq(SaasPageElement::getId, req.getPageId()).list(); - AssertUtil.notEmpty(pageElements, "父级元素不存在。"); - SaasPageElement pageElement = pageElements.get(0); - - SaasPageElement basePageElement = SaasPageElement.builder() - .version(pageElement.getVersion()) - .groupCode(pageElement.getCode()) - .code(req.getCode()) - .name(req.getName()) - .type(PageElementTypeEnum.COMPONENT.getCode()) - .terminal(pageElement.getTerminal()) - .appType(pageElement.getAppType()) - .appId(pageElement.getAppId()) - .itemCode(pageElement.getItemCode()) - .itemName(pageElement.getItemName()) - .build(); - - if (Objects.nonNull(req.getId())) { - SaasPageElement dbPageElement = saasPageElementDao.getById(req.getId()); - AssertUtil.notNull(dbPageElement, "页面组件元素不存在"); - basePageElement.setId(dbPageElement.getId()); - if (!dbPageElement.getCode().equals(basePageElement.getCode())) { - // 校验code唯一 - validCode(basePageElement.getCode()); - // 更新关联关系的page_element_code - saasPageElementFeatureResourceRelationDao.updateGroupCode(dbPageElement.getCode(), basePageElement.getCode(), pageElement.getTerminal()); - } - saasPageElementDao.updateById(basePageElement); - } else { - validCode(basePageElement.getCode()); - saasPageElementDao.save(basePageElement); - } - - // 记录操作日志 - try { - saveOrUpdateComponentOperateLog(req, basePageElement); + saveOrUpdateOperateLog(req, basePageElement); } catch (Exception e) { log.warn("save operate log error", e); } @@ -686,18 +659,7 @@ public class SaasPageElementServiceImpl extends ServiceImpl Date: Fri, 23 Aug 2024 10:36:29 +0800 Subject: [PATCH 069/112] =?UTF-8?q?feat(REQ-2899):=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=88=A0=E9=99=A4=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...PermissionRelationOperateLogSceneEnum.java | 5 +++ .../axzo/tyr/client/feign/PageElementApi.java | 6 ++- .../model/req/DeletePageElementReq.java | 31 +++++++++++++ .../permission/PageElementController.java | 6 +++ .../service/SaasPageElementService.java | 2 + .../impl/SaasPageElementServiceImpl.java | 43 ++++++++++++++++++- 6 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeletePageElementReq.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/PermissionRelationOperateLogSceneEnum.java b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/PermissionRelationOperateLogSceneEnum.java index 7f04e26e..d66d6b02 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/PermissionRelationOperateLogSceneEnum.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/PermissionRelationOperateLogSceneEnum.java @@ -73,6 +73,11 @@ public enum PermissionRelationOperateLogSceneEnum { */ OMS_UPSERT_PAGE_ELEMENT("OMS_UPSERT_PAGE_ELEMENT", "oms新增、编辑页面元素"), + /** + * oms删除页面元素 + */ + OMS_DELETE_PAGE_ELEMENT("OMS_DELETE_PAGE_ELEMENT", "oms删除页面元素"), + ; @EnumValue 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 49867907..047874b8 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 @@ -62,7 +62,11 @@ public interface PageElementApi { @PostMapping("/api/pageElement/pageV2") ApiPageResult pageV2(@RequestBody @Valid PageQueryElementV2Req req); - /** 新增、编辑页面元素类型 **/ + /** 新增、编辑页面元素 **/ @PostMapping("/api/pageElement/saveOrUpdate") ApiResult saveOrUpdate(@RequestBody @Valid SaveOrUpdatePageElementReq req); + + /** 删除页面元素 **/ + @PostMapping("/api/pageElement/delete") + ApiResult delete(@RequestBody @Valid DeletePageElementReq req); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeletePageElementReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeletePageElementReq.java new file mode 100644 index 00000000..aac41833 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeletePageElementReq.java @@ -0,0 +1,31 @@ +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.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/8/21 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DeletePageElementReq { + + @NotNull(message = "ID不能为空") + @Min(value = 1, message = "ID有误") + private Long id; + + /** 操作人personId **/ + @NotNull(message = "操作人不能为空") + @Min(value = 1, message = "操作人有误") + private Long operatorId; +} 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 5b56d023..d1ade634 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 @@ -86,4 +86,10 @@ public class PageElementController implements PageElementApi { saasPageElementService.saveOrUpdate(req); return ApiResult.ok(); } + + @Override + public ApiResult delete(DeletePageElementReq req) { + saasPageElementService.delete(req); + return ApiResult.ok(); + } } 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 8247864a..c55b3b33 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 @@ -81,4 +81,6 @@ public interface SaasPageElementService extends IService { PageResp pageV2(PageQueryElementV2Req req); Long saveOrUpdate(SaveOrUpdatePageElementReq req); + + void delete(DeletePageElementReq req); } 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 36d32179..5f2adea1 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 @@ -47,6 +47,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; @@ -529,7 +530,7 @@ public class SaasPageElementServiceImpl extends ServiceImpl codes = Sets.newHashSet(dbPageElement.getCode()); + + if (PageElementTypeEnum.PAGE.getCode().equals(dbPageElement.getType())) { + // 删除页面的子元素 + List pageElements = saasPageElementDao.listByGroupCodesAndExcludeIds(Lists.newArrayList(dbPageElement.getGroupCode()), null, dbPageElement.getTerminal(), null); + saasPageElementDao.deleteIdsByTerminal(pageElements.stream().map(BaseEntity::getId).collect(Collectors.toList()), dbPageElement.getTerminal()); + codes.addAll(pageElements.stream().map(SaasPageElement::getCode).collect(Collectors.toSet())); + } else { + saasPageElementDao.deleteIdsByTerminal(Lists.newArrayList(req.getId()), dbPageElement.getTerminal()); + } + + // 删除绑定关系 + if (CollectionUtils.isNotEmpty(codes)) { + saasPageElementFeatureResourceRelationDao.deleteByTerminalAndPageElementCodes(dbPageElement.getTerminal(), Lists.newArrayList(codes), req.getOperatorId()); + } + + // 记录操作日志 + try { + saveDeleteOperateLog(req, dbPageElement); + } catch (Exception e) { + log.warn("save operate log error", e); + } + } + private PageElementResp from(SaasPageElement saasPageElement, Map> featureResources) { PageElementResp pageElementResp = PageElementResp.builder().build(); @@ -669,4 +699,15 @@ public class SaasPageElementServiceImpl extends ServiceImpl Date: Fri, 23 Aug 2024 11:07:29 +0800 Subject: [PATCH 070/112] =?UTF-8?q?feat:(REQ-2488)=20=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E5=88=97=E8=A1=A8=E6=8E=A5=E5=8F=A3=E6=94=AF?= =?UTF-8?q?=E6=8C=81roleId=E5=92=8CroleCodes=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/model/req/ListRoleReq.java | 6 ++++ .../req/ListRoleUserRelationParam.java | 7 +++++ .../req/PageRoleUserRelationParam.java | 11 +++++++ .../axzo/tyr/server/service/RoleService.java | 6 ++++ .../impl/SaasRoleUserRelationServiceImpl.java | 31 +++++++++++++++++++ 5 files changed, 61 insertions(+) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListRoleReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListRoleReq.java index 5817a704..90300b78 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListRoleReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListRoleReq.java @@ -7,6 +7,7 @@ import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import java.util.List; +import java.util.Set; @Data @SuperBuilder @@ -83,4 +84,9 @@ public class ListRoleReq { * 例如:((workspaceId = ## and ouId = ##) or (workspaceId = ## and ouId = ##)) */ private List workspaceOuPairs; + + /** + * 角色权限码 + */ + private Set roleCodes; } 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 3c7ba434..b5e6a2f0 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 @@ -11,6 +11,7 @@ import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import java.util.List; +import java.util.Set; @SuperBuilder @Data @@ -106,6 +107,12 @@ public class ListRoleUserRelationParam { @CriteriaField(ignore = true) private Boolean needPermission; + /** + * 角色权限码 + */ + @CriteriaField(ignore = true) + private Set roleCodes; + @Data @Builder @NoArgsConstructor diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/req/PageRoleUserRelationParam.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/req/PageRoleUserRelationParam.java index 01a2af54..4949d781 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/req/PageRoleUserRelationParam.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/roleuser/req/PageRoleUserRelationParam.java @@ -2,11 +2,13 @@ package cn.axzo.tyr.client.model.roleuser.req; import cn.axzo.foundation.dao.support.wrapper.CriteriaField; import cn.axzo.foundation.page.IPageReq; +import cn.axzo.foundation.page.PageResp; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; +import java.util.Collections; import java.util.List; @SuperBuilder @@ -26,4 +28,13 @@ public class PageRoleUserRelationParam extends ListRoleUserRelationParam impleme */ @CriteriaField(ignore = true) List sort; + + 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/RoleService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java index 7e1f5c7b..f69896eb 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 @@ -139,6 +139,12 @@ public interface RoleService extends IService { @CriteriaField(field = "id", operator = Operator.NE) private Long idNE; + /** + * 角色权限码 + */ + @CriteriaField(field = "roleCode", operator = Operator.IN) + private Set roleCodes; + /** * 权限点从saas_feature_resource表查询 */ 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 fdcfb4a2..a387ddf1 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 @@ -9,6 +9,7 @@ import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper; import cn.axzo.framework.domain.page.PageResp; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.common.enums.RoleTypeEnum; +import cn.axzo.tyr.client.model.res.SaasRoleRes; import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserDTO; import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO; import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam; @@ -29,6 +30,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.BooleanUtils; import org.springframework.beans.BeanUtils; @@ -43,6 +45,7 @@ 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; @@ -152,6 +155,12 @@ public class SaasRoleUserRelationServiceImpl extends ServiceImpl roleIds = resolveRoleIds(param); + if (!CollectionUtils.isEmpty(param.getRoleCodes()) && CollectionUtils.isEmpty(roleIds)) { + return param.toEmpty(); + } + wrapper.in(!CollectionUtils.isEmpty(roleIds), "role_id", roleIds); + IPage page = this.page(PageConverter.toMybatis(param, SaasRoleUserRelation.class), wrapper); Map saasRoleUsers = listSaasRoleUser(param, page.getRecords()); @@ -161,6 +170,28 @@ public class SaasRoleUserRelationServiceImpl extends ServiceImpl from(record, saasRoleUsers, saasRoles)); } + private Set resolveRoleIds(PageRoleUserRelationParam param) { + if (CollectionUtils.isEmpty(param.getRoleCodes())) { + return Optional.ofNullable(param.getRoleIds()) + .map(Sets::newHashSet) + .orElseGet(Sets::newHashSet); + } + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .roleCodes(param.getRoleCodes()) + .build(); + Set roleIds = roleService.list(listSaasRoleParam).stream() + .map(SaasRoleRes::getId) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(param.getRoleIds())) { + return roleIds; + } + + return param.getRoleIds().stream() + .filter(roleIds::contains) + .collect(Collectors.toSet()); + } + private Map listSaasRoleUser(PageRoleUserRelationParam param, List saasRoleUserRelations) { if (CollectionUtils.isEmpty(saasRoleUserRelations) || BooleanUtils.isNotTrue(param.getNeedUsers())) { From 40d076efb18df8799d95c453a2916b4e746b3a01 Mon Sep 17 00:00:00 2001 From: lilong Date: Fri, 23 Aug 2024 13:58:46 +0800 Subject: [PATCH 071/112] =?UTF-8?q?feat:(REQ-2488)=20=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E5=88=97=E8=A1=A8=E6=8E=A5=E5=8F=A3=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E8=BF=94=E5=9B=9EroleCode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/client/model/roleuser/dto/SaasRoleUserV2DTO.java | 2 ++ 1 file changed, 2 insertions(+) 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 d031d60a..dd771aa4 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 @@ -72,6 +72,8 @@ public class SaasRoleUserV2DTO { */ private String roleType; + private String roleCode; + private Long workspaceId; private Long ownerOuId; From ffd48916e5f85f481b20db721abc0c6b672329b4 Mon Sep 17 00:00:00 2001 From: lilong Date: Sat, 24 Aug 2024 11:00:33 +0800 Subject: [PATCH 072/112] =?UTF-8?q?feat:(REQ-2699)=20=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E4=B8=AD=E4=BF=AE=E6=94=B9=E8=A7=92=E8=89=B2=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=A7=92=E8=89=B2=E6=9D=83=E9=99=90=E6=9B=B4?= =?UTF-8?q?=E6=96=B0mq=EF=BC=8C=E6=9B=B4=E6=96=B0=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E6=9D=83=E9=99=90=E7=9A=84mq=E6=97=B6=EF=BC=8C=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E5=85=A8=E9=87=8F=E6=9B=B4=E6=96=B0=EF=BC=8C=E5=9B=A0?= =?UTF-8?q?=E4=B8=BA=E5=8F=91=E9=80=81mq=E7=9A=84=E5=9C=B0=E6=96=B9?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=9C=80=E8=A6=81=E9=87=8D=E6=9E=84=E6=89=8D?= =?UTF-8?q?=E8=83=BD=E5=87=86=E7=A1=AE=E7=9A=84=E5=8F=91=E9=80=81mq?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/event/inner/CacheRolePermissionHandler.java | 10 ++++++---- .../service/impl/SaasFeatureResourceServiceImpl.java | 10 ++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java index 093166c1..bed072c8 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java @@ -73,12 +73,14 @@ public class CacheRolePermissionHandler implements InitializingBean { log.info("begin cached role permission handler rocketmq event: {}", event); RolePermissionCreatedPayload payload = event.normalizedData(RolePermissionCreatedPayload.class); - if (CollectionUtils.isEmpty(payload.getRoleIds())) { - return; - } + // 影响角色权限入口的代码没法简单重构,导致发送的roleIds可能不准确,所以一旦有角色权限的更新事件后,全量更新角色权限,角色权限数量不多 + // 后续收口了代码就准确根据角色去更新缓存 +// if (CollectionUtils.isEmpty(payload.getRoleIds())) { +// return; +// } RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() - .roleIds(Lists.newArrayList(payload.getRoleIds())) +// .roleIds(Lists.newArrayList(payload.getRoleIds())) .needPermissionRelation(true) .build(); List roles = roleService.list(listSaasRoleParam); 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 afc0f86b..c1d23595 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 @@ -32,6 +32,7 @@ import cn.axzo.tyr.client.model.res.PageElementResp; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.server.common.util.Throws; import cn.axzo.tyr.server.config.MqProducer; +import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; import cn.axzo.tyr.server.model.ResourcePermission; import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO; @@ -87,6 +88,7 @@ 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.event.inner.EventTypeEnum.ROLE_PERMISSION_CREATED; import static cn.axzo.tyr.server.event.inner.EventTypeEnum.SAAS_FEATURE_RESOURCE_UPSERT; import static cn.axzo.tyr.server.repository.entity.SaasFeatureResource.DEFAULT_WORKSPACE_TYPE; import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; @@ -310,6 +312,14 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl Date: Mon, 26 Aug 2024 13:50:10 +0800 Subject: [PATCH 073/112] =?UTF-8?q?feat:(REQ-2699)=20=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E6=9D=83=E9=99=90=E6=9F=A5=E8=AF=A2=E6=8E=A5=E5=8F=A3=E6=8E=92?= =?UTF-8?q?=E9=99=A4=E7=94=A8=E6=88=B7=E6=B2=A1=E6=9C=89=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E3=80=81=E9=A1=B9=E7=9B=AE=E6=B2=A1=E6=9C=89=E4=BA=A7=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/service/impl/PermissionQueryServiceImpl.java | 6 ++++++ 1 file changed, 6 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 ad316568..637e1011 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 @@ -877,11 +877,17 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { } List saasRoleUsers = listUserPermission(treePermissionReq); + if (CollectionUtils.isEmpty(saasRoleUsers)) { + return Collections.emptySet(); + } Map> roleFeatureResourceMap = listRoleFeatureResource(saasRoleUsers, treePermissionReq); List workspaceProductFeatureSources = listWorkspaceProducts(treePermissionReq); + if (CollectionUtils.isEmpty(workspaceProductFeatureSources)) { + return Collections.emptySet(); + } //免授权 Set authFreeFeatureIds = allFeatureResources.stream() .filter(e -> BooleanUtils.isTrue(e.isNotAuth())) From 4c95776eb0c1393782bd14547ed45d1d22866a27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Mon, 26 Aug 2024 16:07:47 +0800 Subject: [PATCH 074/112] =?UTF-8?q?feat(REQ-2899):=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=88=A0=E9=99=A4=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 | 5 + .../cn/axzo/tyr/client/model/req/IdReq.java | 25 +++ .../model/req/PageQueryElementV2Req.java | 2 + ...reResourcePageElementRelationViewResp.java | 97 ++++++++++ .../tyr/client/model/res/PageElementResp.java | 5 + .../permission/PageElementController.java | 6 + .../service/SaasPageElementService.java | 3 + .../impl/SaasPageElementServiceImpl.java | 180 +++++++++++++++++- 8 files changed, 318 insertions(+), 5 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/IdReq.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourcePageElementRelationViewResp.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 047874b8..e57ad4b5 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 @@ -3,6 +3,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.req.*; +import cn.axzo.tyr.client.model.res.FeatureResourcePageElementRelationViewResp; import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp; import cn.axzo.tyr.client.model.res.PageElementResp; @@ -69,4 +70,8 @@ public interface PageElementApi { /** 删除页面元素 **/ @PostMapping("/api/pageElement/delete") ApiResult delete(@RequestBody @Valid DeletePageElementReq req); + + /** 删除页面元素 **/ + @PostMapping("/api/pageElement/getFeatureResourceRelations") + ApiResult getFeatureResourceRelations(@RequestBody @Valid IdReq req); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/IdReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/IdReq.java new file mode 100644 index 00000000..a17fe876 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/IdReq.java @@ -0,0 +1,25 @@ +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/8/21 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IdReq { + + @NotNull(message = "ID不能为空") + @Min(value = 1, message = "ID有误") + private Long id; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java index 8779107e..a2643372 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java @@ -19,6 +19,8 @@ import java.util.List; @AllArgsConstructor public class PageQueryElementV2Req { + private Long id; + /** * 端 */ diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourcePageElementRelationViewResp.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourcePageElementRelationViewResp.java new file mode 100644 index 00000000..d8f2479e --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourcePageElementRelationViewResp.java @@ -0,0 +1,97 @@ +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/8/23 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FeatureResourcePageElementRelationViewResp { + + /** 菜单资源列表 **/ + private List featureResources; + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class FeatureResourceBasicDTO { + + private Long id; + + /** + * 资源编码-权限码 + */ + private String uniCode; + + /** + * 资源名称 + */ + private String featureName; + + /** + * 资源类型1-菜单 2-页面 3-应用入口 4-组件 5-root 6-分组 + */ + private Integer featureType; + + /** 前端元素资源列表 **/ + private PageElementBasicDTO pageElement; + + private List children; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class PageElementBasicDTO { + private Long id; + /** + * 元素的组编码 + */ + private String groupCode; + + /** + * 元素的组编码 + */ + private String groupName; + + /** + * 元素编码 + */ + private String code; + + /** + * 元素名称 + */ + private String name; + + /** + * 元素类型 + */ + private String type; + + /** + * 是否关联 + */ + private Boolean hasRelation; + + /** + * 1:路由页面 + */ + private Integer relationType; + + + 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 index 3b76766b..5f51c072 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 @@ -86,6 +86,11 @@ public class PageElementResp { */ private List featureResources; + /** ios挑战地址 **/ + private String iosRouterUrl; + + /** android挑战地址 **/ + private String androidRouterUrl; @Data @Builder 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 d1ade634..2875c85c 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 @@ -4,6 +4,7 @@ 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.*; +import cn.axzo.tyr.client.model.res.FeatureResourcePageElementRelationViewResp; import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp; import cn.axzo.tyr.client.model.res.PageElementResp; @@ -92,4 +93,9 @@ public class PageElementController implements PageElementApi { saasPageElementService.delete(req); return ApiResult.ok(); } + + @Override + public ApiResult getFeatureResourceRelations(IdReq req) { + return ApiResult.ok(saasPageElementService.getFeatureResourceRelations(req.getId())); + } } 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 c55b3b33..1ecc29c6 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 @@ -2,6 +2,7 @@ package cn.axzo.tyr.server.service; import cn.axzo.framework.domain.page.PageResp; import cn.axzo.tyr.client.model.req.*; +import cn.axzo.tyr.client.model.res.FeatureResourcePageElementRelationViewResp; import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; import cn.axzo.tyr.client.model.res.PageElementBasicDTO; import cn.axzo.tyr.client.model.res.PageElementResp; @@ -83,4 +84,6 @@ public interface SaasPageElementService extends IService { Long saveOrUpdate(SaveOrUpdatePageElementReq req); void delete(DeletePageElementReq req); + + FeatureResourcePageElementRelationViewResp getFeatureResourceRelations(Long pageElementId); } 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 5f2adea1..378d22b1 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 @@ -17,11 +17,7 @@ import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnu import cn.axzo.tyr.client.common.enums.PageElementTypeEnum; import cn.axzo.tyr.client.common.enums.PermissionRelationOperateLogSceneEnum; import cn.axzo.tyr.client.model.req.*; -import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; -import cn.axzo.tyr.client.model.res.IdentityAuthRes; -import cn.axzo.tyr.client.model.res.PageElementBasicDTO; -import cn.axzo.tyr.client.model.res.PageElementResp; -import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; +import cn.axzo.tyr.client.model.res.*; import cn.axzo.tyr.server.config.MqProducer; import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.model.RelationOperateLogResourceBindElementDO; @@ -497,6 +493,7 @@ public class SaasPageElementServiceImpl extends ServiceImpl pageV2(PageQueryElementV2Req request) { IPage page = saasPageElementDao.lambdaQuery() + .eq(Objects.nonNull(request.getId()), SaasPageElement::getId, request.getId()) .eq(StringUtils.isNotBlank(request.getTerminal()), SaasPageElement::getTerminal, request.getTerminal()) .in(CollectionUtils.isNotEmpty(request.getElementTypes()), SaasPageElement::getType, request.getElementTypes()) .and(StringUtils.isNotBlank(request.getPageElementCodeOrName()), w -> w.like(SaasPageElement::getCode, request.getPageElementCodeOrName()) @@ -508,7 +505,10 @@ public class SaasPageElementServiceImpl extends ServiceImpl(request.getPage(), request.getPageSize())); List list = BeanMapper.copyList(page.getRecords(), PageElementResp.class); + // 补充元素组名 fillGroupName(list); + // 补充元素ios、android路由地址 + fillIosAndAndroidRouteUrl(list); return PageResp.list(page.getCurrent(), page.getSize(), page.getTotal(), list); } @@ -613,6 +613,34 @@ public class SaasPageElementServiceImpl extends ServiceImpl pageElements = saasPageElementDao.listByGroupCodesAndExcludeIds(Lists.newArrayList(dbPageElement.getGroupCode()), null, dbPageElement.getTerminal(), null); + FeatureResourcePageElementRelationViewResp.PageElementBasicDTO elementBasic = getPageElementBasic(pageElements); + if (Objects.isNull(elementBasic)) { + return null; + } + + List relations = saasPageElementFeatureResourceRelationDao.lambdaQuery() + .eq(SaasPageElementFeatureResourceRelation::getIsDelete, DeleteEnum.NORMAL.getValue()) + .in(SaasPageElementFeatureResourceRelation::getPageElementCode, pageElements.stream().map(SaasPageElement::getCode).collect(Collectors.toSet())) + .eq(SaasPageElementFeatureResourceRelation::getTerminal, dbPageElement.getTerminal()) + .list(); + if (CollectionUtils.isEmpty(relations)) { + return null; + } + List featureResourceBasics = getFeatureResourceBasic(relations.stream().map(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode).collect(Collectors.toList()), dbPageElement.getTerminal()); + if (CollectionUtils.isEmpty(featureResourceBasics)) { + return null; + } + + fillElementToResource(featureResourceBasics, relations, elementBasic); + + return FeatureResourcePageElementRelationViewResp.builder().featureResources(featureResourceBasics).build(); + } + private PageElementResp from(SaasPageElement saasPageElement, Map> featureResources) { PageElementResp pageElementResp = PageElementResp.builder().build(); @@ -689,6 +717,19 @@ public class SaasPageElementServiceImpl extends ServiceImpl list) { + if (CollectionUtils.isEmpty(list)) { + return; + } + for (PageElementResp resp : list) { + if (StringUtils.isBlank(resp.getLinkExt())) { + continue; + } + resp.setIosRouterUrl(resp.resolveIosRouterUrl()); + resp.setAndroidRouterUrl(resp.resolveAndroidRouterUrl()); + } + } + private void saveOrUpdateOperateLog(SaveOrUpdatePageElementReq req, SaasPageElement basePageElement) { saasPgroupPermissionRelationOperateLogService.save(PermissionOperateLogReq.builder() .tableName(PAGE_ELEMENT_TABLE_NAME) @@ -710,4 +751,133 @@ public class SaasPageElementServiceImpl extends ServiceImpl pageElements) { + SaasPageElement pageTypeElement = pageElements.stream().filter(e -> PageElementTypeEnum.PAGE.getCode().equals(e.getType())).findFirst().orElse(null); + if (Objects.isNull(pageTypeElement)) { + return null; + } + + return FeatureResourcePageElementRelationViewResp.PageElementBasicDTO.builder() + .id(pageTypeElement.getId()) + .groupCode(pageTypeElement.getGroupCode()) + .groupName(pageTypeElement.getName()) + .code(pageTypeElement.getCode()) + .name(pageTypeElement.getName()) + .type(pageTypeElement.getType()) + .children(pageElements.stream().filter(e -> PageElementTypeEnum.COMPONENT.getCode().equals(e.getType())).map(e -> FeatureResourcePageElementRelationViewResp.PageElementBasicDTO.builder() + .id(e.getId()) + .groupCode(pageTypeElement.getGroupCode()) + .groupName(pageTypeElement.getName()) + .code(e.getCode()) + .name(e.getName()) + .type(e.getType()).build()).collect(Collectors.toList())) + .build(); + } + + private List getFeatureResourceBasic(List uniCodes, String terminal) { + List featureResources = saasFeatureResourceDao.lambdaQuery() + .eq(SaasFeatureResource::getTerminal, terminal) + .in(SaasFeatureResource::getUniCode, uniCodes) + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) + .list(); + + List parentFrs = featureResources.stream().filter(e -> { + if (Objects.isNull(e.getFeatureType())) { + return false; + } + return FeatureResourceType.PAGE.getCode().equals(e.getFeatureType()); + }).collect(Collectors.toList()); + List componentAndAppEntityParentIds = featureResources.stream().filter(e -> { + if (Objects.isNull(e.getFeatureType())) { + return false; + } + return FeatureResourceType.COMPONENT.getCode().equals(e.getFeatureType()) || FeatureResourceType.APP_ENTRY.getCode().equals(e.getFeatureType()); + }).map(SaasFeatureResource::getParentId).collect(Collectors.toList()); + + if (CollectionUtils.isNotEmpty(componentAndAppEntityParentIds)) { + List parentResources = saasFeatureResourceDao.lambdaQuery() + .eq(SaasFeatureResource::getTerminal, terminal) + .in(SaasFeatureResource::getId, componentAndAppEntityParentIds) + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) + .list(); + if (CollectionUtils.isNotEmpty(parentResources)) { + parentFrs.addAll(parentResources); + } + } + parentFrs = parentFrs.stream().distinct().collect(Collectors.toList()); + + Map> childrenMap = featureResources.stream().filter(e -> FeatureResourceType.COMPONENT.getCode().equals(e.getFeatureType()) + || FeatureResourceType.APP_ENTRY.getCode().equals(e.getFeatureType())).collect(Collectors.groupingBy(SaasFeatureResource::getParentId)); + List allParents = parentFrs.stream().map(e -> FeatureResourcePageElementRelationViewResp.FeatureResourceBasicDTO.builder() + .id(e.getId()) + .uniCode(e.getUniCode()) + .featureName(e.getFeatureName()) + .featureType(e.getFeatureType()) + .children(Lists.newArrayList()) + .build()).distinct().collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(allParents)) { + return null; + } + for (FeatureResourcePageElementRelationViewResp.FeatureResourceBasicDTO basic : allParents) { + List children = childrenMap.get(basic.getId()); + if (CollectionUtils.isEmpty(children)) { + continue; + } + basic.setChildren(children.stream().map(e -> FeatureResourcePageElementRelationViewResp.FeatureResourceBasicDTO.builder() + .id(e.getId()) + .uniCode(e.getUniCode()) + .featureName(e.getFeatureName()) + .featureType(e.getFeatureType()) + .build()).collect(Collectors.toList())); + } + + return allParents; + } + + private void fillElementToResource(List resources, List relations, + FeatureResourcePageElementRelationViewResp.PageElementBasicDTO elementBasic) { + Map relationMap = relations.stream().collect(Collectors.toMap(r -> r.getFeatureResourceUniCode() + "_" + r.getPageElementCode(), Function.identity(), (v1, v2) -> v1)); + for (FeatureResourcePageElementRelationViewResp.FeatureResourceBasicDTO resource : resources) { + recursiveSetElementToResource(resource, relationMap, elementBasic); + } + } + + private void recursiveSetElementToResource(FeatureResourcePageElementRelationViewResp.FeatureResourceBasicDTO resource, Map relationMap, + FeatureResourcePageElementRelationViewResp.PageElementBasicDTO elementBasic) { + if (Objects.isNull(resource)) { + return; + } + if (!FeatureResourceType.GROUP.getCode().equals(resource.getFeatureType())) { + FeatureResourcePageElementRelationViewResp.PageElementBasicDTO newPageElementBasic = FeatureResourcePageElementRelationViewResp.PageElementBasicDTO.builder() + .id(elementBasic.getId()) + .groupCode(elementBasic.getGroupCode()) + .groupName(elementBasic.getGroupName()) + .code(elementBasic.getCode()) + .name(elementBasic.getName()) + .type(elementBasic.getType()) + .hasRelation(Optional.ofNullable(relationMap.get(resource.getUniCode() + "_" + elementBasic.getCode())).isPresent()) + .relationType(Optional.ofNullable(relationMap.get(resource.getUniCode() + "_" + elementBasic.getCode())).map(SaasPageElementFeatureResourceRelation::getType).orElse(0)) + .build(); + if (CollectionUtils.isNotEmpty(elementBasic.getChildren())) { + newPageElementBasic.setChildren(elementBasic.getChildren().stream().map(e -> FeatureResourcePageElementRelationViewResp.PageElementBasicDTO.builder() + .id(e.getId()) + .groupCode(e.getGroupCode()) + .groupName(e.getGroupName()) + .code(e.getCode()) + .name(e.getName()) + .type(e.getType()) + .hasRelation(Optional.ofNullable(relationMap.get(resource.getUniCode() + "_" + e.getCode())).isPresent()) + .relationType(Optional.ofNullable(relationMap.get(resource.getUniCode() + "_" + e.getCode())).map(SaasPageElementFeatureResourceRelation::getType).orElse(0)) + .build()).collect(Collectors.toList())); + } + resource.setPageElement(newPageElementBasic); + } + + if (CollectionUtils.isNotEmpty(resource.getChildren())) { + resource.getChildren().forEach(e -> recursiveSetElementToResource(e, relationMap, elementBasic)); + } + + } } From 632056a8c80114d14f229098353d0642c8d5f8f3 Mon Sep 17 00:00:00 2001 From: lilong Date: Mon, 26 Aug 2024 16:50:55 +0800 Subject: [PATCH 075/112] =?UTF-8?q?feat:(REQ-2699)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E9=85=8D=E7=BD=AE=E4=B8=BA=E5=88=86=E9=92=9F?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E6=94=B9=E6=9F=A5=E8=AF=A2=E6=9D=83=E9=99=90?= =?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/ProductPermissionCacheServiceImpl.java | 6 +++--- .../impl/ProductSaasFeatureResourceCacheServiceImpl.java | 6 +++--- .../service/impl/RolePermissionCacheServiceImpl.java | 6 +++--- .../impl/RoleSaasFeatureResourceCacheServiceImpl.java | 6 +++--- .../service/impl/SaasFeatureResourceServiceImpl.java | 6 +++--- .../tyr/server/service/impl/TyrSaasAuthServiceImpl.java | 7 ++----- .../server/service/impl/WorkspaceProductServiceImpl.java | 6 +++--- 7 files changed, 20 insertions(+), 23 deletions(-) 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 index ba3d97bb..8a24245d 100644 --- 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 @@ -51,8 +51,8 @@ public class ProductPermissionCacheServiceImpl implements ProductPermissionCache private CacheProductPermissionHandler cacheProductPermissionHandler; /** 产品权限缓存过期时间 **/ - @Value("${product.permission.expire:180}") - private Long expireInDays; + @Value("${product.permission.expire.minutes:14}") + private Long expireInMinutes; @Override public Map> list(ListProductPermissionParam param) { @@ -136,7 +136,7 @@ public class ProductPermissionCacheServiceImpl implements ProductPermissionCache // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 redisTemplate.delete(redisKey); RedisClient.HashOps.hPutAll(redisKey, redisValues); - redisTemplate.expire(redisKey, expireInDays, TimeUnit.DAYS); + redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); log.info("succeed to store product permission: redisKey:{} value:{}", redisKey, redisValues); } return null; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java index 9bad1442..e5275a53 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java @@ -47,8 +47,8 @@ public class ProductSaasFeatureResourceCacheServiceImpl implements ProductSaasFe @Autowired private CacheProductSaasFeatureResourceHandler cacheProductSaasFeatureResourceHandler; - @Value("${product.feature.resouce.expire:180}") - private Long expireInDays; + @Value("${product.feature.resouce.expire.minutes:14}") + private Long expireInMinutes; @Override public Map> list(ListProductFeatureResourceParam param) { @@ -82,7 +82,7 @@ public class ProductSaasFeatureResourceCacheServiceImpl implements ProductSaasFe // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 redisTemplate.delete(redisKey); RedisClient.HashOps.hPutAll(redisKey, redisValues); - redisTemplate.expire(redisKey, expireInDays, TimeUnit.DAYS); + redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); log.info("succeed to store product featureResource: redisKey:{} value:{}", redisKey, redisValues); } return null; 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 index a237d7f9..4fa6f5d6 100644 --- 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 @@ -48,8 +48,8 @@ public class RolePermissionCacheServiceImpl implements RolePermissionCacheServic /** 角色权限缓存过期时间 **/ - @Value("${role.permission.expire:180}") - private Long expireInDays; + @Value("${role.permission.expire.minutes:14}") + private Long expireInMinutes; @Override public Map> list(ListRolePermissionParam param) { @@ -131,7 +131,7 @@ public class RolePermissionCacheServiceImpl implements RolePermissionCacheServic // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 redisTemplate.delete(redisKey); RedisClient.HashOps.hPutAll(redisKey, redisValues); - redisTemplate.expire(redisKey, expireInDays, TimeUnit.DAYS); + redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); log.info("succeed to store role permission: redisKey:{} value:{}", redisKey, redisValues); } return null; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java index 3d150979..0044c0e2 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java @@ -49,8 +49,8 @@ public class RoleSaasFeatureResourceCacheServiceImpl implements RoleSaasFeatureR /** 角色菜单缓存过期时间 **/ - @Value("${role.feature.resource.expire:180}") - private Long expireInDays; + @Value("${role.feature.resource.expire.minutes:14}") + private Long expireInMinutes; @Override public Map> list(ListRoleSaasFeatureResourceParam param) { @@ -84,7 +84,7 @@ public class RoleSaasFeatureResourceCacheServiceImpl implements RoleSaasFeatureR // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 redisTemplate.delete(redisKey); RedisClient.HashOps.hPutAll(redisKey, redisValues); - redisTemplate.expire(redisKey, expireInDays, TimeUnit.DAYS); + redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); log.info("succeed to store role featureResource: redisKey:{} value:{}", redisKey, redisValues); } return null; 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 c1d23595..ce3e6555 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 @@ -121,8 +121,8 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl redisTemplate; /** 菜单树过期时间 **/ - @Value("${saas.feature.resource.expire:180}") - private Long expireInDays; + @Value("${saas.feature.resource.expire.minutes:14}") + private Long expireInMinutes; private static final String SAAS_FEATURE_RESOURCE_KEY = "saas:feature:resource:%s"; @@ -785,7 +785,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl pairs = BeanMapper.copyList(req.getWorkspaceAndOU(), IdentityAuthReq.WorkspaceOuPair.class); request.setWorkspaceOusPairs(pairs); + request.setFeatureCode(Sets.newHashSet(req.getCodes())); IdentityAuthRes authRes = this.findIdentityAuthMix(request); - HashSet codeSet = new HashSet<>(req.getCodes()); - //比较code return authRes.getPermissions().stream() - .anyMatch(e -> e.getPermissionPoint() - .stream() - .anyMatch(p -> codeSet.contains(p.getFeatureCode()))); + .anyMatch(e -> CollectionUtil.isNotEmpty(e.getPermissionPoint())); } @Data 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 3ce49afd..23a5f76d 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 @@ -62,8 +62,8 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { /** 授权缓存过期时间 **/ - @Value("${workspace.product.expire:90}") - private Long expireInDays; + @Value("${workspace.product.expire.minutes:14}") + private Long expireInMinutes; private static final String WORKSPACE_PRODUCT_KEY = "workspace:product:%s"; @@ -190,7 +190,7 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { for (WorkspaceProductDTO workspaceProduct : param.getWorkspaceProducts()) { String redisKey = getKey(workspaceProduct.getWorkspaceId()); RedisUtil.StringValueOps.setEx(redisKey, JSON.toJSONString(workspaceProduct.getProductIds()), - expireInDays, TimeUnit.DAYS); + expireInMinutes, TimeUnit.MINUTES); } return null; From 251c081828925b9676b79335c8999de416a321d1 Mon Sep 17 00:00:00 2001 From: lilong Date: Mon, 26 Aug 2024 17:19:40 +0800 Subject: [PATCH 076/112] =?UTF-8?q?feat:(REQ-2699)=20=E5=A2=9E=E5=8A=A0@Re?= =?UTF-8?q?freshScope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/service/impl/ProductPermissionCacheServiceImpl.java | 2 ++ .../impl/ProductSaasFeatureResourceCacheServiceImpl.java | 2 ++ .../tyr/server/service/impl/RolePermissionCacheServiceImpl.java | 2 ++ .../service/impl/RoleSaasFeatureResourceCacheServiceImpl.java | 2 ++ .../tyr/server/service/impl/SaasFeatureResourceServiceImpl.java | 2 ++ .../tyr/server/service/impl/WorkspaceProductServiceImpl.java | 2 ++ 6 files changed, 12 insertions(+) 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 index 8a24245d..6e1415b6 100644 --- 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 @@ -21,6 +21,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.BooleanUtils; 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.RedisTemplate; @@ -39,6 +40,7 @@ import static cn.axzo.tyr.server.config.exception.BizResultCode.REDIS_PRODUCT_NO @Slf4j @Service +@RefreshScope public class ProductPermissionCacheServiceImpl implements ProductPermissionCacheService { private static final String PRODUCT_PERMISSION_KEY = "product:permission:%s"; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java index e5275a53..97d7c6cc 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java @@ -17,6 +17,7 @@ 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.RedisTemplate; @@ -36,6 +37,7 @@ import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation. @Slf4j @Service +@RefreshScope public class ProductSaasFeatureResourceCacheServiceImpl implements ProductSaasFeatureResourceCacheService { private static final String PRODUCT_SAAS_FEATURE_RESOURCE_KEY = "product:feature:resource:%s"; 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 index 4fa6f5d6..43ac0dbb 100644 --- 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 @@ -16,6 +16,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.BooleanUtils; 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.RedisCallback; import org.springframework.data.redis.core.RedisOperations; @@ -35,6 +36,7 @@ import static cn.axzo.tyr.server.config.exception.BizResultCode.REDIS_ROLE_NOT_N @Slf4j @Service +@RefreshScope public class RolePermissionCacheServiceImpl implements RolePermissionCacheService { private static final String ROLE_PERMISSION_KEY = "role:permission:%s"; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java index 0044c0e2..f63f3e02 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java @@ -16,6 +16,7 @@ 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.RedisCallback; import org.springframework.data.redis.core.RedisOperations; @@ -36,6 +37,7 @@ import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation. @Slf4j @Service +@RefreshScope public class RoleSaasFeatureResourceCacheServiceImpl implements RoleSaasFeatureResourceCacheService { private static final String ROLE_SAAS_FEATURE_RESOURCE_KEY = "role:feature:resource:%s"; 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 ce3e6555..bcd26f2e 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 @@ -69,6 +69,7 @@ import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.CacheEvict; +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.RedisTemplate; @@ -103,6 +104,7 @@ import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation. */ @Slf4j @Service +@RefreshScope @RequiredArgsConstructor public class SaasFeatureResourceServiceImpl extends ServiceImpl implements SaasFeatureResourceService { 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 23a5f76d..ba53bd08 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 @@ -25,6 +25,7 @@ import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; 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; @@ -45,6 +46,7 @@ import static cn.axzo.tyr.server.config.exception.BizResultCode.WORKSPACE_ID_NOT @Slf4j @Service +@RefreshScope public class WorkspaceProductServiceImpl implements WorkspaceProductService { @Autowired From e3a970dc323483a7e3860022e9c596d6dc2e660c Mon Sep 17 00:00:00 2001 From: lilong Date: Mon, 26 Aug 2024 17:47:27 +0800 Subject: [PATCH 077/112] =?UTF-8?q?feat:(REQ-2699)=20=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=A7=92=E8=89=B2=E6=97=B6=EF=BC=8C=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E8=A7=92=E8=89=B2=E6=9D=83=E9=99=90=E6=9B=B4=E6=96=B0?= =?UTF-8?q?mq?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/tyr/server/service/impl/RoleServiceImpl.java | 8 ++++++++ 1 file changed, 8 insertions(+) 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 a8e97a67..60b0c3eb 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 @@ -1411,6 +1411,14 @@ public class RoleServiceImpl extends ServiceImpl .build()) .build(); mqProducer.send(event); + + // 待收口后,这个事件需要放在角色权限的upsert方法里 + mqProducer.send(Event.builder() + .targetType("saasFeatureResourceId") + .eventCode(ROLE_PERMISSION_CREATED.getEventCode()) + .data(RolePermissionCreatedPayload.builder() + .build()) + .build()); } @Override From 59f0748d2c55b8e31f1f2f75df765b6b732c42c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Mon, 26 Aug 2024 19:34:45 +0800 Subject: [PATCH 078/112] =?UTF-8?q?feat(REQ-2899):=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=88=A0=E9=99=A4=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/model/req/GetPageElementReq.java | 6 ++++++ .../impl/SaasPageElementServiceImpl.java | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) 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 index 56d0c85d..cdf95126 100644 --- 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 @@ -40,4 +40,10 @@ public class GetPageElementReq { */ @Builder.Default private List relationTypes = Lists.newArrayList(0, 1); + + /** + * 是否按组分组返回 + */ + @Builder.Default + private Boolean returnWithGroup = Boolean.FALSE; } 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 378d22b1..829f5f6d 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 @@ -151,7 +151,8 @@ public class SaasPageElementServiceImpl extends ServiceImpl resps = change2PageElementResp(selectedPageElements, selectedIds); + return Boolean.TRUE.equals(request.getReturnWithGroup()) ? changeElementsWithGroup(resps) : resps; } @Override @@ -880,4 +881,19 @@ public class SaasPageElementServiceImpl extends ServiceImpl changeElementsWithGroup(List resps) { + if (CollectionUtils.isEmpty(resps)) { + return Collections.emptyList(); + } + Map groupCodeEntityMap = resps.stream().collect(Collectors.toMap(PageElementResp::getGroupCode, Function.identity(), (v1, v2) -> v1)); + Map> groupCodesMap = resps.stream().collect(Collectors.groupingBy(PageElementResp::getGroupCode)); + List result = Lists.newArrayList(); + groupCodesMap.forEach((k, v) -> { + PageElementResp groupEntity = groupCodeEntityMap.get(k); + result.add(PageElementResp.builder().groupCode(k).groupName(groupEntity.getGroupName()).children(v).build()); + }); + + return result; + } } From a2dede09af260540b265594db40c1a1ba4c593e4 Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 27 Aug 2024 11:17:04 +0800 Subject: [PATCH 079/112] =?UTF-8?q?feat:(REQ-2699)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E6=9D=83=E9=99=90=E6=97=B6=EF=BC=8C=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0roleId=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=BF=AB=E9=80=9F?= =?UTF-8?q?=E5=87=86=E7=A1=AE=E6=9B=B4=E6=96=B0=E8=A7=92=E8=89=B2=E6=9D=83?= =?UTF-8?q?=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/req/FeatureResourceTreeSaveReq.java | 3 -- .../inner/CacheRolePermissionHandler.java | 5 ++- .../CacheRoleSaasFeatureResourceHandler.java | 13 ++++--- .../impl/FeatureResourceSyncServiceImpl.java | 4 +-- .../server/service/impl/RoleServiceImpl.java | 35 +++++++++++++++++++ .../impl/SaasFeatureResourceServiceImpl.java | 8 ----- 6 files changed, 49 insertions(+), 19 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureResourceTreeSaveReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureResourceTreeSaveReq.java index f5c00c4a..e87303ad 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureResourceTreeSaveReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/FeatureResourceTreeSaveReq.java @@ -52,9 +52,6 @@ public class FeatureResourceTreeSaveReq extends BaseFeatureResourceDO { /** 页面组件对象 **/ private List componentSaveReqList; - /** 页面及组件权限对象 **/ - private List permissions; - @NotNull(message = "操作人ID不能为空") private Long operatorId; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java index bed072c8..b902d524 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java @@ -26,6 +26,7 @@ import java.util.Collections; 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; @@ -80,7 +81,9 @@ public class CacheRolePermissionHandler implements InitializingBean { // } RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() -// .roleIds(Lists.newArrayList(payload.getRoleIds())) + .roleIds(Optional.ofNullable(payload.getRoleIds()) + .map(Lists::newArrayList) + .orElse(null)) .needPermissionRelation(true) .build(); List roles = roleService.list(listSaasRoleParam); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java index be92484b..1c9875ea 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java @@ -24,6 +24,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; @@ -68,12 +69,16 @@ public class CacheRoleSaasFeatureResourceHandler implements InitializingBean { log.info("begin cached role saasFeatureResource handler rocketmq event: {}", event); RolePermissionCreatedPayload payload = event.normalizedData(RolePermissionCreatedPayload.class); - if (CollectionUtils.isEmpty(payload.getRoleIds())) { - return; - } + // 影响角色权限入口的代码没法简单重构,导致发送的roleIds可能不准确,所以一旦有角色权限的更新事件后,全量更新角色权限,角色权限数量不多 + // 后续收口了代码就准确根据角色去更新缓存 +// if (CollectionUtils.isEmpty(payload.getRoleIds())) { +// return; +// } RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() - .roleIds(Lists.newArrayList(payload.getRoleIds())) + .roleIds(Optional.ofNullable(payload.getRoleIds()) + .map(Lists::newArrayList) + .orElse(null)) .needPermissionRelation(true) .type(NEW_FEATURE) .build(); 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 fcced913..edca5332 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 @@ -353,13 +353,11 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic logResourceBindRoleDO.setRoleCodes(saasRoles.stream().filter(e -> existRoleIds.contains(e.getId())).map(SaasRole::getRoleCode).collect(Collectors.toList())); } + // 同步这里不要求效率,没有角色id,全部刷新,也不容易找这个 Event event = Event.builder() .targetType(ROLE_PERMISSION_TARGET_TYPE) .eventCode(ROLE_PERMISSION_CREATED.getEventCode()) .data(RolePermissionCreatedPayload.builder() - .roleIds(saasRoles.stream() - .map(SaasRole::getId) - .collect(Collectors.toSet())) .build()) .build(); mqProducer.send(event); 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 60b0c3eb..79cc1352 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 @@ -1338,9 +1338,43 @@ public class RoleServiceImpl extends ServiceImpl return saasRoleGroupRes; } + private Set resolveUpsertRoleIds(List req) { + if (CollectionUtils.isEmpty(req)) { + return Collections.emptySet(); + } + + Set newRoleIds = req.stream() + .map(FeatureRoleRelationReq.RelationRoleSettings::getRoleIds) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + List featureIds = req.stream() + .map(FeatureRoleRelationReq.RelationRoleSettings::getFeatureId) + .collect(Collectors.toList()); + PagePgroupPermissionRelationReq pagePgroupPermissionRelationReq = PagePgroupPermissionRelationReq.builder() + .featureIds(featureIds) + .build(); + List groupIds = saasPgroupPermissionRelationService.list(pagePgroupPermissionRelationReq).stream() + .map(SaasPgroupPermissionRelation::getGroupId) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(groupIds)) { + return newRoleIds; + } + + Set oldRoleIds = saasPgroupRoleRelationDao.listByGroupIds(groupIds).stream() + .map(SaasPgroupRoleRelation::getRoleId) + .collect(Collectors.toSet()); + newRoleIds.addAll(oldRoleIds); + return newRoleIds; + } + @Override @Transactional(rollbackFor = Exception.class) public void saveOrUpdateFeatureRoleRelation(List req, Long operatorId) { + // 查询权限点的历史角色,发送mq + Set allRoleIds = resolveUpsertRoleIds(req); + for (FeatureRoleRelationReq.RelationRoleSettings item : req) { saasFeatureResourceService.updateFeatureAuthType(item.getFeatureId(), item.getAuthType()); if (CollectionUtil.isEmpty(item.getRoleIds()) || item.getAuthType() == 0) { @@ -1417,6 +1451,7 @@ public class RoleServiceImpl extends ServiceImpl .targetType("saasFeatureResourceId") .eventCode(ROLE_PERMISSION_CREATED.getEventCode()) .data(RolePermissionCreatedPayload.builder() + .roleIds(allRoleIds) .build()) .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 bcd26f2e..e58be619 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 @@ -314,14 +314,6 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl Date: Tue, 27 Aug 2024 14:47:21 +0800 Subject: [PATCH 080/112] =?UTF-8?q?feat(REQ-2899):=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=88=A0=E9=99=A4=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 | 9 ++-- .../client/model/req/GetPageElementReq.java | 6 --- .../PageElementCategoryAndElementResp.java | 26 ++++++++++++ .../tyr/client/model/res/PageElementResp.java | 3 ++ .../permission/PageElementController.java | 7 +--- .../service/SaasPageElementService.java | 7 +--- .../impl/SaasPageElementServiceImpl.java | 42 ++++++++++++------- 7 files changed, 62 insertions(+), 38 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementCategoryAndElementResp.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 e57ad4b5..c6bdb2bc 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 @@ -3,10 +3,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.req.*; -import cn.axzo.tyr.client.model.res.FeatureResourcePageElementRelationViewResp; -import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; -import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp; -import cn.axzo.tyr.client.model.res.PageElementResp; +import cn.axzo.tyr.client.model.res.*; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -38,7 +35,7 @@ public interface PageElementApi { /** 分页查询页面资源 **/ @PostMapping("/api/pageElement/page") - ApiPageResult page(@RequestBody @Valid PageQueryElementReq req); + ApiPageResult page(@RequestBody @Valid PageQueryElementReq req); /** 根据用户传入的页面code,查询用户有权限的元素code **/ @PostMapping("/api/pageElement/getUserHasPermissionPageElement") @@ -71,7 +68,7 @@ public interface PageElementApi { @PostMapping("/api/pageElement/delete") ApiResult delete(@RequestBody @Valid DeletePageElementReq req); - /** 删除页面元素 **/ + /** 查询页面元素关联关系 **/ @PostMapping("/api/pageElement/getFeatureResourceRelations") ApiResult getFeatureResourceRelations(@RequestBody @Valid IdReq 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 index cdf95126..56d0c85d 100644 --- 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 @@ -40,10 +40,4 @@ public class GetPageElementReq { */ @Builder.Default private List relationTypes = Lists.newArrayList(0, 1); - - /** - * 是否按组分组返回 - */ - @Builder.Default - private Boolean returnWithGroup = Boolean.FALSE; } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementCategoryAndElementResp.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementCategoryAndElementResp.java new file mode 100644 index 00000000..fcda3eee --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementCategoryAndElementResp.java @@ -0,0 +1,26 @@ +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/8/27 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PageElementCategoryAndElementResp { + /** 项目编码 **/ + private String itemCode; + /** 项目名称 **/ + private String itemName; + /** 元素列表 **/ + private List pageElements; +} 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 5f51c072..8fae72f1 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 @@ -72,7 +72,10 @@ public class PageElementResp { */ private Boolean selected; + /** 业务编码 **/ private String itemCode; + /** 业务名称 **/ + private String itemName; private String linkExt; 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 2875c85c..27dd384e 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 @@ -4,10 +4,7 @@ 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.*; -import cn.axzo.tyr.client.model.res.FeatureResourcePageElementRelationViewResp; -import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; -import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp; -import cn.axzo.tyr.client.model.res.PageElementResp; +import cn.axzo.tyr.client.model.res.*; import cn.axzo.tyr.server.service.SaasPageElementCategoryService; import cn.axzo.tyr.server.service.SaasPageElementService; import lombok.RequiredArgsConstructor; @@ -47,7 +44,7 @@ public class PageElementController implements PageElementApi { } @Override - public ApiPageResult page(PageQueryElementReq req) { + public ApiPageResult page(PageQueryElementReq req) { return ApiPageResult.ok(saasPageElementService.page(req)); } 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 1ecc29c6..cabd9946 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 @@ -2,10 +2,7 @@ package cn.axzo.tyr.server.service; import cn.axzo.framework.domain.page.PageResp; import cn.axzo.tyr.client.model.req.*; -import cn.axzo.tyr.client.model.res.FeatureResourcePageElementRelationViewResp; -import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; -import cn.axzo.tyr.client.model.res.PageElementBasicDTO; -import cn.axzo.tyr.client.model.res.PageElementResp; +import cn.axzo.tyr.client.model.res.*; import cn.axzo.tyr.server.repository.entity.SaasPageElement; import com.baomidou.mybatisplus.extension.service.IService; @@ -64,7 +61,7 @@ public interface SaasPageElementService extends IService { * @param request 查询条件 * @return */ - PageResp page(PageQueryElementReq request); + PageResp page(PageQueryElementReq request); /** * 根据用户传入的页面code,查询用户有权限的元素code 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 829f5f6d..02ce55da 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 @@ -151,8 +151,7 @@ public class SaasPageElementServiceImpl extends ServiceImpl resps = change2PageElementResp(selectedPageElements, selectedIds); - return Boolean.TRUE.equals(request.getReturnWithGroup()) ? changeElementsWithGroup(resps) : resps; + return change2PageElementResp(selectedPageElements, selectedIds); } @Override @@ -231,17 +230,21 @@ public class SaasPageElementServiceImpl extends ServiceImpl page(PageQueryElementReq request) { + 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.like(SaasPageElement::getCode, request.getSearchKey()) .or().like(SaasPageElement::getName, request.getSearchKey()) - .or().like(SaasPageElement::getLinkUrl, request.getSearchKey())) + .or().like(SaasPageElement::getLinkUrl, request.getSearchKey()) + .or().like(SaasPageElement::getItemCode, request.getSearchKey()) + .or().like(SaasPageElement::getItemName, 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); + + List categoryAndElementResps = changeElementWithCategories(list); + return PageResp.list(page.getCurrent(), page.getSize(), page.getTotal(), categoryAndElementResps); } @Override @@ -366,6 +369,8 @@ public class SaasPageElementServiceImpl extends ServiceImpl pageTypeElements = pageElements.stream().filter(e -> PageElementTypeEnum.PAGE.getCode().equals(e.getType())) .map(e -> PageElementResp.builder() .id(e.getId()) + .groupCode(e.getGroupCode()) + .groupName(e.getName()) .code(e.getCode()) .name(e.getName()) .type(e.getType()) @@ -383,6 +388,8 @@ public class SaasPageElementServiceImpl extends ServiceImpl recursiveSetElementToResource(e, relationMap, elementBasic)); } - } - private List changeElementsWithGroup(List resps) { - if (CollectionUtils.isEmpty(resps)) { - return Collections.emptyList(); + private List changeElementWithCategories(List list) { + List resps = Lists.newArrayList(); + if (CollectionUtils.isEmpty(list)) { + return resps; } - Map groupCodeEntityMap = resps.stream().collect(Collectors.toMap(PageElementResp::getGroupCode, Function.identity(), (v1, v2) -> v1)); - Map> groupCodesMap = resps.stream().collect(Collectors.groupingBy(PageElementResp::getGroupCode)); - List result = Lists.newArrayList(); - groupCodesMap.forEach((k, v) -> { - PageElementResp groupEntity = groupCodeEntityMap.get(k); - result.add(PageElementResp.builder().groupCode(k).groupName(groupEntity.getGroupName()).children(v).build()); + Map itemCodeAndElementMap = list.stream().collect(Collectors.toMap(PageElementResp::getItemCode, Function.identity(), (v1, v2) -> v1)); + Map> groupingByItemCodes = list.stream().collect(Collectors.groupingBy(PageElementResp::getItemCode)); + groupingByItemCodes.forEach((k, v) -> { + PageElementResp resp = itemCodeAndElementMap.get(k); + resps.add(PageElementCategoryAndElementResp.builder() + .itemCode(k) + .itemName(resp.getItemName()) + .pageElements(v) + .build()); }); - return result; + return resps; } } From cba58c9c63507c6230e8b2166488bebf29e84e81 Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 27 Aug 2024 15:03:16 +0800 Subject: [PATCH 081/112] =?UTF-8?q?feat:(REQ-2699)=20=E5=A4=84=E7=90=86?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E6=9B=B4=E6=96=B0=E8=B5=84=E6=BA=90=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E8=A7=92=E8=89=B2=E6=B2=A1=E6=9C=89=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java | 1 + 1 file changed, 1 insertion(+) 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 79cc1352..a93414d2 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 @@ -1345,6 +1345,7 @@ public class RoleServiceImpl extends ServiceImpl Set newRoleIds = req.stream() .map(FeatureRoleRelationReq.RelationRoleSettings::getRoleIds) + .filter(Objects::nonNull) .flatMap(Collection::stream) .collect(Collectors.toSet()); From 38e711217ce3d16c50666faafcd4cf46799cc61e Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 27 Aug 2024 16:00:19 +0800 Subject: [PATCH 082/112] =?UTF-8?q?feat:(REQ-2699)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E4=BA=A7=E5=93=81=E7=9A=84=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E5=92=8C=E5=AE=9A=E6=97=B6job=E5=8E=BB?= =?UTF-8?q?=E5=88=B7=E6=96=B0=E9=A1=B9=E7=9B=AE=E7=9A=84=E4=BA=A7=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/PrivateController.java | 19 +++++- .../server/job/CacheWorkspaceProductJob.java | 66 +++++++++++++++++++ .../service/WorkspaceProductService.java | 3 + .../impl/WorkspaceProductServiceImpl.java | 56 ++++++++-------- 4 files changed, 115 insertions(+), 29 deletions(-) create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheWorkspaceProductJob.java 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 a495da22..d0fab5c2 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 @@ -32,6 +32,7 @@ import cn.axzo.tyr.server.job.CacheProductPermissionJob; import cn.axzo.tyr.server.job.CacheRoleFeatureResourceJob; import cn.axzo.tyr.server.job.CacheRolePermissionJob; import cn.axzo.tyr.server.job.CacheSaasFeatureJob; +import cn.axzo.tyr.server.job.CacheWorkspaceProductJob; import cn.axzo.tyr.server.repository.dao.ProductModuleDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; @@ -169,6 +170,8 @@ public class PrivateController { private SaasRoleUserRelationService saasRoleUserRelationService; @Autowired private ProductModuleDao productModuleDao; + @Autowired + private CacheWorkspaceProductJob cacheWorkspaceProductJob; /** * 统一层级的roleGroup按照id升序,sort从1递增 @@ -623,12 +626,24 @@ public class PrivateController { return featureCodeUtil.resolveFeatureCode(request.getFeatureCodes()); } - @PostMapping("/api/private/workspaceProduct/store") - public Object storeWorkspaceProduct(@RequestBody ProductSearchListReq request) throws Exception { + @PostMapping("/api/private/productPermission/store") + public Object storeProductPermission(@RequestBody ProductSearchListReq request) throws Exception { cacheProductPermissionJob.execute(JSON.toJSONString(request)); return "ok"; } + @PostMapping("/api/private/workspaceProduct/store") + public Object storeWorkspaceProduct(@RequestBody WorkspaceProductService.StoreWorkspaceProductParam request) throws Exception { + workspaceProductService.storeWorkspaceProduct(request); + return "ok"; + } + + @PostMapping("/api/private/workspaceProduct/job") + public Object storeWorkspaceProductJob() throws Exception { + cacheWorkspaceProductJob.execute(null); + return "ok"; + } + @PostMapping("/api/private/workspaceProduct/list") public Object listWorkspaceProduct(@RequestBody WorkspaceProductService.WorkspaceProductParam request) { return workspaceProductService.listWorkspaceProductCached(request); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheWorkspaceProductJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheWorkspaceProductJob.java new file mode 100644 index 00000000..e50788e6 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheWorkspaceProductJob.java @@ -0,0 +1,66 @@ +package cn.axzo.tyr.server.job; + +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.service.WorkspaceProductService; +import cn.axzo.tyr.server.utils.RpcInternalUtil; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.IJobHandler; +import com.xxl.job.core.handler.annotation.XxlJob; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +@Component +public class CacheWorkspaceProductJob extends IJobHandler { + + @Autowired + private WorkspaceProductService workspaceProductService; + @Autowired + private ServicePkgClient servicePkgClient; + + @Override + @XxlJob("CacheWorkspaceProductJob") + public ReturnT execute(String s) throws Exception { + + log.info("start CacheWorkspaceProductJob, s:{}", s); + + // 全量更新所有项目的产品数量比较大,所以这里只从缓存中的项目去更新产品 + Map> allWorkspaceProducts = workspaceProductService.listAllWorkspaceProductCached(); + + Set workspaceIds = allWorkspaceProducts.keySet(); + + if (CollectionUtils.isEmpty(workspaceIds)) { + return ReturnT.SUCCESS; + } + + List servicePkgDetailRes = RpcInternalUtil.rpcListProcessor(() -> servicePkgClient.getServicePkgDetailBySpaceId(workspaceIds), + "查询项目的产品", workspaceIds).getData(); + + List workspaceProducts = servicePkgDetailRes.stream() + .map(e -> WorkspaceProductService.WorkspaceProductDTO.builder() + .workspaceId(e.getSpaceId()) + .productIds(Optional.ofNullable(e.getProducts()) + .map(products -> products.stream() + .map(ServicePkgProduct::getProductId) + .collect(Collectors.toSet())) + .orElse(null)) + .build()) + .collect(Collectors.toList()); + + WorkspaceProductService.StoreWorkspaceProductParam storeWorkspaceProductParam = WorkspaceProductService.StoreWorkspaceProductParam.builder() + .workspaceProducts(workspaceProducts) + .build(); + workspaceProductService.storeWorkspaceProduct(storeWorkspaceProductParam); + return ReturnT.SUCCESS; + } +} 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 494b8098..b84067c0 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 @@ -9,6 +9,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; +import java.util.Map; import java.util.Set; public interface WorkspaceProductService { @@ -43,6 +44,8 @@ public interface WorkspaceProductService { */ List listWorkspaceProductFeatureResourceCached(ListWorkspaceProductFeatureSourceCacheParam param); + Map> listAllWorkspaceProductCached(); + @Data @Builder @NoArgsConstructor 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 ba53bd08..ecf78d73 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 @@ -2,7 +2,7 @@ package cn.axzo.tyr.server.service.impl; import cn.axzo.foundation.exception.Axssert; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; -import cn.axzo.pokonyan.config.redis.RedisUtil; +import cn.axzo.pokonyan.config.redis.RedisClient; 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; @@ -22,13 +22,9 @@ import com.google.common.collect.Sets; import com.google.common.collect.Streams; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang3.StringUtils; 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; @@ -37,6 +33,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -67,7 +64,7 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { @Value("${workspace.product.expire.minutes:14}") private Long expireInMinutes; - private static final String WORKSPACE_PRODUCT_KEY = "workspace:product:%s"; + private static final String WORKSPACE_PRODUCT_KEY = "workspace:product"; @Override public List listWorkspaceProduct(WorkspaceProductParam param) { @@ -184,35 +181,28 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { public void storeWorkspaceProduct(StoreWorkspaceProductParam param) { Axssert.checkNotEmpty(param.getWorkspaceProducts(), REDIS_PRODUCT_NOT_NULL); - - redisTemplate.executePipelined(new SessionCallback() { - @Override - public Object execute(RedisOperations operations) throws DataAccessException { - - for (WorkspaceProductDTO workspaceProduct : param.getWorkspaceProducts()) { - String redisKey = getKey(workspaceProduct.getWorkspaceId()); - RedisUtil.StringValueOps.setEx(redisKey, JSON.toJSONString(workspaceProduct.getProductIds()), - expireInMinutes, TimeUnit.MINUTES); - } - - return null; - } - }); + Map redisValues = param.getWorkspaceProducts().stream() + .collect(Collectors.toMap(e -> e.getWorkspaceId().toString(), e -> Optional.ofNullable(e.getProductIds()) + .map(JSON::toJSONString) + .orElseGet(() -> JSON.toJSONString(Sets.newHashSet())))); + String redisKey = getKey(); + RedisClient.HashOps.hPutAll(redisKey, redisValues); + redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); + log.info("succeed to workspace product: redisKey:{} value:{}", redisKey, redisValues); } private Map> listWorkspaceProduct(ListWorkspaceProductParam param) { Axssert.checkNotEmpty(param.getWorkspaceIds(), WORKSPACE_ID_NOT_NULL); - List redisKeys = param.getWorkspaceIds().stream() - .map(this::getKey) - .collect(Collectors.toList()); - List redisValues = redisTemplate.opsForValue().multiGet(redisKeys); + List redisValues = RedisClient.HashOps.hMultiGet(getKey(), param.getWorkspaceIds().stream() + .map(String::valueOf) + .collect(Collectors.toList())); return Streams.zip(param.getWorkspaceIds().stream(), redisValues.stream(), (workspaceId, redisValue) -> { - if (StringUtils.isBlank(redisValue)) { + if (Objects.isNull(redisValue)) { return null; } @@ -222,6 +212,7 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { .collect(Collectors.toSet()); return Pair.of(workspaceId, productIds); + }) .filter(Objects::nonNull) .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); @@ -275,8 +266,8 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { storeWorkspaceProduct(storeWorkspaceProductParam); } - private String getKey(Object... params) { - return String.format(WORKSPACE_PRODUCT_KEY, params); + private String getKey() { + return String.format(WORKSPACE_PRODUCT_KEY); } @Override @@ -398,4 +389,15 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { }) .collect(Collectors.toList()); } + + @Override + public Map> listAllWorkspaceProductCached() { + + return RedisClient.HashOps.hGetAll(getKey()).entrySet() + .stream() + .collect(Collectors.toMap(e -> Long.valueOf(e.getKey().toString()), e -> JSON.parseArray(e.getValue().toString()) + .stream() + .map(productId -> Long.valueOf(productId.toString())) + .collect(Collectors.toSet()))); + } } From d643dae9c40ce79c956eedbeb681216e83d5c555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Tue, 27 Aug 2024 16:59:56 +0800 Subject: [PATCH 083/112] =?UTF-8?q?feat(REQ-2899):=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E6=94=AF=E6=8C=81=E4=BF=AE=E6=94=B9=E7=88=B6?= =?UTF-8?q?=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/req/DeletePageElementCategoryReq.java | 2 -- .../tyr/client/model/req/DeletePageElementReq.java | 2 -- .../req/SaveOrUpdatePageElementCategoryReq.java | 2 -- .../client/model/req/SaveOrUpdatePageElementReq.java | 2 -- .../service/impl/SaasFeatureResourceServiceImpl.java | 12 +++++++++--- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeletePageElementCategoryReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeletePageElementCategoryReq.java index 274d0938..b0942aa8 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeletePageElementCategoryReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeletePageElementCategoryReq.java @@ -25,7 +25,5 @@ public class DeletePageElementCategoryReq { private Long id; /** 操作人personId **/ - @NotNull(message = "操作人不能为空") - @Min(value = 1, message = "操作人有误") private Long operatorId; } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeletePageElementReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeletePageElementReq.java index aac41833..eef88523 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeletePageElementReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeletePageElementReq.java @@ -25,7 +25,5 @@ public class DeletePageElementReq { private Long id; /** 操作人personId **/ - @NotNull(message = "操作人不能为空") - @Min(value = 1, message = "操作人有误") private Long operatorId; } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementCategoryReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementCategoryReq.java index e274380d..8b48c48c 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementCategoryReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementCategoryReq.java @@ -34,7 +34,5 @@ public class SaveOrUpdatePageElementCategoryReq { private String terminal; /** 操作人personId **/ - @NotNull(message = "操作人不能为空") - @Min(value = 1, message = "操作人有误") private Long operatorId; } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementReq.java index 51f391b0..97ad2f9a 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementReq.java @@ -59,7 +59,5 @@ public class SaveOrUpdatePageElementReq { private Integer version; /** 操作人personId **/ - @NotNull(message = "操作人不能为空") - @Min(value = 1, message = "操作人有误") private 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 940cc68b..e62f504b 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 @@ -270,8 +270,13 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl Date: Thu, 29 Aug 2024 11:27:30 +0800 Subject: [PATCH 084/112] =?UTF-8?q?feat:(REQ-2699)=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E7=BC=96=E7=A0=81=E6=9D=83=E9=99=90=E7=9A=84?= =?UTF-8?q?check=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/PrivateController.java | 337 +++++++++++++++++- 1 file changed, 321 insertions(+), 16 deletions(-) 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 d0fab5c2..f2a6055d 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 @@ -55,7 +55,9 @@ import cn.axzo.tyr.server.repository.entity.SaasRoleGroup; import cn.axzo.tyr.server.repository.entity.SaasRoleGroupRelation; import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductPermissionCacheService; +import cn.axzo.tyr.server.service.ProductSaasFeatureResourceCacheService; import cn.axzo.tyr.server.service.RolePermissionCacheService; +import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService; import cn.axzo.tyr.server.service.RoleService; import cn.axzo.tyr.server.service.SaasCommonDictService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; @@ -172,6 +174,8 @@ public class PrivateController { private ProductModuleDao productModuleDao; @Autowired private CacheWorkspaceProductJob cacheWorkspaceProductJob; + @Autowired + private RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService; /** * 统一层级的roleGroup按照id升序,sort从1递增 @@ -820,11 +824,21 @@ public class PrivateController { .build(); List allFeatures = saasFeatureResourceService.listCache(listSaasFeatureResourceCache).get(request.getTerminal()); - List roles = listRole(request); + List roles = listRole(ListRoleUserRelationParam.builder() + .personId(request.getPersonId()) + .workspaceOuPairs(Lists.newArrayList(ListRoleUserRelationParam.WorkspaceOuPair.builder() + .workspaceId(request.getWorkspaceId()) + .ouId(request.getOuId()) + .build())) + .needRole(true) + .build()); List productPermissions = listWorkspaceProductPermission(request); - List products = listProduct(productPermissions); + List productIds = productPermissions.stream() + .map(WorkspaceProductService.ProductPermission::getProductId) + .collect(Collectors.toList()); + List products = listProduct(productIds); Map> rolePermissions = listRolePermission(roles); @@ -835,6 +849,75 @@ public class PrivateController { .build()); } + @PostMapping("/api/private/featureResource/check") + public ApiResult checkFeatureResource(@RequestBody @Validated CheckFeatureResourceParam request) { + + SaasFeatureResourceService.ListSaasFeatureResourceCache listSaasFeatureResourceCache = SaasFeatureResourceService.ListSaasFeatureResourceCache.builder() + .terminals(Sets.newHashSet(request.getTerminal())) + .build(); + List allFeatures = saasFeatureResourceService.listCache(listSaasFeatureResourceCache).get(request.getTerminal()); + + List roles = listRole(ListRoleUserRelationParam.builder() + .personId(request.getPersonId()) + .workspaceOuPairs(Lists.newArrayList(ListRoleUserRelationParam.WorkspaceOuPair.builder() + .workspaceId(request.getWorkspaceId()) + .ouId(request.getOuId()) + .build())) + .needRole(true) + .build()); + + List productFeatureSources = listWorkspaceProductFeatureResource(request); + + List productIds = productFeatureSources.stream() + .map(WorkspaceProductService.ProductFeatureSource::getProductId) + .collect(Collectors.toList()); + List products = listProduct(productIds); + + Map> roleFeatureResources = listRoleFeatureResource(roles); + + return ApiResult.ok(CheckFeatureResourceDTO.builder() + .products(products) + .roles(roles) + .uniCodeCheckResults(resolveUniCode(request, productFeatureSources, roleFeatureResources, roles, allFeatures)) + .build()); + } + + private UniCodeCheckResult resolveAdminRoleFeature(List adminRoles, + List productFeatureResources) { + if (CollectionUtils.isEmpty(adminRoles)) { + return UniCodeCheckResult.builder() + .authPermission(false) + .reasons(Lists.newArrayList("没有管理员角色")) + .build(); + + } + + List reasons = Lists.newArrayList(); + Boolean authPermission = false; + + for (Role adminRole : adminRoles) { + + List adminPermissions = productFeatureResources.stream() + .filter(e -> Objects.equals(e.getCooperateType(), adminRole.getCooperateType().toString())) + .collect(Collectors.toList()); + + if (CollectionUtils.isNotEmpty(adminPermissions)) { + reasons.add("角色Id:" + adminRole.getRoleId() + + ";角色名字:" + adminRole.getRoleName() + + ";单位类型:" + adminRole.getCooperateType() + ";是管理员角色,有该权限code权限"); + authPermission = true; + } else { + reasons.add("角色Id:" + adminRole.getRoleId() + + ";角色名字:" + adminRole.getRoleName() + + ";单位类型:" + adminRole.getCooperateType() + ";没有该权限code权限"); + } + } + return UniCodeCheckResult.builder() + .authPermission(authPermission) + .reasons(reasons) + .build(); + } + private FeatureCodeCheckResult resolveAdminRole(List adminRoles, List productPermissions) { if (CollectionUtils.isEmpty(adminRoles)) { @@ -919,6 +1002,54 @@ public class PrivateController { .build(); } + private UniCodeCheckResult resolveNormalRoleFeature(List normalRoles, + List productFeatureResources, + Map> rolePermissions, + String uniCode) { + if (CollectionUtils.isEmpty(normalRoles)) { + return UniCodeCheckResult.builder() + .authPermission(false) + .reasons(Lists.newArrayList("没有普通角色")) + .build(); + + } + + List reasons = Lists.newArrayList(); + Boolean authPermission = false; + + for (Role normalRole : normalRoles) { + List normalRolepermissions = rolePermissions.getOrDefault(normalRole.getRoleId(), Lists.newArrayList()) + .stream() + .filter(e -> Objects.equals(e.getUniCode(), uniCode)) + .collect(Collectors.toList()); + + Set productCooperateTypes = productFeatureResources.stream() + .map(e -> e.getCooperateType()) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(normalRolepermissions)) { + reasons.add("角色Id:" + normalRole.getRoleId() + + ";角色名字:" + normalRole.getRoleName() + + ";单位类型:" + normalRole.getCooperateType() + ";没有该权限code权限"); + } else if (productCooperateTypes.contains(normalRole.getCooperateType().toString())) { + reasons.add("角色Id:" + normalRole.getRoleId() + + ";角色名字:" + normalRole.getRoleName() + + ";单位类型:" + normalRole.getCooperateType() + ";有该权限code权限;有该权限的产品的单位类型有" + + JSON.toJSONString(productCooperateTypes)); + authPermission = true; + } else { + reasons.add("角色Id:" + normalRole.getRoleId() + + ";角色名字:" + normalRole.getRoleName() + + ";单位类型:" + normalRole.getCooperateType() + ";有该权限code权限;有该权限的产品的单位类型有" + + JSON.toJSONString(productCooperateTypes)); + } + } + return UniCodeCheckResult.builder() + .authPermission(authPermission) + .reasons(reasons) + .build(); + } + private FeatureCodeCheckResult resolveNotAuth(List productPermissions, String featureCode, List allFeatures) { @@ -974,6 +1105,61 @@ public class PrivateController { } } + private UniCodeCheckResult resolveNotAuthFeature(List productFeatureResources, + String uniCode, + List allFeatures) { + // 直接配置成免授权的权限点 + List notAuthFeatures = allFeatures.stream() + .filter(SaasFeatureResourceService.SaasFeatureResourceCache::isNotAuth) + .collect(Collectors.toList()); + + // 子节点是免授权的权限点 + Set parentNotAuthFeatureIds = notAuthFeatures.stream() + .map(e -> Optional.ofNullable(e.getParentIds()) + .map(f -> { + f.add(e.getFeatureId()); + return f; + }) + .orElseGet(() -> Sets.newHashSet(e.getFeatureId()))) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + Set notAuthFeatureIds = notAuthFeatures.stream() + .map(SaasFeatureResourceService.SaasFeatureResourceCache::getFeatureId) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(parentNotAuthFeatureIds) && CollectionUtils.isEmpty(notAuthFeatureIds)) { + return UniCodeCheckResult.builder() + .authPermission(false) + .reasons(Lists.newArrayList("没有免授权权限点")) + .build(); + } + + Set productFeatureIds = productFeatureResources.stream() + .filter(e -> Objects.equals(e.getUniCode(), uniCode)) + .map(ProductSaasFeatureResourceCacheService.FeatureResourceDTO::getFeatureId) + .collect(Collectors.toSet()); + + + + if (!Sets.intersection(notAuthFeatureIds, productFeatureIds).isEmpty()) { + return UniCodeCheckResult.builder() + .authPermission(true) + .reasons(Lists.newArrayList("权限点是免授权")) + .build(); + } else if (!Sets.intersection(parentNotAuthFeatureIds, productFeatureIds).isEmpty()) { + return UniCodeCheckResult.builder() + .authPermission(true) + .reasons(Lists.newArrayList("权限点的子节点是免授权")) + .build(); + } else { + return UniCodeCheckResult.builder() + .authPermission(false) + .reasons(Lists.newArrayList("权限点不是免授权")) + .build(); + } + } + private List resolveFeatureCode(CheckPermissionParam checkPermissionParam, List productPermissions, Map> rolePermissions, @@ -1037,6 +1223,68 @@ public class PrivateController { .collect(Collectors.toList()); } + private List resolveUniCode(CheckFeatureResourceParam checkFeatureResourceParam, + List productFeatureSources, + Map> roleFeatureResources, + List roles, + List allFeatures) { + Map> productFeatureResourceMap = productFeatureSources.stream() + .map(WorkspaceProductService.ProductFeatureSource::getFeatureResources) + .flatMap(Collection::stream) + .collect(Collectors.groupingBy(ProductSaasFeatureResourceCacheService.FeatureResourceDTO::getUniCode)); + List adminRoles = roles.stream() + .filter(e -> RoleTypeEnum.isAdmin(e.getRoleType())) + .collect(Collectors.toList()); + + List normalRoles = roles.stream() + .filter(e -> !RoleTypeEnum.isAdmin(e.getRoleType())) + .collect(Collectors.toList()); + + return checkFeatureResourceParam.getUniCodes().stream() + .map(uniCode -> { + List featureResources = productFeatureResourceMap.get(uniCode); + if (CollectionUtils.isEmpty(featureResources)) { + return UniCodeCheckResult.builder() + .uniCode(uniCode) + .authPermission(false) + .reasons(Lists.newArrayList("项目没有配置产品及权限")) + .build(); + } + + if (CollectionUtils.isEmpty(roles)) { + return UniCodeCheckResult.builder() + .uniCode(uniCode) + .authPermission(false) + .reasons(Lists.newArrayList("用户在项目里没有任何角色")) + .build(); + } + + UniCodeCheckResult adminRoleCheckResult = resolveAdminRoleFeature(adminRoles, featureResources); + + UniCodeCheckResult normalRoleCheckResult = resolveNormalRoleFeature(normalRoles, featureResources, roleFeatureResources, uniCode); + + UniCodeCheckResult notAuthCheckResult = resolveNotAuthFeature(featureResources, uniCode, allFeatures); + + Boolean authPermission = BooleanUtils.isTrue(adminRoleCheckResult.getAuthPermission()) + || BooleanUtils.isTrue(normalRoleCheckResult.getAuthPermission()) + || BooleanUtils.isTrue(notAuthCheckResult.getAuthPermission()); + + List adminRoleReasons = adminRoleCheckResult.getReasons(); + List normalRoleReasons = normalRoleCheckResult.getReasons(); + List notAuthReasons = notAuthCheckResult.getReasons(); + + adminRoleReasons.addAll(normalRoleReasons); + adminRoleReasons.addAll(notAuthReasons); + + return UniCodeCheckResult.builder() + .uniCode(uniCode) + .authPermission(authPermission) + .reasons(adminRoleReasons) + .build(); + }) + .collect(Collectors.toList()); + } + private Map> listRolePermission(List roles) { if (CollectionUtils.isEmpty(roles)) { @@ -1049,15 +1297,23 @@ public class PrivateController { return rolePermissionCacheService.list(listRolePermissionParam); } - private List listProduct(List productPermissions) { + private Map> listRoleFeatureResource(List roles) { - if (CollectionUtils.isEmpty(productPermissions)) { - return Collections.emptyList(); + if (CollectionUtils.isEmpty(roles)) { + return Collections.emptyMap(); } - List productIds = productPermissions.stream() - .map(WorkspaceProductService.ProductPermission::getProductId) - .collect(Collectors.toList()); + RoleSaasFeatureResourceCacheService.ListRoleSaasFeatureResourceParam listRolePermissionParam = RoleSaasFeatureResourceCacheService.ListRoleSaasFeatureResourceParam.builder() + .roleIds(roles.stream().map(Role::getRoleId).collect(Collectors.toSet())) + .build(); + return roleSaasFeatureResourceCacheService.list(listRolePermissionParam); + } + + private List listProduct(List productIds) { + + if (CollectionUtils.isEmpty(productIds)) { + return Collections.emptyList(); + } return productModuleDao.listByIds(productIds).stream() .filter(productModule -> Objects.equals(productModule.getIsDelete(),0L)) @@ -1079,16 +1335,18 @@ public class PrivateController { .collect(Collectors.toList()); } - private List listRole(CheckPermissionParam request) { - ListRoleUserRelationParam listRoleUserRelationParam = ListRoleUserRelationParam.builder() - .personId(request.getPersonId()) - .workspaceOuPairs(Lists.newArrayList(ListRoleUserRelationParam.WorkspaceOuPair.builder() - .workspaceId(request.getWorkspaceId()) - .ouId(request.getOuId()) - .build())) - .needRole(true) + private List listWorkspaceProductFeatureResource(CheckFeatureResourceParam request) { + WorkspaceProductService.ListWorkspaceProductFeatureSourceCacheParam listWorkspaceProductFeatureSourceCacheParam = WorkspaceProductService.ListWorkspaceProductFeatureSourceCacheParam + .builder() + .workspaceIds(Sets.newHashSet(request.getWorkspaceId())) .build(); + return workspaceProductService.listWorkspaceProductFeatureResourceCached(listWorkspaceProductFeatureSourceCacheParam).stream() + .map(WorkspaceProductService.WorkspaceProductFeatureSource::getProductFeatureSources) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + private List listRole(ListRoleUserRelationParam listRoleUserRelationParam) { return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream() .filter(e -> e.getSaasRole() != null) .collect(Collectors.toList()) @@ -1124,6 +1382,28 @@ public class PrivateController { private String terminal; } + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CheckFeatureResourceParam { + + @NotNull(message = "ouId不能为空") + private Long ouId; + + @NotNull(message = "workspaceId不能为空") + private Long workspaceId; + + @NotEmpty(message = "uniCodes不能为空") + private Set uniCodes; + + @NotNull(message = "personId不能为空") + private Long personId; + + @NotBlank(message = "terminal不能为空") + private String terminal; + } + @Data @Builder @NoArgsConstructor @@ -1137,6 +1417,19 @@ public class PrivateController { private List featureCodeCheckResults; } + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CheckFeatureResourceDTO { + + private List products; + + private List roles; + + private List uniCodeCheckResults; + } + @Data @Builder @NoArgsConstructor @@ -1175,6 +1468,18 @@ public class PrivateController { private Boolean authPermission; } + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class UniCodeCheckResult { + private String uniCode; + + private List reasons; + + private Boolean authPermission; + } + @Data @Builder @NoArgsConstructor From 07b8226692233305de65bcb099c33ec0536fce50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Thu, 29 Aug 2024 16:57:35 +0800 Subject: [PATCH 085/112] =?UTF-8?q?feat(REQ-2899):=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=9A=82=E6=B2=A1?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E3=80=82=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/client/feign/PageElementApi.java | 4 + .../model/req/PageElementImportDataReq.java | 86 +++++++++++++++++++ .../model/req/SaveOrUpdatePageElementReq.java | 4 +- .../permission/PageElementController.java | 6 ++ .../service/SaasPageElementService.java | 2 + .../impl/SaasPageElementServiceImpl.java | 7 ++ 6 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementImportDataReq.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 c6bdb2bc..073ea5c4 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 @@ -71,4 +71,8 @@ public interface PageElementApi { /** 查询页面元素关联关系 **/ @PostMapping("/api/pageElement/getFeatureResourceRelations") ApiResult getFeatureResourceRelations(@RequestBody @Valid IdReq req); + + /** 查询页面元素关联关系 **/ + @PostMapping("/api/pageElement/importData") + ApiResult importData(@RequestBody @Valid PageElementImportDataReq req); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementImportDataReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementImportDataReq.java new file mode 100644 index 00000000..2cf3acf5 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageElementImportDataReq.java @@ -0,0 +1,86 @@ +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.io.Serializable; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/8/29 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PageElementImportDataReq implements Serializable { + + /** + * 端 + */ + @NotBlank(message = "端信息不能为空") + private String terminal; + + /** + * 元素分类 + */ + @NotBlank(message = "元素分类不能为空") + private String itemCode; + + /** + * 元素组编码 + */ + @NotBlank(message = "元素组编码不能为空") + private String groupCode; + + /** + * 元素编码 + */ + @NotBlank(message = "元素编码不能为空") + private String code; + + /** + * 元素名称 + */ + @NotBlank(message = "元素名称不能为空") + private String name; + + /** + * 元素类型(PAGE:页面,COMPONENT:页面里的组件) + */ + @NotBlank(message = "元素类型不能为空") + private String type; + + /** + * 元素资源类型:APP、H5、PC + */ + @NotBlank(message = "元素资源类型不能为空") + private String appType; + + /** + * H5的appId + */ + private String appId; + + /** + * 元素支持的最低版本号 + */ + private Integer version; + + /** + * 路由地址 + */ + private String linkUrl; + + /** ios跳转地址 **/ + private String iosRouterUrl; + + /** android跳转地址 **/ + private String androidRouterUrl; + + private Long operatorId; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementReq.java index 97ad2f9a..2b9a38ae 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementReq.java @@ -49,10 +49,10 @@ public class SaveOrUpdatePageElementReq { /** pc/h5路由地址 **/ private String linkUrl; - /** ios挑战地址 **/ + /** ios跳转地址 **/ private String iosRouterUrl; - /** android挑战地址 **/ + /** android跳转地址 **/ private String androidRouterUrl; /** 版本号 **/ 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 27dd384e..8ac431b1 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 @@ -95,4 +95,10 @@ public class PageElementController implements PageElementApi { public ApiResult getFeatureResourceRelations(IdReq req) { return ApiResult.ok(saasPageElementService.getFeatureResourceRelations(req.getId())); } + + @Override + public ApiResult importData(PageElementImportDataReq req) { + saasPageElementService.importData(req); + return ApiResult.ok(); + } } 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 cabd9946..b23f79b9 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 @@ -83,4 +83,6 @@ public interface SaasPageElementService extends IService { void delete(DeletePageElementReq req); FeatureResourcePageElementRelationViewResp getFeatureResourceRelations(Long pageElementId); + + void importData(PageElementImportDataReq req); } 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 02ce55da..00d8cbc3 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 @@ -649,6 +649,13 @@ public class SaasPageElementServiceImpl extends ServiceImpl> featureResources) { PageElementResp pageElementResp = PageElementResp.builder().build(); From 7a3bb207e0644f7a136857d09fac500a32045d76 Mon Sep 17 00:00:00 2001 From: lilong Date: Thu, 29 Aug 2024 17:57:21 +0800 Subject: [PATCH 086/112] =?UTF-8?q?feat:(REQ-2699)=20=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E6=94=AF=E6=8C=81app=E7=AB=AF=E8=AF=AD=E9=9F=B3=E5=8A=A9?= =?UTF-8?q?=E6=89=8B=E5=8A=9F=E8=83=BD=EF=BC=8C=E8=8F=9C=E5=8D=95=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E7=BC=96=E7=A0=81=E6=97=B6=E5=8F=91=E9=80=81=E9=92=89?= =?UTF-8?q?=E9=92=89=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tyr-server/pom.xml | 6 ++ .../tyr/server/common/util/DingTalkUtil.java | 68 +++++++++++++++++++ .../server/controller/PrivateController.java | 13 ++++ .../event/inner/SendDingTalkHandler.java | 63 +++++++++++++++++ .../SaasFeatureResourceUpsertPayload.java | 8 +++ .../entity/SaasFeatureResource.java | 10 +++ .../impl/FeatureResourceSyncServiceImpl.java | 21 ++++++ .../impl/SaasFeatureResourceServiceImpl.java | 25 ++++++- 8 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/common/util/DingTalkUtil.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java diff --git a/tyr-server/pom.xml b/tyr-server/pom.xml index ac8c62dd..7b7f6217 100644 --- a/tyr-server/pom.xml +++ b/tyr-server/pom.xml @@ -138,6 +138,12 @@ apisix-plat-api 2.0.0-SNAPSHOT + + + com.aliyun + alibaba-dingtalk-service-sdk + 2.0.0 + diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/common/util/DingTalkUtil.java b/tyr-server/src/main/java/cn/axzo/tyr/server/common/util/DingTalkUtil.java new file mode 100644 index 00000000..1839c2c3 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/common/util/DingTalkUtil.java @@ -0,0 +1,68 @@ +package cn.axzo.tyr.server.common.util; + + +import cn.hutool.core.util.StrUtil; +import com.dingtalk.api.DefaultDingTalkClient; +import com.dingtalk.api.DingTalkClient; +import com.dingtalk.api.request.OapiRobotSendRequest; +import com.dingtalk.api.response.OapiRobotSendResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** + * @author wangsiqian + * @since 2024/07/30 + */ +@Slf4j +public class DingTalkUtil { + + /** + * 发送消息 + * + * @author wangsiqian + * @date 2024-07-30 + */ + public static void sendMessage(String content, String accessToken, String secret) { + Long timestamp = System.currentTimeMillis(); + String sign = getSign(timestamp, secret); + if (StrUtil.isBlank(sign)) { + return; + } + + String url = StrUtil.format("https://oapi.dingtalk.com/robot/send?access_token={}&sign={}×tamp={}", + accessToken, sign, String.valueOf(timestamp)); + DingTalkClient client = new DefaultDingTalkClient(url); + + OapiRobotSendRequest req = new OapiRobotSendRequest(); + OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text(); + text.setContent(content); + OapiRobotSendRequest.At at = new OapiRobotSendRequest.At(); + at.setIsAtAll(false); + req.setMsgtype("text"); + req.setText(text); + req.setAt(at); + try { + OapiRobotSendResponse response = client.execute(req); + log.info("发送钉钉消息结果:{}", response); + } catch (Exception error) { + log.info("发送钉钉消息失败:{}", error.getMessage()); + } + } + + private static String getSign(Long timestamp, String secret) { + try { + String stringToSign = timestamp + "\n" + secret; + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); + byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8)); + return URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8"); + } catch (Exception ignored) { + return ""; + } + } +} 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 f2a6055d..fc1845b8 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 @@ -25,7 +25,9 @@ import cn.axzo.tyr.client.model.res.SaasRoleRes; import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam; import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO; import cn.axzo.tyr.client.model.vo.SaveOrUpdateRoleVO; +import cn.axzo.tyr.server.event.inner.SendDingTalkHandler; import cn.axzo.tyr.server.event.outer.CacheWorkspaceProductHandler; +import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; import cn.axzo.tyr.server.event.payload.ServicePkgProductCreatedPayload; import cn.axzo.tyr.server.job.CacheProductFeatureResourceJob; import cn.axzo.tyr.server.job.CacheProductPermissionJob; @@ -176,6 +178,8 @@ public class PrivateController { private CacheWorkspaceProductJob cacheWorkspaceProductJob; @Autowired private RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService; + @Autowired + private SendDingTalkHandler sendDingTalkHandler; /** * 统一层级的roleGroup按照id升序,sort从1递增 @@ -1360,6 +1364,15 @@ public class PrivateController { .collect(Collectors.toList()); } + @PostMapping("/api/private/dingtalk/send") + public Object sendUpsertDingTalk(@RequestBody SaasFeatureResourceUpsertPayload request) { + Event event = Event.builder() + .data(request) + .build(); + sendDingTalkHandler.onFeatureResourceUpsert(event, null); + return "ok"; + } + @Data @Builder @NoArgsConstructor diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java new file mode 100644 index 00000000..f6cb2007 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java @@ -0,0 +1,63 @@ +package cn.axzo.tyr.server.event.inner; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.tyr.server.common.util.DingTalkUtil; +import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; +import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.Objects; + +@Slf4j +@Component +public class SendDingTalkHandler implements InitializingBean { + + @Autowired + private EventConsumer eventConsumer; + @Value("${spring.profiles.active}") + private String env; + + // 语音助手菜单变更通知,@沈尚只是临时的方案,所以没改成配置 + private static final String ACCESS_TOKEN = "11cdf26d77211ee887184844910bf249b94aa2675c7ce36d75a7aa87d619490f"; + private static final String SECRET = "SEC3c1be9e4fe4cc09f16eb4b2eebf91659f21d5bdfb1d764b52f3e47825e6bed3f"; + + + public void onFeatureResourceUpsert(Event event, EventConsumer.Context context) { + log.info("begin send dingTalk rocketmq event: {}", event); + SaasFeatureResourceUpsertPayload payload = event.normalizedData(SaasFeatureResourceUpsertPayload.class); + + if (Objects.isNull(payload.getAction())) { + return; + } + + if (Objects.equals(payload.getAction(), SaasFeatureResource.Action.UPDATE) && + Objects.equals(payload.getNewValue().getUniCode(), payload.getOldValue().getUniCode())) { + return; + } + + StringBuilder sb = new StringBuilder(); + sb.append("环境:" + env + "\n"); + sb.append("操作:" + payload.getAction() + "\n"); + if (Objects.equals(payload.getAction(), SaasFeatureResource.Action.CREATE)) { + sb.append("新code:" + payload.getNewValue().getUniCode()); + } else if (Objects.equals(payload.getAction(), SaasFeatureResource.Action.UPDATE)) { + sb.append("新code:" + payload.getNewValue().getUniCode() + "\n"); + sb.append("旧code:" + payload.getOldValue().getUniCode()); + } else if (Objects.equals(payload.getAction(), SaasFeatureResource.Action.DELETE)) { + sb.append("旧code:" + payload.getOldValue().getUniCode()); + } + + DingTalkUtil.sendMessage(sb.toString(), ACCESS_TOKEN, SECRET); + log.info("end send dingTalk rocketmq event: {}", event); + } + + @Override + public void afterPropertiesSet() throws Exception { + eventConsumer.registerHandler(EventTypeEnum.SAAS_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onFeatureResourceUpsert); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java index 1cdcbafb..1cae0180 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java @@ -1,5 +1,6 @@ package cn.axzo.tyr.server.event.payload; +import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -14,5 +15,12 @@ import java.util.Set; @AllArgsConstructor public class SaasFeatureResourceUpsertPayload implements Serializable { + // 只有tyr消费,触发更新缓存,同步等很多批量操作要全部重构收口代码后,才能好修改这个payload private Set terminals; + + private SaasFeatureResource oldValue; + + private SaasFeatureResource newValue; + + private SaasFeatureResource.Action action; } 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 448a4146..a3420f41 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 @@ -198,4 +198,14 @@ public class SaasFeatureResource extends BaseEntity { return Objects.equals(ALL_ROLE.getValue(), authType); } } + + @Getter + @AllArgsConstructor + public enum Action { + DELETE( "删除操作"), + CREATE( "创建操作"), + UPDATE( "更新操作"); + + private String desc; + } } 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 edca5332..a333ab88 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 @@ -241,6 +241,16 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic baseResource.setCreateBy(operatorId); baseResource.setUpdateBy(operatorId); newResource(baseResource, parent); + + Event event = Event.builder() + .targetType(SAAS_FEATURE_RESOURCE_TARGET_TYPE) + .eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode()) + .data(SaasFeatureResourceUpsertPayload.builder() + .newValue(featureResourceDao.getById(baseResource.getId())) + .action(SaasFeatureResource.Action.CREATE) + .build()) + .build(); + mqProducer.send(event); } else { //更新 - 恢复不能变更的数据 baseResource.setId(resource.getId()); @@ -251,6 +261,17 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic baseResource.setUpdateBy(operatorId); baseResource.setAppItemId(resource.getAppItemId()); featureResourceDao.updateById(baseResource); + + Event event = Event.builder() + .targetType(SAAS_FEATURE_RESOURCE_TARGET_TYPE) + .eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode()) + .data(SaasFeatureResourceUpsertPayload.builder() + .newValue(featureResourceDao.getById(baseResource.getId())) + .oldValue(resource) + .action(SaasFeatureResource.Action.UPDATE) + .build()) + .build(); + mqProducer.send(event); } // 处理资源关联的权限 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 e58be619..68a95276 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 @@ -32,7 +32,6 @@ import cn.axzo.tyr.client.model.res.PageElementResp; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.server.common.util.Throws; import cn.axzo.tyr.server.config.MqProducer; -import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; import cn.axzo.tyr.server.model.ResourcePermission; import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO; @@ -89,7 +88,6 @@ 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.event.inner.EventTypeEnum.ROLE_PERMISSION_CREATED; import static cn.axzo.tyr.server.event.inner.EventTypeEnum.SAAS_FEATURE_RESOURCE_UPSERT; import static cn.axzo.tyr.server.repository.entity.SaasFeatureResource.DEFAULT_WORKSPACE_TYPE; import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; @@ -272,12 +270,33 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl Date: Fri, 30 Aug 2024 10:46:32 +0800 Subject: [PATCH 087/112] =?UTF-8?q?feat:(REQ-2699)=20=E4=BF=AE=E6=94=B9app?= =?UTF-8?q?=E8=AF=AD=E9=9F=B3=E5=8A=A9=E6=89=8B=E5=8F=AA=E6=9C=89CMP?= =?UTF-8?q?=E7=AB=AF=E7=9A=84=E8=8F=9C=E5=8D=95=E4=BF=AE=E6=94=B9=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E6=89=8D=E5=8F=91=E9=80=81=E9=92=89=E9=92=89=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/event/inner/SendDingTalkHandler.java | 16 +++++++++++++--- .../impl/SaasFeatureResourceServiceImpl.java | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java index f6cb2007..a79f978f 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java @@ -1,5 +1,6 @@ package cn.axzo.tyr.server.event.inner; +import cn.axzo.framework.auth.domain.TerminalInfo; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.tyr.server.common.util.DingTalkUtil; @@ -12,6 +13,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.util.Objects; +import java.util.Optional; @Slf4j @Component @@ -22,7 +24,7 @@ public class SendDingTalkHandler implements InitializingBean { @Value("${spring.profiles.active}") private String env; - // 语音助手菜单变更通知,@沈尚只是临时的方案,所以没改成配置 + // 语音助手菜单变更通知,@沈尚只是临时的方案,对方接入MQ成本高,所以没改成配置 private static final String ACCESS_TOKEN = "11cdf26d77211ee887184844910bf249b94aa2675c7ce36d75a7aa87d619490f"; private static final String SECRET = "SEC3c1be9e4fe4cc09f16eb4b2eebf91659f21d5bdfb1d764b52f3e47825e6bed3f"; @@ -35,8 +37,16 @@ public class SendDingTalkHandler implements InitializingBean { return; } - if (Objects.equals(payload.getAction(), SaasFeatureResource.Action.UPDATE) && - Objects.equals(payload.getNewValue().getUniCode(), payload.getOldValue().getUniCode())) { + if (Objects.isNull(payload.getNewValue()) && Objects.isNull(payload.getOldValue())) { + return; + } + + // 现在沈尚那边只关心CMP的code有更新的情况 + String terminal = Optional.ofNullable(payload.getNewValue()) + .map(SaasFeatureResource::getTerminal) + .orElseGet(() -> payload.getOldValue().getTerminal()); + + if (!Objects.equals(terminal, TerminalInfo.NT_CMP_APP_GENERAL)) { return; } 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 68a95276..73ffabe5 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 @@ -294,6 +294,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl Date: Fri, 30 Aug 2024 18:46:39 +0800 Subject: [PATCH 088/112] =?UTF-8?q?feat:(REQ-2699)=20=E5=A4=84=E7=90=86?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E6=9F=A5=E8=AF=A2=E8=A7=92=E8=89=B2=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E8=A7=92=E8=89=B2=E6=97=B6=E7=9A=84bug=EF=BC=8C?= =?UTF-8?q?=E9=9C=80=E8=A6=81=E8=BF=87=E6=BB=A4=E6=8E=89=E6=97=A7=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/repository/dao/SaasPgroupPermissionRelationDao.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPgroupPermissionRelationDao.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPgroupPermissionRelationDao.java index 7ce3db6c..dab85e17 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPgroupPermissionRelationDao.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPgroupPermissionRelationDao.java @@ -15,6 +15,8 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; + @Repository public class SaasPgroupPermissionRelationDao extends ServiceImpl { @@ -59,6 +61,7 @@ public class SaasPgroupPermissionRelationDao extends ServiceImpl Date: Fri, 30 Aug 2024 20:24:48 +0800 Subject: [PATCH 089/112] =?UTF-8?q?feat(REQ-2899):=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=9A=82=E6=B2=A1?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E3=80=82=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/client/feign/PageElementApi.java | 4 +- .../model/req/SaveOrUpdatePageElementReq.java | 2 +- ...reResourcePageElementRelationViewResp.java | 97 -------- .../res/ListPageElementCategoryResp.java | 2 + ...ageElementRelationFeatureResourceResp.java | 82 +++++++ .../tyr/server/TyrServerDevApplication.java | 1 + .../permission/PageElementController.java | 4 +- .../service/SaasPageElementService.java | 4 +- .../SaasPageElementCategoryServiceImpl.java | 1 + .../impl/SaasPageElementServiceImpl.java | 222 ++++++------------ 10 files changed, 169 insertions(+), 250 deletions(-) delete mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourcePageElementRelationViewResp.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementRelationFeatureResourceResp.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 073ea5c4..c42e63d2 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 @@ -70,9 +70,9 @@ public interface PageElementApi { /** 查询页面元素关联关系 **/ @PostMapping("/api/pageElement/getFeatureResourceRelations") - ApiResult getFeatureResourceRelations(@RequestBody @Valid IdReq req); + ApiResult> getFeatureResourceRelations(@RequestBody @Valid IdReq req); /** 查询页面元素关联关系 **/ @PostMapping("/api/pageElement/importData") - ApiResult importData(@RequestBody @Valid PageElementImportDataReq req); + ApiResult importData(@RequestBody @Valid List req); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementReq.java index 2b9a38ae..c483477b 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/SaveOrUpdatePageElementReq.java @@ -26,7 +26,7 @@ public class SaveOrUpdatePageElementReq { private String itemCode; /** 分组ID **/ - private Long pageId; + private String groupCode; /** 页面元素类型:PAGE/COMPONENT **/ @NotBlank(message = "页面元素类型不能为空") diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourcePageElementRelationViewResp.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourcePageElementRelationViewResp.java deleted file mode 100644 index d8f2479e..00000000 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourcePageElementRelationViewResp.java +++ /dev/null @@ -1,97 +0,0 @@ -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/8/23 - */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class FeatureResourcePageElementRelationViewResp { - - /** 菜单资源列表 **/ - private List featureResources; - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class FeatureResourceBasicDTO { - - private Long id; - - /** - * 资源编码-权限码 - */ - private String uniCode; - - /** - * 资源名称 - */ - private String featureName; - - /** - * 资源类型1-菜单 2-页面 3-应用入口 4-组件 5-root 6-分组 - */ - private Integer featureType; - - /** 前端元素资源列表 **/ - private PageElementBasicDTO pageElement; - - private List children; - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class PageElementBasicDTO { - private Long id; - /** - * 元素的组编码 - */ - private String groupCode; - - /** - * 元素的组编码 - */ - private String groupName; - - /** - * 元素编码 - */ - private String code; - - /** - * 元素名称 - */ - private String name; - - /** - * 元素类型 - */ - private String type; - - /** - * 是否关联 - */ - private Boolean hasRelation; - - /** - * 1:路由页面 - */ - private Integer relationType; - - - private List children; - } -} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/ListPageElementCategoryResp.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/ListPageElementCategoryResp.java index 0ccf85bd..7a269fba 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/ListPageElementCategoryResp.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/ListPageElementCategoryResp.java @@ -35,5 +35,7 @@ public class ListPageElementCategoryResp { private String itemCode; /** 项目名称 **/ private String itemName; + /** 端 **/ + private String terminal; } } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementRelationFeatureResourceResp.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementRelationFeatureResourceResp.java new file mode 100644 index 00000000..cf6df342 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/PageElementRelationFeatureResourceResp.java @@ -0,0 +1,82 @@ +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; + +/** +* @author likunpeng +* @date 2024/8/30 +* @version 1.0 +*/ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PageElementRelationFeatureResourceResp implements IBaseTree { + + private Long id; + + /** + * 上级资源ID + */ + private Long parentId; + + /** + * 资源编码-权限码 + */ + private String uniCode; + + /** + * 资源名称 + */ + private String featureName; + + /** + * 资源类型1-菜单 2-页面 3-应用入口 4-组件 5-root 6-分组 + */ + private Integer featureType; + + /** + * 子节点 + */ + private List children; + + /** + * 是否关联 + */ + private Boolean hasRelation; + + /** + * 1:路由页面 + */ + private Integer relationType; + + @JsonIgnore + @Override + public Long getNodeCode() { + return this.getId(); + } + + @JsonIgnore + @Override + public Long getParentNodeCode() { + return this.getParentId(); + } + + @JsonIgnore + @Override + public List getNodeChildren() { + return this.children; + } + + @Override + public void setNodeChildren(List nodeChildren) { + this.children = nodeChildren; + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/TyrServerDevApplication.java b/tyr-server/src/main/java/cn/axzo/tyr/server/TyrServerDevApplication.java index b15ee22a..e18dedb6 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/TyrServerDevApplication.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/TyrServerDevApplication.java @@ -31,6 +31,7 @@ public class TyrServerDevApplication { System.setProperty("spring.redis.host","172.16.2.23"); System.setProperty("xxl.job.admin.addresses","http://dev-xxl-job.axzo.cn/xxl-job-admin"); System.setProperty("rocketmq.name-server", "172.16.2.82:9876"); + System.setProperty("spring.datasource.url", "jdbc:mysql://172.16.2.171:3306/pudge?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=true&verifyServerCertificate=false&rewriteBatchedStatements=true"); SpringApplication application = new SpringApplication(TyrServerDevApplication.class); ApplicationContext applicationContext = application.run(args); Environment env = applicationContext.getEnvironment(); 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 8ac431b1..83c37734 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 @@ -92,12 +92,12 @@ public class PageElementController implements PageElementApi { } @Override - public ApiResult getFeatureResourceRelations(IdReq req) { + public ApiResult> getFeatureResourceRelations(IdReq req) { return ApiResult.ok(saasPageElementService.getFeatureResourceRelations(req.getId())); } @Override - public ApiResult importData(PageElementImportDataReq req) { + public ApiResult importData(List req) { saasPageElementService.importData(req); return ApiResult.ok(); } 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 b23f79b9..c7097a19 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 @@ -82,7 +82,7 @@ public interface SaasPageElementService extends IService { void delete(DeletePageElementReq req); - FeatureResourcePageElementRelationViewResp getFeatureResourceRelations(Long pageElementId); + List getFeatureResourceRelations(Long pageElementId); - void importData(PageElementImportDataReq req); + void importData(List req); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementCategoryServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementCategoryServiceImpl.java index 3d4c77d6..09120600 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementCategoryServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementCategoryServiceImpl.java @@ -61,6 +61,7 @@ public class SaasPageElementCategoryServiceImpl implements SaasPageElementCatego .id(c.getId()) .itemCode(c.getItemCode()) .itemName(c.getItemName()) + .terminal(c.getTerminal()) .build()).collect(Collectors.toList())).build()); }); return categoryResps; 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 00d8cbc3..9f03e121 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 @@ -4,6 +4,7 @@ import cn.axzo.basics.common.BeanMapper; import cn.axzo.basics.common.constant.enums.DeleteEnum; import cn.axzo.basics.common.util.AssertUtil; import cn.axzo.basics.common.util.StopWatchUtil; +import cn.axzo.basics.common.util.TreeUtil; import cn.axzo.basics.profiles.api.UserProfileServiceApi; import cn.axzo.basics.profiles.dto.basic.PersonProfileDto; import cn.axzo.foundation.dao.support.converter.PageConverter; @@ -562,10 +563,10 @@ public class SaasPageElementServiceImpl extends ServiceImpl 0, "页面元素不存在"); + AssertUtil.isTrue(StringUtils.isNotBlank(req.getGroupCode()), "页面元素不存在"); List pageElements = saasPageElementDao.lambdaQuery() .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) - .eq(SaasPageElement::getId, req.getPageId()).list(); + .eq(SaasPageElement::getCode, req.getGroupCode()).list(); AssertUtil.notEmpty(pageElements, "父级元素不存在。"); SaasPageElement pageElement = pageElements.get(0); @@ -622,38 +623,95 @@ public class SaasPageElementServiceImpl extends ServiceImpl getFeatureResourceRelations(Long pageElementId) { SaasPageElement dbPageElement = saasPageElementDao.getById(pageElementId); AssertUtil.notNull(dbPageElement, "页面元素资源不存在"); - List pageElements = saasPageElementDao.listByGroupCodesAndExcludeIds(Lists.newArrayList(dbPageElement.getGroupCode()), null, dbPageElement.getTerminal(), null); - FeatureResourcePageElementRelationViewResp.PageElementBasicDTO elementBasic = getPageElementBasic(pageElements); - if (Objects.isNull(elementBasic)) { - return null; - } List relations = saasPageElementFeatureResourceRelationDao.lambdaQuery() .eq(SaasPageElementFeatureResourceRelation::getIsDelete, DeleteEnum.NORMAL.getValue()) - .in(SaasPageElementFeatureResourceRelation::getPageElementCode, pageElements.stream().map(SaasPageElement::getCode).collect(Collectors.toSet())) + .eq(SaasPageElementFeatureResourceRelation::getPageElementCode, dbPageElement.getCode()) .eq(SaasPageElementFeatureResourceRelation::getTerminal, dbPageElement.getTerminal()) .list(); if (CollectionUtils.isEmpty(relations)) { - return null; - } - List featureResourceBasics = getFeatureResourceBasic(relations.stream().map(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode).collect(Collectors.toList()), dbPageElement.getTerminal()); - if (CollectionUtils.isEmpty(featureResourceBasics)) { - return null; + return Collections.emptyList(); } - fillElementToResource(featureResourceBasics, relations, elementBasic); + List pageFeatureResources = saasFeatureResourceDao.lambdaQuery() + .eq(SaasFeatureResource::getTerminal, dbPageElement.getTerminal()) + .in(SaasFeatureResource::getUniCode, relations.stream().map(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode).collect(Collectors.toSet())) + .in(SaasFeatureResource::getFeatureType, Lists.newArrayList(FeatureResourceType.PAGE.getCode(), FeatureResourceType.APP_ENTRY.getCode())) + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) + .list(); + if (CollectionUtils.isEmpty(pageFeatureResources)) { + return Collections.emptyList(); + } + List pageParentFeatureResources = saasFeatureResourceDao.lambdaQuery() + .eq(SaasFeatureResource::getTerminal, dbPageElement.getTerminal()) + .in(SaasFeatureResource::getId, pageFeatureResources.stream().map(SaasFeatureResource::getParentId).collect(Collectors.toSet())) + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) + .list(); + List pageChildrenFeatureResources = saasFeatureResourceDao.lambdaQuery() + .eq(BaseEntity::getIsDelete,0) + .and(i -> pageFeatureResources.forEach(f -> i.or().likeRight(SaasFeatureResource::getPath, f.getPath()))) + .list(); + List allFeatureResources = Lists.newArrayList(pageFeatureResources); + if (CollectionUtils.isNotEmpty(pageParentFeatureResources)) { + allFeatureResources.addAll(pageParentFeatureResources); + } + if (CollectionUtils.isNotEmpty(pageChildrenFeatureResources)) { + allFeatureResources.addAll(pageChildrenFeatureResources); + } - return FeatureResourcePageElementRelationViewResp.builder().featureResources(featureResourceBasics).build(); + Map uniCodeRelationMap = relations.stream() + .collect(Collectors.toMap(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode, Function.identity(), (v1, v2) -> v1)); + List reps = allFeatureResources.stream().map(e -> PageElementRelationFeatureResourceResp.builder() + .id(e.getId()) + .parentId(e.getParentId()) + .uniCode(e.getUniCode()) + .featureName(e.getFeatureName()) + .featureType(e.getFeatureType()) + .hasRelation(uniCodeRelationMap.containsKey(e.getUniCode())) + .relationType(Optional.ofNullable(uniCodeRelationMap.get(e.getUniCode())).map(SaasPageElementFeatureResourceRelation::getType).orElse(null)) + .build()).distinct().collect(Collectors.toList()); + + return TreeUtil.buildTree(reps); } @Override - public void importData(PageElementImportDataReq req) { - saasPageElementDao.lambdaQuery() + public void importData(List req) { + Integer codeCount = saasPageElementDao.lambdaQuery() .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) + .in(SaasPageElement::getCode, req.stream().map(PageElementImportDataReq::getCode).collect(Collectors.toList())) .count(); + AssertUtil.isTrue(codeCount <= 0, "导入的资源编码已存在。"); + + Set itemCodes = req.stream().map(PageElementImportDataReq::getItemCode).collect(Collectors.toSet()); + List categories = saasPageElementCategoryDao.lambdaQuery() + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) + .in(SaasPageElementCategory::getItemCode, itemCodes) + .list(); + AssertUtil.isTrue(itemCodes.size() == categories.size(), "元素分类编码系统中有未存在的。"); + Map categoryMap = categories.stream().collect(Collectors.toMap(SaasPageElementCategory::getItemCode, Function.identity(), (v1, v2) -> v1)); + + List elements = req.stream().map(e -> { + SaasPageElementCategory category = categoryMap.get(e.getItemCode()); + AssertUtil.notNull(category, e.getItemCode() + "不存在。"); + return SaasPageElement.builder() + .version(e.getVersion()) + .groupCode(e.getGroupCode()) + .code(e.getCode()) + .name(e.getName()) + .type(e.getType()) + .linkUrl(e.getLinkUrl()) + .terminal(e.getTerminal()) + .appType(e.getAppType()) + .itemCode(e.getItemCode()) + .itemName(category.getItemName()) + .createName(Optional.ofNullable(e.getOperatorId()).map(Objects::toString).orElse(StringUtils.EMPTY)) + .appId(e.getAppId()) + .build(); + }).collect(Collectors.toList()); + Lists.partition(elements,500).forEach(saasPageElementDao::saveBatch); } private PageElementResp from(SaasPageElement saasPageElement, @@ -767,134 +825,6 @@ public class SaasPageElementServiceImpl extends ServiceImpl pageElements) { - SaasPageElement pageTypeElement = pageElements.stream().filter(e -> PageElementTypeEnum.PAGE.getCode().equals(e.getType())).findFirst().orElse(null); - if (Objects.isNull(pageTypeElement)) { - return null; - } - - return FeatureResourcePageElementRelationViewResp.PageElementBasicDTO.builder() - .id(pageTypeElement.getId()) - .groupCode(pageTypeElement.getGroupCode()) - .groupName(pageTypeElement.getName()) - .code(pageTypeElement.getCode()) - .name(pageTypeElement.getName()) - .type(pageTypeElement.getType()) - .children(pageElements.stream().filter(e -> PageElementTypeEnum.COMPONENT.getCode().equals(e.getType())).map(e -> FeatureResourcePageElementRelationViewResp.PageElementBasicDTO.builder() - .id(e.getId()) - .groupCode(pageTypeElement.getGroupCode()) - .groupName(pageTypeElement.getName()) - .code(e.getCode()) - .name(e.getName()) - .type(e.getType()).build()).collect(Collectors.toList())) - .build(); - } - - private List getFeatureResourceBasic(List uniCodes, String terminal) { - List featureResources = saasFeatureResourceDao.lambdaQuery() - .eq(SaasFeatureResource::getTerminal, terminal) - .in(SaasFeatureResource::getUniCode, uniCodes) - .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) - .list(); - - List parentFrs = featureResources.stream().filter(e -> { - if (Objects.isNull(e.getFeatureType())) { - return false; - } - return FeatureResourceType.PAGE.getCode().equals(e.getFeatureType()); - }).collect(Collectors.toList()); - List componentAndAppEntityParentIds = featureResources.stream().filter(e -> { - if (Objects.isNull(e.getFeatureType())) { - return false; - } - return FeatureResourceType.COMPONENT.getCode().equals(e.getFeatureType()) || FeatureResourceType.APP_ENTRY.getCode().equals(e.getFeatureType()); - }).map(SaasFeatureResource::getParentId).collect(Collectors.toList()); - - if (CollectionUtils.isNotEmpty(componentAndAppEntityParentIds)) { - List parentResources = saasFeatureResourceDao.lambdaQuery() - .eq(SaasFeatureResource::getTerminal, terminal) - .in(SaasFeatureResource::getId, componentAndAppEntityParentIds) - .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) - .list(); - if (CollectionUtils.isNotEmpty(parentResources)) { - parentFrs.addAll(parentResources); - } - } - parentFrs = parentFrs.stream().distinct().collect(Collectors.toList()); - - Map> childrenMap = featureResources.stream().filter(e -> FeatureResourceType.COMPONENT.getCode().equals(e.getFeatureType()) - || FeatureResourceType.APP_ENTRY.getCode().equals(e.getFeatureType())).collect(Collectors.groupingBy(SaasFeatureResource::getParentId)); - List allParents = parentFrs.stream().map(e -> FeatureResourcePageElementRelationViewResp.FeatureResourceBasicDTO.builder() - .id(e.getId()) - .uniCode(e.getUniCode()) - .featureName(e.getFeatureName()) - .featureType(e.getFeatureType()) - .children(Lists.newArrayList()) - .build()).distinct().collect(Collectors.toList()); - - if (CollectionUtils.isEmpty(allParents)) { - return null; - } - for (FeatureResourcePageElementRelationViewResp.FeatureResourceBasicDTO basic : allParents) { - List children = childrenMap.get(basic.getId()); - if (CollectionUtils.isEmpty(children)) { - continue; - } - basic.setChildren(children.stream().map(e -> FeatureResourcePageElementRelationViewResp.FeatureResourceBasicDTO.builder() - .id(e.getId()) - .uniCode(e.getUniCode()) - .featureName(e.getFeatureName()) - .featureType(e.getFeatureType()) - .build()).collect(Collectors.toList())); - } - - return allParents; - } - - private void fillElementToResource(List resources, List relations, - FeatureResourcePageElementRelationViewResp.PageElementBasicDTO elementBasic) { - Map relationMap = relations.stream().collect(Collectors.toMap(r -> r.getFeatureResourceUniCode() + "_" + r.getPageElementCode(), Function.identity(), (v1, v2) -> v1)); - for (FeatureResourcePageElementRelationViewResp.FeatureResourceBasicDTO resource : resources) { - recursiveSetElementToResource(resource, relationMap, elementBasic); - } - } - - private void recursiveSetElementToResource(FeatureResourcePageElementRelationViewResp.FeatureResourceBasicDTO resource, Map relationMap, - FeatureResourcePageElementRelationViewResp.PageElementBasicDTO elementBasic) { - if (Objects.isNull(resource)) { - return; - } - if (!FeatureResourceType.GROUP.getCode().equals(resource.getFeatureType())) { - FeatureResourcePageElementRelationViewResp.PageElementBasicDTO newPageElementBasic = FeatureResourcePageElementRelationViewResp.PageElementBasicDTO.builder() - .id(elementBasic.getId()) - .groupCode(elementBasic.getGroupCode()) - .groupName(elementBasic.getGroupName()) - .code(elementBasic.getCode()) - .name(elementBasic.getName()) - .type(elementBasic.getType()) - .hasRelation(Optional.ofNullable(relationMap.get(resource.getUniCode() + "_" + elementBasic.getCode())).isPresent()) - .relationType(Optional.ofNullable(relationMap.get(resource.getUniCode() + "_" + elementBasic.getCode())).map(SaasPageElementFeatureResourceRelation::getType).orElse(0)) - .build(); - if (CollectionUtils.isNotEmpty(elementBasic.getChildren())) { - newPageElementBasic.setChildren(elementBasic.getChildren().stream().map(e -> FeatureResourcePageElementRelationViewResp.PageElementBasicDTO.builder() - .id(e.getId()) - .groupCode(e.getGroupCode()) - .groupName(e.getGroupName()) - .code(e.getCode()) - .name(e.getName()) - .type(e.getType()) - .hasRelation(Optional.ofNullable(relationMap.get(resource.getUniCode() + "_" + e.getCode())).isPresent()) - .relationType(Optional.ofNullable(relationMap.get(resource.getUniCode() + "_" + e.getCode())).map(SaasPageElementFeatureResourceRelation::getType).orElse(0)) - .build()).collect(Collectors.toList())); - } - resource.setPageElement(newPageElementBasic); - } - - if (CollectionUtils.isNotEmpty(resource.getChildren())) { - resource.getChildren().forEach(e -> recursiveSetElementToResource(e, relationMap, elementBasic)); - } - } - private List changeElementWithCategories(List list) { List resps = Lists.newArrayList(); if (CollectionUtils.isEmpty(list)) { From 3730235afe857c63cdb1db8e23d83121660e6cc2 Mon Sep 17 00:00:00 2001 From: lilong Date: Fri, 30 Aug 2024 20:27:32 +0800 Subject: [PATCH 090/112] =?UTF-8?q?feat:(REQ-2699)=20=E5=A4=84=E7=90=86?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E6=9F=A5=E8=AF=A2=E8=A7=92=E8=89=B2=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E8=A7=92=E8=89=B2=E6=97=B6=E7=9A=84bug=EF=BC=8C?= =?UTF-8?q?=E9=9C=80=E8=A6=81=E8=BF=87=E6=BB=A4=E6=8E=89=E6=97=A7=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/repository/dao/SaasPgroupPermissionRelationDao.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPgroupPermissionRelationDao.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPgroupPermissionRelationDao.java index dab85e17..f59c2b39 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPgroupPermissionRelationDao.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasPgroupPermissionRelationDao.java @@ -61,7 +61,7 @@ public class SaasPgroupPermissionRelationDao extends ServiceImpl Date: Mon, 2 Sep 2024 09:38:14 +0800 Subject: [PATCH 091/112] =?UTF-8?q?feat:(REQ-2699)=20CMP=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=97=B6=EF=BC=8C=E5=8F=AA=E6=9C=89=E7=BB=84?= =?UTF-8?q?=E4=BB=B6code=E6=9C=89=E5=8F=98=E5=8C=96=E6=89=8D=E5=8F=91?= =?UTF-8?q?=E9=80=81=E9=92=89=E9=92=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java index a79f978f..9e6484c0 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java @@ -50,6 +50,11 @@ public class SendDingTalkHandler implements InitializingBean { return; } + if (Objects.equals(payload.getAction(), SaasFeatureResource.Action.UPDATE) && + Objects.equals(payload.getNewValue().getUniCode(), payload.getOldValue().getUniCode())) { + return; + } + StringBuilder sb = new StringBuilder(); sb.append("环境:" + env + "\n"); sb.append("操作:" + payload.getAction() + "\n"); From 3efcffff7510ef61de32ec7ba7225dd9897d1716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Mon, 2 Sep 2024 12:47:06 +0800 Subject: [PATCH 092/112] =?UTF-8?q?feat(REQ-2899):=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=9A=82=E6=B2=A1?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E3=80=82=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java | 5 +++++ .../tyr/server/service/impl/SaasPageElementServiceImpl.java | 1 + 2 files changed, 6 insertions(+) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java index a2643372..47b9abab 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java @@ -21,6 +21,11 @@ public class PageQueryElementV2Req { private Long id; + /** + * 业务编码 + */ + private String itemCode; + /** * 端 */ 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 9f03e121..7d3139aa 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 @@ -504,6 +504,7 @@ public class SaasPageElementServiceImpl extends ServiceImpl page = saasPageElementDao.lambdaQuery() .eq(Objects.nonNull(request.getId()), SaasPageElement::getId, request.getId()) .eq(StringUtils.isNotBlank(request.getTerminal()), SaasPageElement::getTerminal, request.getTerminal()) + .eq(StringUtils.isNotBlank(request.getItemCode()), SaasPageElement::getItemCode, request.getItemCode()) .in(CollectionUtils.isNotEmpty(request.getElementTypes()), SaasPageElement::getType, request.getElementTypes()) .and(StringUtils.isNotBlank(request.getPageElementCodeOrName()), w -> w.like(SaasPageElement::getCode, request.getPageElementCodeOrName()) .or().like(SaasPageElement::getName, request.getPageElementCodeOrName())) From 16cb46db1c9ff498bd56f3f94096566d35a59b75 Mon Sep 17 00:00:00 2001 From: lilong Date: Mon, 2 Sep 2024 21:41:25 +0800 Subject: [PATCH 093/112] =?UTF-8?q?feat:(REQ-2699)=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E6=9B=B4=E6=96=B0=E6=97=B6=EF=BC=8C=E5=8E=BB?= =?UTF-8?q?=E6=8E=89delete=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/service/impl/ProductPermissionCacheServiceImpl.java | 2 -- .../impl/ProductSaasFeatureResourceCacheServiceImpl.java | 2 -- .../server/service/impl/RolePermissionCacheServiceImpl.java | 2 -- .../service/impl/RoleSaasFeatureResourceCacheServiceImpl.java | 3 --- 4 files changed, 9 deletions(-) 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 index 6e1415b6..f48dd604 100644 --- 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 @@ -135,8 +135,6 @@ public class ProductPermissionCacheServiceImpl implements ProductPermissionCache .stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); - // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 - redisTemplate.delete(redisKey); RedisClient.HashOps.hPutAll(redisKey, redisValues); redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); log.info("succeed to store product permission: redisKey:{} value:{}", redisKey, redisValues); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java index 97d7c6cc..8e6fca2d 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java @@ -81,8 +81,6 @@ public class ProductSaasFeatureResourceCacheServiceImpl implements ProductSaasFe .stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); - // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 - redisTemplate.delete(redisKey); RedisClient.HashOps.hPutAll(redisKey, redisValues); redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); log.info("succeed to store product featureResource: redisKey:{} value:{}", redisKey, redisValues); 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 index 43ac0dbb..cc6865b3 100644 --- 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 @@ -130,8 +130,6 @@ public class RolePermissionCacheServiceImpl implements RolePermissionCacheServic .stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); - // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 - redisTemplate.delete(redisKey); RedisClient.HashOps.hPutAll(redisKey, redisValues); redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); log.info("succeed to store role permission: redisKey:{} value:{}", redisKey, redisValues); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java index f63f3e02..a2e90b11 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java @@ -82,9 +82,6 @@ public class RoleSaasFeatureResourceCacheServiceImpl implements RoleSaasFeatureR .entrySet() .stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); - - // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 - redisTemplate.delete(redisKey); RedisClient.HashOps.hPutAll(redisKey, redisValues); redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); log.info("succeed to store role featureResource: redisKey:{} value:{}", redisKey, redisValues); From 900daa42b905c037a9a5ced5f55d40240daf415c Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 3 Sep 2024 09:00:40 +0800 Subject: [PATCH 094/112] =?UTF-8?q?feat:(REQ-2699)=20=E7=81=B0=E5=BA=A6del?= =?UTF-8?q?ete=E9=80=BB=E8=BE=91=EF=BC=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/service/impl/ProductPermissionCacheServiceImpl.java | 2 ++ .../impl/ProductSaasFeatureResourceCacheServiceImpl.java | 2 ++ .../server/service/impl/RolePermissionCacheServiceImpl.java | 2 ++ .../service/impl/RoleSaasFeatureResourceCacheServiceImpl.java | 3 +++ 4 files changed, 9 insertions(+) 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 index f48dd604..6e1415b6 100644 --- 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 @@ -135,6 +135,8 @@ public class ProductPermissionCacheServiceImpl implements ProductPermissionCache .stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); + // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 + redisTemplate.delete(redisKey); RedisClient.HashOps.hPutAll(redisKey, redisValues); redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); log.info("succeed to store product permission: redisKey:{} value:{}", redisKey, redisValues); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java index 8e6fca2d..97d7c6cc 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java @@ -81,6 +81,8 @@ public class ProductSaasFeatureResourceCacheServiceImpl implements ProductSaasFe .stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); + // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 + redisTemplate.delete(redisKey); RedisClient.HashOps.hPutAll(redisKey, redisValues); redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); log.info("succeed to store product featureResource: redisKey:{} value:{}", redisKey, redisValues); 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 index cc6865b3..43ac0dbb 100644 --- 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 @@ -130,6 +130,8 @@ public class RolePermissionCacheServiceImpl implements RolePermissionCacheServic .stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); + // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 + redisTemplate.delete(redisKey); RedisClient.HashOps.hPutAll(redisKey, redisValues); redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); log.info("succeed to store role permission: redisKey:{} value:{}", redisKey, redisValues); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java index a2e90b11..f63f3e02 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java @@ -82,6 +82,9 @@ public class RoleSaasFeatureResourceCacheServiceImpl implements RoleSaasFeatureR .entrySet() .stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); + + // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 + redisTemplate.delete(redisKey); RedisClient.HashOps.hPutAll(redisKey, redisValues); redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); log.info("succeed to store role featureResource: redisKey:{} value:{}", redisKey, redisValues); From bf389fa81ae8f72f3c3f9156d8ca507cd61e7671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Tue, 3 Sep 2024 12:56:33 +0800 Subject: [PATCH 095/112] =?UTF-8?q?feat(REQ-2899):=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=9A=82=E6=B2=A1?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E3=80=82=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java | 1 + 1 file changed, 1 insertion(+) 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 7d3139aa..1124f9fc 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 @@ -680,6 +680,7 @@ public class SaasPageElementServiceImpl extends ServiceImpl req) { + log.info("导入资源的数量:{}", req.size()); Integer codeCount = saasPageElementDao.lambdaQuery() .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) .in(SaasPageElement::getCode, req.stream().map(PageElementImportDataReq::getCode).collect(Collectors.toList())) From ab3e0b5ef97dc42d5a96de01a966914a9f8d2b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Tue, 3 Sep 2024 18:12:15 +0800 Subject: [PATCH 096/112] =?UTF-8?q?feat(REQ-2899):=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=9A=82=E6=B2=A1?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E3=80=82=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/service/impl/SaasPageElementServiceImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 1124f9fc..223d8efc 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 @@ -692,9 +692,8 @@ public class SaasPageElementServiceImpl extends ServiceImpl categoryMap = categories.stream().collect(Collectors.toMap(SaasPageElementCategory::getItemCode, Function.identity(), (v1, v2) -> v1)); - List elements = req.stream().map(e -> { SaasPageElementCategory category = categoryMap.get(e.getItemCode()); AssertUtil.notNull(category, e.getItemCode() + "不存在。"); From 991661c1fc631aa691ac3f6ad37417828bbdbc89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Wed, 4 Sep 2024 11:18:26 +0800 Subject: [PATCH 097/112] =?UTF-8?q?feat(REQ-2899):=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E5=85=83=E7=B4=A0=E5=88=86=E7=B1=BB=E3=80=81=E5=85=83=E7=B4=A0?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8F=91=E9=80=81mq=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/SaasPageElementCategoryServiceImpl.java | 16 ++++++++++++++++ .../service/impl/SaasPageElementServiceImpl.java | 9 +++++++++ 2 files changed, 25 insertions(+) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementCategoryServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementCategoryServiceImpl.java index 09120600..3cbabbeb 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementCategoryServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementCategoryServiceImpl.java @@ -2,12 +2,15 @@ package cn.axzo.tyr.server.service.impl; import cn.axzo.basics.common.constant.enums.DeleteEnum; import cn.axzo.basics.common.util.AssertUtil; +import cn.axzo.framework.rocketmq.Event; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.common.enums.PermissionRelationOperateLogSceneEnum; import cn.axzo.tyr.client.model.req.DeletePageElementCategoryReq; import cn.axzo.tyr.client.model.req.PermissionOperateLogReq; import cn.axzo.tyr.client.model.req.SaveOrUpdatePageElementCategoryReq; import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp; +import cn.axzo.tyr.server.config.MqProducer; +import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.repository.dao.SaasPageElementCategoryDao; import cn.axzo.tyr.server.repository.dao.SaasPageElementDao; import cn.axzo.tyr.server.repository.dao.SaasPageElementFeatureResourceRelationDao; @@ -27,6 +30,8 @@ import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; +import static cn.axzo.tyr.server.event.inner.EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT; + /** * @author likunpeng * @version 1.0 @@ -38,11 +43,13 @@ import java.util.stream.Collectors; public class SaasPageElementCategoryServiceImpl implements SaasPageElementCategoryService { public static final String PAGE_ELEMENT_CATEGORY_TABLE_NAME = "saas_page_element_category"; + private static final String TARGET_TYPE = "pageElementFeatureResourceId"; private final SaasPageElementCategoryDao saasPageElementCategoryDao; private final SaasPageElementDao saasPageElementDao; private final SaasPageElementFeatureResourceRelationDao saasPageElementFeatureResourceRelationDao; private final SaasPgroupPermissionRelationOperateLogService saasPgroupPermissionRelationOperateLogService; + private final MqProducer mqProducer; @Override public List listGroupByTerminal() { @@ -132,6 +139,15 @@ public class SaasPageElementCategoryServiceImpl implements SaasPageElementCatego } catch (Exception e) { log.warn("save operate log error", e); } + + Event event = Event.builder() + .targetType(TARGET_TYPE) + .eventCode(PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode()) + .data(PageElementFeatureResourceUpsertPayload.builder() + .terminal(dbCategory.getTerminal()) + .build()) + .build(); + mqProducer.send(event); } private void validItemCode(String itemCode) { 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 223d8efc..0835ef13 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 @@ -621,6 +621,15 @@ public class SaasPageElementServiceImpl extends ServiceImpl Date: Thu, 5 Sep 2024 09:34:54 +0800 Subject: [PATCH 098/112] =?UTF-8?q?feat(REQ-2899):cms=E4=B8=8A=E6=8A=A5?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=88=86=E7=B1=BBcode=E5=92=8C=E5=90=8D?= =?UTF-8?q?=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/service/impl/SaasPageElementServiceImpl.java | 4 ++++ 1 file changed, 4 insertions(+) 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 0835ef13..0602c9f7 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 @@ -318,6 +318,8 @@ public class SaasPageElementServiceImpl extends ServiceImpl Date: Thu, 5 Sep 2024 14:10:11 +0800 Subject: [PATCH 099/112] =?UTF-8?q?feat(REQ-2899):cms=E4=B8=8A=E6=8A=A5?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=B5=84=E6=BA=90appType?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/service/impl/SaasPageElementServiceImpl.java | 2 ++ 1 file changed, 2 insertions(+) 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 0602c9f7..b9a9d192 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 @@ -318,6 +318,7 @@ public class SaasPageElementServiceImpl extends ServiceImpl Date: Thu, 5 Sep 2024 14:25:52 +0800 Subject: [PATCH 100/112] =?UTF-8?q?feat(REQ-2899):cms=E4=B8=8A=E6=8A=A5?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=B5=84=E6=BA=90appType?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/enums/PageElementAppTypeEnum.java | 16 ++++++++++++++++ .../service/impl/SaasPageElementServiceImpl.java | 9 +++------ 2 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/PageElementAppTypeEnum.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/PageElementAppTypeEnum.java b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/PageElementAppTypeEnum.java new file mode 100644 index 00000000..484edad4 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/PageElementAppTypeEnum.java @@ -0,0 +1,16 @@ +package cn.axzo.tyr.client.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/9/5 + */ +@Getter +@AllArgsConstructor +public enum PageElementAppTypeEnum { + + PC,H5,APP; +} 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 b9a9d192..413c9387 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 @@ -13,10 +13,7 @@ import cn.axzo.foundation.exception.BusinessException; import cn.axzo.framework.domain.page.PageResp; import cn.axzo.framework.rocketmq.Event; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; -import cn.axzo.tyr.client.common.enums.FeatureResourceType; -import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum; -import cn.axzo.tyr.client.common.enums.PageElementTypeEnum; -import cn.axzo.tyr.client.common.enums.PermissionRelationOperateLogSceneEnum; +import cn.axzo.tyr.client.common.enums.*; import cn.axzo.tyr.client.model.req.*; import cn.axzo.tyr.client.model.res.*; import cn.axzo.tyr.server.config.MqProducer; @@ -318,7 +315,7 @@ public class SaasPageElementServiceImpl extends ServiceImpl Date: Fri, 6 Sep 2024 11:28:51 +0800 Subject: [PATCH 101/112] =?UTF-8?q?feat:(HOTFIX)=20=E5=A4=84=E7=90=86?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E6=B2=A1=E6=9C=89=E6=9C=8D=E5=8A=A1=E5=8C=85?= =?UTF-8?q?=E5=AF=B9=E5=BA=94=E7=9A=84=E4=BA=A7=E5=93=81=E7=9A=84=E6=83=85?= =?UTF-8?q?=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/service/impl/WorkspaceProductServiceImpl.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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 ecf78d73..0c3b6463 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 @@ -240,9 +240,11 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService { List workspaceProductDTOS = Lists.newArrayList(); servicePkgDetailRes.forEach(e -> { - Set workpsaceProductIds = e.getProducts().stream() - .map(ServicePkgProduct::getProductId) - .collect(Collectors.toSet()); + Set workpsaceProductIds = Optional.ofNullable(e.getProducts()) + .map(products -> products.stream() + .map(ServicePkgProduct::getProductId) + .collect(Collectors.toSet())) + .orElse(null); if (CollectionUtils.isEmpty(workpsaceProductIds)) { return; } From 5b99747ed097be48587fd21b352830c1b933022a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Fri, 6 Sep 2024 14:44:00 +0800 Subject: [PATCH 102/112] =?UTF-8?q?feat(REQ-2899):=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E5=85=B3=E8=81=94=E5=85=B3=E7=B3=BB=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/SaasPageElementServiceImpl.java | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) 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 413c9387..9a1f533c 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 @@ -649,15 +649,11 @@ public class SaasPageElementServiceImpl extends ServiceImpl pageFeatureResources = saasFeatureResourceDao.lambdaQuery() - .eq(SaasFeatureResource::getTerminal, dbPageElement.getTerminal()) - .in(SaasFeatureResource::getUniCode, relations.stream().map(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode).collect(Collectors.toSet())) - .in(SaasFeatureResource::getFeatureType, Lists.newArrayList(FeatureResourceType.PAGE.getCode(), FeatureResourceType.APP_ENTRY.getCode())) - .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) - .list(); + List pageFeatureResources = getPageFeatureResources(dbPageElement.getTerminal(), relations.stream().map(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode).collect(Collectors.toList())); if (CollectionUtils.isEmpty(pageFeatureResources)) { return Collections.emptyList(); } + List pageParentFeatureResources = saasFeatureResourceDao.lambdaQuery() .eq(SaasFeatureResource::getTerminal, dbPageElement.getTerminal()) .in(SaasFeatureResource::getId, pageFeatureResources.stream().map(SaasFeatureResource::getParentId).collect(Collectors.toSet())) @@ -856,4 +852,22 @@ public class SaasPageElementServiceImpl extends ServiceImpl getPageFeatureResources(String terminal, List uniCodes) { + List pageFeatureResources = saasFeatureResourceDao.lambdaQuery() + .eq(SaasFeatureResource::getTerminal, terminal) + .in(SaasFeatureResource::getUniCode, uniCodes) + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) + .list(); + + List allIds = pageFeatureResources.stream().map(e -> Arrays.stream(e.getPath().split(",")).filter(StringUtils::isNotBlank).map(Long::valueOf) + .collect(Collectors.toList())).flatMap(List::stream).distinct().collect(Collectors.toList()); + + return saasFeatureResourceDao.lambdaQuery() + .eq(SaasFeatureResource::getTerminal, terminal) + .in(SaasFeatureResource::getId, allIds) + .in(SaasFeatureResource::getFeatureType, Lists.newArrayList(FeatureResourceType.PAGE.getCode(), FeatureResourceType.APP_ENTRY.getCode())) + .eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue()) + .list(); + } } From 8a8c40be9e61a510312bbf79381b41023a8a6f64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Fri, 6 Sep 2024 16:14:49 +0800 Subject: [PATCH 103/112] =?UTF-8?q?feat(REQ-2899):=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E5=85=B3=E8=81=94=E5=85=B3=E7=B3=BB=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/permission/FeatureResourceController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 fff49fd2..7deb0210 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 @@ -10,6 +10,7 @@ import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; import cn.axzo.tyr.server.service.FeatureResourceSyncService; import cn.axzo.tyr.server.service.SaasFeatureResourceService; import cn.hutool.core.collection.CollectionUtil; +import com.alibaba.fastjson.JSON; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RestController; @@ -52,7 +53,7 @@ public class FeatureResourceController implements FeatureResourceApi { @Override public ApiResult saveMenu(FeatureResourceTreeSaveReq req) { - log.info("save feature resource req : " + req.toString()); + log.info("save feature resource req : " + JSON.toJSONString(req)); Long featureId = featureResourceService.saveOrUpdateMenu(req); log.info("save feature resource resp : " + featureId.toString()); return ApiResult.ok(featureId); From a033919e17d32b902ff9ec7471ae73d43442ed46 Mon Sep 17 00:00:00 2001 From: lilong Date: Wed, 11 Sep 2024 15:12:28 +0800 Subject: [PATCH 104/112] =?UTF-8?q?feat:(hotfix/20240906)=20=E6=8A=8A?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E3=80=81=E8=A7=92=E8=89=B2=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E3=80=81=E4=BA=A7=E5=93=81=E8=8F=9C=E5=8D=95=E3=80=81=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E6=9D=83=E9=99=90=E3=80=81=E8=A7=92=E8=89=B2=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E4=BB=8Eredis=E7=BC=93=E5=AD=98=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E5=88=B0=E6=9C=AC=E5=9C=B0=E5=86=85=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/RocketMQEventConfiguration.java | 7 +- .../server/controller/PrivateController.java | 146 +++--- .../inner/CacheProductPermissionHandler.java | 284 +----------- ...acheProductSaasFeatureResourceHandler.java | 194 +------- .../inner/CacheRolePermissionHandler.java | 272 +---------- .../CacheRoleSaasFeatureResourceHandler.java | 174 +------ .../event/inner/CacheSaasFeatureHandler.java | 9 +- .../CacheSaasFeatureResourceHandler.java | 9 +- .../job/CacheProductFeatureResourceJob.java | 19 +- .../server/job/CacheProductPermissionJob.java | 20 +- .../job/CacheRoleFeatureResourceJob.java | 106 +---- .../server/job/CacheRolePermissionJob.java | 103 +--- .../tyr/server/job/CacheSaasFeatureJob.java | 74 +-- .../ProductPermissionCacheService.java | 19 +- ...roductSaasFeatureResourceCacheService.java | 10 +- .../service/RolePermissionCacheService.java | 21 +- .../RoleSaasFeatureResourceCacheService.java | 9 +- .../service/SaasFeatureResourceService.java | 12 +- .../ProductPermissionCacheServiceImpl.java | 438 +++++++++++------- ...ctSaasFeatureResourceCacheServiceImpl.java | 311 ++++++++----- .../impl/RolePermissionCacheServiceImpl.java | 425 +++++++++++------ ...leSaasFeatureResourceCacheServiceImpl.java | 298 +++++++----- .../impl/SaasFeatureResourceServiceImpl.java | 137 +++--- 23 files changed, 1260 insertions(+), 1837 deletions(-) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/config/RocketMQEventConfiguration.java b/tyr-server/src/main/java/cn/axzo/tyr/server/config/RocketMQEventConfiguration.java index 86ff70f1..f418db02 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/config/RocketMQEventConfiguration.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/config/RocketMQEventConfiguration.java @@ -9,6 +9,7 @@ import cn.axzo.framework.rocketmq.RocketMQEventProducer; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.spring.annotation.ConsumeMode; +import org.apache.rocketmq.spring.annotation.MessageModel; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; import org.apache.rocketmq.spring.core.RocketMQListener; import org.apache.rocketmq.spring.core.RocketMQTemplate; @@ -67,7 +68,7 @@ public class RocketMQEventConfiguration { @Component @RocketMQMessageListener(topic = "topic_thrones_${spring.profiles.active}", consumerGroup = "GID_topic_thrones_${spring.application.name}_${spring.profiles.active}", - consumeMode = ConsumeMode.ORDERLY, + messageModel = MessageModel.BROADCASTING, nameServer = "${rocketmq.name-server}" ) public static class ThronesListener extends BaseListener implements RocketMQListener { @@ -85,7 +86,7 @@ public class RocketMQEventConfiguration { @Component @RocketMQMessageListener(topic = "topic_tyr_${spring.profiles.active}", consumerGroup = "GID_topic_tyr_${spring.application.name}_${spring.profiles.active}", - consumeMode = ConsumeMode.ORDERLY, + messageModel = MessageModel.BROADCASTING, nameServer = "${rocketmq.name-server}" ) public static class TyrListener extends BaseListener implements RocketMQListener { @@ -103,7 +104,7 @@ public class RocketMQEventConfiguration { @Component @RocketMQMessageListener(topic = "topic_apisix_plat_${spring.profiles.active}", consumerGroup = "GID_topic_apisix_plat_${spring.application.name}_${spring.profiles.active}", - consumeMode = ConsumeMode.ORDERLY, + messageModel = MessageModel.BROADCASTING, nameServer = "${rocketmq.name-server}" ) public static class ApiSixPlatListener extends BaseListener implements RocketMQListener { 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 fc1845b8..e0d94537 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 @@ -180,6 +180,8 @@ public class PrivateController { private RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService; @Autowired private SendDingTalkHandler sendDingTalkHandler; + @Autowired + private ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService; /** * 统一层级的roleGroup按照id升序,sort从1递增 @@ -363,22 +365,17 @@ public class PrivateController { }); } - @PostMapping("/api/private/productPermission/add") - public Object addProductPermission(@Validated @RequestBody ProductPermissionCacheService.StoreProductPermissionParam request) { - productPermissionCacheService.store(request); + @PostMapping("/api/private/productPermission/refresh") + public Object addProductPermission(@Validated @RequestBody ProductPermissionCacheService.RefreshProductPermissionCacheParam request) { + productPermissionCacheService.refreshCache(request); return "ok"; } - @PostMapping("/api/private/productPermission/get") + @PostMapping("/api/private/productPermission/list") 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); - } - @PostMapping("/api/private/permission/auth") public Object authPermission(@Validated @RequestBody PermissionCheckReq request) { return tyrSaasAuthService.authPermission(request); @@ -634,6 +631,12 @@ public class PrivateController { return featureCodeUtil.resolveFeatureCode(request.getFeatureCodes()); } + /** + * 缓存产品权限 + * @param request + * @return + * @throws Exception + */ @PostMapping("/api/private/productPermission/store") public Object storeProductPermission(@RequestBody ProductSearchListReq request) throws Exception { cacheProductPermissionJob.execute(JSON.toJSONString(request)); @@ -666,104 +669,109 @@ public class PrivateController { return "ok"; } - @PostMapping("/api/private/role/insert") - public Object insertRole(@RequestPart("file") MultipartFile file) throws IOException { - - List importExcels = EasyExcel.read(file.getInputStream()) - .head(CreateRoleParam.class) - .sheet() - .doReadSync(); - - importExcels = importExcels.stream() - .filter(e -> Objects.equals(e.getType(), "c")) - .filter(e -> Objects.nonNull(e.getGroupId())) - .collect(Collectors.toList()); - - Set roleGroupIds = importExcels.stream() - .map(CreateRoleParam::getGroupId) - .collect(Collectors.toSet()); - - Map saasRoleGroups = saasRoleGroupDao.listByIds(roleGroupIds).stream() - .collect(Collectors.toMap(SaasRoleGroup::getId, Function.identity())); - - importExcels.forEach(e -> { - - SaasRoleGroup saasRoleGroup = saasRoleGroups.get(e.getGroupId()); - if (saasRoleGroup == null) { - log.info("not found saasRoleGroup,{}", e.getGroupId()); - return; - } - - SaveOrUpdateRoleVO.GroupInfoVO groupInfoVO = new SaveOrUpdateRoleVO.GroupInfoVO(); - groupInfoVO.setId(e.getGroupId()); - groupInfoVO.setWorkspaceTypeCode(saasRoleGroup.getWorkspaceTypeCode()); - SaveOrUpdateRoleVO saveOrUpdateRoleVO = SaveOrUpdateRoleVO.builder() - .name(e.getRoleName()) - .roleType("init") - .workspaceId(-1L) - .ownerOuId(-1L) - .operatorId(2007696L) - .operatorName("李龙") - .groupTree(Lists.newArrayList(groupInfoVO)) - .permissionGroupName("通用权限") - .permissionGroupType("feature") - .roleCode(e.getRoleCode()) - .isDisplay(true) - .enabled(true) - .build(); - try { - roleService.saveOrUpdate(saveOrUpdateRoleVO); - } catch (Exception ex) { - log.info("roleName {},ex:", e.getRoleName(), ex); - } - }); - return "ok"; - } - + /** + * 缓存角色权限 + * @param request + * @return + * @throws Exception + */ @PostMapping("/api/private/rolePermission/store") - public Object storeRolePermission(@RequestBody RoleService.PageSaasRoleParam request) throws Exception { + public Object storeRolePermission(@RequestBody RoleService.ListSaasRoleParam request) throws Exception { cacheRolePermissionJob.execute(JSON.toJSONString(request)); return "ok"; } + /** + * 缓存菜单 + * @param request + * @return + * @throws Exception + */ @PostMapping("/api/private/saasFeature/store") public Object storeSaasFeature(@RequestBody StoreFeatureParam request) throws Exception { cacheSaasFeatureJob.execute(JSON.toJSONString(request)); return "ok"; } + /** + * 缓存产品菜单 + * @param request + * @return + * @throws Exception + */ @PostMapping("/api/private/productSaasFeature/store") public Object storeProductSaasFeature(@RequestBody ProductSearchListReq request) throws Exception { cacheProductFeatureResourceJob.execute(JSON.toJSONString(request)); return "ok"; } + /** + * 缓存角色菜单 + * @param request + * @return + * @throws Exception + */ @PostMapping("/api/private/roleSaasFeature/store") public Object storeRoleSaasFeature(@RequestBody RoleService.PageSaasRoleParam request) throws Exception { cacheRoleFeatureResourceJob.execute(JSON.toJSONString(request)); return "ok"; } - @PostMapping("/api/private/saasFeature/list") - public Object listSaasFeature(@RequestBody SaasFeatureResourceService.ListSaasFeatureResourceCache request) throws Exception { - return saasFeatureResourceService.listCache(request); - } - @PostMapping("/api/private/workspaceProductCached/list") public Object workspaceProductCached(@RequestBody WorkspaceProductService.ListWorkspaceProductPermissionCacheParam request) { return workspaceProductService.listWorkspaceProductPermissionCached(request); } + /** + * 查询角色权限 + * @param request + * @return + */ @PostMapping("/api/private/rolePermissionCache/list") public Object rolePermissionCache(@RequestBody RolePermissionCacheService.ListRolePermissionParam request) { return rolePermissionCacheService.list(request); } + /** + * 查询产品权限 + * @param request + * @return + */ @PostMapping("/api/private/productPermissionCached/list") public Object productPermissionCached(@RequestBody ProductPermissionCacheService.ListProductPermissionParam request) { return productPermissionCacheService.list(request); } + /** + * 查询角色菜单 + * @param request + * @return + */ + @PostMapping("/api/private/roleSaasFeatureResourceCache/list") + public Object listRoleSaasFeatureResourceCache(@RequestBody RoleSaasFeatureResourceCacheService.ListRoleSaasFeatureResourceParam request) { + return roleSaasFeatureResourceCacheService.list(request); + } + + /** + * 查询产品菜单 + * @param request + * @return + */ + @PostMapping("/api/private/productFeatureResourceCached/list") + public Object listProductSaasFeatureResourceCache(@RequestBody ProductSaasFeatureResourceCacheService.ListProductFeatureResourceParam request) { + return productSaasFeatureResourceCacheService.list(request); + } + + /** + * 查询菜单树 + * @param request + * @return + */ + @PostMapping("/api/private/featureResourceCache/list") + public Object listSaasFeatureResourceCache(@RequestBody SaasFeatureResourceService.ListSaasFeatureResourceCache request) { + return saasFeatureResourceService.listCache(request); + } + @PostMapping("/api/private/saasPageElement/refreshCmpFeatureResourceLinkUrl") public ApiResult refreshCmpFeatureResourceLinkUrl(@RequestBody RefreshFeatureResourceLinkUrlParam request) { Long startId = 0L; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java index a39257d2..3c5a48fa 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductPermissionHandler.java @@ -2,18 +2,12 @@ package cn.axzo.tyr.server.event.inner; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; -import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq; -import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; -import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; +import cn.axzo.tyr.client.model.product.ProductSearchListReq; +import cn.axzo.tyr.client.model.product.ProductVO; import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload; -import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; -import cn.axzo.tyr.server.repository.entity.SaasFeature; -import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; -import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductPermissionCacheService; -import cn.axzo.tyr.server.service.SaasFeatureResourceService; -import com.google.common.collect.Lists; +import cn.axzo.tyr.server.service.ProductService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; @@ -21,18 +15,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -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.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; - /** * 缓存产品的权限 */ @@ -45,29 +30,8 @@ public class CacheProductPermissionHandler implements InitializingBean { @Autowired private ProductPermissionCacheService productPermissionCacheService; @Autowired - private ProductFeatureRelationService productFeatureRelationService; - @Autowired - private SaasFeatureResourceService saasFeatureResourceService; - @Autowired - private SaasFeatureDao saasFeatureDao; + private ProductService productService; - private void storeProductPermission(List productFeatures) { - - if (CollectionUtils.isEmpty(productFeatures)) { - return; - } - - List productPermissions = resolveProductPermissions(productFeatures); - - if (CollectionUtils.isEmpty(productPermissions)) { - return; - } - - ProductPermissionCacheService.StoreProductPermissionParam storeProductPermissionParam = ProductPermissionCacheService.StoreProductPermissionParam.builder() - .productPermissions(productPermissions) - .build(); - productPermissionCacheService.store(storeProductPermissionParam); - } public void onProductPermissionUpsert(Event event, EventConsumer.Context context) { log.info("begin cached product permission handler rocketmq event: {}", event); @@ -76,16 +40,11 @@ public class CacheProductPermissionHandler implements InitializingBean { if (CollectionUtils.isEmpty(payload.getProductModuleIds())) { return; } - PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() - .productModuleIds(payload.getProductModuleIds()) + + ProductPermissionCacheService.RefreshProductPermissionCacheParam param = ProductPermissionCacheService.RefreshProductPermissionCacheParam.builder() + .productIds(payload.getProductModuleIds()) .build(); - List productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq); - - if (CollectionUtils.isEmpty(productFeatures)) { - return; - } - - storeProductPermission(productFeatures); + productPermissionCacheService.refreshCache(param); log.info("end cached product permission handler rocketmq event: {}", event); } @@ -97,14 +56,17 @@ public class CacheProductPermissionHandler implements InitializingBean { return; } - PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() - .build(); - List productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq); - - if (CollectionUtils.isEmpty(productFeatures)) { + Set productIds = productService.list(new ProductSearchListReq()).getData().stream() + .map(ProductVO::getId) + .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(productIds)) { return; } - storeProductPermission(productFeatures); + + ProductPermissionCacheService.RefreshProductPermissionCacheParam param = ProductPermissionCacheService.RefreshProductPermissionCacheParam.builder() + .productIds(productIds) + .build(); + productPermissionCacheService.refreshCache(param); log.info("end cached product permission handler rocketmq event: {}", event); } @@ -113,216 +75,4 @@ public class CacheProductPermissionHandler implements InitializingBean { eventConsumer.registerHandler(EventTypeEnum.PRODUCT_PERMISSION_CREATED.getEventCode(), this::onProductPermissionUpsert); eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert); } - - public List resolveProductPermissions(List productPermissions) { - if (CollectionUtils.isEmpty(productPermissions)) { - return Collections.emptyList(); - } - - // 新的菜单树是是把有权限点的父节点也存进去了,所以直接解析 - Map featureResources = listSaasFeatureResource(productPermissions); - - Map parentFeatureResources = listParentSaasFeatureResource(featureResources); - - // 旧的菜单树只存储了权限点信息,没有把父节点存进去,需要解析父节点进行存储 - Map saasFeatures = listSaasFeature(productPermissions); - - Map parentSaasFeatures = listParentSaasFeature(saasFeatures); - - return productPermissions.stream() - .collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId)) - .entrySet() - .stream() - .map(e -> { - List productFeatureRelations = e.getValue(); - - if (CollectionUtils.isEmpty(productFeatureRelations)) { - return null; - } - - List permissions = productFeatureRelations.stream() - .map(relation -> { - if (Objects.equals(relation.getType(), NEW_FEATURE)) { - return resolveFeatureResourcePermission(relation, featureResources, parentFeatureResources); - } - - return resolveFeaturePermission(relation, saasFeatures, parentSaasFeatures); - }) - .filter(Objects::nonNull) - .flatMap(Collection::stream) - .distinct() - .collect(Collectors.toList()); - - if (CollectionUtils.isEmpty(permissions)) { - return null; - } - - return ProductPermissionCacheService.ProductPermission.builder() - .productId(e.getKey()) - .permissions(permissions) - .build(); - - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } - - private List resolveFeaturePermission(SaasProductModuleFeatureRelation relation, Map saasFeatures, Map parentSaasFeatures) { - SaasFeature saasFeature = saasFeatures.get(relation.getFeatureId()); - if (Objects.isNull(saasFeature)) { - return null; - } - - List permissionDTOS = Lists.newArrayList(ProductPermissionCacheService.PermissionDTO.builder() - .featureId(saasFeature.getId()) - .featureCode(saasFeature.getFeatureCode()) - .featureType(saasFeature.getFeatureType()) - .terminal(saasFeature.getTerminal()) - .cooperateType(relation.getDictCode()) - .build()); - - List parentPermissions = saasFeature.splitPath().stream() - .map(parentSaasFeatures::get) - .filter(Objects::nonNull) - .map(f -> ProductPermissionCacheService.PermissionDTO.builder() - .featureId(f.getId()) - .featureCode(f.getFeatureCode()) - .featureType(f.getFeatureType()) - .terminal(f.getTerminal()) - .cooperateType(relation.getDictCode()) - .build()) - .collect(Collectors.toList()); - - permissionDTOS.addAll(parentPermissions); - return permissionDTOS; - } - - private List resolveFeatureResourcePermission(SaasProductModuleFeatureRelation relation, Map featureResources, Map parentFeatureResources) { - SaasFeatureResourceResp featureResource = featureResources.get(relation.getFeatureId()); - // 菜单节点是不会关联元素code,所以缓存的featureCode使用菜单编码 - if (Objects.isNull(featureResource)) { - return null; - } - - if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) { - return null; - } - - List permissionDTOS = featureResource.getSaasPageElements().stream() - .map(pageElement -> ProductPermissionCacheService.PermissionDTO.builder() - .featureId(featureResource.getId()) - .featureCode(pageElement.getCode()) - .featureType(featureResource.getFeatureType()) - .terminal(featureResource.getTerminal()) - .cooperateType(relation.getDictCode()) - .itemCode(pageElement.getItemCode()) - .version(pageElement.getVersion()) - .appType(pageElement.getAppType()) - .build()) - .collect(Collectors.toList()); - - List parentPermissions = featureResource.resolvePath().stream() - .map(parentFeatureResources::get) - .filter(Objects::nonNull) - .map(f -> { - if (CollectionUtils.isEmpty(f.getSaasPageElements())) { - return null; - } - - return f.getSaasPageElements().stream() - .map(pageElement -> ProductPermissionCacheService.PermissionDTO.builder() - .featureId(f.getId()) - .featureCode(pageElement.getCode()) - .featureType(f.getFeatureType()) - .terminal(f.getTerminal()) - .cooperateType(relation.getDictCode()) - .itemCode(pageElement.getItemCode()) - .version(pageElement.getVersion()) - .appType(pageElement.getAppType()) - .build()) - .collect(Collectors.toList()); - }) - .filter(Objects::nonNull) - .flatMap(Collection::stream) - .collect(Collectors.toList()); - - permissionDTOS.addAll(parentPermissions); - return permissionDTOS; - } - - - private Map listSaasFeatureResource(List productPermissions) { - - List featureIds = productPermissions.stream() - .filter(e -> Objects.equals(e.getType(), NEW_FEATURE)) - .map(SaasProductModuleFeatureRelation::getFeatureId) - .distinct() - .collect(Collectors.toList()); - - if (CollectionUtils.isEmpty(featureIds)) { - return Collections.emptyMap(); - } - - PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() - .ids(featureIds) - .needPageElement(true) - .build(); - return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() - .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); - } - - private Map listParentSaasFeatureResource(Map productPermissions) { - - List parentIds = productPermissions.values().stream() - .map(SaasFeatureResourceResp::resolvePath) - .flatMap(Collection::stream) - .distinct() - .collect(Collectors.toList()); - - if (CollectionUtils.isEmpty(parentIds)) { - return Collections.emptyMap(); - } - - PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() - .ids(parentIds) - .needPageElement(true) - .build(); - return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() - .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); - } - - private Map listSaasFeature(List productPermissions) { - - Set featureIds = productPermissions.stream() - .filter(e -> Objects.equals(e.getType(), OLD_FEATURE)) - .map(SaasProductModuleFeatureRelation::getFeatureId) - .collect(Collectors.toSet()); - - if (CollectionUtils.isEmpty(featureIds)) { - return Collections.emptyMap(); - } - - return saasFeatureDao.listByIds(featureIds).stream() - .collect(Collectors.toMap(SaasFeature::getId, Function.identity())); - } - - private Map listParentSaasFeature(Map saasFeatures) { - - if (CollectionUtils.isEmpty(saasFeatures)) { - return Collections.emptyMap(); - } - - List parentIds = saasFeatures.values().stream() - .map(SaasFeature::splitPath) - .flatMap(Collection::stream) - .distinct() - .collect(Collectors.toList()); - - if (CollectionUtils.isEmpty(parentIds)) { - return Collections.emptyMap(); - } - - return saasFeatureDao.listByIds(parentIds).stream() - .collect(Collectors.toMap(SaasFeature::getId, Function.identity())); - } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java index 113ca793..56c680e8 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheProductSaasFeatureResourceHandler.java @@ -2,20 +2,12 @@ package cn.axzo.tyr.server.event.inner; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; -import cn.axzo.tyr.client.common.enums.FeatureResourceType; -import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum; -import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq; -import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; -import cn.axzo.tyr.client.model.res.PageElementResp; -import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; +import cn.axzo.tyr.client.model.product.ProductSearchListReq; +import cn.axzo.tyr.client.model.product.ProductVO; import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload; -import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; -import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductSaasFeatureResourceCacheService; -import cn.axzo.tyr.server.service.SaasFeatureResourceService; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; +import cn.axzo.tyr.server.service.ProductService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; @@ -23,18 +15,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.Collection; -import java.util.Collections; -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.SaasPgroupPermissionRelation.NEW_FEATURE; - @Slf4j @Component public class CacheProductSaasFeatureResourceHandler implements InitializingBean { @@ -42,36 +25,9 @@ public class CacheProductSaasFeatureResourceHandler implements InitializingBean @Autowired private EventConsumer eventConsumer; @Autowired - private ProductFeatureRelationService productFeatureRelationService; - @Autowired private ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService; @Autowired - private SaasFeatureResourceService saasFeatureResourceService; - - public static final Set FEATURE_RESOURCE_TYPES = Sets.newHashSet(FeatureResourceType.MENU.getCode(), - FeatureResourceType.PAGE.getCode(), - FeatureResourceType.MENU_PARTITION_GROUP.getCode(), - FeatureResourceType.GROUP.getCode(), - FeatureResourceType.APP_ENTRY.getCode()); - - private void storeProductFeatureResource(List productFeatures) { - - if (CollectionUtils.isEmpty(productFeatures)) { - return; - } - - List productFeatureResources = resolveProductFeatureResources(productFeatures); - - if (CollectionUtils.isEmpty(productFeatureResources)) { - return; - } - - ProductSaasFeatureResourceCacheService.StoreProductFeatureResourceParam storeProductFeatureResourceParam = ProductSaasFeatureResourceCacheService.StoreProductFeatureResourceParam.builder() - .productFeatureResources(productFeatureResources) - .build(); - productSaasFeatureResourceCacheService.store(storeProductFeatureResourceParam); - - } + private ProductService productService; public void onProductPermissionUpsert(Event event, EventConsumer.Context context) { log.info("begin cached product featureResource handler rocketmq event: {}", event); @@ -81,13 +37,10 @@ public class CacheProductSaasFeatureResourceHandler implements InitializingBean return; } - PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() - .productModuleIds(payload.getProductModuleIds()) - .type(NEW_FEATURE) + ProductSaasFeatureResourceCacheService.RefreshProductFeatureResourceCacheParam param = ProductSaasFeatureResourceCacheService.RefreshProductFeatureResourceCacheParam.builder() + .productIds(payload.getProductModuleIds()) .build(); - List productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq); - - storeProductFeatureResource(productFeatures); + productSaasFeatureResourceCacheService.refreshCache(param); log.info("end cached product featureResource handler rocketmq event: {}", event); } @@ -99,15 +52,17 @@ public class CacheProductSaasFeatureResourceHandler implements InitializingBean return; } - PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() - .type(NEW_FEATURE) - .build(); - List productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq); - - if (CollectionUtils.isEmpty(productFeatures)) { + Set productIds = productService.list(new ProductSearchListReq()).getData().stream() + .map(ProductVO::getId) + .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(productIds)) { return; } - storeProductFeatureResource(productFeatures); + + ProductSaasFeatureResourceCacheService.RefreshProductFeatureResourceCacheParam param = ProductSaasFeatureResourceCacheService.RefreshProductFeatureResourceCacheParam.builder() + .productIds(productIds) + .build(); + productSaasFeatureResourceCacheService.refreshCache(param); log.info("end cached product featureResource handler rocketmq event: {}", event); } @@ -117,121 +72,4 @@ public class CacheProductSaasFeatureResourceHandler implements InitializingBean eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert); } - - public List resolveProductFeatureResources(List productPermissions) { - if (CollectionUtils.isEmpty(productPermissions)) { - return Collections.emptyList(); - } - - Map featureResources = listSaasFeatureResource(productPermissions); - - Map parentFeatureResources = listParentSaasFeatureResource(featureResources); - - return productPermissions.stream() - .collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId)) - .entrySet() - .stream() - .map(e -> { - List productFeatureRelations = e.getValue(); - - if (CollectionUtils.isEmpty(productFeatureRelations)) { - return null; - } - - List productFeatureResources = productFeatureRelations.stream() - .map(relation -> { - SaasFeatureResourceResp featureResource = featureResources.get(relation.getFeatureId()); - if (Objects.isNull(featureResource) || StringUtils.isBlank(featureResource.getUniCode())) { - return null; - } - - ProductSaasFeatureResourceCacheService.FeatureResourceDTO featureResourceDTO = from(featureResource, relation); - List featureResourceDTOS = Lists.newArrayList(featureResourceDTO); - - List parentPermissions = featureResource.resolvePath().stream() - .map(parentFeatureResources::get) - .filter(Objects::nonNull) - .map(f -> { - - if (StringUtils.isBlank(f.getUniCode())) { - return null; - } - - return from(featureResource, relation); - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - featureResourceDTOS.addAll(parentPermissions); - - return featureResourceDTOS; - }) - .filter(Objects::nonNull) - .flatMap(Collection::stream) - .distinct() - .filter(f -> FEATURE_RESOURCE_TYPES.contains(f.getFeatureType())) - .collect(Collectors.toList()); - - if (CollectionUtils.isEmpty(productFeatureResources)) { - return null; - } - - return ProductSaasFeatureResourceCacheService.ProductFeatureResource.builder() - .productId(e.getKey()) - .featureResources(productFeatureResources) - .build(); - - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } - - private ProductSaasFeatureResourceCacheService.FeatureResourceDTO from(SaasFeatureResourceResp featureResource, - SaasProductModuleFeatureRelation relation) { - return ProductSaasFeatureResourceCacheService.FeatureResourceDTO.builder() - .featureId(featureResource.getId()) - .featureType(featureResource.getFeatureType()) - .terminal(featureResource.getTerminal()) - .uniCode(featureResource.getUniCode()) - .cooperateType(relation.getDictCode()) - .build(); - } - - private Map listSaasFeatureResource(List productPermissions) { - - List featureIds = productPermissions.stream() - .map(SaasProductModuleFeatureRelation::getFeatureId) - .distinct() - .collect(Collectors.toList()); - - if (CollectionUtils.isEmpty(featureIds)) { - return Collections.emptyMap(); - } - - // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 - PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() - .ids(featureIds) - .build(); - return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() - .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); - } - - private Map listParentSaasFeatureResource(Map productPermissions) { - - List parentIds = productPermissions.values().stream() - .map(SaasFeatureResourceResp::resolvePath) - .flatMap(Collection::stream) - .distinct() - .collect(Collectors.toList()); - - if (CollectionUtils.isEmpty(parentIds)) { - return Collections.emptyMap(); - } - - // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 - PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() - .ids(parentIds) - .build(); - return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() - .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); - } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java index b902d524..b0a66cc4 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java @@ -2,17 +2,11 @@ package cn.axzo.tyr.server.event.inner; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; -import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; -import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; -import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; import cn.axzo.tyr.client.model.res.SaasRoleRes; import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; -import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; -import cn.axzo.tyr.server.repository.entity.SaasFeature; import cn.axzo.tyr.server.service.RolePermissionCacheService; import cn.axzo.tyr.server.service.RoleService; -import cn.axzo.tyr.server.service.SaasFeatureResourceService; import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -21,19 +15,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.Collection; -import java.util.Collections; -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.SaasPgroupPermissionRelation.NEW_FEATURE; -import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE; - /** * 缓存角色的权限 */ @@ -47,28 +32,6 @@ public class CacheRolePermissionHandler implements InitializingBean { private RolePermissionCacheService rolePermissionCacheService; @Autowired private RoleService roleService; - @Autowired - private SaasFeatureResourceService saasFeatureResourceService; - @Autowired - private SaasFeatureDao saasFeatureDao; - - private void storeRolePermission(List roles) { - - if (CollectionUtils.isEmpty(roles)) { - return; - } - - List rolePermissions = resolveRolePermission(roles); - - if (CollectionUtils.isEmpty(rolePermissions)) { - return; - } - - RolePermissionCacheService.StoreRolePermissionParam storeRolePermissionParam = RolePermissionCacheService.StoreRolePermissionParam.builder() - .rolePermissions(rolePermissions) - .build(); - rolePermissionCacheService.store(storeRolePermissionParam); - } public void onRolePermissionUpsert(Event event, EventConsumer.Context context) { log.info("begin cached role permission handler rocketmq event: {}", event); @@ -84,11 +47,19 @@ public class CacheRolePermissionHandler implements InitializingBean { .roleIds(Optional.ofNullable(payload.getRoleIds()) .map(Lists::newArrayList) .orElse(null)) - .needPermissionRelation(true) .build(); - List roles = roleService.list(listSaasRoleParam); + Set roleIds = roleService.list(listSaasRoleParam).stream() + .map(SaasRoleRes::getId) + .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(roleIds)) { + return; + } + + RolePermissionCacheService.RefreshRolePermissionCacheParam refreshRolePermissionCacheParam = RolePermissionCacheService.RefreshRolePermissionCacheParam.builder() + .roleIds(roleIds) + .build(); + rolePermissionCacheService.refreshCache(refreshRolePermissionCacheParam); - storeRolePermission(roles); log.info("end cached role permission handler rocketmq event: {}", event); } @@ -99,12 +70,18 @@ public class CacheRolePermissionHandler implements InitializingBean { return; } - RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() - .needPermissionRelation(true) - .build(); - List roles = roleService.list(listSaasRoleParam); + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder().build(); + Set roleIds = roleService.list(listSaasRoleParam).stream() + .map(SaasRoleRes::getId) + .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(roleIds)) { + return; + } - storeRolePermission(roles); + RolePermissionCacheService.RefreshRolePermissionCacheParam refreshRolePermissionCacheParam = RolePermissionCacheService.RefreshRolePermissionCacheParam.builder() + .roleIds(roleIds) + .build(); + rolePermissionCacheService.refreshCache(refreshRolePermissionCacheParam); } @Override @@ -112,209 +89,4 @@ public class CacheRolePermissionHandler implements InitializingBean { eventConsumer.registerHandler(EventTypeEnum.ROLE_PERMISSION_CREATED.getEventCode(), this::onRolePermissionUpsert); eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert); } - - public List resolveRolePermission(List roles) { - - - Map featureResources = listSaasFeatureResource(roles); - - Map parentFeatureResources = listParentSaasFeatureResource(featureResources); - - Map saasFeatures = listSaasFeature(roles); - - Map parentSaasFeatures = listParentSaasFeature(saasFeatures); - - - return roles.stream() - .map(e -> { - if (CollectionUtils.isEmpty(e.getPermissionRelations())) { - return null; - } - - List permissions = e.getPermissionRelations().stream() - .distinct() - .map(permissionRelation -> { - if (Objects.equals(permissionRelation.getType(), NEW_FEATURE)) { - return resolveFeatureResourcePermission(permissionRelation, featureResources, parentFeatureResources); - } - return resolveFeaturePermission(permissionRelation, saasFeatures, parentSaasFeatures); - }) - .filter(Objects::nonNull) - .flatMap(Collection::stream) - .distinct() - .collect(Collectors.toList()); - - if (CollectionUtils.isEmpty(permissions)) { - return null; - } - - return RolePermissionCacheService.RolePermission.builder() - .roleId(e.getId()) - .permissions(permissions) - .build(); - - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } - - private static List resolveFeaturePermission(SaasPermissionRelationRes permissionRelation, Map saasFeatures, Map parentSaasFeatures) { - SaasFeature saasFeature = saasFeatures.get(permissionRelation.getFeatureId()); - if (Objects.isNull(saasFeature)) { - return null; - } - - List permissionDTOS = Lists.newArrayList(RolePermissionCacheService.PermissionDTO.builder() - .featureId(saasFeature.getId()) - .featureCode(saasFeature.getFeatureCode()) - .featureType(saasFeature.getFeatureType()) - .terminal(saasFeature.getTerminal()) - .build()); - - List parentPermissions = saasFeature.splitPath().stream() - .map(parentSaasFeatures::get) - .filter(Objects::nonNull) - .map(f -> RolePermissionCacheService.PermissionDTO.builder() - .featureId(f.getId()) - .featureCode(f.getFeatureCode()) - .featureType(f.getFeatureType()) - .terminal(f.getTerminal()) - .build()) - .collect(Collectors.toList()); - - permissionDTOS.addAll(parentPermissions); - return permissionDTOS; - } - - private static List resolveFeatureResourcePermission(SaasPermissionRelationRes permissionRelation, Map featureResources, Map parentFeatureResources) { - SaasFeatureResourceResp featureResource = featureResources.get(permissionRelation.getFeatureId()); - // 菜单节点是不会关联元素code,所以缓存的featureCode使用菜单编码 - if (Objects.isNull(featureResource)) { - return null; - } - - if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) { - return null; - } - - List permissionDTOS = featureResource.getSaasPageElements().stream() - .map(pageElement -> RolePermissionCacheService.PermissionDTO.builder() - .featureId(featureResource.getId()) - .featureCode(pageElement.getCode()) - .featureType(featureResource.getFeatureType()) - .terminal(featureResource.getTerminal()) - .build()) - .collect(Collectors.toList()); - - List parentPermissions = featureResource.resolvePath().stream() - .map(parentFeatureResources::get) - .filter(Objects::nonNull) - .map(f -> { - - if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) { - return null; - } - - return featureResource.getSaasPageElements().stream() - .map(pageElement -> RolePermissionCacheService.PermissionDTO.builder() - .featureId(f.getId()) - .featureCode(pageElement.getCode()) - .featureType(f.getFeatureType()) - .terminal(f.getTerminal()) - .build()) - .collect(Collectors.toList()); - }) - .filter(Objects::nonNull) - .flatMap(Collection::stream) - .collect(Collectors.toList()); - - permissionDTOS.addAll(parentPermissions); - - return permissionDTOS; - } - - - private Map listSaasFeatureResource(List roles) { - - List featureIds = roles.stream() - .filter(e -> !CollectionUtils.isEmpty(e.getPermissionRelations())) - .map(SaasRoleRes::getPermissionRelations) - .flatMap(Collection::stream) - .filter(e -> Objects.equals(e.getType(), NEW_FEATURE)) - .map(SaasPermissionRelationRes::getFeatureId) - .distinct() - .collect(Collectors.toList()); - - if (CollectionUtils.isEmpty(featureIds)) { - return Collections.emptyMap(); - } - - - PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() - .ids(featureIds) - .needPageElement(true) - .build(); - return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() - .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); - } - - private Map listParentSaasFeatureResource(Map productPermissions) { - - List parentIds = productPermissions.values().stream() - .map(SaasFeatureResourceResp::resolvePath) - .flatMap(Collection::stream) - .distinct() - .collect(Collectors.toList()); - - if (CollectionUtils.isEmpty(parentIds)) { - return Collections.emptyMap(); - } - - // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 - PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() - .ids(parentIds) - .needPageElement(true) - .build(); - return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() - .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); - } - - private Map listSaasFeature(List roles) { - - Set featureIds = roles.stream() - .filter(e -> !CollectionUtils.isEmpty(e.getPermissionRelations())) - .map(SaasRoleRes::getPermissionRelations) - .flatMap(Collection::stream) - .filter(e -> Objects.equals(e.getType(), OLD_FEATURE)) - .map(SaasPermissionRelationRes::getFeatureId) - .collect(Collectors.toSet()); - - if (CollectionUtils.isEmpty(featureIds)) { - return Collections.emptyMap(); - } - - return saasFeatureDao.listByIds(featureIds) - .stream() - .collect(Collectors.toMap(SaasFeature::getId, Function.identity(), (f, s) -> s)); - } - - private Map listParentSaasFeature(Map saasFeatures) { - - if (CollectionUtils.isEmpty(saasFeatures)) { - return Collections.emptyMap(); - } - - List parentIds = saasFeatures.values().stream() - .map(SaasFeature::splitPath) - .flatMap(Collection::stream) - .distinct() - .collect(Collectors.toList()); - - if (CollectionUtils.isEmpty(parentIds)) { - return Collections.emptyMap(); - } - - return saasFeatureDao.listByIds(parentIds).stream() - .collect(Collectors.toMap(SaasFeature::getId, Function.identity())); - } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java index 1c9875ea..93be689b 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java @@ -2,15 +2,11 @@ package cn.axzo.tyr.server.event.inner; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; -import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; -import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; -import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; import cn.axzo.tyr.client.model.res.SaasRoleRes; import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService; import cn.axzo.tyr.server.service.RoleService; -import cn.axzo.tyr.server.service.SaasFeatureResourceService; import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -19,18 +15,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.Collection; -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.Set; import java.util.stream.Collectors; -import static cn.axzo.tyr.server.event.inner.CacheProductSaasFeatureResourceHandler.FEATURE_RESOURCE_TYPES; -import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; - /** * 因为菜单树不一定有权限code * 登录时需要查询菜单树,所以把菜单树缓存起来 @@ -44,27 +32,8 @@ public class CacheRoleSaasFeatureResourceHandler implements InitializingBean { @Autowired private RoleService roleService; @Autowired - private SaasFeatureResourceService saasFeatureResourceService; - @Autowired private RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService; - private void storeRoleFeatureResource(List roles) { - - if (CollectionUtils.isEmpty(roles)) { - return; - } - - List rolePermissions = resolveRoleFeatureResource(roles); - - if (CollectionUtils.isEmpty(rolePermissions)) { - return; - } - - RoleSaasFeatureResourceCacheService.StoreRoleSaasFeatureResourceParam storeRoleFeatureResourceParam = RoleSaasFeatureResourceCacheService.StoreRoleSaasFeatureResourceParam.builder() - .roleSaasFeatureResources(rolePermissions) - .build(); - roleSaasFeatureResourceCacheService.store(storeRoleFeatureResourceParam); - } public void onRolePermissionUpsert(Event event, EventConsumer.Context context) { log.info("begin cached role saasFeatureResource handler rocketmq event: {}", event); RolePermissionCreatedPayload payload = event.normalizedData(RolePermissionCreatedPayload.class); @@ -79,12 +48,18 @@ public class CacheRoleSaasFeatureResourceHandler implements InitializingBean { .roleIds(Optional.ofNullable(payload.getRoleIds()) .map(Lists::newArrayList) .orElse(null)) - .needPermissionRelation(true) - .type(NEW_FEATURE) .build(); - List roles = roleService.list(listSaasRoleParam); + Set roleIds = roleService.list(listSaasRoleParam).stream() + .map(SaasRoleRes::getId) + .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(roleIds)) { + return; + } - storeRoleFeatureResource(roles); + RoleSaasFeatureResourceCacheService.RefreshRoleFeatureResourceCacheParam param = RoleSaasFeatureResourceCacheService.RefreshRoleFeatureResourceCacheParam.builder() + .roleIds(roleIds) + .build(); + roleSaasFeatureResourceCacheService.refreshCache(param); log.info("end cached role saasFeatureResource handler rocketmq event: {}", event); } @@ -97,12 +72,19 @@ public class CacheRoleSaasFeatureResourceHandler implements InitializingBean { } RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() - .needPermissionRelation(true) - .type(NEW_FEATURE) .build(); - List roles = roleService.list(listSaasRoleParam); - storeRoleFeatureResource(roles); + Set roleIds = roleService.list(listSaasRoleParam).stream() + .map(SaasRoleRes::getId) + .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(roleIds)) { + return; + } + + RoleSaasFeatureResourceCacheService.RefreshRoleFeatureResourceCacheParam param = RoleSaasFeatureResourceCacheService.RefreshRoleFeatureResourceCacheParam.builder() + .roleIds(roleIds) + .build(); + roleSaasFeatureResourceCacheService.refreshCache(param); } @Override @@ -111,116 +93,4 @@ public class CacheRoleSaasFeatureResourceHandler implements InitializingBean { eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert); } - - public List resolveRoleFeatureResource(List roles) { - - Map featureResources = listSaasFeatureResource(roles); - - Map parentFeatureResources = listParentSaasFeatureResource(featureResources); - - return roles.stream() - .map(e -> { - if (CollectionUtils.isEmpty(e.getPermissionRelations())) { - return null; - } - - List permissions = e.getPermissionRelations().stream() - .distinct() - .map(permissionRelation -> { - SaasFeatureResourceResp featureResource = featureResources.get(permissionRelation.getFeatureId()); - if (Objects.isNull(featureResource) || StringUtils.isBlank(featureResource.getUniCode())) { - return null; - } - - List featureResourceDTOS = Lists.newArrayList(RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO.builder() - .featureId(featureResource.getId()) - .featureType(featureResource.getFeatureType()) - .terminal(featureResource.getTerminal()) - .uniCode(featureResource.getUniCode()) - .build()); - List parentPermissions = featureResource.resolvePath().stream() - .map(parentFeatureResources::get) - .filter(Objects::nonNull) - .map(f -> { - - if (StringUtils.isBlank(f.getUniCode())) { - return null; - } - - return RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO.builder() - .featureId(f.getId()) - .featureType(f.getFeatureType()) - .terminal(f.getTerminal()) - .uniCode(f.getUniCode()) - .build(); - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - featureResourceDTOS.addAll(parentPermissions); - - return featureResourceDTOS; - }) - .filter(Objects::nonNull) - .flatMap(Collection::stream) - .distinct() - .filter(f -> FEATURE_RESOURCE_TYPES.contains(f.getFeatureType())) - .collect(Collectors.toList()); - - if (CollectionUtils.isEmpty(permissions)) { - return null; - } - - return RoleSaasFeatureResourceCacheService.RoleFeatureResource.builder() - .roleId(e.getId()) - .saasFeatureResources(permissions) - .build(); - - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } - - private Map listSaasFeatureResource(List roles) { - - List featureIds = roles.stream() - .filter(e -> !CollectionUtils.isEmpty(e.getPermissionRelations())) - .map(SaasRoleRes::getPermissionRelations) - .flatMap(Collection::stream) - .map(SaasPermissionRelationRes::getFeatureId) - .distinct() - .collect(Collectors.toList()); - - if (CollectionUtils.isEmpty(featureIds)) { - return Collections.emptyMap(); - } - - // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 - PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() - .ids(featureIds) - .needFeatureCodes(true) - .build(); - return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() - .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); - } - - private Map listParentSaasFeatureResource(Map productPermissions) { - - List parentIds = productPermissions.values().stream() - .map(SaasFeatureResourceResp::resolvePath) - .flatMap(Collection::stream) - .distinct() - .collect(Collectors.toList()); - - if (CollectionUtils.isEmpty(parentIds)) { - return Collections.emptyMap(); - } - - // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 - PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() - .ids(parentIds) - .needFeatureCodes(true) - .build(); - return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() - .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); - } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java index b5651162..268cb780 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureHandler.java @@ -4,7 +4,7 @@ import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; import cn.axzo.tyr.server.event.payload.SaasFeatureUpsertPayload; -import cn.axzo.tyr.server.job.CacheSaasFeatureJob; +import cn.axzo.tyr.server.service.SaasFeatureResourceService; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -22,7 +22,7 @@ public class CacheSaasFeatureHandler implements EventHandler, InitializingBean { @Autowired private EventConsumer eventConsumer; @Autowired - private CacheSaasFeatureJob cacheSaasFeatureJob; + private SaasFeatureResourceService saasFeatureResourceService; @Override public void onEvent(Event event, EventConsumer.Context context) { @@ -33,7 +33,10 @@ public class CacheSaasFeatureHandler implements EventHandler, InitializingBean { return; } - cacheSaasFeatureJob.cacheSaasFeature(Sets.newHashSet(payload.getTerminal())); + SaasFeatureResourceService.RefreshFeatureResourceCacheParam param = SaasFeatureResourceService.RefreshFeatureResourceCacheParam.builder() + .terminals(Sets.newHashSet(payload.getTerminal())) + .build(); + saasFeatureResourceService.refreshCache(param); log.info("end cached saasFeature handler rocketmq event: {}", event); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java index 9695a0e0..ea56c5cc 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheSaasFeatureResourceHandler.java @@ -4,7 +4,7 @@ import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; -import cn.axzo.tyr.server.job.CacheSaasFeatureJob; +import cn.axzo.tyr.server.service.SaasFeatureResourceService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.factory.InitializingBean; @@ -21,7 +21,7 @@ public class CacheSaasFeatureResourceHandler implements EventHandler, Initializi @Autowired private EventConsumer eventConsumer; @Autowired - private CacheSaasFeatureJob cacheSaasFeatureJob; + private SaasFeatureResourceService saasFeatureResourceService; @Override public void onEvent(Event event, EventConsumer.Context context) { @@ -32,7 +32,10 @@ public class CacheSaasFeatureResourceHandler implements EventHandler, Initializi return; } - cacheSaasFeatureJob.cacheSaasFeatureResource(payload.getTerminals()); + SaasFeatureResourceService.RefreshFeatureResourceCacheParam param = SaasFeatureResourceService.RefreshFeatureResourceCacheParam.builder() + .terminals(payload.getTerminals()) + .build(); + saasFeatureResourceService.refreshCache(param); log.info("end cached saasFeatureResource handler rocketmq event: {}", event); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductFeatureResourceJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductFeatureResourceJob.java index 2a4c602e..0bbc2b63 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductFeatureResourceJob.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductFeatureResourceJob.java @@ -1,10 +1,8 @@ package cn.axzo.tyr.server.job; -import cn.axzo.framework.rocketmq.Event; import cn.axzo.tyr.client.model.product.ProductSearchListReq; import cn.axzo.tyr.client.model.product.ProductVO; -import cn.axzo.tyr.server.event.inner.CacheProductSaasFeatureResourceHandler; -import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload; +import cn.axzo.tyr.server.service.ProductSaasFeatureResourceCacheService; import cn.axzo.tyr.server.service.ProductService; import com.alibaba.fastjson.JSONObject; import com.xxl.job.core.biz.model.ReturnT; @@ -13,6 +11,7 @@ import com.xxl.job.core.handler.annotation.XxlJob; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; import java.util.Optional; import java.util.Set; @@ -23,7 +22,7 @@ import java.util.stream.Collectors; public class CacheProductFeatureResourceJob extends IJobHandler { @Autowired - private CacheProductSaasFeatureResourceHandler cacheProductSaasFeatureResourceHandler; + private ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService; @Autowired private ProductService productService; @@ -41,14 +40,14 @@ public class CacheProductFeatureResourceJob extends IJobHandler { .map(ProductVO::getId) .collect(Collectors.toSet()); - ProductPermissionCreatedPayload payload = ProductPermissionCreatedPayload.builder() - .productModuleIds(productIds) - .build(); + if (CollectionUtils.isEmpty(productIds)) { + return ReturnT.SUCCESS; + } - Event event = Event.builder() - .data(payload) + ProductSaasFeatureResourceCacheService.RefreshProductFeatureResourceCacheParam param = ProductSaasFeatureResourceCacheService.RefreshProductFeatureResourceCacheParam.builder() + .productIds(productIds) .build(); - cacheProductSaasFeatureResourceHandler.onProductPermissionUpsert(event, null); + productSaasFeatureResourceCacheService.refreshCache(param); return ReturnT.SUCCESS; } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductPermissionJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductPermissionJob.java index b05d63a3..e7913351 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductPermissionJob.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheProductPermissionJob.java @@ -1,10 +1,8 @@ package cn.axzo.tyr.server.job; -import cn.axzo.framework.rocketmq.Event; import cn.axzo.tyr.client.model.product.ProductSearchListReq; import cn.axzo.tyr.client.model.product.ProductVO; -import cn.axzo.tyr.server.event.inner.CacheProductPermissionHandler; -import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload; +import cn.axzo.tyr.server.service.ProductPermissionCacheService; import cn.axzo.tyr.server.service.ProductService; import com.alibaba.fastjson.JSONObject; import com.xxl.job.core.biz.model.ReturnT; @@ -13,6 +11,7 @@ import com.xxl.job.core.handler.annotation.XxlJob; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; import java.util.Optional; import java.util.Set; @@ -23,7 +22,7 @@ import java.util.stream.Collectors; public class CacheProductPermissionJob extends IJobHandler { @Autowired - private CacheProductPermissionHandler cacheProductPermissionHandler; + private ProductPermissionCacheService productPermissionCacheService; @Autowired private ProductService productService; @@ -40,15 +39,14 @@ public class CacheProductPermissionJob extends IJobHandler { .stream() .map(ProductVO::getId) .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(productIds)) { + return ReturnT.SUCCESS; + } - ProductPermissionCreatedPayload payload = ProductPermissionCreatedPayload.builder() - .productModuleIds(productIds) + ProductPermissionCacheService.RefreshProductPermissionCacheParam param = ProductPermissionCacheService.RefreshProductPermissionCacheParam.builder() + .productIds(productIds) .build(); - - Event event = Event.builder() - .data(payload) - .build(); - cacheProductPermissionHandler.onProductPermissionUpsert(event, null); + productPermissionCacheService.refreshCache(param); return ReturnT.SUCCESS; } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRoleFeatureResourceJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRoleFeatureResourceJob.java index d1eb092c..725bec72 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRoleFeatureResourceJob.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRoleFeatureResourceJob.java @@ -1,15 +1,8 @@ package cn.axzo.tyr.server.job; -import cn.axzo.foundation.page.PageResp; -import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; import cn.axzo.tyr.client.model.res.SaasRoleRes; -import cn.axzo.tyr.server.event.inner.CacheRoleSaasFeatureResourceHandler; -import cn.axzo.tyr.server.repository.dao.SaasPgroupRoleRelationDao; -import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation; -import cn.axzo.tyr.server.repository.entity.SaasPgroupRoleRelation; import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService; import cn.axzo.tyr.server.service.RoleService; -import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService; import com.alibaba.fastjson.JSONObject; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; @@ -19,9 +12,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.Collection; -import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -30,102 +20,32 @@ import java.util.stream.Collectors; @Component public class CacheRoleFeatureResourceJob extends IJobHandler { - @Autowired - private CacheRoleSaasFeatureResourceHandler cacheRoleSaasFeatureResourceHandler; @Autowired private RoleService roleService; @Autowired - private SaasPgroupPermissionRelationService saasPgroupPermissionRelationService; - @Autowired - private SaasPgroupRoleRelationDao saasPgroupRoleRelationDao; - @Autowired private RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService; - private static final Integer DEFAULT_PAGE_SIZE = 2000; - @Override @XxlJob("CacheRoleFeatureResourceJob") public ReturnT execute(String s) throws Exception { log.info("start CacheRoleFeatureResourceJob, s:{}", s); - RoleService.PageSaasRoleParam pageSaasRoleParam = Optional.ofNullable(s) - .map(e -> JSONObject.parseObject(e, RoleService.PageSaasRoleParam.class)) - .orElseGet(() -> RoleService.PageSaasRoleParam.builder().build()); + RoleService.ListSaasRoleParam listSaasRoleParam = Optional.ofNullable(s) + .map(e -> JSONObject.parseObject(e, RoleService.ListSaasRoleParam.class)) + .orElseGet(() -> RoleService.ListSaasRoleParam.builder().build()); - // 因为角色权限集是重复使用,通过角色找权限集数据量太大,直接查询所有权限集的权限,比较快 - Map> permissionRelations = listPgroupPermissionRelation(); - - Integer pageNumber = 1; - while (true) { - pageSaasRoleParam.setPage(pageNumber++); - pageSaasRoleParam.setPageSize(DEFAULT_PAGE_SIZE); - PageResp page = roleService.page(pageSaasRoleParam); - - store(page.getData(), permissionRelations); - - if (!page.hasNext()) { - break; - } + Set roleIds = roleService.list(listSaasRoleParam).stream() + .map(SaasRoleRes::getId) + .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(roleIds)) { + return ReturnT.SUCCESS; } + RoleSaasFeatureResourceCacheService.RefreshRoleFeatureResourceCacheParam param = RoleSaasFeatureResourceCacheService.RefreshRoleFeatureResourceCacheParam.builder() + .roleIds(roleIds) + .build(); + roleSaasFeatureResourceCacheService.refreshCache(param); + return ReturnT.SUCCESS; } - - private Map> listPgroupPermissionRelation() { - return saasPgroupPermissionRelationService.list().stream() - .collect(Collectors.groupingBy(SaasPgroupPermissionRelation::getGroupId, - Collectors.mapping(e -> SaasPermissionRelationRes.builder() - .featureId(e.getFeatureId()) - .featureType(e.getFeatureType()) - .type(e.getType()) - .build(), Collectors.toList()))); - - } - - private Map> listPermissionGroup(List roleIds) { - - return saasPgroupRoleRelationDao.findByRoleIds(roleIds).stream() - .collect(Collectors.groupingBy(SaasPgroupRoleRelation::getRoleId, - Collectors.mapping(SaasPgroupRoleRelation::getGroupId, Collectors.toSet()))); - } - - private void store(List roles, - Map> permissionRelations) { - - if (CollectionUtils.isEmpty(roles)) { - return; - } - - List roleIds = roles.stream() - .map(SaasRoleRes::getId) - .collect(Collectors.toList()); - Map> roleGroupMap = listPermissionGroup(roleIds); - - roles.forEach(e -> { - Set groupIds = roleGroupMap.get(e.getId()); - if (CollectionUtils.isEmpty(groupIds)) { - return; - } - - List rolePermissions = groupIds.stream() - .map(permissionRelations::get) - .filter(f -> !CollectionUtils.isEmpty(f)) - .flatMap(Collection::stream) - .distinct() - .collect(Collectors.toList()); - - e.setPermissionRelations(rolePermissions); - }); - - List roleFeatureResources = cacheRoleSaasFeatureResourceHandler.resolveRoleFeatureResource(roles); - - if (CollectionUtils.isEmpty(roleFeatureResources)) { - return; - } - - RoleSaasFeatureResourceCacheService.StoreRoleSaasFeatureResourceParam storeRolePermissionParam = RoleSaasFeatureResourceCacheService.StoreRoleSaasFeatureResourceParam.builder() - .roleSaasFeatureResources(roleFeatureResources) - .build(); - roleSaasFeatureResourceCacheService.store(storeRolePermissionParam); - } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java index 3b0d3bea..d97fa08b 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java @@ -1,15 +1,8 @@ package cn.axzo.tyr.server.job; -import cn.axzo.foundation.page.PageResp; -import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; import cn.axzo.tyr.client.model.res.SaasRoleRes; -import cn.axzo.tyr.server.event.inner.CacheRolePermissionHandler; -import cn.axzo.tyr.server.repository.dao.SaasPgroupRoleRelationDao; -import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation; -import cn.axzo.tyr.server.repository.entity.SaasPgroupRoleRelation; import cn.axzo.tyr.server.service.RolePermissionCacheService; import cn.axzo.tyr.server.service.RoleService; -import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService; import com.alibaba.fastjson.JSONObject; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; @@ -19,9 +12,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.Collection; -import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -30,102 +20,33 @@ import java.util.stream.Collectors; @Component public class CacheRolePermissionJob extends IJobHandler { - @Autowired - private CacheRolePermissionHandler cacheRolePermissionHandler; @Autowired private RoleService roleService; @Autowired - private SaasPgroupPermissionRelationService saasPgroupPermissionRelationService; - @Autowired - private SaasPgroupRoleRelationDao saasPgroupRoleRelationDao; - @Autowired private RolePermissionCacheService rolePermissionCacheService; - private static final Integer DEFAULT_PAGE_SIZE = 2000; @Override @XxlJob("CacheRolePermissionJob") public ReturnT execute(String s) throws Exception { log.info("start CacheRolePermissionJob, s:{}", s); - RoleService.PageSaasRoleParam pageSaasRoleParam = Optional.ofNullable(s) - .map(e -> JSONObject.parseObject(e, RoleService.PageSaasRoleParam.class)) - .orElseGet(() -> RoleService.PageSaasRoleParam.builder().build()); + RoleService.ListSaasRoleParam listSaasRoleParam = Optional.ofNullable(s) + .map(e -> JSONObject.parseObject(e, RoleService.ListSaasRoleParam.class)) + .orElseGet(() -> RoleService.ListSaasRoleParam.builder().build()); - // 因为角色权限集是重复使用,通过角色找权限集数据量太大,直接查询所有权限集的权限,比较快 - Map> permissionRelations = listPgroupPermissionRelation(); - - Integer pageNumber = 1; - while (true) { - pageSaasRoleParam.setPage(pageNumber++); - pageSaasRoleParam.setPageSize(DEFAULT_PAGE_SIZE); - PageResp page = roleService.page(pageSaasRoleParam); - - store(page.getData(), permissionRelations); - - if (!page.hasNext()) { - break; - } + Set roleIds = roleService.list(listSaasRoleParam).stream() + .map(SaasRoleRes::getId) + .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(roleIds)) { + return ReturnT.SUCCESS; } + RolePermissionCacheService.RefreshRolePermissionCacheParam refreshRolePermissionCacheParam = RolePermissionCacheService.RefreshRolePermissionCacheParam.builder() + .roleIds(roleIds) + .build(); + rolePermissionCacheService.refreshCache(refreshRolePermissionCacheParam); return ReturnT.SUCCESS; } - private Map> listPgroupPermissionRelation() { - return saasPgroupPermissionRelationService.list().stream() - .collect(Collectors.groupingBy(SaasPgroupPermissionRelation::getGroupId, - Collectors.mapping(e -> SaasPermissionRelationRes.builder() - .featureId(e.getFeatureId()) - .featureType(e.getFeatureType()) - .type(e.getType()) - .build(), Collectors.toList()))); - - } - - private Map> listPermissionGroup(List roleIds) { - - return saasPgroupRoleRelationDao.findByRoleIds(roleIds).stream() - .collect(Collectors.groupingBy(SaasPgroupRoleRelation::getRoleId, - Collectors.mapping(SaasPgroupRoleRelation::getGroupId, Collectors.toSet()))); - } - - private void store(List roles, - Map> permissionRelations) { - - if (CollectionUtils.isEmpty(roles)) { - return; - } - - List roleIds = roles.stream() - .map(SaasRoleRes::getId) - .collect(Collectors.toList()); - Map> roleGroupMap = listPermissionGroup(roleIds); - - roles.forEach(e -> { - Set groupIds = roleGroupMap.get(e.getId()); - if (CollectionUtils.isEmpty(groupIds)) { - return; - } - - List rolePermissions = groupIds.stream() - .map(permissionRelations::get) - .filter(f -> !CollectionUtils.isEmpty(f)) - .flatMap(Collection::stream) - .distinct() - .collect(Collectors.toList()); - - e.setPermissionRelations(rolePermissions); - }); - - List rolePermissions = cacheRolePermissionHandler.resolveRolePermission(roles); - - if (CollectionUtils.isEmpty(rolePermissions)) { - return; - } - - RolePermissionCacheService.StoreRolePermissionParam storeRolePermissionParam = RolePermissionCacheService.StoreRolePermissionParam.builder() - .rolePermissions(rolePermissions) - .build(); - rolePermissionCacheService.store(storeRolePermissionParam); - } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java index b667eb0d..622a1b4c 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheSaasFeatureJob.java @@ -1,13 +1,9 @@ package cn.axzo.tyr.server.job; -import cn.axzo.tyr.client.common.enums.FeatureResourceStatus; -import cn.axzo.tyr.client.model.enums.DelegatedType; import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; -import cn.axzo.tyr.client.model.res.PageElementResp; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; import cn.axzo.tyr.server.repository.entity.SaasFeature; -import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import cn.axzo.tyr.server.service.SaasFeatureResourceService; import com.alibaba.fastjson.JSONObject; import com.xxl.job.core.biz.model.ReturnT; @@ -22,8 +18,6 @@ import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -37,11 +31,6 @@ public class CacheSaasFeatureJob extends IJobHandler { @Autowired private SaasFeatureResourceService saasFeatureResourceService; - /** - * 分组这些菜单节点没有版本号,默认为0,方便权限过滤 - */ - private static final int DEFAULT_VERSION = 0; - @Override @XxlJob("CacheSaasFeatureJob") public ReturnT execute(String s) throws Exception { @@ -50,6 +39,7 @@ public class CacheSaasFeatureJob extends IJobHandler { StoreSaasFeatureParam req = Optional.ofNullable(s) .map(e -> JSONObject.parseObject(e, StoreSaasFeatureParam.class)) .orElseGet(() -> StoreSaasFeatureParam.builder().build()); + cacheSaasFeature(req.getTerminals()); cacheSaasFeatureResource(req.getTerminals()); @@ -57,66 +47,42 @@ public class CacheSaasFeatureJob extends IJobHandler { } public void cacheSaasFeature(Set terminals) { - Map> saasFeatures = saasFeatureDao.lambdaQuery() + // 没有办法只有所有端,除非写sql去重,菜单数量不多 + Set updateTerminals = saasFeatureDao.lambdaQuery() .in(CollectionUtils.isNotEmpty(terminals), SaasFeature::getTerminal, terminals) .list() .stream() - .collect(Collectors.groupingBy(SaasFeature::getTerminal, - Collectors.mapping(e -> SaasFeatureResourceService.SaasFeatureResourceCache - .builder() - .featureId(e.getId()) - .notAuth(DelegatedType.notAuth(e.getDelegatedType())) - .parentIds(e.splitPath()) - .build(), Collectors.toList()))); + .map(SaasFeature::getTerminal) + .collect(Collectors.toSet()); - List saasFeatureResources = saasFeatures.entrySet().stream() - .map(e -> SaasFeatureResourceService.SaasFeatureResourceDTO.builder() - .terminal(e.getKey()) - .features(e.getValue()) - .build()) - .collect(Collectors.toList()); + if (CollectionUtils.isEmpty(updateTerminals)) { + return; + } - SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() - .saasFeatureResources(saasFeatureResources) + SaasFeatureResourceService.RefreshFeatureResourceCacheParam param = SaasFeatureResourceService.RefreshFeatureResourceCacheParam.builder() + .terminals(updateTerminals) .build(); - saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); + saasFeatureResourceService.refreshCache(param); } public void cacheSaasFeatureResource(Set terminals) { PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() - .needPageElement(true) .terminals(terminals) .build(); - Map> saasFeatureResources = saasFeatureResourceService.list(pageSaasFeatureResourceReq) + Set updateTerminals = saasFeatureResourceService.list(pageSaasFeatureResourceReq) .stream() - .collect(Collectors.groupingBy(SaasFeatureResourceResp::getTerminal, - Collectors.mapping(e -> SaasFeatureResourceService.SaasFeatureResourceCache - .builder() - .featureId(e.getId()) - .notAuth(SaasFeatureResource.AuthType.isAllRole(e.getAuthType())) - .parentIds(e.resolvePath()) - .uniCode(e.getUniCode()) - .status(e.getStatus()) - .version(Optional.ofNullable(e.getSaasPageElements()) - .map(pageElement -> pageElement.stream() - .findFirst() - .map(PageElementResp::getVersion) - .orElse(DEFAULT_VERSION)) - .orElse(DEFAULT_VERSION)) - .build(), Collectors.toList()))); + .map(SaasFeatureResourceResp::getTerminal) + .collect(Collectors.toSet()); - List featureResources = saasFeatureResources.entrySet().stream() - .map(e -> SaasFeatureResourceService.SaasFeatureResourceDTO.builder() - .terminal(e.getKey()) - .features(e.getValue()) - .build()) - .collect(Collectors.toList()); + if (CollectionUtils.isEmpty(updateTerminals)) { + return; + } - SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() - .saasFeatureResources(featureResources) + SaasFeatureResourceService.RefreshFeatureResourceCacheParam param = SaasFeatureResourceService.RefreshFeatureResourceCacheParam.builder() + .terminals(updateTerminals) .build(); - saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache); + saasFeatureResourceService.refreshCache(param); } @Data 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 index d222620d..1e67c38a 100644 --- 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 @@ -18,18 +18,15 @@ public interface ProductPermissionCacheService { */ Map> list(ListProductPermissionParam param); - /** - * 存储产品的权限信息 - * @param param - */ - void store(StoreProductPermissionParam param); + void refreshCache(RefreshProductPermissionCacheParam param); - /** - * 产品是否有缓存权限 - * @param param - * @return - */ - List hasProductIds(HasProductPermissionParam param); + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class RefreshProductPermissionCacheParam { + private Set productIds; + } @Data @Builder diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductSaasFeatureResourceCacheService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductSaasFeatureResourceCacheService.java index 71ddb527..e7441513 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductSaasFeatureResourceCacheService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/ProductSaasFeatureResourceCacheService.java @@ -13,7 +13,15 @@ public interface ProductSaasFeatureResourceCacheService { Map> list(ListProductFeatureResourceParam param); - void store(StoreProductFeatureResourceParam param); + void refreshCache(RefreshProductFeatureResourceCacheParam param); + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class RefreshProductFeatureResourceCacheParam { + private Set productIds; + } @Data @Builder 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 index ae332e55..67b62a8d 100644 --- 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 @@ -14,29 +14,14 @@ public interface RolePermissionCacheService { Map> list(ListRolePermissionParam param); - /** - * redisKey:roleId - * redisValue:permission - * @param param - */ - void store(StoreRolePermissionParam param); - - List hasRoleIds(HasRolePermissionParam param); + void refreshCache(RefreshRolePermissionCacheParam param); @Data @Builder @NoArgsConstructor @AllArgsConstructor - class HasRolePermissionParam { - private List roleIds; - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - class StoreRolePermissionParam { - private List rolePermissions; + class RefreshRolePermissionCacheParam { + private Set roleIds; } @Data diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleSaasFeatureResourceCacheService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleSaasFeatureResourceCacheService.java index f5a95828..5d70fe28 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleSaasFeatureResourceCacheService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleSaasFeatureResourceCacheService.java @@ -13,8 +13,15 @@ public interface RoleSaasFeatureResourceCacheService { Map> list(ListRoleSaasFeatureResourceParam param); - void store(StoreRoleSaasFeatureResourceParam param); + void refreshCache(RefreshRoleFeatureResourceCacheParam param); + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class RefreshRoleFeatureResourceCacheParam { + private Set roleIds; + } @Data @Builder 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 10ec91e5..7aa6fa61 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 @@ -64,10 +64,18 @@ public interface SaasFeatureResourceService extends IService> listCache(ListSaasFeatureResourceCache param); + void refreshCache(RefreshFeatureResourceCacheParam param); + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + class RefreshFeatureResourceCacheParam { + private Set terminals; + } + @Data @Builder @NoArgsConstructor 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 index 6e1415b6..2c48a40b 100644 --- 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 @@ -1,228 +1,348 @@ package cn.axzo.tyr.server.service.impl; -import cn.axzo.foundation.exception.Axssert; -import cn.axzo.pokonyan.config.redis.RedisClient; +import cn.axzo.basics.common.exception.ServiceException; import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq; -import cn.axzo.tyr.server.event.inner.CacheProductPermissionHandler; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; +import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; +import cn.axzo.tyr.server.repository.entity.SaasFeature; import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductPermissionCacheService; +import cn.axzo.tyr.server.service.SaasFeatureResourceService; import cn.hutool.core.lang.Pair; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import com.google.common.collect.Streams; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.BooleanUtils; 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.RedisTemplate; -import org.springframework.data.redis.core.SessionCallback; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.stream.Collectors; -import static cn.axzo.tyr.server.config.exception.BizResultCode.REDIS_PRODUCT_NOT_NULL; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE; @Slf4j @Service @RefreshScope public class ProductPermissionCacheServiceImpl implements ProductPermissionCacheService { - private static final String PRODUCT_PERMISSION_KEY = "product:permission:%s"; - - @Autowired - private RedisTemplate redisTemplate; @Autowired private ProductFeatureRelationService productFeatureRelationService; @Autowired - private CacheProductPermissionHandler cacheProductPermissionHandler; + private SaasFeatureResourceService saasFeatureResourceService; + @Autowired + private SaasFeatureDao saasFeatureDao; /** 产品权限缓存过期时间 **/ @Value("${product.permission.expire.minutes:14}") private Long expireInMinutes; + private LoadingCache>> productPermissionCache = CacheBuilder.newBuilder() + .expireAfterWrite(14, TimeUnit.MINUTES) + .maximumSize(5000) + .build(new CacheLoader>>() { + @Override + public Optional> load(Long productId) { + return listProductPermissions(Lists.newArrayList(productId)) + .values() + .stream() + .findFirst(); + } + + @Override + public Map>> loadAll(Iterable keys) throws Exception { + List productIds = Lists.newArrayList(keys); + + Map> productPermissions = listProductPermissions(productIds); + + return Maps.toMap(productIds, productId -> Optional.ofNullable(productPermissions.get(productId))); + } + }); + @Override public Map> list(ListProductPermissionParam param) { if (CollectionUtils.isEmpty(param.getProductIds())) { return Collections.emptyMap(); } - Map> permissionCached = listProductPermissionCached(param); + Map> productPermissions; + try { + productPermissions = productPermissionCache.getAll(param.getProductIds()).entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().orElseGet(Lists::newArrayList))); + } catch (ExecutionException ex) { + log.error("list product cache permission error:{} error", param.getProductIds(), ex); + // 外面有做降级 + throw new ServiceException("查询产品权限缓存异常"); + } - fillCacheProductPermissions(param, permissionCached); + if (CollectionUtils.isEmpty(param.getFeatureCodes())) { + return productPermissions; + } - return permissionCached; - } - - private Map> listProductPermissionCached(ListProductPermissionParam param) { - - List redisValues = redisTemplate.executePipelined(new SessionCallback() { - @Override - public Object execute(RedisOperations operations) throws DataAccessException { - - for (Long productId : param.getProductIds()) { - String redisKey = getKey(productId); - - if (CollectionUtils.isEmpty(param.getFeatureCodes())) { - RedisClient.HashOps.hGetAll(redisKey); - } else { - RedisClient.HashOps.hMultiGet(redisKey, Lists.newArrayList(param.getFeatureCodes())); - } - - } - return null; - } - }); - - return Streams.zip(param.getProductIds().stream(), - redisValues.stream(), - (productId, redisValue) -> { - - if (Objects.isNull(redisValue)) { - return null; - } - - if (CollectionUtils.isEmpty(param.getFeatureCodes())) { - List permissions = (List) ((Map) redisValue).values().stream() - .flatMap(e -> JSONArray.parseArray(JSONArray.toJSONString(e), PermissionDTO.class).stream()) - .collect(Collectors.toList()); - - return Pair.of(productId, permissions); - } - - List permissions = (List) ((List) redisValue).stream() - .filter(Objects::nonNull) - .flatMap(e -> JSONArray.parseArray((String) e, PermissionDTO.class).stream()) - .collect(Collectors.toList()); - - return Pair.of(productId, permissions); - - }) - .filter(Objects::nonNull) + return productPermissions.entrySet() + .stream() + .map(e -> Pair.of(e.getKey(), e.getValue().stream() + .filter(permission -> param.getFeatureCodes().contains(permission.getFeatureCode())) + .collect(Collectors.toList())) + ) + .filter(e -> !CollectionUtils.isEmpty(e.getValue())) .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); } @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()); - - Map redisValues = productPermission.getPermissions().stream() - .collect(Collectors.groupingBy(PermissionDTO::getFeatureCode)) - .entrySet() - .stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); - - // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 - redisTemplate.delete(redisKey); - RedisClient.HashOps.hPutAll(redisKey, redisValues); - redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); - 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()); - } - - /** - * 组装在缓存中没有查询到权限的产品 - * @param param - * @param permissionCached - */ - private void fillCacheProductPermissions(ListProductPermissionParam param, - Map> permissionCached) { - - Sets.SetView difference = Sets.difference(param.getProductIds(), permissionCached.keySet()); - if (difference.isEmpty()) { + public void refreshCache(RefreshProductPermissionCacheParam param) { + if (CollectionUtils.isEmpty(param.getProductIds())) { return; } + Map> productPermissions = listProductPermissions(Lists.newArrayList(param.getProductIds())); + + productPermissionCache.putAll(Maps.toMap(param.getProductIds(), productId -> Optional.ofNullable(productPermissions.get(productId)))); + } + + private Map> listProductPermissions(List productIds) { + + if (CollectionUtils.isEmpty(productIds)) { + return Collections.emptyMap(); + } + PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() - .productModuleIds(difference) + .productModuleIds(Sets.newHashSet(productIds)) .build(); List productPermissions = productFeatureRelationService.list(pageProductFeatureRelationReq); - List productPermissionsCache = cacheProductPermissionHandler.resolveProductPermissions(productPermissions); - if (CollectionUtils.isEmpty(productPermissionsCache)) return; - - StoreProductPermissionParam storeWorkspaceProductParam = StoreProductPermissionParam.builder() - .productPermissions(productPermissionsCache) - .build(); - store(storeWorkspaceProductParam); - - Map> productPermissionMap = productPermissionsCache.stream() + return resolveProductPermissions(productPermissions).stream() .collect(Collectors.toMap(ProductPermission::getProductId, ProductPermission::getPermissions)); - permissionCached.putAll(productPermissionMap); } - private String getKey(Object... params) { - return String.format(PRODUCT_PERMISSION_KEY, params); + private List resolveProductPermissions(List productPermissions) { + if (CollectionUtils.isEmpty(productPermissions)) { + return Collections.emptyList(); + } + + // 新的菜单树是是把有权限点的父节点也存进去了,所以直接解析 + Map featureResources = listSaasFeatureResource(productPermissions); + + Map parentFeatureResources = listParentSaasFeatureResource(featureResources); + + // 旧的菜单树只存储了权限点信息,没有把父节点存进去,需要解析父节点进行存储 + Map saasFeatures = listSaasFeature(productPermissions); + + Map parentSaasFeatures = listParentSaasFeature(saasFeatures); + + return productPermissions.stream() + .collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId)) + .entrySet() + .stream() + .map(e -> { + List productFeatureRelations = e.getValue(); + + if (CollectionUtils.isEmpty(productFeatureRelations)) { + return null; + } + + List permissions = productFeatureRelations.stream() + .map(relation -> { + if (Objects.equals(relation.getType(), NEW_FEATURE)) { + return resolveFeatureResourcePermission(relation, featureResources, parentFeatureResources); + } + + return resolveFeaturePermission(relation, saasFeatures, parentSaasFeatures); + }) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(permissions)) { + return null; + } + + return ProductPermissionCacheService.ProductPermission.builder() + .productId(e.getKey()) + .permissions(permissions) + .build(); + + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); } - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - static class PermissionWrapper { + private List resolveFeaturePermission(SaasProductModuleFeatureRelation relation, Map saasFeatures, Map parentSaasFeatures) { + SaasFeature saasFeature = saasFeatures.get(relation.getFeatureId()); + if (Objects.isNull(saasFeature)) { + return null; + } - /** - * 协同关系类型 - * 原saas_product_module_feature_relation.dictCode - */ - private String cooperateType; + List permissionDTOS = Lists.newArrayList(ProductPermissionCacheService.PermissionDTO.builder() + .featureId(saasFeature.getId()) + .featureCode(saasFeature.getFeatureCode()) + .featureType(saasFeature.getFeatureType()) + .terminal(saasFeature.getTerminal()) + .cooperateType(relation.getDictCode()) + .build()); - private Long featureId; + List parentPermissions = saasFeature.splitPath().stream() + .map(parentSaasFeatures::get) + .filter(Objects::nonNull) + .map(f -> ProductPermissionCacheService.PermissionDTO.builder() + .featureId(f.getId()) + .featureCode(f.getFeatureCode()) + .featureType(f.getFeatureType()) + .terminal(f.getTerminal()) + .cooperateType(relation.getDictCode()) + .build()) + .collect(Collectors.toList()); - private String featureCode; + permissionDTOS.addAll(parentPermissions); + return permissionDTOS; + } - private String terminal; + private List resolveFeatureResourcePermission(SaasProductModuleFeatureRelation relation, Map featureResources, Map parentFeatureResources) { + SaasFeatureResourceResp featureResource = featureResources.get(relation.getFeatureId()); + // 菜单节点是不会关联元素code,所以缓存的featureCode使用菜单编码 + if (Objects.isNull(featureResource)) { + return null; + } - private Integer featureType; + if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) { + return null; + } - private Long productId; + List permissionDTOS = featureResource.getSaasPageElements().stream() + .map(pageElement -> ProductPermissionCacheService.PermissionDTO.builder() + .featureId(featureResource.getId()) + .featureCode(pageElement.getCode()) + .featureType(featureResource.getFeatureType()) + .terminal(featureResource.getTerminal()) + .cooperateType(relation.getDictCode()) + .itemCode(pageElement.getItemCode()) + .version(pageElement.getVersion()) + .appType(pageElement.getAppType()) + .build()) + .collect(Collectors.toList()); + + List parentPermissions = featureResource.resolvePath().stream() + .map(parentFeatureResources::get) + .filter(Objects::nonNull) + .map(f -> { + if (CollectionUtils.isEmpty(f.getSaasPageElements())) { + return null; + } + + return f.getSaasPageElements().stream() + .map(pageElement -> ProductPermissionCacheService.PermissionDTO.builder() + .featureId(f.getId()) + .featureCode(pageElement.getCode()) + .featureType(f.getFeatureType()) + .terminal(f.getTerminal()) + .cooperateType(relation.getDictCode()) + .itemCode(pageElement.getItemCode()) + .version(pageElement.getVersion()) + .appType(pageElement.getAppType()) + .build()) + .collect(Collectors.toList()); + }) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + permissionDTOS.addAll(parentPermissions); + return permissionDTOS; + } + + + private Map listSaasFeatureResource(List productPermissions) { + + List featureIds = productPermissions.stream() + .filter(e -> Objects.equals(e.getType(), NEW_FEATURE)) + .map(SaasProductModuleFeatureRelation::getFeatureId) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyMap(); + } + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(featureIds) + .needPageElement(true) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); + } + + private Map listParentSaasFeatureResource(Map productPermissions) { + + List parentIds = productPermissions.values().stream() + .map(SaasFeatureResourceResp::resolvePath) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(parentIds)) { + return Collections.emptyMap(); + } + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(parentIds) + .needPageElement(true) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); + } + + private Map listSaasFeature(List productPermissions) { + + Set featureIds = productPermissions.stream() + .filter(e -> Objects.equals(e.getType(), OLD_FEATURE)) + .map(SaasProductModuleFeatureRelation::getFeatureId) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyMap(); + } + + return saasFeatureDao.listByIds(featureIds).stream() + .collect(Collectors.toMap(SaasFeature::getId, Function.identity())); + } + + private Map listParentSaasFeature(Map saasFeatures) { + + if (CollectionUtils.isEmpty(saasFeatures)) { + return Collections.emptyMap(); + } + + List parentIds = saasFeatures.values().stream() + .map(SaasFeature::splitPath) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(parentIds)) { + return Collections.emptyMap(); + } + + return saasFeatureDao.listByIds(parentIds).stream() + .collect(Collectors.toMap(SaasFeature::getId, Function.identity())); } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java index 97d7c6cc..09eeb53f 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java @@ -1,38 +1,41 @@ package cn.axzo.tyr.server.service.impl; -import cn.axzo.foundation.exception.Axssert; -import cn.axzo.pokonyan.config.redis.RedisClient; +import cn.axzo.basics.common.exception.ServiceException; import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq; -import cn.axzo.tyr.server.event.inner.CacheProductSaasFeatureResourceHandler; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation; import cn.axzo.tyr.server.service.ProductFeatureRelationService; import cn.axzo.tyr.server.service.ProductSaasFeatureResourceCacheService; +import cn.axzo.tyr.server.service.SaasFeatureResourceService; import cn.hutool.core.lang.Pair; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import com.google.common.collect.Streams; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; 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.RedisTemplate; -import org.springframework.data.redis.core.SessionCallback; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.stream.Collectors; -import static cn.axzo.tyr.server.config.exception.BizResultCode.REDIS_PRODUCT_NOT_NULL; import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; @Slf4j @@ -40,139 +43,213 @@ import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation. @RefreshScope public class ProductSaasFeatureResourceCacheServiceImpl implements ProductSaasFeatureResourceCacheService { - private static final String PRODUCT_SAAS_FEATURE_RESOURCE_KEY = "product:feature:resource:%s"; - - @Autowired - private RedisTemplate redisTemplate; @Autowired private ProductFeatureRelationService productFeatureRelationService; @Autowired - private CacheProductSaasFeatureResourceHandler cacheProductSaasFeatureResourceHandler; + private SaasFeatureResourceService saasFeatureResourceService; @Value("${product.feature.resouce.expire.minutes:14}") private Long expireInMinutes; + public static final Set FEATURE_RESOURCE_TYPES = Sets.newHashSet(FeatureResourceType.MENU.getCode(), + FeatureResourceType.PAGE.getCode(), + FeatureResourceType.MENU_PARTITION_GROUP.getCode(), + FeatureResourceType.GROUP.getCode(), + FeatureResourceType.APP_ENTRY.getCode()); + + private LoadingCache>> productFeatureResourceCache = CacheBuilder.newBuilder() + .expireAfterWrite(14, TimeUnit.MINUTES) + .maximumSize(5000) + .build(new CacheLoader>>() { + @Override + public Optional> load(Long productId) { + return listProductFeatureResource(Lists.newArrayList(productId)) + .values() + .stream() + .findFirst(); + } + + @Override + public Map>> loadAll(Iterable keys) throws Exception { + List productIds = Lists.newArrayList(keys); + + Map> productPermissions = listProductFeatureResource(productIds); + + return Maps.toMap(productIds, productId -> Optional.ofNullable(productPermissions.get(productId))); + } + }); + @Override public Map> list(ListProductFeatureResourceParam param) { if (CollectionUtils.isEmpty(param.getProductIds())) { return Collections.emptyMap(); } - Map> featureResourceCached = listProductFeatureResourceCached(param); + Map> productFeatureResources; + try { + productFeatureResources = productFeatureResourceCache.getAll(param.getProductIds()).entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().orElseGet(Lists::newArrayList))); + } catch (ExecutionException ex) { + log.error("list product cache featureResource error:{} error", param.getProductIds(), ex); + // 外面有做降级 + throw new ServiceException("查询产品菜单缓存异常"); + } - fillCacheProductFeatureResource(param, featureResourceCached); + if (CollectionUtils.isEmpty(param.getUniCodes())) { + return productFeatureResources; + } - return featureResourceCached; - } - - @Override - public void store(StoreProductFeatureResourceParam param) { - Axssert.check(param.getProductFeatureResources().stream().allMatch(e -> Objects.nonNull(e.getProductId())), REDIS_PRODUCT_NOT_NULL); - - redisTemplate.executePipelined(new SessionCallback() { - @Override - public Object execute(RedisOperations operations) throws DataAccessException { - - for (ProductFeatureResource productFeatureResource : param.getProductFeatureResources()) { - String redisKey = getKey(productFeatureResource.getProductId()); - - Map redisValues = productFeatureResource.getFeatureResources().stream() - .collect(Collectors.groupingBy(FeatureResourceDTO::getUniCode)) - .entrySet() - .stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); - - // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 - redisTemplate.delete(redisKey); - RedisClient.HashOps.hPutAll(redisKey, redisValues); - redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); - log.info("succeed to store product featureResource: redisKey:{} value:{}", redisKey, redisValues); - } - return null; - } - }); - } - - private Map> listProductFeatureResourceCached(ListProductFeatureResourceParam param) { - - List redisValues = redisTemplate.executePipelined(new SessionCallback() { - @Override - public Object execute(RedisOperations operations) throws DataAccessException { - - for (Long productId : param.getProductIds()) { - String redisKey = getKey(productId); - - if (CollectionUtils.isEmpty(param.getUniCodes())) { - RedisClient.HashOps.hGetAll(redisKey); - } else { - RedisClient.HashOps.hMultiGet(redisKey, Lists.newArrayList(param.getUniCodes())); - } - - } - return null; - } - }); - - return Streams.zip(param.getProductIds().stream(), - redisValues.stream(), - (productId, redisValue) -> { - - if (Objects.isNull(redisValue)) { - return null; - } - - if (CollectionUtils.isEmpty(param.getUniCodes())) { - List featureResources = (List) ((Map) redisValue).values().stream() - .flatMap(e -> JSONArray.parseArray(JSONArray.toJSONString(e), FeatureResourceDTO.class).stream()) - .collect(Collectors.toList()); - - return Pair.of(productId, featureResources); - } - - List featureResources = (List) ((List) redisValue).stream() - .filter(Objects::nonNull) - .flatMap(e -> JSONArray.parseArray((String) e, FeatureResourceDTO.class).stream()) - .collect(Collectors.toList()); - - return Pair.of(productId, featureResources); - - }) - .filter(Objects::nonNull) + return productFeatureResources.entrySet() + .stream() + .map(e -> Pair.of(e.getKey(), e.getValue().stream() + .filter(permission -> param.getUniCodes().contains(permission.getUniCode())) + .collect(Collectors.toList())) + ) + .filter(e -> !CollectionUtils.isEmpty(e.getValue())) .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); } - private void fillCacheProductFeatureResource(ListProductFeatureResourceParam param, - Map> featureResourceCached) { - - Sets.SetView difference = Sets.difference(param.getProductIds(), featureResourceCached.keySet()); - if (difference.isEmpty()) { + @Override + public void refreshCache(RefreshProductFeatureResourceCacheParam param) { + if (CollectionUtils.isEmpty(param.getProductIds())) { return; } + Map> productPermissions = listProductFeatureResource(Lists.newArrayList(param.getProductIds())); + + productFeatureResourceCache.putAll(Maps.toMap(param.getProductIds(), productId -> Optional.ofNullable(productPermissions.get(productId)))); + } + + private Map> listProductFeatureResource(List productIds) { + + if (CollectionUtils.isEmpty(productIds)) { + return Collections.emptyMap(); + } + PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder() - .productModuleIds(difference) + .productModuleIds(Sets.newHashSet(productIds)) .type(NEW_FEATURE) - .featureResourceTypes(Lists.newArrayList(FeatureResourceType.MENU.getCode(), - FeatureResourceType.PAGE.getCode(), - FeatureResourceType.MENU_PARTITION_GROUP.getCode(), - FeatureResourceType.GROUP.getCode(), - FeatureResourceType.APP_ENTRY.getCode())) .build(); List productPermissions = productFeatureRelationService.list(pageProductFeatureRelationReq); - List productFeatureResources = cacheProductSaasFeatureResourceHandler.resolveProductFeatureResources(productPermissions); - if (CollectionUtils.isEmpty(productFeatureResources)) return; - - StoreProductFeatureResourceParam storeProductFeatureResourceParam = StoreProductFeatureResourceParam.builder() - .productFeatureResources(productFeatureResources) - .build(); - store(storeProductFeatureResourceParam); - - Map> productFeatureResourceMap = productFeatureResources.stream() + return resolveProductFeatureResources(productPermissions).stream() .collect(Collectors.toMap(ProductFeatureResource::getProductId, ProductFeatureResource::getFeatureResources)); - featureResourceCached.putAll(productFeatureResourceMap); } - private String getKey(Object... params) { - return String.format(PRODUCT_SAAS_FEATURE_RESOURCE_KEY, params); + private List resolveProductFeatureResources(List productPermissions) { + if (CollectionUtils.isEmpty(productPermissions)) { + return Collections.emptyList(); + } + + Map featureResources = listSaasFeatureResource(productPermissions); + + Map parentFeatureResources = listParentSaasFeatureResource(featureResources); + + return productPermissions.stream() + .collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId)) + .entrySet() + .stream() + .map(e -> { + List productFeatureRelations = e.getValue(); + + if (CollectionUtils.isEmpty(productFeatureRelations)) { + return null; + } + + List productFeatureResources = productFeatureRelations.stream() + .map(relation -> { + SaasFeatureResourceResp featureResource = featureResources.get(relation.getFeatureId()); + if (Objects.isNull(featureResource) || StringUtils.isBlank(featureResource.getUniCode())) { + return null; + } + + ProductSaasFeatureResourceCacheService.FeatureResourceDTO featureResourceDTO = from(featureResource, relation); + List featureResourceDTOS = Lists.newArrayList(featureResourceDTO); + + List parentPermissions = featureResource.resolvePath().stream() + .map(parentFeatureResources::get) + .filter(Objects::nonNull) + .map(f -> { + + if (StringUtils.isBlank(f.getUniCode())) { + return null; + } + + return from(featureResource, relation); + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + featureResourceDTOS.addAll(parentPermissions); + + return featureResourceDTOS; + }) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .distinct() + .filter(f -> FEATURE_RESOURCE_TYPES.contains(f.getFeatureType())) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(productFeatureResources)) { + return null; + } + + return ProductSaasFeatureResourceCacheService.ProductFeatureResource.builder() + .productId(e.getKey()) + .featureResources(productFeatureResources) + .build(); + + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + private ProductSaasFeatureResourceCacheService.FeatureResourceDTO from(SaasFeatureResourceResp featureResource, + SaasProductModuleFeatureRelation relation) { + return ProductSaasFeatureResourceCacheService.FeatureResourceDTO.builder() + .featureId(featureResource.getId()) + .featureType(featureResource.getFeatureType()) + .terminal(featureResource.getTerminal()) + .uniCode(featureResource.getUniCode()) + .cooperateType(relation.getDictCode()) + .build(); + } + + private Map listSaasFeatureResource(List productPermissions) { + + List featureIds = productPermissions.stream() + .map(SaasProductModuleFeatureRelation::getFeatureId) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyMap(); + } + + // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(featureIds) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); + } + + private Map listParentSaasFeatureResource(Map productPermissions) { + + List parentIds = productPermissions.values().stream() + .map(SaasFeatureResourceResp::resolvePath) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(parentIds)) { + return Collections.emptyMap(); + } + + // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(parentIds) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); } } 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 index 43ac0dbb..14eb0b7a 100644 --- 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 @@ -1,207 +1,338 @@ package cn.axzo.tyr.server.service.impl; -import cn.axzo.foundation.exception.Axssert; -import cn.axzo.pokonyan.config.redis.RedisClient; +import cn.axzo.basics.common.exception.ServiceException; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; +import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; import cn.axzo.tyr.client.model.res.SaasRoleRes; -import cn.axzo.tyr.server.event.inner.CacheRolePermissionHandler; +import cn.axzo.tyr.server.repository.dao.SaasFeatureDao; +import cn.axzo.tyr.server.repository.entity.SaasFeature; import cn.axzo.tyr.server.service.RolePermissionCacheService; import cn.axzo.tyr.server.service.RoleService; +import cn.axzo.tyr.server.service.SaasFeatureResourceService; import cn.hutool.core.lang.Pair; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import com.google.common.collect.Streams; +import com.google.common.collect.Maps; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.BooleanUtils; 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.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.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.stream.Collectors; -import static cn.axzo.tyr.server.config.exception.BizResultCode.REDIS_ROLE_NOT_NULL; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; +import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE; @Slf4j @Service @RefreshScope public class RolePermissionCacheServiceImpl implements RolePermissionCacheService { - private static final String ROLE_PERMISSION_KEY = "role:permission:%s"; - - @Autowired - protected StringRedisTemplate redisTemplate; @Autowired private RoleService roleService; @Autowired - private CacheRolePermissionHandler cacheRolePermissionHandler; - + private SaasFeatureResourceService saasFeatureResourceService; + @Autowired + private SaasFeatureDao saasFeatureDao; /** 角色权限缓存过期时间 **/ @Value("${role.permission.expire.minutes:14}") - private Long expireInMinutes; + private static Long expireInMinutes; + + private LoadingCache>> rolePermissionCache = CacheBuilder.newBuilder() + .expireAfterWrite(14, TimeUnit.MINUTES) + .maximumSize(5000) + .build(new CacheLoader>>() { + @Override + public Optional> load(Long roleId) { + return listRolePermission(Lists.newArrayList(roleId)) + .values() + .stream() + .findFirst(); + } + + @Override + public Map>> loadAll(Iterable keys) throws Exception { + List roleIds = Lists.newArrayList(keys); + + Map> rolePermissions = listRolePermission(roleIds); + + return Maps.toMap(roleIds, roleId -> Optional.ofNullable(rolePermissions.get(roleId))); + } + }); @Override public Map> list(ListRolePermissionParam param) { if (CollectionUtils.isEmpty(param.getRoleIds())) { return Collections.emptyMap(); } + Map> rolePermissions; + try { + rolePermissions = rolePermissionCache.getAll(param.getRoleIds()).entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().orElseGet(Lists::newArrayList))); + } catch (ExecutionException ex) { + log.error("list role cache permission error:{} error", param.getRoleIds(), ex); + // 外面有做降级 + throw new ServiceException("查询角色权限缓存异常"); + } - Map> permissions = listRolePermissionCached(param); + if (CollectionUtils.isEmpty(param.getFeatureCodes())) { + return rolePermissions; + } - fillCacheRolePermissions(param, permissions); - return permissions; - } - - - private Map> listRolePermissionCached(ListRolePermissionParam param) { - - List redisValues = redisTemplate.executePipelined(new SessionCallback() { - @Override - public Object execute(RedisOperations operations) throws DataAccessException { - - for (Long roleId : param.getRoleIds()) { - String redisKey = getKey(roleId); - if (CollectionUtils.isEmpty(param.getFeatureCodes())) { - RedisClient.HashOps.hGetAll(redisKey); - } else { - RedisClient.HashOps.hMultiGet(redisKey, Lists.newArrayList(param.getFeatureCodes())); - } - - } - return null; - } - }); - - return Streams.zip(param.getRoleIds().stream(), - redisValues.stream(), - (roleId, redisValue) -> { - - if (Objects.isNull(redisValue)) { - return null; - } - - if (CollectionUtils.isEmpty(param.getFeatureCodes())) { - - List permissions = (List) ((Map) redisValue).values().stream() - .flatMap(e -> JSONArray.parseArray(JSONArray.toJSONString(e), PermissionDTO.class).stream()) - .collect(Collectors.toList()); - return Pair.of(roleId, permissions); - } - - List permissions = (List) ((List) redisValue).stream() - .filter(Objects::nonNull) - .flatMap(e -> JSONArray.parseArray((String) e, PermissionDTO.class).stream()) - .collect(Collectors.toList()); - return Pair.of(roleId, permissions); - - }) - .filter(Objects::nonNull) + return rolePermissions.entrySet() + .stream() + .map(e -> Pair.of(e.getKey(), e.getValue().stream() + .filter(permission -> param.getFeatureCodes().contains(permission.getFeatureCode())) + .collect(Collectors.toList())) + ) + .filter(e -> !CollectionUtils.isEmpty(e.getValue())) .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); } @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()); - - Map redisValues = rolePermission.getPermissions().stream() - .collect(Collectors.groupingBy(PermissionDTO::getFeatureCode)) - .entrySet() - .stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); - - // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 - redisTemplate.delete(redisKey); - RedisClient.HashOps.hPutAll(redisKey, redisValues); - redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); - 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()); - } - - /** - * 组装在缓存中没有查询到权限的角色权限 - * @param param - * @param permissionCached - */ - private void fillCacheRolePermissions(ListRolePermissionParam param, - Map> permissionCached) { - - Sets.SetView difference = Sets.difference(param.getRoleIds(), permissionCached.keySet()); - if (difference.isEmpty()) { + public void refreshCache(RefreshRolePermissionCacheParam param) { + if (CollectionUtils.isEmpty(param.getRoleIds())) { return; } + Map> rolePermissions = listRolePermission(Lists.newArrayList(param.getRoleIds())); + rolePermissionCache.putAll(Maps.toMap(param.getRoleIds(), roleId -> Optional.ofNullable(rolePermissions.get(roleId)))); + } + private Map> listRolePermission(List roleIds) { RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() - .roleIds(Lists.newArrayList(difference)) + .roleIds(roleIds) .needPermissionRelation(true) .build(); List roles = roleService.list(listSaasRoleParam); if (CollectionUtils.isEmpty(roles)) { - return; + return Collections.emptyMap(); } - List rolePermissions = cacheRolePermissionHandler.resolveRolePermission(roles); - - if (CollectionUtils.isEmpty(rolePermissions)) { - return; - } - - StoreRolePermissionParam storeRolePermissionParam = StoreRolePermissionParam.builder() - .rolePermissions(rolePermissions) - .build(); - store(storeRolePermissionParam); - - Map> rolePermissionMap = rolePermissions.stream() - .collect(Collectors.toMap(RolePermission::getRoleId, RolePermission::getPermissions)); - permissionCached.putAll(rolePermissionMap); + return resolveRolePermission(roles).stream() + .collect(Collectors.toMap(RolePermissionCacheService.RolePermission::getRoleId, + RolePermissionCacheService.RolePermission::getPermissions)); } - private String getKey(Object... params) { - return String.format(ROLE_PERMISSION_KEY, params); + private List resolveRolePermission(List roles) { + + + Map featureResources = listSaasFeatureResource(roles); + + Map parentFeatureResources = listParentSaasFeatureResource(featureResources); + + Map saasFeatures = listSaasFeature(roles); + + Map parentSaasFeatures = listParentSaasFeature(saasFeatures); + + + return roles.stream() + .map(e -> { + if (CollectionUtils.isEmpty(e.getPermissionRelations())) { + return null; + } + + List permissions = e.getPermissionRelations().stream() + .distinct() + .map(permissionRelation -> { + if (Objects.equals(permissionRelation.getType(), NEW_FEATURE)) { + return resolveFeatureResourcePermission(permissionRelation, featureResources, parentFeatureResources); + } + return resolveFeaturePermission(permissionRelation, saasFeatures, parentSaasFeatures); + }) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(permissions)) { + return null; + } + + return RolePermissionCacheService.RolePermission.builder() + .roleId(e.getId()) + .permissions(permissions) + .build(); + + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + private static List resolveFeaturePermission(SaasPermissionRelationRes permissionRelation, Map saasFeatures, Map parentSaasFeatures) { + SaasFeature saasFeature = saasFeatures.get(permissionRelation.getFeatureId()); + if (Objects.isNull(saasFeature)) { + return null; + } + + List permissionDTOS = Lists.newArrayList(RolePermissionCacheService.PermissionDTO.builder() + .featureId(saasFeature.getId()) + .featureCode(saasFeature.getFeatureCode()) + .featureType(saasFeature.getFeatureType()) + .terminal(saasFeature.getTerminal()) + .build()); + + List parentPermissions = saasFeature.splitPath().stream() + .map(parentSaasFeatures::get) + .filter(Objects::nonNull) + .map(f -> RolePermissionCacheService.PermissionDTO.builder() + .featureId(f.getId()) + .featureCode(f.getFeatureCode()) + .featureType(f.getFeatureType()) + .terminal(f.getTerminal()) + .build()) + .collect(Collectors.toList()); + + permissionDTOS.addAll(parentPermissions); + return permissionDTOS; + } + + private static List resolveFeatureResourcePermission(SaasPermissionRelationRes permissionRelation, Map featureResources, Map parentFeatureResources) { + SaasFeatureResourceResp featureResource = featureResources.get(permissionRelation.getFeatureId()); + // 菜单节点是不会关联元素code,所以缓存的featureCode使用菜单编码 + if (Objects.isNull(featureResource)) { + return null; + } + + if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) { + return null; + } + + List permissionDTOS = featureResource.getSaasPageElements().stream() + .map(pageElement -> RolePermissionCacheService.PermissionDTO.builder() + .featureId(featureResource.getId()) + .featureCode(pageElement.getCode()) + .featureType(featureResource.getFeatureType()) + .terminal(featureResource.getTerminal()) + .build()) + .collect(Collectors.toList()); + + List parentPermissions = featureResource.resolvePath().stream() + .map(parentFeatureResources::get) + .filter(Objects::nonNull) + .map(f -> { + + if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) { + return null; + } + + return featureResource.getSaasPageElements().stream() + .map(pageElement -> RolePermissionCacheService.PermissionDTO.builder() + .featureId(f.getId()) + .featureCode(pageElement.getCode()) + .featureType(f.getFeatureType()) + .terminal(f.getTerminal()) + .build()) + .collect(Collectors.toList()); + }) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + permissionDTOS.addAll(parentPermissions); + + return permissionDTOS; + } + + + private Map listSaasFeatureResource(List roles) { + + List featureIds = roles.stream() + .filter(e -> !CollectionUtils.isEmpty(e.getPermissionRelations())) + .map(SaasRoleRes::getPermissionRelations) + .flatMap(Collection::stream) + .filter(e -> Objects.equals(e.getType(), NEW_FEATURE)) + .map(SaasPermissionRelationRes::getFeatureId) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyMap(); + } + + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(featureIds) + .needPageElement(true) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); + } + + private Map listParentSaasFeatureResource(Map productPermissions) { + + List parentIds = productPermissions.values().stream() + .map(SaasFeatureResourceResp::resolvePath) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(parentIds)) { + return Collections.emptyMap(); + } + + // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(parentIds) + .needPageElement(true) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); + } + + private Map listSaasFeature(List roles) { + + Set featureIds = roles.stream() + .filter(e -> !CollectionUtils.isEmpty(e.getPermissionRelations())) + .map(SaasRoleRes::getPermissionRelations) + .flatMap(Collection::stream) + .filter(e -> Objects.equals(e.getType(), OLD_FEATURE)) + .map(SaasPermissionRelationRes::getFeatureId) + .collect(Collectors.toSet()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyMap(); + } + + return saasFeatureDao.listByIds(featureIds) + .stream() + .collect(Collectors.toMap(SaasFeature::getId, Function.identity(), (f, s) -> s)); + } + + private Map listParentSaasFeature(Map saasFeatures) { + + if (CollectionUtils.isEmpty(saasFeatures)) { + return Collections.emptyMap(); + } + + List parentIds = saasFeatures.values().stream() + .map(SaasFeature::splitPath) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(parentIds)) { + return Collections.emptyMap(); + } + + return saasFeatureDao.listByIds(parentIds).stream() + .collect(Collectors.toMap(SaasFeature::getId, Function.identity())); } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java index f63f3e02..5a3e4a7c 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java @@ -1,153 +1,127 @@ package cn.axzo.tyr.server.service.impl; -import cn.axzo.foundation.exception.Axssert; -import cn.axzo.pokonyan.config.redis.RedisClient; +import cn.axzo.basics.common.exception.ServiceException; import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; +import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes; import cn.axzo.tyr.client.model.res.SaasRoleRes; -import cn.axzo.tyr.server.event.inner.CacheRoleSaasFeatureResourceHandler; import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService; import cn.axzo.tyr.server.service.RoleService; +import cn.axzo.tyr.server.service.SaasFeatureResourceService; import cn.hutool.core.lang.Pair; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import com.google.common.collect.Streams; +import com.google.common.collect.Maps; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; 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.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.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.stream.Collectors; -import static cn.axzo.tyr.server.config.exception.BizResultCode.REDIS_ROLE_NOT_NULL; import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; +import static cn.axzo.tyr.server.service.impl.ProductSaasFeatureResourceCacheServiceImpl.FEATURE_RESOURCE_TYPES; @Slf4j @Service @RefreshScope public class RoleSaasFeatureResourceCacheServiceImpl implements RoleSaasFeatureResourceCacheService { - private static final String ROLE_SAAS_FEATURE_RESOURCE_KEY = "role:feature:resource:%s"; - - @Autowired - protected StringRedisTemplate redisTemplate; @Autowired private RoleService roleService; @Autowired - private CacheRoleSaasFeatureResourceHandler cacheRoleSaasFeatureResourceHandler; - + private SaasFeatureResourceService saasFeatureResourceService; /** 角色菜单缓存过期时间 **/ @Value("${role.feature.resource.expire.minutes:14}") private Long expireInMinutes; + private LoadingCache>> roleFeatureResourceCache = CacheBuilder.newBuilder() + .expireAfterWrite(14, TimeUnit.MINUTES) + .maximumSize(5000) + .build(new CacheLoader>>() { + @Override + public Optional> load(Long roleId) { + return listRoleFeatureResource(Lists.newArrayList(roleId)) + .values() + .stream() + .findFirst(); + } + + @Override + public Map>> loadAll(Iterable keys) throws Exception { + List roleIds = Lists.newArrayList(keys); + + Map> roleFeatureResources = listRoleFeatureResource(roleIds); + + return Maps.toMap(roleIds, roleId -> Optional.ofNullable(roleFeatureResources.get(roleId))); + } + }); + @Override public Map> list(ListRoleSaasFeatureResourceParam param) { if (CollectionUtils.isEmpty(param.getRoleIds())) { return Collections.emptyMap(); } - Map> featureResources = listRoleSaasFeatureResourceCached(param); + Map> roleFeatureResources; + try { + roleFeatureResources = roleFeatureResourceCache.getAll(param.getRoleIds()).entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().orElseGet(Lists::newArrayList))); + } catch (ExecutionException ex) { + log.error("list role cache featureResource error:{} error", param.getRoleIds(), ex); + // 外面有做降级 + throw new ServiceException("查询角色菜单缓存异常"); + } - fillCacheRoleFeatureResources(param, featureResources); - return featureResources; - } + if (CollectionUtils.isEmpty(param.getUniCodes())) { + return roleFeatureResources; + } - @Override - public void store(StoreRoleSaasFeatureResourceParam param) { - Axssert.check(param.getRoleSaasFeatureResources().stream().allMatch(e -> Objects.nonNull(e.getRoleId())), REDIS_ROLE_NOT_NULL); - - redisTemplate.executePipelined((RedisCallback) connection -> { - - connection.openPipeline(); - - for (RoleFeatureResource roleFeatureResource : param.getRoleSaasFeatureResources()) { - String redisKey = getKey(roleFeatureResource.getRoleId()); - - Map redisValues = roleFeatureResource.getSaasFeatureResources().stream() - .collect(Collectors.groupingBy(SaasFeatureResourceDTO::getUniCode)) - .entrySet() - .stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue()))); - - // 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁 - redisTemplate.delete(redisKey); - RedisClient.HashOps.hPutAll(redisKey, redisValues); - redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES); - log.info("succeed to store role featureResource: redisKey:{} value:{}", redisKey, redisValues); - } - return null; - }); - } - - private Map> listRoleSaasFeatureResourceCached(ListRoleSaasFeatureResourceParam param) { - - List redisValues = redisTemplate.executePipelined(new SessionCallback() { - @Override - public Object execute(RedisOperations operations) throws DataAccessException { - - for (Long roleId : param.getRoleIds()) { - String redisKey = getKey(roleId); - if (CollectionUtils.isEmpty(param.getUniCodes())) { - RedisClient.HashOps.hGetAll(redisKey); - } else { - RedisClient.HashOps.hMultiGet(redisKey, Lists.newArrayList(param.getUniCodes())); - } - } - return null; - } - }); - - return Streams.zip(param.getRoleIds().stream(), - redisValues.stream(), - (roleId, redisValue) -> { - - if (Objects.isNull(redisValue)) { - return null; - } - - if (CollectionUtils.isEmpty(param.getUniCodes())) { - - List featureResources = (List) ((Map) redisValue).values().stream() - .flatMap(e -> JSONArray.parseArray(JSONArray.toJSONString(e), SaasFeatureResourceDTO.class).stream()) - .collect(Collectors.toList()); - return Pair.of(roleId, featureResources); - } - - List featureResources = (List) ((List) redisValue).stream() - .filter(Objects::nonNull) - .flatMap(e -> JSONArray.parseArray((String) e, SaasFeatureResourceDTO.class).stream()) - .collect(Collectors.toList()); - return Pair.of(roleId, featureResources); - - }) - .filter(Objects::nonNull) + return roleFeatureResources.entrySet() + .stream() + .map(e -> Pair.of(e.getKey(), e.getValue().stream() + .filter(permission -> param.getUniCodes().contains(permission.getUniCode())) + .collect(Collectors.toList())) + ) + .filter(e -> !CollectionUtils.isEmpty(e.getValue())) .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); } - private void fillCacheRoleFeatureResources(ListRoleSaasFeatureResourceParam param, - Map> featureResources) { - - Sets.SetView difference = Sets.difference(param.getRoleIds(), featureResources.keySet()); - if (difference.isEmpty()) { + @Override + public void refreshCache(RefreshRoleFeatureResourceCacheParam param) { + if (CollectionUtils.isEmpty(param.getRoleIds())) { return; } + Map> roleFeatureResources = listRoleFeatureResource(Lists.newArrayList(param.getRoleIds())); + + roleFeatureResourceCache.putAll(Maps.toMap(param.getRoleIds(), roleId -> Optional.ofNullable(roleFeatureResources.get(roleId)))); + } + + private Map> listRoleFeatureResource(List roleIds) { + + if (CollectionUtils.isEmpty(roleIds)) { + return Collections.emptyMap(); + } RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() - .roleIds(Lists.newArrayList(difference)) + .roleIds(roleIds) .needPermissionRelation(true) .type(NEW_FEATURE) .featureResourceTypes(Lists.newArrayList(FeatureResourceType.MENU, @@ -159,26 +133,122 @@ public class RoleSaasFeatureResourceCacheServiceImpl implements RoleSaasFeatureR List roles = roleService.list(listSaasRoleParam); if (CollectionUtils.isEmpty(roles)) { - return; + return Collections.emptyMap(); } - List roleFeatureResources = cacheRoleSaasFeatureResourceHandler.resolveRoleFeatureResource(roles); - - if (CollectionUtils.isEmpty(roleFeatureResources)) { - return; - } - - StoreRoleSaasFeatureResourceParam storeRolePermissionParam = StoreRoleSaasFeatureResourceParam.builder() - .roleSaasFeatureResources(roleFeatureResources) - .build(); - store(storeRolePermissionParam); - - Map> rolePermissionMap = roleFeatureResources.stream() + return resolveRoleFeatureResource(roles).stream() .collect(Collectors.toMap(RoleSaasFeatureResourceCacheService.RoleFeatureResource::getRoleId, RoleSaasFeatureResourceCacheService.RoleFeatureResource::getSaasFeatureResources)); - featureResources.putAll(rolePermissionMap); } - private String getKey(Object... params) { - return String.format(ROLE_SAAS_FEATURE_RESOURCE_KEY, params); + private List resolveRoleFeatureResource(List roles) { + + Map featureResources = listSaasFeatureResource(roles); + + Map parentFeatureResources = listParentSaasFeatureResource(featureResources); + + return roles.stream() + .map(e -> { + if (CollectionUtils.isEmpty(e.getPermissionRelations())) { + return null; + } + + List permissions = e.getPermissionRelations().stream() + .distinct() + .map(permissionRelation -> { + SaasFeatureResourceResp featureResource = featureResources.get(permissionRelation.getFeatureId()); + if (Objects.isNull(featureResource) || StringUtils.isBlank(featureResource.getUniCode())) { + return null; + } + + List featureResourceDTOS = Lists.newArrayList(RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO.builder() + .featureId(featureResource.getId()) + .featureType(featureResource.getFeatureType()) + .terminal(featureResource.getTerminal()) + .uniCode(featureResource.getUniCode()) + .build()); + List parentPermissions = featureResource.resolvePath().stream() + .map(parentFeatureResources::get) + .filter(Objects::nonNull) + .map(f -> { + + if (StringUtils.isBlank(f.getUniCode())) { + return null; + } + + return RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO.builder() + .featureId(f.getId()) + .featureType(f.getFeatureType()) + .terminal(f.getTerminal()) + .uniCode(f.getUniCode()) + .build(); + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + featureResourceDTOS.addAll(parentPermissions); + + return featureResourceDTOS; + }) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .distinct() + .filter(f -> FEATURE_RESOURCE_TYPES.contains(f.getFeatureType())) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(permissions)) { + return null; + } + + return RoleSaasFeatureResourceCacheService.RoleFeatureResource.builder() + .roleId(e.getId()) + .saasFeatureResources(permissions) + .build(); + + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + private Map listSaasFeatureResource(List roles) { + + List featureIds = roles.stream() + .filter(e -> !CollectionUtils.isEmpty(e.getPermissionRelations())) + .map(SaasRoleRes::getPermissionRelations) + .flatMap(Collection::stream) + .map(SaasPermissionRelationRes::getFeatureId) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(featureIds)) { + return Collections.emptyMap(); + } + + // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(featureIds) + .needFeatureCodes(true) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); + } + + private Map listParentSaasFeatureResource(Map productPermissions) { + + List parentIds = productPermissions.values().stream() + .map(SaasFeatureResourceResp::resolvePath) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(parentIds)) { + return Collections.emptyMap(); + } + + // 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限 + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(parentIds) + .needFeatureCodes(true) + .build(); + return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s)); } } 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 5f426559..5592923d 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,6 +1,7 @@ package cn.axzo.tyr.server.service.impl; import cn.axzo.basics.common.BeanMapper; +import cn.axzo.basics.common.exception.ServiceException; import cn.axzo.basics.common.util.StopWatchUtil; import cn.axzo.basics.common.util.TreeUtil; import cn.axzo.foundation.dao.support.converter.PageConverter; @@ -10,7 +11,6 @@ import cn.axzo.foundation.page.PageResp; import cn.axzo.framework.domain.web.code.BaseCode; import cn.axzo.framework.rocketmq.Event; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; -import cn.axzo.pokonyan.config.redis.RedisClient; import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType; import cn.axzo.tyr.client.common.enums.FeatureResourceStatus; import cn.axzo.tyr.client.common.enums.FeatureResourceType; @@ -50,29 +50,24 @@ 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.lang.Pair; import cn.hutool.core.util.ObjectUtil; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; 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.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import com.google.common.collect.Streams; 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.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.CacheEvict; 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.RedisTemplate; -import org.springframework.data.redis.core.SessionCallback; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -82,7 +77,9 @@ import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; @@ -117,16 +114,35 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl redisTemplate; /** 菜单树过期时间 **/ @Value("${saas.feature.resource.expire.minutes:14}") private Long expireInMinutes; - private static final String SAAS_FEATURE_RESOURCE_KEY = "saas:feature:resource:%s"; - private static final String TARGET_TYPE = "saasFeatureResourceId"; + + private LoadingCache>> featureResourceCache = CacheBuilder.newBuilder() + .expireAfterWrite(14, TimeUnit.MINUTES) + .maximumSize(5000) + .build(new CacheLoader>>() { + @Override + public Optional> load(String terminal) { + return listFeatureSources(Lists.newArrayList(terminal)) + .values() + .stream() + .findFirst(); + } + + @Override + public Map>> loadAll(Iterable keys) throws Exception { + List terminals = Lists.newArrayList(keys); + + Map> featureResources = listFeatureSources(terminals); + + return Maps.toMap(terminals, terminal -> Optional.ofNullable(featureResources.get(terminal))); + } + }); + @Override public List listNavByIds(List featureIds, List featureTypes) { //按需扩展要查询的字段 @@ -791,85 +807,44 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl() { - @Override - public Object execute(RedisOperations operations) throws DataAccessException { - - for (SaasFeatureResourceDTO saasFeatureResource : param.getSaasFeatureResources()) { - String redisKey = getKey(saasFeatureResource.getTerminal()); - String redisValue = JSONObject.toJSONString(saasFeatureResource.getFeatures()); - RedisClient.StringOps.setEx(redisKey, redisValue, - expireInMinutes, TimeUnit.MINUTES); - log.info("succeed to store featureResource: redisKey:{} value:{}", redisKey, redisValue); - } - return null; - } - }); - } - @Override public Map> listCache(ListSaasFeatureResourceCache param) { if (org.springframework.util.CollectionUtils.isEmpty(param.getTerminals())) { return Collections.emptyMap(); } - Map> featureSourceCached = listFeatureSourceCached(param); - - fillCacheFeatureSources(param, featureSourceCached); - - return featureSourceCached; + Map> terminalFeatureResources; + try { + terminalFeatureResources = featureResourceCache.getAll(param.getTerminals()).entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().orElseGet(Lists::newArrayList))); + } catch (ExecutionException ex) { + log.error("list terminal cache featureResource error:{} error", param.getTerminals(), ex); + // 外面有做降级 + throw new ServiceException("查询端的菜单缓存异常"); + } + return terminalFeatureResources; } - private Map> listFeatureSourceCached(ListSaasFeatureResourceCache param) { - - List redisValues = redisTemplate.executePipelined(new SessionCallback() { - @Override - public Object execute(RedisOperations operations) throws DataAccessException { - - for (String terminal : param.getTerminals()) { - String redisKey = getKey(terminal); - - RedisClient.StringOps.get(redisKey); - } - return null; - } - }); - - return Streams.zip(param.getTerminals().stream(), - redisValues.stream(), - (terminal, redisValue) -> { - - if (Objects.isNull(redisValue)) { - return null; - } - return Pair.of(terminal, JSONArray.parseArray((String) redisValue, - SaasFeatureResourceCache.class)); - }) - .filter(Objects::nonNull) - .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); - } - - private void fillCacheFeatureSources(ListSaasFeatureResourceCache param, - Map> featureSourceCached) { - - Sets.SetView difference = Sets.difference(param.getTerminals(), featureSourceCached.keySet()); - if (difference.isEmpty()) { + @Override + public void refreshCache(RefreshFeatureResourceCacheParam param) { + if (org.springframework.util.CollectionUtils.isEmpty(param.getTerminals())) { return; } - List saasFeatureResources = resolveSaasFeature(difference); + Map> featureResources = listFeatureSources(Lists.newArrayList(param.getTerminals())); - SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder() - .saasFeatureResources(saasFeatureResources) - .build(); - storeCache(storeSaasFeatureResourceCache); + featureResourceCache.putAll(Maps.toMap(param.getTerminals(), terminal -> Optional.ofNullable(featureResources.get(terminal)))); + } - Map> featureSourceMap = saasFeatureResources.stream() + private Map> listFeatureSources(List terminals) { + + if (CollectionUtils.isEmpty(terminals)) { + return Collections.emptyMap(); + } + + return resolveSaasFeature(Sets.newHashSet(terminals)).stream() .collect(Collectors.toMap(SaasFeatureResourceDTO::getTerminal, SaasFeatureResourceDTO::getFeatures)); - featureSourceCached.putAll(featureSourceMap); } private List resolveSaasFeature(Set terminals) { @@ -915,8 +890,4 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl Date: Wed, 11 Sep 2024 15:26:05 +0800 Subject: [PATCH 105/112] =?UTF-8?q?feat:(hotfix/20240906)=20=E5=8F=AA?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E6=99=AE=E9=80=9A=E8=A7=92=E8=89=B2=E4=BB=A5?= =?UTF-8?q?=E5=8F=8A=E7=BC=93=E5=AD=98=E6=9C=89=E6=95=88=E6=9C=9F=E6=94=B9?= =?UTF-8?q?=E6=88=901=E5=A4=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/tyr/client/common/enums/RoleTypeEnum.java | 7 +++++++ .../server/event/inner/CacheRolePermissionHandler.java | 6 +++++- .../event/inner/CacheRoleSaasFeatureResourceHandler.java | 3 +++ .../axzo/tyr/server/job/CacheRoleFeatureResourceJob.java | 2 ++ .../cn/axzo/tyr/server/job/CacheRolePermissionJob.java | 3 +++ .../main/java/cn/axzo/tyr/server/service/RoleService.java | 3 +++ .../service/impl/ProductPermissionCacheServiceImpl.java | 7 +------ .../impl/ProductSaasFeatureResourceCacheServiceImpl.java | 6 +----- .../service/impl/RolePermissionCacheServiceImpl.java | 7 +------ .../impl/RoleSaasFeatureResourceCacheServiceImpl.java | 6 +----- .../service/impl/SaasFeatureResourceServiceImpl.java | 8 +------- 11 files changed, 28 insertions(+), 30 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/RoleTypeEnum.java b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/RoleTypeEnum.java index c94a57f7..6b765e76 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/RoleTypeEnum.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/RoleTypeEnum.java @@ -5,6 +5,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -56,4 +57,10 @@ public enum RoleTypeEnum { return Objects.equals(this.value, value); } + public static List listAdmin() { + return Arrays.stream(values()) + .filter(RoleTypeEnum::isAdminRole) + .map(RoleTypeEnum::getValue) + .collect(Collectors.toList()); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java index b0a66cc4..b048fdc7 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java @@ -2,6 +2,7 @@ package cn.axzo.tyr.server.event.inner; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.tyr.client.common.enums.RoleTypeEnum; import cn.axzo.tyr.client.model.res.SaasRoleRes; import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; @@ -47,6 +48,7 @@ public class CacheRolePermissionHandler implements InitializingBean { .roleIds(Optional.ofNullable(payload.getRoleIds()) .map(Lists::newArrayList) .orElse(null)) + .roleTypesNotIn(RoleTypeEnum.listAdmin()) .build(); Set roleIds = roleService.list(listSaasRoleParam).stream() .map(SaasRoleRes::getId) @@ -70,7 +72,9 @@ public class CacheRolePermissionHandler implements InitializingBean { return; } - RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder().build(); + RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .roleTypesNotIn(RoleTypeEnum.listAdmin()) + .build(); Set roleIds = roleService.list(listSaasRoleParam).stream() .map(SaasRoleRes::getId) .collect(Collectors.toSet()); diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java index 93be689b..aec6cc72 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java @@ -2,6 +2,7 @@ package cn.axzo.tyr.server.event.inner; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.tyr.client.common.enums.RoleTypeEnum; import cn.axzo.tyr.client.model.res.SaasRoleRes; import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; @@ -48,6 +49,7 @@ public class CacheRoleSaasFeatureResourceHandler implements InitializingBean { .roleIds(Optional.ofNullable(payload.getRoleIds()) .map(Lists::newArrayList) .orElse(null)) + .roleTypesNotIn(RoleTypeEnum.listAdmin()) .build(); Set roleIds = roleService.list(listSaasRoleParam).stream() .map(SaasRoleRes::getId) @@ -72,6 +74,7 @@ public class CacheRoleSaasFeatureResourceHandler implements InitializingBean { } RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder() + .roleTypesNotIn(RoleTypeEnum.listAdmin()) .build(); Set roleIds = roleService.list(listSaasRoleParam).stream() diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRoleFeatureResourceJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRoleFeatureResourceJob.java index 725bec72..698c947e 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRoleFeatureResourceJob.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRoleFeatureResourceJob.java @@ -1,5 +1,6 @@ package cn.axzo.tyr.server.job; +import cn.axzo.tyr.client.common.enums.RoleTypeEnum; import cn.axzo.tyr.client.model.res.SaasRoleRes; import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService; import cn.axzo.tyr.server.service.RoleService; @@ -33,6 +34,7 @@ public class CacheRoleFeatureResourceJob extends IJobHandler { RoleService.ListSaasRoleParam listSaasRoleParam = Optional.ofNullable(s) .map(e -> JSONObject.parseObject(e, RoleService.ListSaasRoleParam.class)) .orElseGet(() -> RoleService.ListSaasRoleParam.builder().build()); + listSaasRoleParam.setRoleTypesNotIn(RoleTypeEnum.listAdmin()); Set roleIds = roleService.list(listSaasRoleParam).stream() .map(SaasRoleRes::getId) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java index d97fa08b..72b4faef 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java @@ -1,5 +1,6 @@ package cn.axzo.tyr.server.job; +import cn.axzo.tyr.client.common.enums.RoleTypeEnum; import cn.axzo.tyr.client.model.res.SaasRoleRes; import cn.axzo.tyr.server.service.RolePermissionCacheService; import cn.axzo.tyr.server.service.RoleService; @@ -35,6 +36,8 @@ public class CacheRolePermissionJob extends IJobHandler { .map(e -> JSONObject.parseObject(e, RoleService.ListSaasRoleParam.class)) .orElseGet(() -> RoleService.ListSaasRoleParam.builder().build()); + listSaasRoleParam.setRoleTypesNotIn(RoleTypeEnum.listAdmin()); + Set roleIds = roleService.list(listSaasRoleParam).stream() .map(SaasRoleRes::getId) .collect(Collectors.toSet()); 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 f8ca3353..2274e702 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 @@ -136,6 +136,9 @@ public interface RoleService extends IService { @CriteriaField(field = "roleType", operator = Operator.IN) private List roleTypes; + @CriteriaField(field = "roleType", operator = Operator.NOT_IN) + private List roleTypesNotIn; + @CriteriaField(field = "id", operator = Operator.NE) private Long idNE; 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 index 2c48a40b..710e7ee5 100644 --- 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 @@ -19,7 +19,6 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; 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.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -51,12 +50,8 @@ public class ProductPermissionCacheServiceImpl implements ProductPermissionCache @Autowired private SaasFeatureDao saasFeatureDao; - /** 产品权限缓存过期时间 **/ - @Value("${product.permission.expire.minutes:14}") - private Long expireInMinutes; - private LoadingCache>> productPermissionCache = CacheBuilder.newBuilder() - .expireAfterWrite(14, TimeUnit.MINUTES) + .expireAfterWrite(1, TimeUnit.DAYS) .maximumSize(5000) .build(new CacheLoader>>() { @Override diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java index 09eeb53f..79a8fa4d 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/ProductSaasFeatureResourceCacheServiceImpl.java @@ -19,7 +19,6 @@ import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; 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.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -48,9 +47,6 @@ public class ProductSaasFeatureResourceCacheServiceImpl implements ProductSaasFe @Autowired private SaasFeatureResourceService saasFeatureResourceService; - @Value("${product.feature.resouce.expire.minutes:14}") - private Long expireInMinutes; - public static final Set FEATURE_RESOURCE_TYPES = Sets.newHashSet(FeatureResourceType.MENU.getCode(), FeatureResourceType.PAGE.getCode(), FeatureResourceType.MENU_PARTITION_GROUP.getCode(), @@ -58,7 +54,7 @@ public class ProductSaasFeatureResourceCacheServiceImpl implements ProductSaasFe FeatureResourceType.APP_ENTRY.getCode()); private LoadingCache>> productFeatureResourceCache = CacheBuilder.newBuilder() - .expireAfterWrite(14, TimeUnit.MINUTES) + .expireAfterWrite(1, TimeUnit.DAYS) .maximumSize(5000) .build(new CacheLoader>>() { @Override 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 index 14eb0b7a..d819fdb7 100644 --- 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 @@ -18,7 +18,6 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; 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.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -50,12 +49,8 @@ public class RolePermissionCacheServiceImpl implements RolePermissionCacheServic @Autowired private SaasFeatureDao saasFeatureDao; - /** 角色权限缓存过期时间 **/ - @Value("${role.permission.expire.minutes:14}") - private static Long expireInMinutes; - private LoadingCache>> rolePermissionCache = CacheBuilder.newBuilder() - .expireAfterWrite(14, TimeUnit.MINUTES) + .expireAfterWrite(1, TimeUnit.DAYS) .maximumSize(5000) .build(new CacheLoader>>() { @Override diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java index 5a3e4a7c..f28d2523 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java @@ -18,7 +18,6 @@ import com.google.common.collect.Maps; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; 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.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -47,12 +46,9 @@ public class RoleSaasFeatureResourceCacheServiceImpl implements RoleSaasFeatureR @Autowired private SaasFeatureResourceService saasFeatureResourceService; - /** 角色菜单缓存过期时间 **/ - @Value("${role.feature.resource.expire.minutes:14}") - private Long expireInMinutes; private LoadingCache>> roleFeatureResourceCache = CacheBuilder.newBuilder() - .expireAfterWrite(14, TimeUnit.MINUTES) + .expireAfterWrite(1, TimeUnit.DAYS) .maximumSize(5000) .build(new CacheLoader>>() { @Override 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 5592923d..20cdf985 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 @@ -65,7 +65,6 @@ 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.beans.factory.annotation.Value; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Service; @@ -114,15 +113,10 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl>> featureResourceCache = CacheBuilder.newBuilder() - .expireAfterWrite(14, TimeUnit.MINUTES) + .expireAfterWrite(1, TimeUnit.DAYS) .maximumSize(5000) .build(new CacheLoader>>() { @Override From 602ac6561887edc9e7aa4097d46ed66cd9d79f8d Mon Sep 17 00:00:00 2001 From: lilong Date: Wed, 11 Sep 2024 18:24:36 +0800 Subject: [PATCH 106/112] =?UTF-8?q?feat:(hotfix/20240906)=20=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E8=8F=9C=E5=8D=95=E7=BC=93=E5=AD=98=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/PermissionQueryServiceImpl.java | 24 ++++++++++++------- .../impl/SaasFeatureResourceServiceImpl.java | 14 +++++++++++ 2 files changed, 30 insertions(+), 8 deletions(-) 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 637e1011..39dc6c8e 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 @@ -1002,13 +1002,16 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { Set adminFeatureIds = resolveAdminRole(productFeatureSources, saasRole); Set notAuthFeatureIds = resolveNotAuthFeatureIds(productFeatureSources, authFreeFeatureIds); - List roleFeatureResources = roleFeatureResourceMap.get(saasRole.getId()).stream() - .filter(e -> StringUtils.isBlank(treePermissionReq.getTerminal()) - || Objects.equals(e.getTerminal(), treePermissionReq.getTerminal())) - .filter(e -> CollectionUtils.isEmpty(featureTypes) || featureTypes.contains(e.getFeatureType())) - .collect(Collectors.toList()); - Set normalFeatureIds = resolveNormalRole(productFeatureSources, saasRole, roleFeatureResources); + List roleFeatureResources = Optional.ofNullable(roleFeatureResourceMap.get(saasRole.getId())) + .map(role -> role.stream() + .filter(e -> StringUtils.isBlank(treePermissionReq.getTerminal()) + || Objects.equals(e.getTerminal(), treePermissionReq.getTerminal())) + .filter(e -> CollectionUtils.isEmpty(featureTypes) || featureTypes.contains(e.getFeatureType())) + .collect(Collectors.toList())) + .orElseGet(Lists::newArrayList); + + Set normalFeatureIds = resolveNormalRole(productFeatureSources, saasRole, roleFeatureResources, roleFeatureResourceMap); Set result = Sets.newHashSet(); result.addAll(adminFeatureIds); @@ -1038,8 +1041,13 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { } private Set resolveNormalRole(List workspaceProduct, - SaasRoleUserV2DTO.SaasRole saasRole, - List roleFeatureResources) { + SaasRoleUserV2DTO.SaasRole saasRole, + List roleFeatureResources, + Map> roleFeatureResourceMap) { + + if (RoleTypeEnum.isAdmin(saasRole.getRoleType())) { + return Collections.emptySet(); + } if (CollectionUtils.isEmpty(roleFeatureResources)) { return Collections.emptySet(); 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 20cdf985..427ab713 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 @@ -114,6 +114,10 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl>> featureResourceCache = CacheBuilder.newBuilder() .expireAfterWrite(1, TimeUnit.DAYS) @@ -851,6 +855,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl allFeatureResources = Lists.newArrayList(); @@ -872,6 +877,15 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl pageElement.stream() + .findFirst() + .map(PageElementResp::getVersion) + .orElse(DEFAULT_VERSION)) + .orElse(DEFAULT_VERSION)) .build(), Collectors.toList()))) .entrySet().stream() .map(e -> SaasFeatureResourceDTO.builder() From b16da5cd22aef4e5e1a5a9ac0c14ac75e8124343 Mon Sep 17 00:00:00 2001 From: lilong Date: Wed, 11 Sep 2024 18:31:07 +0800 Subject: [PATCH 107/112] =?UTF-8?q?feat:(hotfix/20240906)=20=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E8=8F=9C=E5=8D=95=E7=BC=93=E5=AD=98=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/service/impl/PermissionQueryServiceImpl.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) 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 39dc6c8e..e8c34ff8 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 @@ -1011,7 +1011,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { .collect(Collectors.toList())) .orElseGet(Lists::newArrayList); - Set normalFeatureIds = resolveNormalRole(productFeatureSources, saasRole, roleFeatureResources, roleFeatureResourceMap); + Set normalFeatureIds = resolveNormalRole(productFeatureSources, saasRole, roleFeatureResources); Set result = Sets.newHashSet(); result.addAll(adminFeatureIds); @@ -1042,12 +1042,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService { private Set resolveNormalRole(List workspaceProduct, SaasRoleUserV2DTO.SaasRole saasRole, - List roleFeatureResources, - Map> roleFeatureResourceMap) { - - if (RoleTypeEnum.isAdmin(saasRole.getRoleType())) { - return Collections.emptySet(); - } + List roleFeatureResources) { if (CollectionUtils.isEmpty(roleFeatureResources)) { return Collections.emptySet(); From f4b99c62092a8009fb7dfb33066f44844ba95d1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Sat, 14 Sep 2024 13:12:12 +0800 Subject: [PATCH 108/112] =?UTF-8?q?feat(REQ-2899):pageV2=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/service/impl/SaasPageElementServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 9a1f533c..b878eb24 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 @@ -511,7 +511,7 @@ public class SaasPageElementServiceImpl extends ServiceImpl w.like(SaasPageElement::getCode, request.getPageElementCodeOrName()) .or().like(SaasPageElement::getName, request.getPageElementCodeOrName())) - .eq(StringUtils.isNotBlank(request.getPageElementGroupCodeOrName()), SaasPageElement::getType, PageElementTypeEnum.PAGE.getCode()) +// .eq(StringUtils.isNotBlank(request.getPageElementGroupCodeOrName()), SaasPageElement::getType, PageElementTypeEnum.PAGE.getCode()) .and(StringUtils.isNotBlank(request.getPageElementGroupCodeOrName()), w -> w.like(SaasPageElement::getGroupCode, request.getPageElementGroupCodeOrName()) .or().like(SaasPageElement::getName, request.getPageElementGroupCodeOrName())) From a2069f8377706063c1315538f62ea42402aeb822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Sat, 14 Sep 2024 13:36:56 +0800 Subject: [PATCH 109/112] =?UTF-8?q?feat(REQ-2899):pageV2=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/server/service/impl/SaasPageElementServiceImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 b878eb24..3f6eaa60 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 @@ -80,9 +80,9 @@ public class SaasPageElementServiceImpl extends ServiceImpl w.like(SaasPageElement::getCode, request.getPageElementCodeOrName()) .or().like(SaasPageElement::getName, request.getPageElementCodeOrName())) -// .eq(StringUtils.isNotBlank(request.getPageElementGroupCodeOrName()), SaasPageElement::getType, PageElementTypeEnum.PAGE.getCode()) + .eq(StringUtils.isNotBlank(request.getPageElementGroupCodeOrName()), SaasPageElement::getType, PageElementTypeEnum.PAGE.getCode()) .and(StringUtils.isNotBlank(request.getPageElementGroupCodeOrName()), w -> w.like(SaasPageElement::getGroupCode, request.getPageElementGroupCodeOrName()) .or().like(SaasPageElement::getName, request.getPageElementGroupCodeOrName())) @@ -870,4 +870,5 @@ public class SaasPageElementServiceImpl extends ServiceImpl Date: Sat, 14 Sep 2024 14:01:52 +0800 Subject: [PATCH 110/112] =?UTF-8?q?feat(REQ-2899):=E5=85=B3=E7=B3=BB?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E8=B0=83=E6=95=B4=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/SaasPageElementServiceImpl.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) 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 3f6eaa60..57d510e5 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 @@ -671,8 +671,18 @@ public class SaasPageElementServiceImpl extends ServiceImpl uniCodeRelationMap = relations.stream() - .collect(Collectors.toMap(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode, Function.identity(), (v1, v2) -> v1)); + Map uniCodeRelationMap = Maps.newHashMap(); + List pageRouteUniCodes = Lists.newArrayList(); + for(SaasPageElementFeatureResourceRelation relation : relations) { + if (pageRouteUniCodes.contains(relation.getFeatureResourceUniCode())) { + continue; + } + uniCodeRelationMap.put(relation.getFeatureResourceUniCode(), relation); + if (PageElementFeatureResourceRelationTypeEnum.PAGE_ROUTE.getValue().equals(relation.getType())) { + pageRouteUniCodes.add(relation.getFeatureResourceUniCode()); + } + } + List reps = allFeatureResources.stream().map(e -> PageElementRelationFeatureResourceResp.builder() .id(e.getId()) .parentId(e.getParentId()) From 92d0a627d25f47afd418d1e557fe1c4f68e4c474 Mon Sep 17 00:00:00 2001 From: lilong Date: Sat, 14 Sep 2024 14:32:53 +0800 Subject: [PATCH 111/112] =?UTF-8?q?feat:(feature/REQ-2899)=20=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E9=80=9A=E8=BF=87=E9=A1=B5=E9=9D=A2code=E6=88=96?= =?UTF-8?q?=E8=80=85name=E6=A8=A1=E7=B3=8A=E6=9F=A5=E8=AF=A2bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/req/PageQueryElementV2Req.java | 12 ++- .../impl/SaasPageElementServiceImpl.java | 73 ++++++++++++++++--- 2 files changed, 72 insertions(+), 13 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java index 47b9abab..2ae8ad4d 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageQueryElementV2Req.java @@ -1,11 +1,12 @@ package cn.axzo.tyr.client.model.req; +import cn.axzo.framework.domain.page.PageResp; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import javax.validation.constraints.NotBlank; +import java.util.Collections; import java.util.List; /** @@ -57,4 +58,13 @@ public class PageQueryElementV2Req { */ @Builder.Default private Long pageSize = 20L; + + public PageResp toEmpty() { + return PageResp.builder() + .page(this.getPage()) + .pageSize(this.getPageSize()) + .list(Collections.emptyList()) + .totalCount(0L) + .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 57d510e5..b18a6b40 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 @@ -13,9 +13,32 @@ import cn.axzo.foundation.exception.BusinessException; import cn.axzo.framework.domain.page.PageResp; import cn.axzo.framework.rocketmq.Event; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; -import cn.axzo.tyr.client.common.enums.*; -import cn.axzo.tyr.client.model.req.*; -import cn.axzo.tyr.client.model.res.*; +import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.client.common.enums.PageElementAppTypeEnum; +import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum; +import cn.axzo.tyr.client.common.enums.PageElementTypeEnum; +import cn.axzo.tyr.client.common.enums.PermissionRelationOperateLogSceneEnum; +import cn.axzo.tyr.client.model.req.DeletePageElementReq; +import cn.axzo.tyr.client.model.req.GetPageElementReq; +import cn.axzo.tyr.client.model.req.GetUserHasPermissionPageElementReq; +import cn.axzo.tyr.client.model.req.IdentityAuthReq; +import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO; +import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq; +import cn.axzo.tyr.client.model.req.PageElementImportDataReq; +import cn.axzo.tyr.client.model.req.PageElementReportReq; +import cn.axzo.tyr.client.model.req.PageElementReq; +import cn.axzo.tyr.client.model.req.PageQueryElementReq; +import cn.axzo.tyr.client.model.req.PageQueryElementV2Req; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.client.model.req.PermissionOperateLogReq; +import cn.axzo.tyr.client.model.req.SaveOrUpdatePageElementReq; +import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp; +import cn.axzo.tyr.client.model.res.IdentityAuthRes; +import cn.axzo.tyr.client.model.res.PageElementBasicDTO; +import cn.axzo.tyr.client.model.res.PageElementCategoryAndElementResp; +import cn.axzo.tyr.client.model.res.PageElementRelationFeatureResourceResp; +import cn.axzo.tyr.client.model.res.PageElementResp; +import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.server.config.MqProducer; import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload; import cn.axzo.tyr.server.model.RelationOperateLogResourceBindElementDO; @@ -23,7 +46,11 @@ import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; import cn.axzo.tyr.server.repository.dao.SaasPageElementCategoryDao; import cn.axzo.tyr.server.repository.dao.SaasPageElementDao; import cn.axzo.tyr.server.repository.dao.SaasPageElementFeatureResourceRelationDao; -import cn.axzo.tyr.server.repository.entity.*; +import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; +import cn.axzo.tyr.server.repository.entity.SaasPageElement; +import cn.axzo.tyr.server.repository.entity.SaasPageElementCategory; +import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation; +import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelationOperateLog; import cn.axzo.tyr.server.repository.mapper.SaasPageElementMapper; import cn.axzo.tyr.server.service.SaasFeatureResourceService; import cn.axzo.tyr.server.service.SaasPageElementFeatureResourceRelationService; @@ -36,6 +63,7 @@ import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.google.common.base.Strings; @@ -56,7 +84,13 @@ import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.*; +import java.util.Arrays; +import java.util.Collections; +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.ExecutorService; import java.util.function.Function; @@ -504,19 +538,34 @@ public class SaasPageElementServiceImpl extends ServiceImpl pageV2(PageQueryElementV2Req request) { - IPage page = saasPageElementDao.lambdaQuery() + LambdaQueryChainWrapper wrapper = saasPageElementDao.lambdaQuery() .eq(Objects.nonNull(request.getId()), SaasPageElement::getId, request.getId()) .eq(StringUtils.isNotBlank(request.getTerminal()), SaasPageElement::getTerminal, request.getTerminal()) .eq(StringUtils.isNotBlank(request.getItemCode()), SaasPageElement::getItemCode, request.getItemCode()) .in(CollectionUtils.isNotEmpty(request.getElementTypes()), SaasPageElement::getType, request.getElementTypes()) .and(StringUtils.isNotBlank(request.getPageElementCodeOrName()), w -> w.like(SaasPageElement::getCode, request.getPageElementCodeOrName()) - .or().like(SaasPageElement::getName, request.getPageElementCodeOrName())) - .eq(StringUtils.isNotBlank(request.getPageElementGroupCodeOrName()), SaasPageElement::getType, PageElementTypeEnum.PAGE.getCode()) - .and(StringUtils.isNotBlank(request.getPageElementGroupCodeOrName()), - w -> w.like(SaasPageElement::getGroupCode, request.getPageElementGroupCodeOrName()) - .or().like(SaasPageElement::getName, request.getPageElementGroupCodeOrName())) - .orderByDesc(BaseEntity::getId) + .or().like(SaasPageElement::getName, request.getPageElementCodeOrName())); + + + // 待切换写法,收口page,pageV2查询 + // 因为页面名字没有每条记录冗余,查询条件可能是页面名字或者code,所以需要根据入参找到对应的页面code,然后作为页面code查询 + if (StringUtils.isNotBlank(request.getPageElementGroupCodeOrName())) { + List groupPageElements = saasPageElementDao.lambdaQuery() + .eq(SaasPageElement::getType, PageElementTypeEnum.PAGE.getCode()) + .and(w -> w.like(SaasPageElement::getGroupCode, request.getPageElementGroupCodeOrName()) + .or() + .like(SaasPageElement::getName, request.getPageElementGroupCodeOrName())) + .list(); + if (CollectionUtils.isEmpty(groupPageElements)) { + return request.toEmpty(); + } + + wrapper.in(SaasPageElement::getGroupCode, groupPageElements.stream().map(SaasPageElement::getGroupCode).collect(Collectors.toSet())); + } + + IPage page = wrapper.orderByDesc(BaseEntity::getId) .page(new Page<>(request.getPage(), request.getPageSize())); + List list = BeanMapper.copyList(page.getRecords(), PageElementResp.class); // 补充元素组名 fillGroupName(list); From e19f25473720a3490886d9a4cd2fb655ca4162e3 Mon Sep 17 00:00:00 2001 From: lilong Date: Fri, 20 Sep 2024 19:30:53 +0800 Subject: [PATCH 112/112] =?UTF-8?q?feat:hotfix-20240920=20=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E9=A1=B9=E7=9B=AE=E4=B8=8B=E5=8F=AA=E6=9C=89=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=91=98=E8=A7=92=E8=89=B2=E5=AF=BC=E8=87=B4=E5=B7=AE?= =?UTF-8?q?=E6=99=AE=E9=80=9A=E8=A7=92=E8=89=B2=E6=97=B6=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E6=8E=A5=E5=8F=A3=E8=BF=87=E6=85=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/common/enums/RoleTypeEnum.java | 7 +++++++ .../service/impl/TyrSaasAuthServiceImpl.java | 21 ++++++++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/RoleTypeEnum.java b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/RoleTypeEnum.java index 6b765e76..c1b3136f 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/RoleTypeEnum.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/common/enums/RoleTypeEnum.java @@ -63,4 +63,11 @@ public enum RoleTypeEnum { .map(RoleTypeEnum::getValue) .collect(Collectors.toList()); } + + public static List listNormal() { + return Arrays.stream(values()) + .filter(e -> !e.isAdmin) + .map(RoleTypeEnum::getValue) + .collect(Collectors.toList()); + } } 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 7e2c7bfd..1fbeaa3e 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 @@ -583,7 +583,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { } private Set resolvePermissionNormalRole(ListPermissionUser req, - List productPermissions, + List productPermissions, Set featureIds) { // 因为通过权限id找对应的角色数据量巨大,所以通过找项目的角色,再找有权限的角色比较快 @@ -595,8 +595,17 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { return Collections.emptySet(); } + List normalRoles = roleService.list(RoleService.ListSaasRoleParam.builder() + .roleIds(Lists.newArrayList(allRoleIds)) + .roleTypes(RoleTypeEnum.listNormal()) + .build()); + + if (CollectionUtils.isEmpty(normalRoles)) { + return Collections.emptySet(); + } + RolePermissionCacheService.ListRolePermissionParam listRolePermissionParam = RolePermissionCacheService.ListRolePermissionParam.builder() - .roleIds(allRoleIds) + .roleIds(normalRoles.stream().map(SaasRoleRes::getId).collect(Collectors.toSet())) .featureCodes(productPermissions.stream() .map(ProductPermissionCacheService.PermissionDTO::getFeatureCode) .collect(Collectors.toSet())) @@ -610,10 +619,8 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { || e.getValue().stream().anyMatch(p -> Objects.equals(p.getTerminal(), req.getTerminal()))) .map(Map.Entry::getKey) .collect(Collectors.toSet()); - Map normalRoles = roleService.list(RoleService.ListSaasRoleParam.builder() - .roleIds(Lists.newArrayList(normalRoleIds)) - .build()) - .stream() + Map normalRoleMap = normalRoles.stream() + .filter(e -> normalRoleIds.contains(e.getId())) .collect(Collectors.toMap(SaasRoleRes::getId, Function.identity())); Map> featureCodeCooperateTypeMap = productPermissions.stream() @@ -621,7 +628,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService { Collectors.mapping(ProductPermissionCacheService.PermissionDTO::getCooperateType, Collectors.toSet()))); return normalRolePermissionMap.entrySet().stream() .filter(e -> { - SaasRoleRes saasRoleRes = normalRoles.get(e.getKey()); + SaasRoleRes saasRoleRes = normalRoleMap.get(e.getKey()); if (Objects.isNull(saasRoleRes)) { return false; }