feat(REQ-2488): 合并master的代码

This commit is contained in:
luofu 2024-09-02 14:05:55 +08:00
commit 066537a210
123 changed files with 7868 additions and 988 deletions

View File

@ -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;
@ -34,6 +36,6 @@ public enum AttrPermissionEnum {
public static List<AttrPermissionEnum> 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);
}
}

View File

@ -14,6 +14,7 @@ public enum PageElementTypeEnum {
PAGE("PAGE", "页面"),
COMPONENT("COMPONENT", "组件"),
APP_ENTRY("APP_ENTRY", "应用入口"),
;

View File

@ -28,6 +28,11 @@ public enum PermissionRelationOperateLogSceneEnum {
*/
OMS_ROLE_BIND_FEATURE_RESOURCE("OMS_ROLE_BIND_FEATURE_RESOURCE", "oms后台更新角色绑定的资源"),
/**
* []oms后台更新角色绑定资源绑定的
*/
OLD_OMS_ROLE_BIND_FEATURE("OLD_OMS_ROLE_BIND_FEATURE", "[老]oms后台更新角色绑定的资源"),
/**
* oms后台更新资源绑定的页面元素
*/
@ -38,6 +43,36 @@ public enum PermissionRelationOperateLogSceneEnum {
*/
OMS_PRODUCT_BIND_FEATURE_RESOURCE("OMS_PRODUCT_BIND_FEATURE_RESOURCE", "oms后台更新产品榜的资源"),
/**
* []oms后台更新产品权限点
*/
OLD_OMS_PRODUCT__UPDATE("OLD_OMS_PRODUCT__UPDATE", "[老]oms后台更新产品"),
/**
* []oms后台更新产品权限点
*/
OLD_OMS_PRODUCT_PERMISSION_POINT__SAVE_BATCH("OLD_OMS_PRODUCT_PERMISSION_POINT__SAVE_BATCH", "[老]oms后台更新产品权限点"),
/**
* []角色分组新增/更新
*/
OLD_OMS_ROLE_GROUP__SAVE_OR_UPDATE("OLD_OMS_ROLE_GROUP__SAVE_OR_UPDATE", "[老]角色分组新增/更新"),
/**
* []角色分组删除
*/
OLD_OMS_ROLE_GROUP__DELETE("OLD_OMS_ROLE_GROUP__DELETE", "[老]角色分组删除"),
/**
* []权限点删除
*/
OLD_OMS_SAAS_FEATURE__DELETE("OLD_OMS_SAAS_FEATURE__DELETE", "[老]权限点删除"),
/**
* []权限点新增/更新
*/
OLD_OMS_SAAS_FEATURE__SAVE_OR_UPDATE("OLD_OMS_SAAS_FEATURE__SAVE_OR_UPDATE", "[老]权限点新增/更新"),
/**
* oms后台添加API
*/

View File

@ -18,14 +18,16 @@ public enum RowPermissionEnum {
DEPARTMENT_SUBORDINATE(4, "本部门及以下数据"),
UNIT_ONLY(5, "仅本单位数据"),
UNIT_ONLY(5, "仅本单位数据(包含班组)"),
UNIT_DIRECT_SUBORDINATE(6, "本单位及下级直属单位数据"),
UNIT_COOPERATE_SUBORDINATE(7, "本单位及下级协同(直属+合作)单位数据"),
UNIT_ALL_SUBORDINATE(8, "本单位及以下协同(直属+合作)单位数据"),
WORKSPACE(9, "本项目数据"),
WORKSPACE(9, "本项目部数据"),
UNIT_ONLY_EXCLUDE_TEAM(10, "仅本单位数据(不包含班组)"),
;
@ -41,7 +43,7 @@ public enum RowPermissionEnum {
public static List<RowPermissionEnum> listRowPermissionForNotWorkspace() {
return Lists.newArrayList(SELF_ONLY, SELF_SUBORDINATE,
DEPARTMENT_ONLY, DEPARTMENT_SUBORDINATE, UNIT_ONLY);
DEPARTMENT_ONLY, DEPARTMENT_SUBORDINATE, UNIT_ONLY, UNIT_ONLY_EXCLUDE_TEAM);
}
}

View File

@ -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<Long> createDataObject(@RequestBody @Valid CreateDataObjectReq req);
/**
* 修改数据对象
* @param req
@ -63,4 +58,12 @@ public interface DataObjectApi {
*/
@GetMapping("/api/dataObject/get")
ApiResult<DataObjectRes> getDataObject(@RequestParam Long dataObjectId);
/**
* 根据租户范围数据对象code查询数据对象
* @param req
* @return
*/
@PostMapping("/api/dataObject/query")
ApiResult<DataObjectRes> queryDataObject(@RequestBody @Valid QueryDataObjectReq req);
}

View File

@ -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<GetUserHasPermissionPageElementResp> getUserHasPermissionPageElement(@RequestBody @Valid GetUserHasPermissionPageElementReq req);
@PostMapping("/api/pageElement/list")
ApiResult<List<PageElementResp>> list(PageElementReq param);
}

View File

@ -1,6 +1,7 @@
package cn.axzo.tyr.client.feign;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.tyr.client.model.permission.DeletePermissionPointRequest;
import cn.axzo.tyr.client.model.permission.PermissionPointDTO;
import cn.axzo.tyr.client.model.permission.PermissionPointListQueryRequest;
import cn.axzo.tyr.client.model.permission.PermissionPointMoveRequest;
@ -16,6 +17,7 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import javax.validation.Valid;
import java.util.List;
/**
@ -48,6 +50,10 @@ public interface PermissionPointApi {
@PostMapping(value = "/api/v1/permissionPoint/delete/{permissionId}")
ApiResult<List<String>> deletePermissionPoint(@PathVariable Long permissionId);
/** 删除权限点 **/
@PostMapping(value = "/api/v1/permissionPoint/delete/v2/deletePermissionPoint")
ApiResult<List<String>> deletePermissionPointV2(@Valid @RequestBody DeletePermissionPointRequest request);
/** 位置移动 **/
@PostMapping(value = "/api/v1/permissionPoint/move")

View File

@ -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<List<TreePermissionResp>> treePermission(@RequestBody @Validated TreePermissionReq req);
/**
* 查询有权限的菜单树节点
* @param req
* @return
*/
@PostMapping(value = "/api/v3/permission/featureResource/list")
ApiResult<List<ListPermissionFeatureResp>> listPermission(@RequestBody @Validated ListPermissionFeatureReq req);
}

View File

@ -2,7 +2,16 @@ package cn.axzo.tyr.client.feign;
import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.tyr.client.model.product.*;
import cn.axzo.tyr.client.model.product.OldUpdateFeatureRelationRequestV2;
import cn.axzo.tyr.client.model.product.ProductAddReq;
import cn.axzo.tyr.client.model.product.ProductDetailReq;
import cn.axzo.tyr.client.model.product.ProductFeatureRelationSearchReq;
import cn.axzo.tyr.client.model.product.ProductFeatureRelationUpdateReq;
import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO;
import cn.axzo.tyr.client.model.product.ProductSearchListReq;
import cn.axzo.tyr.client.model.product.ProductSearchPageReq;
import cn.axzo.tyr.client.model.product.ProductUpdateReq;
import cn.axzo.tyr.client.model.product.ProductVO;
import cn.axzo.tyr.client.model.req.ProductSaveReq;
import cn.axzo.tyr.client.model.req.UpdateProductStatusReq;
import cn.axzo.tyr.client.model.res.GovernmentTerminalResp;
@ -102,6 +111,16 @@ public interface ProductApi {
@PostMapping("api/auth/product/feature/relation/update")
ApiResult<Boolean> updateFeatureRelation(@Validated @RequestBody List<ProductFeatureRelationUpdateReq> req);
/**
* 更新产品与权限点的关联关系
* <p/>携带操作人员信息
*
* @param req {@link ProductFeatureRelationUpdateReq}
* @return
*/
@PostMapping("api/auth/product/feature/relation/v2/update")
ApiResult<Boolean> updateFeatureRelationV2(@Validated @RequestBody OldUpdateFeatureRelationRequestV2 req);
/**
* 查询指定工作台关联的服务包下的产品权限点
*

View File

@ -5,6 +5,7 @@ import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.tyr.client.model.req.ListSaasRoleGroupParam;
import cn.axzo.tyr.client.model.req.PageSaasRoleGroupParam;
import cn.axzo.tyr.client.model.req.QuerySaasRoleGroupReq;
import cn.axzo.tyr.client.model.req.SaasRoleGroupDeleteRequest;
import cn.axzo.tyr.client.model.req.UpdateRoleGroupOffsetReq;
import cn.axzo.tyr.client.model.res.SaasRoleGroupDTO;
import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO;
@ -57,6 +58,14 @@ public interface SaasRoleGroupApi {
@PostMapping("/api/saasRoleGroup/delete")
ApiResult<Void> delete(@RequestParam @NotEmpty List<Long> ids);
/**
* 删除角色分组
* @param request 角色分组ID
* @return 返回删除角色分组状态
*/
@PostMapping("/api/saasRoleGroup/v2/delete")
ApiResult<Void> deleteV2(@RequestBody @Valid SaasRoleGroupDeleteRequest request);
/**
*
* 通过categoryCode查询分组

View File

@ -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-可编辑
}

View File

@ -39,10 +39,19 @@ public class DataObjectRuleBO {
* 岗位/角色id
*/
private List<Long> relationId;
/**
* 岗位code
*/
private List<String> relationCodes;
/**
* 岗位列表
*/
private List<JobInfo> jobs;
/**
* 行级数据权限单选 1:仅本人数据 2:本人及下属数据 3:仅本部门数据 4:本部门及以下数据
* 5:仅本单位数据 6:本单位及下级直属单位数据 7:本单位及下级协同直属+合作单位数据 8:本单位及以下协同直属+合作单位数据 9:本项目数据
* 5:仅本单位数据(包含班组) 6:本单位及下级直属单位数据 7:本单位及下级协同直属+合作单位数据 8:本单位及以下协同直属+合作单位数据
* 9:本项目部数据 10:仅本单位数据(不包含班组)
*/
private Integer rowPermission;
/**
@ -50,4 +59,12 @@ public class DataObjectRuleBO {
*/
private List<AttributePermissionBO> attributePermissionBOList;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class JobInfo{
private Long id;
private String code;
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,19 @@
package cn.axzo.tyr.client.model.permission;
import cn.axzo.tyr.client.model.vo.OperatorRequest;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotNull;
/**
* @author yanglin
*/
@Setter
@Getter
public class DeletePermissionPointRequest extends OperatorRequest {
@NotNull
private Long permissionId;
}

View File

@ -1,5 +1,6 @@
package cn.axzo.tyr.client.model.permission;
import cn.axzo.tyr.client.model.vo.Operator;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@ -160,6 +161,12 @@ public class PermissionPointDTO {
/** 业务编码 **/
private String businessNo;
private Operator operator;
public Operator determineOperator() {
return operator == null ? Operator.absent() : operator;
}
public Long mergeFitOuTypeBit() {
if (this.fitOuTypeList == null || this.fitOuTypeList.isEmpty()) {
return null;

View File

@ -0,0 +1,25 @@
package cn.axzo.tyr.client.model.product;
import cn.axzo.tyr.client.model.vo.OperatorRequest;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author yanglin
*/
@Setter
@Getter
public class OldUpdateFeatureRelationRequestV2 extends OperatorRequest {
private List<ProductFeatureRelationUpdateReq> relations;
private Map<String, Object> externalLogs = new ConcurrentHashMap<>();
public void addExternalLogThreadSafe(String key, Object value) {
externalLogs.put(key, value);
}
}

View File

@ -1,5 +1,6 @@
package cn.axzo.tyr.client.model.product;
import cn.axzo.tyr.client.model.vo.Operator;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -69,4 +70,9 @@ public class ProductUpdateReq {
*/
private List<Integer> ouTypes;
private Operator operator;
public Operator determineOperator() {
return operator == null ? Operator.absent() : operator;
}
}

View File

@ -39,6 +39,11 @@ public class FeatureResourceTreeSaveReq extends BaseFeatureResourceDO {
*/
private Long workspaceType;
/**
* 应用范围(租户类型)1:企业工作台 2;项目工作台 以英文逗号分隔
*/
private String workspaceTypes;
/**
* 最低版本序列,主要支持版本灰度策略
*/
@ -47,9 +52,6 @@ public class FeatureResourceTreeSaveReq extends BaseFeatureResourceDO {
/** 页面组件对象 **/
private List<FeatureComponentSaveReq> componentSaveReqList;
/** 页面及组件权限对象 **/
private List<RolePermissionSaveReq> permissions;
@NotNull(message = "操作人ID不能为空")
private Long operatorId;

View File

@ -64,6 +64,22 @@ public class IdentityAuthReq {
/** 是否使用缓存 - 默认true **/
@Builder.Default
private boolean useCache = true;
/**
* app类型APP:原生H5:h5页面
*/
private String appType;
/**
* 项目codeH5会拉取项目下所有的元素
*/
private String itemCode;
/**
* 客户端版本号
*/
private Integer versionMax;
public IdentityAuthRes toEmpty() {
IdentityAuthRes result = new IdentityAuthRes();
result.setIdentity(this.getIdentityId());
@ -112,6 +128,9 @@ public class IdentityAuthReq {
/** 基于角色标签查询逻辑不再用该参数 **/
private Integer workspaceJoinType;
public String buildOuWorkspaceKey() {
return this.getOuId() + "_" + this.getWorkspaceId();
}
}
}

View File

@ -0,0 +1,70 @@
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;
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<WorkspaceOUPair> workspaceOUPairs;
/**
* 菜单节点的uniCode
* 查询指定组件code集合里有权限的组件code
*/
private Set<String> uniCodes;
private Boolean needPageElement;
/**
* 菜单跟页面元素绑定的类型
*/
private Set<PageElementFeatureResourceRelationTypeEnum> pageElementTypes;
/**
* 客户端版本号
*/
private Integer versionMax;
/**
* 查询菜单树节点类型
*/
private List<FeatureResourceType> featureResourceTypes;
/**
* 查询父组件code下的有权限的uniCode
*/
private String parentUniCode;
/**
* 显示或者隐藏如果父节点是隐藏则子节点也会隐藏
*/
private FeatureResourceStatus status;
}

View File

@ -44,6 +44,12 @@ public class ListPermissionFromRoleGroupReq {
/** 角色组ID **/
private List<Long> roleGroupIds;
/**
* 原接口使用方有的需要2有的需要3当时加这个出了问题默认为3
* 1-仅查当前code 2-对应code角色组及子级角色组 3-仅对应code角色组的子级
*/
private Integer categoryType;
@Data
@Builder
@AllArgsConstructor

View File

@ -25,5 +25,4 @@ public class ListSaasRoleGroupParam {
@CriteriaField(ignore = true)
private Boolean needRole;
}

View File

@ -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;
@ -30,11 +31,14 @@ public class PageElementFeatureResourceRelationReq implements IPageReq {
List<String> sort;
@CriteriaField(field = "featureResourceUniCode", operator = Operator.IN)
private List<String> featureResourceUniCodes;
private Set<String> featureResourceUniCodes;
@CriteriaField(field = "pageElementCode", operator = Operator.IN)
private Set<String> pageElementCodes;
@CriteriaField(field = "terminal", operator = Operator.EQ)
private String terminal;
@CriteriaField(ignore = true)
private Set<PageElementFeatureResourceRelationTypeEnum> types;
}

View File

@ -0,0 +1,37 @@
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<String> sort;
@CriteriaField(field = "code", operator = Operator.IN)
private Set<String> codes;
@CriteriaField(ignore = true)
private Boolean needFeatureSource;
}

View File

@ -3,12 +3,14 @@ package cn.axzo.tyr.client.model.req;
import cn.axzo.foundation.dao.support.wrapper.CriteriaField;
import cn.axzo.foundation.dao.support.wrapper.Operator;
import cn.axzo.foundation.page.IPageReq;
import cn.axzo.tyr.client.common.enums.FeatureResourceType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Set;
@Data
@Builder
@ -30,4 +32,22 @@ public class PageProductFeatureRelationReq implements IPageReq {
@CriteriaField(field = "id", operator = Operator.IN)
private List<Long> ids;
/**
* 产品 ID
*/
@CriteriaField(field = "productModuleId", operator = Operator.IN)
private Set<Long> productModuleIds;
@CriteriaField(field = "type", operator = Operator.EQ)
private Integer type;
/**
* 查询菜单树节点类型
*/
@CriteriaField(field = "featureType", operator = Operator.IN)
private List<Integer> featureResourceTypes;
@CriteriaField(field = "terminal", operator = Operator.EQ)
private String terminal;
}

View File

@ -4,7 +4,7 @@ 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;
import lombok.Data;
@ -70,6 +70,21 @@ public class PageSaasFeatureResourceReq implements IPageReq {
@CriteriaField(ignore = true)
private Set<String> paths;
@CriteriaField(field = "terminal", operator = Operator.IN)
private Set<String> terminals;
@CriteriaField(ignore = true)
private Boolean needPageElement;
@CriteriaField(field = "status", operator = Operator.EQ)
private Integer status;
/**
* 菜单跟页面元素绑定的类型
*/
@CriteriaField(ignore = true)
private Set<PageElementFeatureResourceRelationTypeEnum> pageElementTypes;
public PageResp toEmpty() {
return PageResp.builder()
.current(this.getPage())

View File

@ -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;
}

View File

@ -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;
}

View File

@ -0,0 +1,20 @@
package cn.axzo.tyr.client.model.req;
import cn.axzo.tyr.client.model.vo.OperatorRequest;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotEmpty;
import java.util.List;
/**
* @author yanglin
*/
@Setter
@Getter
public class SaasRoleGroupDeleteRequest extends OperatorRequest {
@NotEmpty(message = "ids不能为空")
private List<Long> ids;
}

View File

@ -1,15 +1,20 @@
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;
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 +42,41 @@ public class TreePermissionReq {
*/
private List<FeatureResourceType> featureResourceTypes;
/**
* 菜单节点的uniCode
*/
private String uniCode;
/**
* 是否需要返回权限码
*/
private boolean needFeatureCodes;
/**
* 菜单节点的uniCode
* 查询指定组件code集合里有权限的组件code
*/
private Set<String> uniCodes;
/**
* 客户端版本号
*/
private Integer versionMax;
/**
* 查询父组件code下的有权限的uniCode
*/
private String parentUniCode;
private Boolean needPageElement;
/**
* 菜单跟页面元素绑定的类型
*/
private Set<PageElementFeatureResourceRelationTypeEnum> pageElementTypes;
/**
* 默认会增加config配置的默认权限不需要就传true
*/
private Boolean excludeDefaultPermission;
/**
* 显示或者隐藏如果父节点是隐藏则子节点也会隐藏
*/
private FeatureResourceStatus status;
}

View File

@ -144,6 +144,11 @@ public class FeatureResourceDTO implements Serializable {
*/
private Long workspaceType;
/**
* 应用范围(租户类型)1:企业工作台 2;项目工作台 以英文逗号分隔
*/
private String workspaceTypes;
/**
* 最低版本序列,主要支持版本灰度策略
*/

View File

@ -56,16 +56,11 @@ public class IdentityAuthRes {
public static class PermissionPoint {
private Long featureId;
private String featureCode;
private String featureCode;
// private FeatureType featureType;
private Integer featureType;
private String terminal;
/**
* 应用范围(租户类型)1:企业工作台 2;项目工作台
*/
private Long workspaceType;
}

View File

@ -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<PageElementResp> saasPageElements;
}

View File

@ -57,6 +57,11 @@ public class ListPermissionFromRoleGroupResp {
*/
private String roleName;
/**
* 角色编码
*/
private String roleCode;
/**
* 权限集ID
*/

View File

@ -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
@ -48,13 +52,65 @@ public class PageElementResp {
*/
private String linkUrl;
/**
* app类型APP:原生H5:h5页面
*/
private String appType;
/**
* 客户端版本号
*/
private Integer version;
/**
* 是否已勾选
*/
private Boolean selected;
private String itemCode;
private String linkExt;
/**
* 子元素只包含一级
*/
private List<PageElementResp> children;
/**
* 元素对应的菜单信息可能会存在多个
*/
private List<SaasFeatureResourceResp> featureResources;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class LinkExt {
private String system;
private String routerUrl;
}
public List<LinkExt> 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);
}
}

View File

@ -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.Sets;
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,15 @@ public class SaasFeatureResourceResp {
* 唯一编码用于pre环境菜单同步
*/
private String uniCode;
/**
* 页面元素信息
*/
private List<PageElementResp> saasPageElements;
public Set<Long> resolvePath() {
return Optional.ofNullable(this.getPath())
.map(e -> Arrays.stream(e.split(",")).map(Long::valueOf).collect(Collectors.toSet()))
.orElseGet(Sets::newHashSet);
}
}

View File

@ -37,6 +37,11 @@ public class SimplePermissionPointResp implements IBaseTree<SimplePermissionPoin
/** 上级权限点ID **/
private Long parentId;
/**
* 类型 0.模块 1.菜单 2页面 3功能
*/
private Integer featureType;
/** 子节点 **/
private List<SimplePermissionPointResp> children;

View File

@ -80,6 +80,8 @@ public class TreePermissionResp implements IBaseTree<TreePermissionResp, Long> {
*/
private Integer displayOrder;
private List<PageElementResp> saasPageElements;
/**
* 菜单树子节点信息
*/

View File

@ -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

View File

@ -0,0 +1,42 @@
package cn.axzo.tyr.client.model.vo;
import cn.axzo.framework.auth.domain.ContextInfo;
import cn.axzo.framework.auth.domain.ContextInfoHolder;
import cn.axzo.framework.auth.domain.UserInfo;
import lombok.Data;
/**
* @author yanglin
*/
@Data
public class Operator {
private String realName;
private Long personId;
/**
* For a gateway like yoke
*/
public static Operator fromAuthContext() {
ContextInfo ctx = ContextInfoHolder.get();
if (ctx == null) {
return absent();
}
UserInfo userInfo = ctx.getUserInfo();
if (userInfo == null) {
return absent();
}
Operator operator = new Operator();
operator.setRealName(userInfo.getRealName());
operator.setPersonId(userInfo.getPersonId());
return operator;
}
public static Operator absent() {
Operator operator = new Operator();
operator.setRealName("");
operator.setPersonId(0L);
return operator;
}
}

View File

@ -0,0 +1,18 @@
package cn.axzo.tyr.client.model.vo;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
public class OperatorRequest {
private Operator operator;
public Operator determineOperator() {
return operator == null ? Operator.absent() : operator;
}
}

View File

@ -70,4 +70,10 @@ public class SaasRoleGroupVO {
* 上级分组id
*/
private Long parentId;
private Operator operator;
public Operator determineOperator() {
return operator == null ? Operator.absent() : operator;
}
}

View File

@ -138,6 +138,12 @@
<artifactId>apisix-plat-api</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>

View File

@ -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={}&timestamp={}",
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 "";
}
}
}

View File

@ -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<Event> events){
events.forEach(this::send);
}
}

View File

@ -70,7 +70,43 @@ public class RocketMQEventConfiguration {
consumeMode = ConsumeMode.ORDERLY,
nameServer = "${rocketmq.name-server}"
)
public static class DefaultListener extends BaseListener implements RocketMQListener<MessageExt> {
public static class ThronesListener extends BaseListener implements RocketMQListener<MessageExt> {
@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<MessageExt> {
@Autowired
private EventConsumer eventConsumer;
@Override
public void onMessage(MessageExt message) {
super.onEvent(message, eventConsumer);
}
}
@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<MessageExt> {
@Autowired
private EventConsumer eventConsumer;

View File

@ -4,9 +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.common.enums.RoleTypeEnum;
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;
@ -17,12 +22,24 @@ 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.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;
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;
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;
@ -30,6 +47,8 @@ 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;
@ -38,18 +57,25 @@ 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;
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;
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;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -57,6 +83,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;
@ -66,6 +93,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;
@ -74,6 +102,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;
@ -123,6 +152,34 @@ public class PrivateController {
private CacheWorkspaceProductHandler cacheWorkspaceProductHandler;
@Autowired
private SaasRoleGroupDao saasRoleGroupDao;
@Autowired
private CacheProductPermissionJob cacheProductPermissionJob;
@Autowired
private CacheRolePermissionJob cacheRolePermissionJob;
@Autowired
private CacheSaasFeatureJob cacheSaasFeatureJob;
@Autowired
private CacheProductFeatureResourceJob cacheProductFeatureResourceJob;
@Autowired
private CacheRoleFeatureResourceJob cacheRoleFeatureResourceJob;
@Autowired
private SaasFeatureResourceService saasFeatureResourceService;
@Autowired
private RolePermissionCacheService rolePermissionCacheService;
@Autowired
private SaasPageElementDao saasPageElementDao;
@Autowired
private SaasPageElementFeatureResourceRelationDao saasPageElementFeatureResourceRelationDao;
@Autowired
private SaasRoleUserRelationService saasRoleUserRelationService;
@Autowired
private ProductModuleDao productModuleDao;
@Autowired
private CacheWorkspaceProductJob cacheWorkspaceProductJob;
@Autowired
private RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService;
@Autowired
private SendDingTalkHandler sendDingTalkHandler;
/**
* 统一层级的roleGroup按照id升序sort从1递增
@ -577,12 +634,24 @@ public class PrivateController {
return featureCodeUtil.resolveFeatureCode(request.getFeatureCodes());
}
@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) {
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);
@ -651,6 +720,787 @@ 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(JSON.toJSONString(request));
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";
}
@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);
}
@PostMapping("/api/private/rolePermissionCache/list")
public Object rolePermissionCache(@RequestBody RolePermissionCacheService.ListRolePermissionParam request) {
return rolePermissionCacheService.list(request);
}
@PostMapping("/api/private/productPermissionCached/list")
public Object productPermissionCached(@RequestBody ProductPermissionCacheService.ListProductPermissionParam request) {
return productPermissionCacheService.list(request);
}
@PostMapping("/api/private/saasPageElement/refreshCmpFeatureResourceLinkUrl")
public ApiResult refreshCmpFeatureResourceLinkUrl(@RequestBody RefreshFeatureResourceLinkUrlParam request) {
Long startId = 0L;
while (true) {
List<SaasPageElement> saasPageElements = saasPageElementDao.lambdaQuery()
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue())
.eq(SaasPageElement::getTerminal, TerminalInfo.NT_CMP_APP_GENERAL)
.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())
.list();
if (CollectionUtils.isEmpty(saasPageElements)) {
return ApiResult.ok();
}
for (SaasPageElement pageElement : saasPageElements) {
if (org.apache.commons.lang3.StringUtils.isBlank(pageElement.getLinkUrl())) {
continue;
}
List<SaasPageElementFeatureResourceRelation> 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<SaasFeatureResource> 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())) {
continue;
}
if (pageElement.getLinkUrl().equals(saasFeatureResource.getLinkUrl())
&& pageElement.getLinkExt().equals(saasFeatureResource.getLinkExt())) {
continue;
}
saasFeatureResourceDao.lambdaUpdate()
.eq(BaseEntity::getId, saasFeatureResource.getId())
.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());
}
startId = saasPageElements.get(saasPageElements.size() - 1).getId();
}
// return ApiResult.ok();
}
@PostMapping("/api/private/permission/check")
public ApiResult<CheckPermissionDTO> checkPermission(@RequestBody @Validated CheckPermissionParam request) {
SaasFeatureResourceService.ListSaasFeatureResourceCache listSaasFeatureResourceCache = SaasFeatureResourceService.ListSaasFeatureResourceCache.builder()
.terminals(Sets.newHashSet(request.getTerminal()))
.build();
List<SaasFeatureResourceService.SaasFeatureResourceCache> allFeatures = saasFeatureResourceService.listCache(listSaasFeatureResourceCache).get(request.getTerminal());
List<Role> roles = listRole(ListRoleUserRelationParam.builder()
.personId(request.getPersonId())
.workspaceOuPairs(Lists.newArrayList(ListRoleUserRelationParam.WorkspaceOuPair.builder()
.workspaceId(request.getWorkspaceId())
.ouId(request.getOuId())
.build()))
.needRole(true)
.build());
List<WorkspaceProductService.ProductPermission> productPermissions = listWorkspaceProductPermission(request);
List<Long> productIds = productPermissions.stream()
.map(WorkspaceProductService.ProductPermission::getProductId)
.collect(Collectors.toList());
List<Product> products = listProduct(productIds);
Map<Long, List<RolePermissionCacheService.PermissionDTO>> rolePermissions = listRolePermission(roles);
return ApiResult.ok(CheckPermissionDTO.builder()
.products(products)
.roles(roles)
.featureCodeCheckResults(resolveFeatureCode(request, productPermissions, rolePermissions, roles, allFeatures))
.build());
}
@PostMapping("/api/private/featureResource/check")
public ApiResult<CheckFeatureResourceDTO> checkFeatureResource(@RequestBody @Validated CheckFeatureResourceParam request) {
SaasFeatureResourceService.ListSaasFeatureResourceCache listSaasFeatureResourceCache = SaasFeatureResourceService.ListSaasFeatureResourceCache.builder()
.terminals(Sets.newHashSet(request.getTerminal()))
.build();
List<SaasFeatureResourceService.SaasFeatureResourceCache> allFeatures = saasFeatureResourceService.listCache(listSaasFeatureResourceCache).get(request.getTerminal());
List<Role> roles = listRole(ListRoleUserRelationParam.builder()
.personId(request.getPersonId())
.workspaceOuPairs(Lists.newArrayList(ListRoleUserRelationParam.WorkspaceOuPair.builder()
.workspaceId(request.getWorkspaceId())
.ouId(request.getOuId())
.build()))
.needRole(true)
.build());
List<WorkspaceProductService.ProductFeatureSource> productFeatureSources = listWorkspaceProductFeatureResource(request);
List<Long> productIds = productFeatureSources.stream()
.map(WorkspaceProductService.ProductFeatureSource::getProductId)
.collect(Collectors.toList());
List<Product> products = listProduct(productIds);
Map<Long, List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO>> roleFeatureResources = listRoleFeatureResource(roles);
return ApiResult.ok(CheckFeatureResourceDTO.builder()
.products(products)
.roles(roles)
.uniCodeCheckResults(resolveUniCode(request, productFeatureSources, roleFeatureResources, roles, allFeatures))
.build());
}
private UniCodeCheckResult resolveAdminRoleFeature(List<Role> adminRoles,
List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> productFeatureResources) {
if (CollectionUtils.isEmpty(adminRoles)) {
return UniCodeCheckResult.builder()
.authPermission(false)
.reasons(Lists.newArrayList("没有管理员角色"))
.build();
}
List<String> reasons = Lists.newArrayList();
Boolean authPermission = false;
for (Role adminRole : adminRoles) {
List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> 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<Role> adminRoles,
List<ProductPermissionCacheService.PermissionDTO> productPermissions) {
if (CollectionUtils.isEmpty(adminRoles)) {
return FeatureCodeCheckResult.builder()
.authPermission(false)
.reasons(Lists.newArrayList("没有管理员角色"))
.build();
}
List<String> reasons = Lists.newArrayList();
Boolean authPermission = false;
for (Role adminRole : adminRoles) {
List<ProductPermissionCacheService.PermissionDTO> 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<Role> normalRoles,
List<ProductPermissionCacheService.PermissionDTO> productPermissions,
Map<Long, List<RolePermissionCacheService.PermissionDTO>> rolePermissions,
String featureCode) {
if (CollectionUtils.isEmpty(normalRoles)) {
return FeatureCodeCheckResult.builder()
.authPermission(false)
.reasons(Lists.newArrayList("没有普通角色"))
.build();
}
List<String> reasons = Lists.newArrayList();
Boolean authPermission = false;
for (Role normalRole : normalRoles) {
List<RolePermissionCacheService.PermissionDTO> normalRolepermissions = rolePermissions.getOrDefault(normalRole.getRoleId(), Lists.newArrayList())
.stream()
.filter(e -> Objects.equals(e.getFeatureCode(), featureCode))
.collect(Collectors.toList());
Set<String> 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 UniCodeCheckResult resolveNormalRoleFeature(List<Role> normalRoles,
List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> productFeatureResources,
Map<Long, List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO>> rolePermissions,
String uniCode) {
if (CollectionUtils.isEmpty(normalRoles)) {
return UniCodeCheckResult.builder()
.authPermission(false)
.reasons(Lists.newArrayList("没有普通角色"))
.build();
}
List<String> reasons = Lists.newArrayList();
Boolean authPermission = false;
for (Role normalRole : normalRoles) {
List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO> normalRolepermissions = rolePermissions.getOrDefault(normalRole.getRoleId(), Lists.newArrayList())
.stream()
.filter(e -> Objects.equals(e.getUniCode(), uniCode))
.collect(Collectors.toList());
Set<String> 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<ProductPermissionCacheService.PermissionDTO> productPermissions,
String featureCode,
List<SaasFeatureResourceService.SaasFeatureResourceCache> allFeatures) {
// 直接配置成免授权的权限点
List<SaasFeatureResourceService.SaasFeatureResourceCache> notAuthFeatures = allFeatures.stream()
.filter(SaasFeatureResourceService.SaasFeatureResourceCache::isNotAuth)
.collect(Collectors.toList());
// 子节点是免授权的权限点
Set<Long> 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<Long> 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<Long> productFeatureIds = productPermissions.stream()
.filter(e -> Objects.equals(e.getFeatureCode(), featureCode))
.map(ProductPermissionCacheService.PermissionDTO::getFeatureId)
.collect(Collectors.toSet());
if (!Sets.intersection(notAuthFeatureIds, productFeatureIds).isEmpty()) {
return FeatureCodeCheckResult.builder()
.authPermission(true)
.reasons(Lists.newArrayList("权限点是免授权"))
.build();
} else if (!Sets.intersection(parentNotAuthFeatureIds, productFeatureIds).isEmpty()) {
return FeatureCodeCheckResult.builder()
.authPermission(true)
.reasons(Lists.newArrayList("权限点的子节点是免授权"))
.build();
} else {
return FeatureCodeCheckResult.builder()
.authPermission(false)
.reasons(Lists.newArrayList("权限点不是免授权"))
.build();
}
}
private UniCodeCheckResult resolveNotAuthFeature(List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> productFeatureResources,
String uniCode,
List<SaasFeatureResourceService.SaasFeatureResourceCache> allFeatures) {
// 直接配置成免授权的权限点
List<SaasFeatureResourceService.SaasFeatureResourceCache> notAuthFeatures = allFeatures.stream()
.filter(SaasFeatureResourceService.SaasFeatureResourceCache::isNotAuth)
.collect(Collectors.toList());
// 子节点是免授权的权限点
Set<Long> 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<Long> 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<Long> 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<FeatureCodeCheckResult> resolveFeatureCode(CheckPermissionParam checkPermissionParam,
List<WorkspaceProductService.ProductPermission> productPermissions,
Map<Long, List<RolePermissionCacheService.PermissionDTO>> rolePermissions,
List<Role> roles,
List<SaasFeatureResourceService.SaasFeatureResourceCache> allFeatures) {
Map<String, List<ProductPermissionCacheService.PermissionDTO>> productPermissionMap = productPermissions.stream()
.map(WorkspaceProductService.ProductPermission::getPermissions)
.flatMap(Collection::stream)
.collect(Collectors.groupingBy(ProductPermissionCacheService.PermissionDTO::getFeatureCode));
List<Role> adminRoles = roles.stream()
.filter(e -> RoleTypeEnum.isAdmin(e.getRoleType()))
.collect(Collectors.toList());
List<Role> normalRoles = roles.stream()
.filter(e -> !RoleTypeEnum.isAdmin(e.getRoleType()))
.collect(Collectors.toList());
return checkPermissionParam.getFeatureCodes().stream()
.map(featureCode -> {
List<ProductPermissionCacheService.PermissionDTO> permissions = productPermissionMap.get(featureCode);
if (CollectionUtils.isEmpty(permissions)) {
return FeatureCodeCheckResult.builder()
.featureCode(featureCode)
.authPermission(false)
.reasons(Lists.newArrayList("项目没有配置产品及权限"))
.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);
FeatureCodeCheckResult notAuthCheckResult = resolveNotAuth(permissions, featureCode, allFeatures);
Boolean authPermission = BooleanUtils.isTrue(adminRoleCheckResult.getAuthPermission())
|| BooleanUtils.isTrue(normalRoleCheckResult.getAuthPermission())
|| BooleanUtils.isTrue(notAuthCheckResult.getAuthPermission());
List<String> adminRoleReasons = adminRoleCheckResult.getReasons();
List<String> normalRoleReasons = normalRoleCheckResult.getReasons();
List<String> notAuthReasons = notAuthCheckResult.getReasons();
adminRoleReasons.addAll(normalRoleReasons);
adminRoleReasons.addAll(notAuthReasons);
return FeatureCodeCheckResult.builder()
.featureCode(featureCode)
.authPermission(authPermission)
.reasons(adminRoleReasons)
.build();
})
.collect(Collectors.toList());
}
private List<UniCodeCheckResult> resolveUniCode(CheckFeatureResourceParam checkFeatureResourceParam,
List<WorkspaceProductService.ProductFeatureSource> productFeatureSources,
Map<Long, List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO>> roleFeatureResources,
List<Role> roles,
List<SaasFeatureResourceService.SaasFeatureResourceCache> allFeatures) {
Map<String, List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO>> productFeatureResourceMap = productFeatureSources.stream()
.map(WorkspaceProductService.ProductFeatureSource::getFeatureResources)
.flatMap(Collection::stream)
.collect(Collectors.groupingBy(ProductSaasFeatureResourceCacheService.FeatureResourceDTO::getUniCode));
List<Role> adminRoles = roles.stream()
.filter(e -> RoleTypeEnum.isAdmin(e.getRoleType()))
.collect(Collectors.toList());
List<Role> normalRoles = roles.stream()
.filter(e -> !RoleTypeEnum.isAdmin(e.getRoleType()))
.collect(Collectors.toList());
return checkFeatureResourceParam.getUniCodes().stream()
.map(uniCode -> {
List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> 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<String> adminRoleReasons = adminRoleCheckResult.getReasons();
List<String> normalRoleReasons = normalRoleCheckResult.getReasons();
List<String> notAuthReasons = notAuthCheckResult.getReasons();
adminRoleReasons.addAll(normalRoleReasons);
adminRoleReasons.addAll(notAuthReasons);
return UniCodeCheckResult.builder()
.uniCode(uniCode)
.authPermission(authPermission)
.reasons(adminRoleReasons)
.build();
})
.collect(Collectors.toList());
}
private Map<Long, List<RolePermissionCacheService.PermissionDTO>> listRolePermission(List<Role> 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 Map<Long, List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO>> listRoleFeatureResource(List<Role> roles) {
if (CollectionUtils.isEmpty(roles)) {
return Collections.emptyMap();
}
RoleSaasFeatureResourceCacheService.ListRoleSaasFeatureResourceParam listRolePermissionParam = RoleSaasFeatureResourceCacheService.ListRoleSaasFeatureResourceParam.builder()
.roleIds(roles.stream().map(Role::getRoleId).collect(Collectors.toSet()))
.build();
return roleSaasFeatureResourceCacheService.list(listRolePermissionParam);
}
private List<Product> listProduct(List<Long> productIds) {
if (CollectionUtils.isEmpty(productIds)) {
return Collections.emptyList();
}
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<WorkspaceProductService.ProductPermission> 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<WorkspaceProductService.ProductFeatureSource> 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<Role> listRole(ListRoleUserRelationParam listRoleUserRelationParam) {
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());
}
@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
@AllArgsConstructor
public static class CheckPermissionParam {
@NotNull(message = "ouId不能为空")
private Long ouId;
@NotNull(message = "workspaceId不能为空")
private Long workspaceId;
@NotEmpty(message = "featureCodes不能为空")
private Set<String> featureCodes;
@NotNull(message = "personId不能为空")
private Long personId;
@NotBlank(message = "terminal不能为空")
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<String> uniCodes;
@NotNull(message = "personId不能为空")
private Long personId;
@NotBlank(message = "terminal不能为空")
private String terminal;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class CheckPermissionDTO {
private List<Product> products;
private List<Role> roles;
private List<FeatureCodeCheckResult> featureCodeCheckResults;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class CheckFeatureResourceDTO {
private List<Product> products;
private List<Role> roles;
private List<UniCodeCheckResult> uniCodeCheckResults;
}
@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<String> reasons;
private Boolean authPermission;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class UniCodeCheckResult {
private String uniCode;
private List<String> reasons;
private Boolean authPermission;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class StoreFeatureParam {
private String terminal;
}
@Data
@Builder
@NoArgsConstructor
@ -722,4 +1572,13 @@ public class PrivateController {
private List<Long> ids;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class RefreshFeatureResourceLinkUrlParam {
@Builder.Default
private Integer pageSize = 10;
}
}

View File

@ -85,6 +85,7 @@ public class TyrSaasAuthController implements TyrSaasAuthApi {
@Override
public ApiResult<List<ListIdentityFromPermissionResp>> listWorkspacePermissionIdentity(WorkspacePermissionIdentityReq req) {
return ApiResult.ok(tyrSaasAuthService.listWorkspacePermissionIdentity(req));
}
@Override

View File

@ -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<DataObjectRes> queryDataObject(QueryDataObjectReq req) {
return ApiResult.ok(dataObjectService.queryDataObject(req));
}
}

View File

@ -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<GetUserHasPermissionPageElementResp> getUserHasPermissionPageElement(GetUserHasPermissionPageElementReq req) {
return ApiResult.ok(saasPageElementService.getUserHasPermissionPageElement(req));
}
@Override
public ApiResult<List<PageElementResp>> list(PageElementReq param) {
return ApiResult.ok(saasPageElementService.list(param));
}
}

View File

@ -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.PermissionPointApi;
import cn.axzo.tyr.client.model.permission.DeletePermissionPointRequest;
import cn.axzo.tyr.client.model.permission.PermissionPointDTO;
import cn.axzo.tyr.client.model.permission.PermissionPointListQueryRequest;
import cn.axzo.tyr.client.model.permission.PermissionPointMoveRequest;
@ -59,6 +60,9 @@ public class PermissionPointController implements PermissionPointApi {
return ApiResult.ok(permissionPointService.delete(permissionId));
}
@Override public ApiResult<List<String>> deletePermissionPointV2(DeletePermissionPointRequest request) {
return ApiResult.ok(permissionPointService.deleteV2(request));
}
@Override
public ApiResult<Void> move(PermissionPointMoveRequest request) {

View File

@ -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<List<TreePermissionResp>> treePermission(TreePermissionReq req) {
return ApiResult.ok(permissionService.treePermission(req));
}
@Override
public ApiResult<List<ListPermissionFeatureResp>> listPermission(ListPermissionFeatureReq req) {
return ApiResult.ok(permissionService.listPermission(req));
}
}

View File

@ -3,7 +3,16 @@ package cn.axzo.tyr.server.controller.product;
import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.tyr.client.feign.ProductApi;
import cn.axzo.tyr.client.model.product.*;
import cn.axzo.tyr.client.model.product.OldUpdateFeatureRelationRequestV2;
import cn.axzo.tyr.client.model.product.ProductAddReq;
import cn.axzo.tyr.client.model.product.ProductDetailReq;
import cn.axzo.tyr.client.model.product.ProductFeatureRelationSearchReq;
import cn.axzo.tyr.client.model.product.ProductFeatureRelationUpdateReq;
import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO;
import cn.axzo.tyr.client.model.product.ProductSearchListReq;
import cn.axzo.tyr.client.model.product.ProductSearchPageReq;
import cn.axzo.tyr.client.model.product.ProductUpdateReq;
import cn.axzo.tyr.client.model.product.ProductVO;
import cn.axzo.tyr.client.model.req.ProductSaveReq;
import cn.axzo.tyr.client.model.req.UpdateProductStatusReq;
import cn.axzo.tyr.client.model.res.GovernmentTerminalResp;
@ -127,6 +136,14 @@ public class ProductController implements ProductApi {
return productFeatureRelationService.updateFeatureRelation(req);
}
@Override
public ApiResult<Boolean> updateFeatureRelationV2(OldUpdateFeatureRelationRequestV2 req) {
if(CollectionUtils.isEmpty(req.getRelations())) {
return ApiResult.ok(false);
}
permissionCacheService.markTempDisable(PermissionCacheKey.builder().disableAll(true).build());
return productFeatureRelationService.updateFeatureRelationV2(req);
}
@Override
public ApiResult<Map<Long, List<ProductFeatureRelationVO>>> queryProductFeatureRelationByWorkspace(Set<Long> workspaceIds) {

View File

@ -8,6 +8,7 @@ import cn.axzo.tyr.client.feign.SaasRoleGroupApi;
import cn.axzo.tyr.client.model.req.ListSaasRoleGroupParam;
import cn.axzo.tyr.client.model.req.PageSaasRoleGroupParam;
import cn.axzo.tyr.client.model.req.QuerySaasRoleGroupReq;
import cn.axzo.tyr.client.model.req.SaasRoleGroupDeleteRequest;
import cn.axzo.tyr.client.model.req.UpdateRoleGroupOffsetReq;
import cn.axzo.tyr.client.model.res.SaasRoleGroupDTO;
import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO;
@ -56,6 +57,12 @@ public class SaasRoleGroupController implements SaasRoleGroupApi {
return ApiResult.ok(roleGroups.get(0));
}
@Override
public ApiResult<Void> deleteV2(SaasRoleGroupDeleteRequest request) {
saasRoleGroupService.deleteV2(request);
return ApiResult.ok();
}
@Override
public ApiResult<Void> delete(List<Long> ids) {
saasRoleGroupService.delete(ids);

View File

@ -0,0 +1,328 @@
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.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 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.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;
/**
* 缓存产品的权限
*/
@Slf4j
@Component
public class CacheProductPermissionHandler implements InitializingBean {
@Autowired
private EventConsumer eventConsumer;
@Autowired
private ProductPermissionCacheService productPermissionCacheService;
@Autowired
private ProductFeatureRelationService productFeatureRelationService;
@Autowired
private SaasFeatureResourceService saasFeatureResourceService;
@Autowired
private SaasFeatureDao saasFeatureDao;
private void storeProductPermission(List<SaasProductModuleFeatureRelation> productFeatures) {
if (CollectionUtils.isEmpty(productFeatures)) {
return;
}
List<ProductPermissionCacheService.ProductPermission> 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);
ProductPermissionCreatedPayload payload = event.normalizedData(ProductPermissionCreatedPayload.class);
if (CollectionUtils.isEmpty(payload.getProductModuleIds())) {
return;
}
PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder()
.productModuleIds(payload.getProductModuleIds())
.build();
List<SaasProductModuleFeatureRelation> productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq);
if (CollectionUtils.isEmpty(productFeatures)) {
return;
}
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 (StringUtils.isBlank(payload.getTerminal())) {
return;
}
PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder()
.build();
List<SaasProductModuleFeatureRelation> productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq);
if (CollectionUtils.isEmpty(productFeatures)) {
return;
}
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::onProductPermissionUpsert);
eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert);
}
public List<ProductPermissionCacheService.ProductPermission> resolveProductPermissions(List<SaasProductModuleFeatureRelation> productPermissions) {
if (CollectionUtils.isEmpty(productPermissions)) {
return Collections.emptyList();
}
// 新的菜单树是是把有权限点的父节点也存进去了所以直接解析
Map<Long, SaasFeatureResourceResp> featureResources = listSaasFeatureResource(productPermissions);
Map<Long, SaasFeatureResourceResp> parentFeatureResources = listParentSaasFeatureResource(featureResources);
// 旧的菜单树只存储了权限点信息没有把父节点存进去需要解析父节点进行存储
Map<Long, SaasFeature> saasFeatures = listSaasFeature(productPermissions);
Map<Long, SaasFeature> parentSaasFeatures = listParentSaasFeature(saasFeatures);
return productPermissions.stream()
.collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId))
.entrySet()
.stream()
.map(e -> {
List<SaasProductModuleFeatureRelation> productFeatureRelations = e.getValue();
if (CollectionUtils.isEmpty(productFeatureRelations)) {
return null;
}
List<ProductPermissionCacheService.PermissionDTO> 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<ProductPermissionCacheService.PermissionDTO> resolveFeaturePermission(SaasProductModuleFeatureRelation relation, Map<Long, SaasFeature> saasFeatures, Map<Long, SaasFeature> parentSaasFeatures) {
SaasFeature saasFeature = saasFeatures.get(relation.getFeatureId());
if (Objects.isNull(saasFeature)) {
return null;
}
List<ProductPermissionCacheService.PermissionDTO> permissionDTOS = Lists.newArrayList(ProductPermissionCacheService.PermissionDTO.builder()
.featureId(saasFeature.getId())
.featureCode(saasFeature.getFeatureCode())
.featureType(saasFeature.getFeatureType())
.terminal(saasFeature.getTerminal())
.cooperateType(relation.getDictCode())
.build());
List<ProductPermissionCacheService.PermissionDTO> 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<ProductPermissionCacheService.PermissionDTO> resolveFeatureResourcePermission(SaasProductModuleFeatureRelation relation, Map<Long, SaasFeatureResourceResp> featureResources, Map<Long, SaasFeatureResourceResp> parentFeatureResources) {
SaasFeatureResourceResp featureResource = featureResources.get(relation.getFeatureId());
// 菜单节点是不会关联元素code所以缓存的featureCode使用菜单编码
if (Objects.isNull(featureResource)) {
return null;
}
if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) {
return null;
}
List<ProductPermissionCacheService.PermissionDTO> 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<ProductPermissionCacheService.PermissionDTO> 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<Long, SaasFeatureResourceResp> listSaasFeatureResource(List<SaasProductModuleFeatureRelation> productPermissions) {
List<Long> 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<Long, SaasFeatureResourceResp> listParentSaasFeatureResource(Map<Long, SaasFeatureResourceResp> productPermissions) {
List<Long> 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<Long, SaasFeature> listSaasFeature(List<SaasProductModuleFeatureRelation> productPermissions) {
Set<Long> 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<Long, SaasFeature> listParentSaasFeature(Map<Long, SaasFeature> saasFeatures) {
if (CollectionUtils.isEmpty(saasFeatures)) {
return Collections.emptyMap();
}
List<Long> 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()));
}
}

View File

@ -0,0 +1,237 @@
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.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 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.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 {
@Autowired
private EventConsumer eventConsumer;
@Autowired
private ProductFeatureRelationService productFeatureRelationService;
@Autowired
private ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService;
@Autowired
private SaasFeatureResourceService saasFeatureResourceService;
public static final Set<Integer> 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<SaasProductModuleFeatureRelation> productFeatures) {
if (CollectionUtils.isEmpty(productFeatures)) {
return;
}
List<ProductSaasFeatureResourceCacheService.ProductFeatureResource> productFeatureResources = resolveProductFeatureResources(productFeatures);
if (CollectionUtils.isEmpty(productFeatureResources)) {
return;
}
ProductSaasFeatureResourceCacheService.StoreProductFeatureResourceParam storeProductFeatureResourceParam = ProductSaasFeatureResourceCacheService.StoreProductFeatureResourceParam.builder()
.productFeatureResources(productFeatureResources)
.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<SaasProductModuleFeatureRelation> 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 (StringUtils.isBlank(payload.getTerminal())) {
return;
}
PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder()
.type(NEW_FEATURE)
.build();
List<SaasProductModuleFeatureRelation> productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq);
if (CollectionUtils.isEmpty(productFeatures)) {
return;
}
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::onProductPermissionUpsert);
eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert);
}
public List<ProductSaasFeatureResourceCacheService.ProductFeatureResource> resolveProductFeatureResources(List<SaasProductModuleFeatureRelation> productPermissions) {
if (CollectionUtils.isEmpty(productPermissions)) {
return Collections.emptyList();
}
Map<Long, SaasFeatureResourceResp> featureResources = listSaasFeatureResource(productPermissions);
Map<Long, SaasFeatureResourceResp> parentFeatureResources = listParentSaasFeatureResource(featureResources);
return productPermissions.stream()
.collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId))
.entrySet()
.stream()
.map(e -> {
List<SaasProductModuleFeatureRelation> productFeatureRelations = e.getValue();
if (CollectionUtils.isEmpty(productFeatureRelations)) {
return null;
}
List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> 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<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> featureResourceDTOS = Lists.newArrayList(featureResourceDTO);
List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> 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<Long, SaasFeatureResourceResp> listSaasFeatureResource(List<SaasProductModuleFeatureRelation> productPermissions) {
List<Long> 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<Long, SaasFeatureResourceResp> listParentSaasFeatureResource(Map<Long, SaasFeatureResourceResp> productPermissions) {
List<Long> 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));
}
}

View File

@ -0,0 +1,320 @@
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;
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.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;
/**
* 缓存角色的权限
*/
@Slf4j
@Component
public class CacheRolePermissionHandler implements InitializingBean {
@Autowired
private EventConsumer eventConsumer;
@Autowired
private RolePermissionCacheService rolePermissionCacheService;
@Autowired
private RoleService roleService;
@Autowired
private SaasFeatureResourceService saasFeatureResourceService;
@Autowired
private SaasFeatureDao saasFeatureDao;
private void storeRolePermission(List<SaasRoleRes> roles) {
if (CollectionUtils.isEmpty(roles)) {
return;
}
List<RolePermissionCacheService.RolePermission> 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);
RolePermissionCreatedPayload payload = event.normalizedData(RolePermissionCreatedPayload.class);
// 影响角色权限入口的代码没法简单重构导致发送的roleIds可能不准确所以一旦有角色权限的更新事件后全量更新角色权限角色权限数量不多
// 后续收口了代码就准确根据角色去更新缓存
// if (CollectionUtils.isEmpty(payload.getRoleIds())) {
// return;
// }
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
.roleIds(Optional.ofNullable(payload.getRoleIds())
.map(Lists::newArrayList)
.orElse(null))
.needPermissionRelation(true)
.build();
List<SaasRoleRes> 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 (StringUtils.isBlank(payload.getTerminal())) {
return;
}
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
.needPermissionRelation(true)
.build();
List<SaasRoleRes> roles = roleService.list(listSaasRoleParam);
storeRolePermission(roles);
}
@Override
public void afterPropertiesSet() throws Exception {
eventConsumer.registerHandler(EventTypeEnum.ROLE_PERMISSION_CREATED.getEventCode(), this::onRolePermissionUpsert);
eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert);
}
public List<RolePermissionCacheService.RolePermission> resolveRolePermission(List<SaasRoleRes> roles) {
Map<Long, SaasFeatureResourceResp> featureResources = listSaasFeatureResource(roles);
Map<Long, SaasFeatureResourceResp> parentFeatureResources = listParentSaasFeatureResource(featureResources);
Map<Long, SaasFeature> saasFeatures = listSaasFeature(roles);
Map<Long, SaasFeature> parentSaasFeatures = listParentSaasFeature(saasFeatures);
return roles.stream()
.map(e -> {
if (CollectionUtils.isEmpty(e.getPermissionRelations())) {
return null;
}
List<RolePermissionCacheService.PermissionDTO> 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<RolePermissionCacheService.PermissionDTO> resolveFeaturePermission(SaasPermissionRelationRes permissionRelation, Map<Long, SaasFeature> saasFeatures, Map<Long, SaasFeature> parentSaasFeatures) {
SaasFeature saasFeature = saasFeatures.get(permissionRelation.getFeatureId());
if (Objects.isNull(saasFeature)) {
return null;
}
List<RolePermissionCacheService.PermissionDTO> permissionDTOS = Lists.newArrayList(RolePermissionCacheService.PermissionDTO.builder()
.featureId(saasFeature.getId())
.featureCode(saasFeature.getFeatureCode())
.featureType(saasFeature.getFeatureType())
.terminal(saasFeature.getTerminal())
.build());
List<RolePermissionCacheService.PermissionDTO> 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<RolePermissionCacheService.PermissionDTO> resolveFeatureResourcePermission(SaasPermissionRelationRes permissionRelation, Map<Long, SaasFeatureResourceResp> featureResources, Map<Long, SaasFeatureResourceResp> parentFeatureResources) {
SaasFeatureResourceResp featureResource = featureResources.get(permissionRelation.getFeatureId());
// 菜单节点是不会关联元素code所以缓存的featureCode使用菜单编码
if (Objects.isNull(featureResource)) {
return null;
}
if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) {
return null;
}
List<RolePermissionCacheService.PermissionDTO> 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<RolePermissionCacheService.PermissionDTO> 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<Long, SaasFeatureResourceResp> listSaasFeatureResource(List<SaasRoleRes> roles) {
List<Long> 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<Long, SaasFeatureResourceResp> listParentSaasFeatureResource(Map<Long, SaasFeatureResourceResp> productPermissions) {
List<Long> 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<Long, SaasFeature> listSaasFeature(List<SaasRoleRes> roles) {
Set<Long> 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<Long, SaasFeature> listParentSaasFeature(Map<Long, SaasFeature> saasFeatures) {
if (CollectionUtils.isEmpty(saasFeatures)) {
return Collections.emptyMap();
}
List<Long> 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()));
}
}

View File

@ -0,0 +1,226 @@
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;
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.Optional;
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;
/**
* 因为菜单树不一定有权限code
* 登录时需要查询菜单树所以把菜单树缓存起来
*/
@Slf4j
@Component
public class CacheRoleSaasFeatureResourceHandler implements InitializingBean {
@Autowired
private EventConsumer eventConsumer;
@Autowired
private RoleService roleService;
@Autowired
private SaasFeatureResourceService saasFeatureResourceService;
@Autowired
private RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService;
private void storeRoleFeatureResource(List<SaasRoleRes> roles) {
if (CollectionUtils.isEmpty(roles)) {
return;
}
List<RoleSaasFeatureResourceCacheService.RoleFeatureResource> 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);
// 影响角色权限入口的代码没法简单重构导致发送的roleIds可能不准确所以一旦有角色权限的更新事件后全量更新角色权限角色权限数量不多
// 后续收口了代码就准确根据角色去更新缓存
// if (CollectionUtils.isEmpty(payload.getRoleIds())) {
// return;
// }
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
.roleIds(Optional.ofNullable(payload.getRoleIds())
.map(Lists::newArrayList)
.orElse(null))
.needPermissionRelation(true)
.type(NEW_FEATURE)
.build();
List<SaasRoleRes> 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 (StringUtils.isBlank(payload.getTerminal())) {
return;
}
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
.needPermissionRelation(true)
.type(NEW_FEATURE)
.build();
List<SaasRoleRes> roles = roleService.list(listSaasRoleParam);
storeRoleFeatureResource(roles);
}
@Override
public void afterPropertiesSet() throws Exception {
eventConsumer.registerHandler(EventTypeEnum.ROLE_PERMISSION_CREATED.getEventCode(), this::onRolePermissionUpsert);
eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert);
}
public List<RoleSaasFeatureResourceCacheService.RoleFeatureResource> resolveRoleFeatureResource(List<SaasRoleRes> roles) {
Map<Long, SaasFeatureResourceResp> featureResources = listSaasFeatureResource(roles);
Map<Long, SaasFeatureResourceResp> parentFeatureResources = listParentSaasFeatureResource(featureResources);
return roles.stream()
.map(e -> {
if (CollectionUtils.isEmpty(e.getPermissionRelations())) {
return null;
}
List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO> permissions = e.getPermissionRelations().stream()
.distinct()
.map(permissionRelation -> {
SaasFeatureResourceResp featureResource = featureResources.get(permissionRelation.getFeatureId());
if (Objects.isNull(featureResource) || StringUtils.isBlank(featureResource.getUniCode())) {
return null;
}
List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO> featureResourceDTOS = Lists.newArrayList(RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO.builder()
.featureId(featureResource.getId())
.featureType(featureResource.getFeatureType())
.terminal(featureResource.getTerminal())
.uniCode(featureResource.getUniCode())
.build());
List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO> 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<Long, SaasFeatureResourceResp> listSaasFeatureResource(List<SaasRoleRes> roles) {
List<Long> 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<Long, SaasFeatureResourceResp> listParentSaasFeatureResource(Map<Long, SaasFeatureResourceResp> productPermissions) {
List<Long> 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));
}
}

View File

@ -0,0 +1,44 @@
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.server.event.payload.SaasFeatureUpsertPayload;
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;
/**
* 缓存全量权限点因为鉴权等逻辑需要查询免授权和权限点是否存在数据量大数据库压力大
*/
@Slf4j
@Component
public class CacheSaasFeatureHandler implements EventHandler, InitializingBean {
@Autowired
private EventConsumer eventConsumer;
@Autowired
private CacheSaasFeatureJob cacheSaasFeatureJob;
@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;
}
cacheSaasFeatureJob.cacheSaasFeature(Sets.newHashSet(payload.getTerminal()));
log.info("end cached saasFeature handler rocketmq event: {}", event);
}
@Override
public void afterPropertiesSet() throws Exception {
eventConsumer.registerHandler(EventTypeEnum.SAAS_FEATURE_UPSERT.getEventCode(), this);
}
}

View File

@ -0,0 +1,43 @@
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.server.event.payload.SaasFeatureResourceUpsertPayload;
import cn.axzo.tyr.server.job.CacheSaasFeatureJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 缓存全量权限点因为鉴权等逻辑需要查询免授权和权限点是否存在数据量大数据库压力大
*/
@Slf4j
@Component
public class CacheSaasFeatureResourceHandler implements EventHandler, InitializingBean {
@Autowired
private EventConsumer eventConsumer;
@Autowired
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 (CollectionUtils.isEmpty(payload.getTerminals())) {
return;
}
cacheSaasFeatureJob.cacheSaasFeatureResource(payload.getTerminals());
log.info("end cached saasFeatureResource handler rocketmq event: {}", event);
}
@Override
public void afterPropertiesSet() throws Exception {
eventConsumer.registerHandler(EventTypeEnum.SAAS_FEATURE_RESOURCE_UPSERT.getEventCode(), this);
}
}

View File

@ -0,0 +1,30 @@
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", "角色权限添加"),
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) {
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;
}

View File

@ -0,0 +1,78 @@
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;
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;
import java.util.Optional;
@Slf4j
@Component
public class SendDingTalkHandler implements InitializingBean {
@Autowired
private EventConsumer eventConsumer;
@Value("${spring.profiles.active}")
private String env;
// 语音助手菜单变更通知@沈尚只是临时的方案对方接入MQ成本高所以没改成配置
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.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;
}
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);
}
}

View File

@ -0,0 +1,56 @@
package cn.axzo.tyr.server.event.outer;
import cn.axzo.framework.rocketmq.Event;
import cn.axzo.framework.rocketmq.EventConsumer;
import cn.axzo.tyr.server.event.payload.SaasFeatureDeletedPayload;
import cn.axzo.tyr.server.event.payload.SaasFeatureUpsertPayload;
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;
/**
* 缓存全量权限点因为鉴权等逻辑需要查询免授权和权限点是否存在数据量大数据库压力大
*/
@Slf4j
@Component
public class CacheSaasFeatureOldHandler implements InitializingBean {
@Autowired
private EventConsumer eventConsumer;
@Autowired
private CacheSaasFeatureJob cacheSaasFeatureJob;
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;
}
cacheSaasFeatureJob.cacheSaasFeature(Sets.newHashSet(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;
}
cacheSaasFeatureJob.cacheSaasFeature(Sets.newHashSet(payload.getTerminal()));
log.info("end cached saasFeature handler rocketmq event: {}", event);
}
@Override
public void afterPropertiesSet() throws Exception {
eventConsumer.registerHandler(EventTypeEnum.SAAS_FEATURE_UPSERT.getEventCode(), this::onSaasFeatureUpserted);
eventConsumer.registerHandler(EventTypeEnum.SAAS_FEATURE_DELETED.getEventCode(), this::onSaasFeatureDeleted);
}
}

View File

@ -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) {

View File

@ -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 String terminal;
}

View File

@ -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<Long> productModuleIds;
}

View File

@ -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<Long> roleIds;
}

View File

@ -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;
}

View File

@ -0,0 +1,26 @@
package cn.axzo.tyr.server.event.payload;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
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 {
// 只有tyr消费触发更新缓存同步等很多批量操作要全部重构收口代码后才能好修改这个payload
private Set<String> terminals;
private SaasFeatureResource oldValue;
private SaasFeatureResource newValue;
private SaasFeatureResource.Action action;
}

View File

@ -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 SaasFeatureUpsertPayload implements Serializable {
private Long id;
private String terminal;
}

View File

@ -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<String> 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<Long> 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.onProductPermissionUpsert(event, null);
return ReturnT.SUCCESS;
}
}

View File

@ -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<String> 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<Long> 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.onProductPermissionUpsert(event, null);
return ReturnT.SUCCESS;
}
}

View File

@ -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<String> 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<Long, List<SaasPermissionRelationRes>> permissionRelations = listPgroupPermissionRelation();
Integer pageNumber = 1;
while (true) {
pageSaasRoleParam.setPage(pageNumber++);
pageSaasRoleParam.setPageSize(DEFAULT_PAGE_SIZE);
PageResp<SaasRoleRes> page = roleService.page(pageSaasRoleParam);
store(page.getData(), permissionRelations);
if (!page.hasNext()) {
break;
}
}
return ReturnT.SUCCESS;
}
private Map<Long, List<SaasPermissionRelationRes>> 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<Long, Set<Long>> listPermissionGroup(List<Long> roleIds) {
return saasPgroupRoleRelationDao.findByRoleIds(roleIds).stream()
.collect(Collectors.groupingBy(SaasPgroupRoleRelation::getRoleId,
Collectors.mapping(SaasPgroupRoleRelation::getGroupId, Collectors.toSet())));
}
private void store(List<SaasRoleRes> roles,
Map<Long, List<SaasPermissionRelationRes>> permissionRelations) {
if (CollectionUtils.isEmpty(roles)) {
return;
}
List<Long> roleIds = roles.stream()
.map(SaasRoleRes::getId)
.collect(Collectors.toList());
Map<Long, Set<Long>> roleGroupMap = listPermissionGroup(roleIds);
roles.forEach(e -> {
Set<Long> groupIds = roleGroupMap.get(e.getId());
if (CollectionUtils.isEmpty(groupIds)) {
return;
}
List<SaasPermissionRelationRes> rolePermissions = groupIds.stream()
.map(permissionRelations::get)
.filter(f -> !CollectionUtils.isEmpty(f))
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
e.setPermissionRelations(rolePermissions);
});
List<RoleSaasFeatureResourceCacheService.RoleFeatureResource> roleFeatureResources = cacheRoleSaasFeatureResourceHandler.resolveRoleFeatureResource(roles);
if (CollectionUtils.isEmpty(roleFeatureResources)) {
return;
}
RoleSaasFeatureResourceCacheService.StoreRoleSaasFeatureResourceParam storeRolePermissionParam = RoleSaasFeatureResourceCacheService.StoreRoleSaasFeatureResourceParam.builder()
.roleSaasFeatureResources(roleFeatureResources)
.build();
roleSaasFeatureResourceCacheService.store(storeRolePermissionParam);
}
}

View File

@ -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.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;
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 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<String> 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());
// 因为角色权限集是重复使用通过角色找权限集数据量太大直接查询所有权限集的权限比较快
Map<Long, List<SaasPermissionRelationRes>> permissionRelations = listPgroupPermissionRelation();
Integer pageNumber = 1;
while (true) {
pageSaasRoleParam.setPage(pageNumber++);
pageSaasRoleParam.setPageSize(DEFAULT_PAGE_SIZE);
PageResp<SaasRoleRes> page = roleService.page(pageSaasRoleParam);
store(page.getData(), permissionRelations);
if (!page.hasNext()) {
break;
}
}
return ReturnT.SUCCESS;
}
private Map<Long, List<SaasPermissionRelationRes>> 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<Long, Set<Long>> listPermissionGroup(List<Long> roleIds) {
return saasPgroupRoleRelationDao.findByRoleIds(roleIds).stream()
.collect(Collectors.groupingBy(SaasPgroupRoleRelation::getRoleId,
Collectors.mapping(SaasPgroupRoleRelation::getGroupId, Collectors.toSet())));
}
private void store(List<SaasRoleRes> roles,
Map<Long, List<SaasPermissionRelationRes>> permissionRelations) {
if (CollectionUtils.isEmpty(roles)) {
return;
}
List<Long> roleIds = roles.stream()
.map(SaasRoleRes::getId)
.collect(Collectors.toList());
Map<Long, Set<Long>> roleGroupMap = listPermissionGroup(roleIds);
roles.forEach(e -> {
Set<Long> groupIds = roleGroupMap.get(e.getId());
if (CollectionUtils.isEmpty(groupIds)) {
return;
}
List<SaasPermissionRelationRes> rolePermissions = groupIds.stream()
.map(permissionRelations::get)
.filter(f -> !CollectionUtils.isEmpty(f))
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
e.setPermissionRelations(rolePermissions);
});
List<RolePermissionCacheService.RolePermission> rolePermissions = cacheRolePermissionHandler.resolveRolePermission(roles);
if (CollectionUtils.isEmpty(rolePermissions)) {
return;
}
RolePermissionCacheService.StoreRolePermissionParam storeRolePermissionParam = RolePermissionCacheService.StoreRolePermissionParam.builder()
.rolePermissions(rolePermissions)
.build();
rolePermissionCacheService.store(storeRolePermissionParam);
}
}

View File

@ -0,0 +1,129 @@
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;
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.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
@Component
public class CacheSaasFeatureJob extends IJobHandler {
@Autowired
private SaasFeatureDao saasFeatureDao;
@Autowired
private SaasFeatureResourceService saasFeatureResourceService;
/**
* 分组这些菜单节点没有版本号默认为0方便权限过滤
*/
private static final int DEFAULT_VERSION = 0;
@Override
@XxlJob("CacheSaasFeatureJob")
public ReturnT<String> 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());
cacheSaasFeatureResource(req.getTerminals());
return ReturnT.SUCCESS;
}
public void cacheSaasFeature(Set<String> terminals) {
Map<String, List<SaasFeatureResourceService.SaasFeatureResourceCache>> saasFeatures = 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())));
List<SaasFeatureResourceService.SaasFeatureResourceDTO> 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);
}
public void cacheSaasFeatureResource(Set<String> terminals) {
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
.needPageElement(true)
.terminals(terminals)
.build();
Map<String, List<SaasFeatureResourceService.SaasFeatureResourceCache>> 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()))
.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())));
List<SaasFeatureResourceService.SaasFeatureResourceDTO> 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);
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class StoreSaasFeatureParam {
private Set<String> terminals;
}
}

View File

@ -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<String> execute(String s) throws Exception {
log.info("start CacheWorkspaceProductJob, s:{}", s);
// 全量更新所有项目的产品数量比较大所以这里只从缓存中的项目去更新产品
Map<Long, Set<Long>> allWorkspaceProducts = workspaceProductService.listAllWorkspaceProductCached();
Set<Long> workspaceIds = allWorkspaceProducts.keySet();
if (CollectionUtils.isEmpty(workspaceIds)) {
return ReturnT.SUCCESS;
}
List<ServicePkgDetailRes> servicePkgDetailRes = RpcInternalUtil.rpcListProcessor(() -> servicePkgClient.getServicePkgDetailBySpaceId(workspaceIds),
"查询项目的产品", workspaceIds).getData();
List<WorkspaceProductService.WorkspaceProductDTO> 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;
}
}

View File

@ -32,7 +32,8 @@ public class SaasFeatureResourceDao extends ServiceImpl<SaasFeatureResourceMappe
SaasFeatureResource::getFeatureName, SaasFeatureResource::getFeatureType,
SaasFeatureResource::getTerminal, SaasFeatureResource::getParentId,
SaasFeatureResource::getDisplayOrder,
SaasFeatureResource::getWorkspaceType)
SaasFeatureResource::getWorkspaceType,
SaasFeatureResource::getWorkspaceTypes)
.eq(SaasFeatureResource::getIsDelete, TableIsDeleteEnum.NORMAL.value)
.in(CollectionUtils.isNotEmpty(req.getTerminals()), SaasFeatureResource::getTerminal, req.getTerminals())
.eq(Objects.nonNull(req.getStatus()), SaasFeatureResource::getStatus, req.getStatus())

View File

@ -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<SaasPgroupPermissionRelationMapper, SaasPgroupPermissionRelation> {
@ -59,6 +61,7 @@ public class SaasPgroupPermissionRelationDao extends ServiceImpl<SaasPgroupPermi
return lambdaQuery()
.in(SaasPgroupPermissionRelation::getFeatureId,featureIds)
.eq(BaseEntity::getIsDelete, TableIsDeleteEnum.NORMAL.value)
.eq(SaasPgroupPermissionRelation::getType, NEW_FEATURE)
.list();
}
}

View File

@ -36,4 +36,8 @@ public class DataObjectRuleScope extends BaseOperatorEntity<DataObjectRuleScope>
* 岗位id/角色id
*/
private Long relationId;
/**
* 岗位编码
*/
private String relationCode;
}

View File

@ -162,6 +162,11 @@ public class SaasFeatureResource extends BaseEntity<SaasFeatureResource> {
*/
private Long workspaceType;
/**
* 应用范围(租户类型)1:企业工作台 2;项目工作台 以英文逗号分隔 cmp的应用可以配置支持多工作台类型
*/
private String workspaceTypes;
/**
* 最低版本序列,主要支持版本灰度策略
*/
@ -193,4 +198,14 @@ public class SaasFeatureResource extends BaseEntity<SaasFeatureResource> {
return Objects.equals(ALL_ROLE.getValue(), authType);
}
}
@Getter
@AllArgsConstructor
public enum Action {
DELETE( "删除操作"),
CREATE( "创建操作"),
UPDATE( "更新操作");
private String desc;
}
}

View File

@ -20,6 +20,11 @@ import lombok.*;
@TableName("saas_page_element")
public class SaasPageElement extends BaseEntity<SaasPageElement> {
/**
* 客户端版本号
*/
private Integer version;
/**
* 元素的组编码
*/
@ -50,6 +55,11 @@ public class SaasPageElement extends BaseEntity<SaasPageElement> {
@TableField("link_url")
private String linkUrl;
/**
* APP适配参数
*/
private String linkExt;
/**
* 所属端
*/
@ -61,4 +71,27 @@ public class SaasPageElement extends BaseEntity<SaasPageElement> {
*/
@TableField("create_name")
private String createName;
/**
* app类型APP:原生H5:h5页面
*/
@TableField("app_type")
private String appType;
/**
* 项目codeH5会拉取项目下所有的元素
*/
@TableField("item_code")
private String itemCode;
/**
* 项目名称
*/
@TableField("item_name")
private String itemName;
/**
* H5的应用ID
*/
private String appId;
}

View File

@ -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<SaasPgroupPermissionRelationOperateLog> {
/**
@ -63,4 +66,7 @@ public class SaasPgroupPermissionRelationOperateLog extends BaseEntity<SaasPgrou
* 操作人角色
*/
private String createByRole;
@TableField(typeHandler = FastjsonTypeHandler.class)
private JSONObject ext;
}

View File

@ -2,6 +2,8 @@ package cn.axzo.tyr.server.repository.mapper;
import cn.axzo.tyr.server.repository.entity.SaasFeature;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
/**
@ -19,4 +21,6 @@ public interface SaasFeatureMapper extends BaseMapper<SaasFeature> {
"WHERE path LIKE CONCAT(#{pathPrefix},'%') ")
void updateChildrenPath(Long updater, String pathPrefix, String newPathPrefix);
@Select("SELECT * FROM saas_feature WHERE id = #{id}")
SaasFeature getByIdDeleteAware(@Param("id") Long id);
}

View File

@ -3,9 +3,21 @@ package cn.axzo.tyr.server.repository.mapper;
import cn.axzo.tyr.server.repository.entity.SaasRoleGroup;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface SaasRoleGroupMapper extends BaseMapper<SaasRoleGroup> {
@Select("<script>SELECT * FROM saas_role_group WHERE id IN\n" +
" <foreach collection=\"ids\" item=\"id\" open=\"(\" separator=\",\" close=\")\">\n" +
" #{id}\n" +
" </foreach>\n" +
"</script>")
List<SaasRoleGroup> getByIdsDeleteAware(
@Param("ids") List<Long> ids);
}

View File

@ -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<SaasRoleUserRelation> {
Page<SaasRoleUserRelation> batListCleanRelation(IPage<SaasRoleUserRelation> page, @Param("param") SaasRoleUserRelation cleanParam);
/**
* 现在没有数据可以查询项目的角色
* 通过权限点找有权限的人需要这个接口
* @param listRole
* @return
*/
Set<Long> listRoleIds(@Param("param") ListRole listRole);
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class ListRole {
private Long ouId;
private Long workspaceId;
}
}

View File

@ -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<SimpleDataObjectRes> pageDataObject(PageDataObjectReq req);
DataObjectRes getDataObject(Long dataObjectId);
DataObjectRes queryDataObject(QueryDataObjectReq req);
}

View File

@ -1,5 +1,6 @@
package cn.axzo.tyr.server.service;
import cn.axzo.tyr.client.model.permission.DeletePermissionPointRequest;
import cn.axzo.tyr.client.model.permission.PermissionPointDTO;
import cn.axzo.tyr.client.model.permission.PermissionPointListQueryRequest;
import cn.axzo.tyr.client.model.permission.PermissionPointMoveRequest;
@ -42,6 +43,9 @@ public interface PermissionPointService {
/** 删除权限点 返回business_no **/
List<String> delete(Long permissionId);
/** 删除权限点 返回business_no **/
List<String> deleteV2(DeletePermissionPointRequest request);
/** 位置移动-父级和排序 **/
void move(PermissionPointMoveRequest request);

View File

@ -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<TreePermissionResp> treePermission(TreePermissionReq req);
List<ListPermissionFeatureResp> listPermission(ListPermissionFeatureReq req);
}

View File

@ -2,6 +2,7 @@ package cn.axzo.tyr.server.service;
import cn.axzo.foundation.page.PageResp;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.tyr.client.model.product.OldUpdateFeatureRelationRequestV2;
import cn.axzo.tyr.client.model.product.ProductFeatureRelationSearchReq;
import cn.axzo.tyr.client.model.product.ProductFeatureRelationUpdateReq;
import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO;
@ -25,6 +26,8 @@ public interface ProductFeatureRelationService extends IService<SaasProductModul
ApiResult<Boolean> updateFeatureRelation(List<ProductFeatureRelationUpdateReq> req);
ApiResult<Boolean> updateFeatureRelationV2(OldUpdateFeatureRelationRequestV2 request);
/**
* 更新产品功能权限关系仅支持saas_feature_resource功能点
*

View File

@ -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<PermissionDTO> list(ListProductPermissionParam param);
/**
* 查询产品的权限信息
* @param param
* @return
*/
Map<Long, List<PermissionDTO>> list(ListProductPermissionParam param);
/**
* 存储产品的权限信息
* @param param
*/
void store(StoreProductPermissionParam param);
/**
* 产品是否有缓存权限
* @param param
* @return
*/
List<Long> hasProductIds(HasProductPermissionParam param);
@Data
@ -47,7 +62,9 @@ public interface ProductPermissionCacheService {
@NoArgsConstructor
@AllArgsConstructor
class ListProductPermissionParam {
private List<Long> productIds;
private Set<Long> productIds;
private Set<String> featureCodes;
}
@Data
@ -57,12 +74,32 @@ 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;
/**
* app类型APP:原生H5:h5页面
*/
private String appType;
/**
* 项目codeH5会拉取项目下所有的元素
*/
private String itemCode;
/**
* 客户端版本号
*/
private Integer version;
}
}

View File

@ -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<Long, List<FeatureResourceDTO>> list(ListProductFeatureResourceParam param);
void store(StoreProductFeatureResourceParam param);
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class StoreProductFeatureResourceParam {
private List<ProductFeatureResource> productFeatureResources;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class ProductFeatureResource {
private Long productId;
private List<FeatureResourceDTO> featureResources;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class ListProductFeatureResourceParam {
private Set<Long> productIds;
private Set<String> 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;
}
}

View File

@ -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<PermissionDTO> list(ListRolePermissionParam param);
Map<Long, List<PermissionDTO>> list(ListRolePermissionParam param);
/**
* redisKey:roleId
@ -53,7 +54,9 @@ public interface RolePermissionCacheService {
@NoArgsConstructor
@AllArgsConstructor
class ListRolePermissionParam {
private List<Long> roleIds;
private Set<Long> roleIds;
private Set<String> featureCodes;
}
@Data
@ -80,5 +83,7 @@ public interface RolePermissionCacheService {
* 资源所属端
*/
private String terminal;
private Integer featureType;
}
}

View File

@ -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<Long, List<SaasFeatureResourceDTO>> list(ListRoleSaasFeatureResourceParam param);
void store(StoreRoleSaasFeatureResourceParam param);
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class StoreRoleSaasFeatureResourceParam {
private List<RoleFeatureResource> roleSaasFeatureResources;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class RoleFeatureResource {
private Long roleId;
private List<SaasFeatureResourceDTO> saasFeatureResources;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class ListRoleSaasFeatureResourceParam {
private Set<Long> roleIds;
private Set<String> 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;
}
}

View File

@ -203,6 +203,12 @@ public interface RoleService extends IService<SaasRole> {
*/
@CriteriaField(ignore = true)
private List<ListRoleUserRelationParam.WorkspaceOuPair> workspaceOuPairs;
@CriteriaField(field = "workspaceId", operator = Operator.EQ)
private Long workspaceId;
@CriteriaField(field = "ownerOuId", operator = Operator.EQ)
private Long ouId;
}
@SuperBuilder

View File

@ -1,62 +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 java.util.List;
import java.util.Set;
/**
* 功能资源服务
*
* @version V1.0
* @author: ZhanSiHu
* @date: 2024/4/3 10:17
*/
public interface SaasFeatureResourceService extends IService<SaasFeatureResource> {
Long saveOrUpdateMenu(FeatureResourceTreeSaveReq req);
void updateFeatureAuthType(Long featureId, Integer authType);
/**递归的**/
List<SaasFeatureResource> batchListDescendant(List<Long> featureIds);
SaasFeatureResource featureResourceById(Long featureId);
FeatureResourceTreeNode getTreeFeatureDescendant(Long featureId, Integer featureType);
/**菜单重排序**/
void reorderMenuFeature(Long featureId, Integer offset);
/** 根据ID查询导航菜单页面信息 仅可显示 - 限制查询字段 **/
List<SaasFeatureResource> listNavByIds(List<Long> featureIds, List<Integer> featureTypes);
/** 资源权限通用查询 **/
List<ResourcePermission> permissionQuery(ResourcePermissionQueryDTO param);
/** 查询资源树 **/
List<FeatureResourceTreeNode> getTree(GetFeatureResourceTreeReq req);
SaasFeatureResource getByCode(String featureCode);
Set<Long> listAuthFree();
List<SaasFeatureResource> listByParentIdAndTerminalAndIds(Long parentId, String terminal, List<Long> featureIds);
List<SaasFeatureResourceResp> list(PageSaasFeatureResourceReq param);
PageResp<SaasFeatureResourceResp> page(PageSaasFeatureResourceReq param);
void deleteFeatureResource(DeleteFeatureResourceReq param);
}
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<SaasFeatureResource> {
Long saveOrUpdateMenu(FeatureResourceTreeSaveReq req);
void updateFeatureAuthType(Long featureId, Integer authType);
/**递归的**/
List<SaasFeatureResource> batchListDescendant(List<Long> featureIds);
SaasFeatureResource featureResourceById(Long featureId);
FeatureResourceTreeNode getTreeFeatureDescendant(Long featureId, Integer featureType);
/**菜单重排序**/
void reorderMenuFeature(Long featureId, Integer offset);
/** 根据ID查询导航菜单页面信息 仅可显示 - 限制查询字段 **/
List<SaasFeatureResource> listNavByIds(List<Long> featureIds, List<Integer> featureTypes);
/** 资源权限通用查询 **/
List<ResourcePermission> permissionQuery(ResourcePermissionQueryDTO param);
/** 查询资源树 **/
List<FeatureResourceTreeNode> getTree(GetFeatureResourceTreeReq req);
SaasFeatureResource getByCode(String featureCode);
Set<Long> listAuthFree();
List<SaasFeatureResource> listByParentIdAndTerminalAndIds(Long parentId, String terminal, List<Long> featureIds);
List<SaasFeatureResourceResp> list(PageSaasFeatureResourceReq param);
PageResp<SaasFeatureResourceResp> page(PageSaasFeatureResourceReq param);
void deleteFeatureResource(DeleteFeatureResourceReq param);
void storeCache(StoreSaasFeatureResourceCache param);
Map<String, List<SaasFeatureResourceCache>> listCache(ListSaasFeatureResourceCache param);
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class StoreSaasFeatureResourceCache {
private List<SaasFeatureResourceDTO> saasFeatureResources;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class SaasFeatureResourceDTO {
private String terminal;
private List<SaasFeatureResourceCache> features;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class ListSaasFeatureResourceCache {
private Set<String> terminals;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class SaasFeatureResourceCache {
private Long featureId;
private boolean notAuth;
private Set<Long> parentIds;
private String uniCode;
/**
* 客户端版本号
* 在根据版本号查询菜单树限的时候需要
*/
private Integer version;
/**
* 1展示
* 0隐藏
* FeatureResourceStatus
*/
private Integer status;
}
}

View File

@ -1,10 +1,17 @@
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;
import cn.axzo.tyr.server.repository.entity.SaasPageElement;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
@ -13,7 +20,7 @@ import java.util.List;
* @version 1.0
* @date 2024/6/18
*/
public interface SaasPageElementService {
public interface SaasPageElementService extends IService<SaasPageElement> {
/**
* 页面元素上报
@ -70,4 +77,9 @@ public interface SaasPageElementService {
* @return
*/
GetUserHasPermissionPageElementResp getUserHasPermissionPageElement(GetUserHasPermissionPageElementReq request);
List<PageElementResp> list(PageElementReq param);
cn.axzo.foundation.page.PageResp<PageElementResp> page(PageElementReq param);
}

View File

@ -4,6 +4,7 @@ import cn.axzo.foundation.page.PageResp;
import cn.axzo.tyr.client.model.req.ListSaasRoleGroupParam;
import cn.axzo.tyr.client.model.req.PageSaasRoleGroupParam;
import cn.axzo.tyr.client.model.req.QuerySaasRoleGroupReq;
import cn.axzo.tyr.client.model.req.SaasRoleGroupDeleteRequest;
import cn.axzo.tyr.client.model.res.SaasRoleGroupDTO;
import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO;
import cn.axzo.tyr.server.repository.entity.SaasRoleGroup;
@ -32,6 +33,8 @@ public interface SaasRoleGroupService extends IService<SaasRoleGroup> {
void delete(List<Long> ids);
void deleteV2(SaasRoleGroupDeleteRequest request);
/**
* 分组CODE查询角色分组
* @param categoryCode

View File

@ -66,4 +66,10 @@ public interface TyrSaasAuthService {
* @return
*/
boolean authNewPermission(PermissionCheckReq req);
/**
* 增加统一的开关权限是否从数据库查询
* @return
*/
boolean permissionFromDB();
}

View File

@ -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 {
@ -29,6 +30,48 @@ public interface WorkspaceProductService {
*/
void storeWorkspaceProduct(StoreWorkspaceProductParam param);
/**
* 从缓存中查询项目的产品及产品的权限
* @param param
* @return
*/
List<WorkspaceProductPermission> listWorkspaceProductPermissionCached(ListWorkspaceProductPermissionCacheParam param);
/**
* 从缓存中查询项目的产品及产品的菜单信息
* @param param
* @return
*/
List<WorkspaceProductFeatureSource> listWorkspaceProductFeatureResourceCached(ListWorkspaceProductFeatureSourceCacheParam param);
Map<Long, Set<Long>> listAllWorkspaceProductCached();
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class ListWorkspaceProductFeatureSourceCacheParam {
/**
* 项目id
*/
private Set<Long> workspaceIds;
private Set<String> uniCodes;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class ListWorkspaceProductPermissionCacheParam {
/**
* 项目id
*/
private Set<Long> workspaceIds;
private Set<String> featureCodes;
}
@Data
@Builder
@NoArgsConstructor
@ -74,6 +117,31 @@ public interface WorkspaceProductService {
private List<SaasProductModuleFeatureRelation> saasProductModuleFeatureRelations;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class WorkspaceProductPermission {
/**
* 项目id
*/
private Long workspaceId;
private List<ProductPermission> productPermissions;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class ProductPermission {
private Long productId;
private List<ProductPermissionCacheService.PermissionDTO> permissions;
}
@Data
@Builder
@NoArgsConstructor
@ -110,5 +178,30 @@ public interface WorkspaceProductService {
*/
private Set<Long> workspaceIds;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class WorkspaceProductFeatureSource {
/**
* 项目id
*/
private Long workspaceId;
private List<ProductFeatureSource> productFeatureSources;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class ProductFeatureSource {
private Long productId;
private List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> featureResources;
}
}

View File

@ -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;
@ -31,13 +33,17 @@ 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 com.google.common.collect.Maps;
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.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.Resource;
@ -64,6 +70,7 @@ public class DataObjectServiceImpl implements DataObjectService {
private TransactionTemplate transactionTemplate;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createDataObject(CreateDataObjectReq req) {
// 校验
// objectNameobjectCode不能重复
@ -88,6 +95,7 @@ public class DataObjectServiceImpl implements DataObjectService {
}
List<DataObjectRule> dataObjectRules = DataObjectMapper.INSTANCE.ruleBOs2Rules(req.getDataObjectRuleBOList());
handleJobs(dataObjectRules, req.getDataObjectRuleBOList());
int size = (CollUtil.isNotEmpty(defaultDataObjectRules) ? defaultDataObjectRules.size() : 0)
+ (CollUtil.isNotEmpty(dataObjectRules) ? dataObjectRules.size() : 0);
@ -167,6 +175,7 @@ public class DataObjectServiceImpl implements DataObjectService {
}
@Override
@Transactional(rollbackFor = Exception.class)
public void editDataObject(EditDataObjectReq req) {
// 对象属性名和code不能重复
checkObjectAttrNameOrCodeUnique(req.getAttrs());
@ -196,6 +205,7 @@ public class DataObjectServiceImpl implements DataObjectService {
}
List<DataObjectRule> 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<DataObjectRule> generalObjectRuleList = new ArrayList<>(size);
@ -235,6 +245,7 @@ public class DataObjectServiceImpl implements DataObjectService {
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteDataObject(Long dataObjectId, Long updateBy) {
List<Long> idList = Collections.singletonList(dataObjectId);
transactionTemplate.executeWithoutResult(status -> {
@ -274,87 +285,22 @@ 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<DataObjectAttr> objectAttrList = dataObjectAttrDao.listByBO(bo1);
Map<String, String> attrMap;
if (CollUtil.isNotEmpty(objectAttrList)) {
List<AttributeBO> attributeBOS = DataObjectMapper.INSTANCE.dataObjectAttrs2AttributeBOs(objectAttrList);
List<AttributeBO> 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<DataObject> 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)) {
log.warn("数据权限记录不存在param:{}", JSON.toJSONString(req));
return null;
}
// 获取数据对象规则
DataObjectRuleQueryBO bo2 = DataObjectRuleQueryBO.builder().dataObjectId(dataObjectId).build();
List<DataObjectRule> 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<DataObjectRuleBO> sortedRuleList = res.getDataObjectRuleBOList().stream().sorted(Comparator.comparing(DataObjectRuleBO::getSort)).collect(Collectors.toList());
res.setDataObjectRuleBOList(sortedRuleList);
}
}
// 获取数据对象规则字段
RuleAttrQueryBO bo3 = RuleAttrQueryBO.builder().dataObjectId(dataObjectId).build();
List<DataObjectRuleAttr> ruleAttrList = dataObjectRuleAttrDao.listByBO(bo3);
if (CollUtil.isNotEmpty(attrMap) && CollUtil.isNotEmpty(ruleAttrList)) {
Map<Long, List<DataObjectRuleAttr>> ruleAttrMap = ruleAttrList.stream().collect(Collectors.groupingBy(DataObjectRuleAttr::getDataObjectRuleId));
// 默认
List<DataObjectRuleAttr> ruleAttrList1 = ruleAttrMap.get(res.getDefaultDataObjectRuleBO().getDataObjectRuleId());
if (CollUtil.isNotEmpty(ruleAttrList1)) {
List<AttributePermissionBO> permissionBOs = DataObjectMapper.INSTANCE.ruleAttrs2AttrPermissionBOs(ruleAttrList1);
permissionBOs.forEach(e -> e.setAttrName(attrMap.get(e.getAttrCode())));
List<AttributePermissionBO> 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<DataObjectRuleScope> scopeList = dataObjectRuleScopeDao.listByBO(bo4);
if (CollUtil.isNotEmpty(scopeList)) {
Map<Long, List<DataObjectRuleScope>> scopeMap = scopeList.stream().collect(Collectors.groupingBy(DataObjectRuleScope::getDataObjectRuleId));
// 默认
List<DataObjectRuleScope> defaultScopeList = scopeMap.get(res.getDefaultDataObjectRuleBO().getDataObjectRuleId());
if (CollUtil.isNotEmpty(defaultScopeList)) {
List<Long> relationIdList = defaultScopeList.stream().map(DataObjectRuleScope::getRelationId).collect(Collectors.toList());
res.getDefaultDataObjectRuleBO().setRelationId(relationIdList);
}
//自定义
if (CollUtil.isNotEmpty(res.getDataObjectRuleBOList())) {
res.getDataObjectRuleBOList().forEach(e -> {
List<DataObjectRuleScope> scopeList1 = scopeMap.get(e.getDataObjectRuleId());
if (CollUtil.isNotEmpty(scopeList1)) {
List<Long> relationIdList = scopeList1.stream().map(DataObjectRuleScope::getRelationId).collect(Collectors.toList());
e.setRelationId(relationIdList);
}
});
}
}
return res;
return buildDataObjectRes(dataObjects.get(0));
}
private static void buildRuleAttr(Map<String, String> attrMap, Map<Long, List<DataObjectRuleAttr>> ruleAttrMap, DataObjectRuleBO e) {
@ -428,4 +374,114 @@ 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<DataObjectAttr> objectAttrList = dataObjectAttrDao.listByBO(bo1);
Map<String, String> attrMap;
if (CollUtil.isNotEmpty(objectAttrList)) {
List<AttributeBO> attributeBOS = DataObjectMapper.INSTANCE.dataObjectAttrs2AttributeBOs(objectAttrList);
List<AttributeBO> 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<DataObjectRule> 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<DataObjectRuleBO> sortedRuleList = res.getDataObjectRuleBOList().stream().sorted(Comparator.comparing(DataObjectRuleBO::getSort)).collect(Collectors.toList());
res.setDataObjectRuleBOList(sortedRuleList);
}
}
// 获取数据对象规则字段
RuleAttrQueryBO bo3 = RuleAttrQueryBO.builder().dataObjectId(dataObject.getId()).build();
List<DataObjectRuleAttr> ruleAttrList = dataObjectRuleAttrDao.listByBO(bo3);
if (CollUtil.isNotEmpty(attrMap) && CollUtil.isNotEmpty(ruleAttrList)) {
Map<Long, List<DataObjectRuleAttr>> ruleAttrMap = ruleAttrList.stream().collect(Collectors.groupingBy(DataObjectRuleAttr::getDataObjectRuleId));
// 默认
List<DataObjectRuleAttr> ruleAttrList1 = ruleAttrMap.get(res.getDefaultDataObjectRuleBO().getDataObjectRuleId());
if (CollUtil.isNotEmpty(ruleAttrList1)) {
List<AttributePermissionBO> permissionBOs = DataObjectMapper.INSTANCE.ruleAttrs2AttrPermissionBOs(ruleAttrList1);
permissionBOs.forEach(e -> e.setAttrName(attrMap.get(e.getAttrCode())));
List<AttributePermissionBO> 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<DataObjectRuleScope> scopeList = dataObjectRuleScopeDao.listByBO(bo4);
if (CollUtil.isNotEmpty(scopeList)) {
Map<Long, List<DataObjectRuleScope>> scopeMap = scopeList.stream().collect(Collectors.groupingBy(DataObjectRuleScope::getDataObjectRuleId));
// 默认
List<DataObjectRuleScope> defaultScopeList = scopeMap.get(res.getDefaultDataObjectRuleBO().getDataObjectRuleId());
if (CollUtil.isNotEmpty(defaultScopeList)) {
List<Long> relationIdList = defaultScopeList.stream().map(DataObjectRuleScope::getRelationId).collect(Collectors.toList());
res.getDefaultDataObjectRuleBO().setRelationId(relationIdList);
}
//自定义
if (CollUtil.isNotEmpty(res.getDataObjectRuleBOList())) {
res.getDataObjectRuleBOList().forEach(e -> {
List<DataObjectRuleScope> scopeList1 = scopeMap.get(e.getDataObjectRuleId());
if (CollUtil.isNotEmpty(scopeList1)) {
List<Long> 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()));
}
});
}
}
return res;
}
private void handleJobs(List<DataObjectRule> dataObjectRules, List<DataObjectRuleBO> dataObjectRuleBOList) {
if (CollectionUtils.isEmpty(dataObjectRules) || CollectionUtils.isEmpty(dataObjectRuleBOList)) {
return;
}
Map<Long, DataObjectRuleBO.JobInfo> 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());
}
});
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More