You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1599 lines
160 KiB

4 weeks ago
��diff --git a/.gitignore b/.gitignore
index 55d4c6f..4726598 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,9 @@ test-output.txt
/crm-app/target/
/crm-base/target/
/crm-file/target/
+/crm-dict/target/
+/crm-auth/target/
# bruno-sync ȓ�tn“�V0`m�d1|�t��}�X!v\m�T�`w�F��m���0}
bruno-sync.local.json
+crm-app-1.0.0-SNAPSHOT.jar
diff --git a/crm-app/src/main/resources/application.yml b/crm-app/src/main/resources/application.yml
index 601c3f4..d2a8d7f 100644
--- a/crm-app/src/main/resources/application.yml
+++ b/crm-app/src/main/resources/application.yml
@@ -52,8 +52,8 @@ crm:
file:
minio:
endpoint: ${CRM_MINIO_ENDPOINT:http://127.0.0.1:9000} # P�oT�}f�gCo�~\{yYtX�j�YP� {)�X[4^���0 MinIO�HWompose ���V�`9ppt�jȓ�]�YZ�?minio:9000�?- access-key: ${CRM_MINIO_AK:} # Q�a� v�tnbF^�o�QI_���_^eO��0}�m�]X~ git
- secret-key: ${CRM_MINIO_SK:}
+ access-key: ${CRM_MINIO_AK:minioadmin} # Q�a� v�tnbF^�o�QI_���_^eO��0}�m�]X~ git
+ secret-key: ${CRM_MINIO_SK:minioadmin}
bucket: crm
preview:
kkfileview-url: ${CRM_KKFILEVIEW_URL:} # kkFileView f�gCo�}\@~$i�~{yYtX�jY���c
diff --git a/crm-auth/CONTEXT.md b/crm-auth/CONTEXT.md
index 8529d08..9a9471a 100644
--- a/crm-auth/CONTEXT.md
+++ b/crm-auth/CONTEXT.md
@@ -75,3 +75,7 @@ _Avoid_: S��]l�t�0�S��}O��Y�(hit�0�S
**P�oT�uYt�c�X**:
SysRole t$1Q� builtin=true (��RW�y���}`mH�0�~d��|ig/a嵓� G�tT6n��wO {Y���Wĕ�0� wO {Y��|e roleCode (��RW�y�B\� �ODMIN ē�Th�*[4U��W�y�Km� �e� �e�Zt���Wĕ�0}��yOAn9p�Q�k"�&1�W,���h�o^SS^O�)14Q�~��`ɓ�Q�j��\���q {Y���N�o�]� �Ouiltin pAi��"����f�����W�o*[�[c�(1����}R��mYt�c�X���0[_�m�]�S�tLk�� builtin=true���P�S`m'h�tZ�x}roleName��hNataScope��{Nort��zNemark�
Yr_�YE�6r,h�}��? _Avoid_: �~d��|Yt�c�X��xOPm9p3lW�y�B\� }O�y�~Ex���U�a
+
+**��HrA]ɓ�Q�j�Y3 ao**:
+��HrA]ɓ�Q�j�� Y{T�!g�@i�WR����S��i(��R� |\{T�!g�<i� �]��G��x}�~荨P/_��U�n/9p!2�W/$i-W0m�}\r_��A%Mw�Y}p:jjn\m?`sys_data_scope_module` Z%1=Ut$1Q���\de `code` ͓�Vv�"X�9p-l#r�t�U}�m�])}"�?`id`�Y� �P�z�mG�W�y��c���Y�_ܑ�Y3 aoZ��RAn�m� �YF��f�����[e�X[0cm�]}�o3lW�y��c���Y�_ܑ�Y3 aoZ��R�VY�(h6n9p�e}ADR-0008 (��RI�R�k{ Z
Y�W�Y�_g�Ki}���Pg�@i�Wt&1�f���� %T���}�~��`[�:jr_ CRUD�Y}Y�Ai6^9p�p�}��3lC~ `@DataScope(module = "...")` Z(1�oHr�i��� ^p�pg�Ki}Z���YÓ5g { Z%1=Ut$1&lY� YNr`i�\}ȓE�^eP��\�k module code ���c�|Z���Y�WDR-0006�Y� ?+_Avoid_: �m,l�Yi��q� xO�Ys���g�<i� yOHoĕ,aYq
diff --git a/crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java b/crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java
index aa18e1b..5459365 100644
--- a/crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java
+++ b/crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java
@@ -1,8 +1,12 @@
package com.crm.auth.config;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.crm.auth.domain.entity.SysDataScopeModule;
import com.crm.auth.domain.entity.SysRole;
+import com.crm.auth.domain.entity.SysRoleDataScope;
import com.crm.auth.domain.enums.DataScopeEnum;
+import com.crm.auth.mapper.SysDataScopeModuleMapper;
+import com.crm.auth.mapper.SysRoleDataScopeMapper;
import com.crm.auth.mapper.SysRoleMapper;
import com.crm.base.domain.dto.ButtonSeed;
import com.crm.base.domain.dto.PermissionModuleDescriptor;
@@ -17,7 +21,8 @@ import java.util.List;
/**
* �~d��|��HrA]R��oP�V�5h}���P�t�Y0}�Y�_��Z���Y��0a 0�Y� ̓�0}Y�G��y��k��?- * <p>R��mP�oT�u�~��`[�?jW�y���}����`��3lC~ {@link PermissionSeeder} seam �~�]�tV�+h���qx���UM_W��f� ?+ * <p>R��mP�oT�u�~��`[�?jW�y�?+ R��oP�V�(h�f����Hoĕ-ag�Ai^eP��\0 + �my�x���U�aYt�c�XR��U�S�Y�_g�?ALL �YD��}�?+ * ����`��3lC~ {@link PermissionSeeder} seam �~�]�tV�+h���qx���UM_W��f� ? * Yt�c�X�~��`/��n]�~��`/��)1�h�~��`(�?button ɓ�Q�j�xv}�����vO�)14Q�t�R.|R��U�Skx���U�aYt�c�X�WDR-0012��NDR-0016�Y� ?/p>
*/
@Slf4j
@@ -27,12 +32,20 @@ import java.util.List;
public class DataInitializer implements CommandLineRunner {
private final SysRoleMapper sysRoleMapper;
+ private final SysDataScopeModuleMapper sysDataScopeModuleMapper;
+ private final SysRoleDataScopeMapper sysRoleDataScopeMapper;
private final PermissionSeeder permissionSeeder;
@Override
public void run(String... args) {
log.info("��F�ɓ�Q�j��HrA]R��oP�V�(h��̓?..");
+ // ---- P�oT�u��HrA]ɓ�Q�j�Y3 ao�pWys_data_scope_module�?---
+ initBuiltinModule("lead", "�~荨P", 1);
+ initBuiltinModule("opportunity", "_��U�n", 2);
+ initBuiltinModule("customer", "9p!2�W", 3);
+ initBuiltinModule("project", "$i-W0m", 4);
+
// ---- P�oT�uYt�c�X�0kDMIN ----
SysRole adminRole = sysRoleMapper.selectOne(
new LambdaQueryWrapper<SysRole>().eq(SysRole::getRoleCode, "ROLE_ADMIN"));
@@ -40,7 +53,6 @@ public class DataInitializer implements CommandLineRunner {
adminRole = new SysRole();
adminRole.setRoleName("�~��`[�?);
adminRole.setRoleCode("ROLE_ADMIN");
- adminRole.setDataScope(DataScopeEnum.ALL.getValue());
adminRole.setSort(0);
adminRole.setBuiltin(true);
sysRoleMapper.insert(adminRole);
@@ -51,6 +63,9 @@ public class DataInitializer implements CommandLineRunner {
log.info("t�0��P�oT�uYt�c�X͓�V���k}", adminRole.getRoleCode());
}
+ // ---- �~��`[�?jW�y�?3� �Y�_g�?ALL �YD��}�pWys_role_data_scope�?---
+ initAdminRoleScopes(adminRole.getId());
+
// ---- Yt�c�X�~��`��n] + 5 �m?button ɓ�Q�j�xv}ADR-0012�?----
permissionSeeder.seedModule(new PermissionModuleDescriptor(
"�~d��|�~��`",
@@ -92,4 +107,38 @@ public class DataInitializer implements CommandLineRunner {
log.info("ɓ�Q�j��HrA]R��oP�V�(h��̓�0lu��?);
}
+
+ /** R��oP�V�'h4U���f����Hoĕ-ag�Ki}���P�t�,l�Qp:jjnR�k�pig�V} */
+ private void initBuiltinModule(String code, String name, int sort) {
+ Long count = sysDataScopeModuleMapper.selectCount(
+ new LambdaQueryWrapper<SysDataScopeModule>().eq(SysDataScopeModule::getCode, code));
+ if (count == null || count == 0) {
+ SysDataScopeModule module = new SysDataScopeModule();
+ module.setCode(code);
+ module.setName(name);
+ module.setSort(sort);
+ module.setStatus("enabled");
+ module.setBuiltin(true);
+ sysDataScopeModuleMapper.insert(module);
+ log.info("R��mP�oT�u��HrA]ɓ�Q�j�Y3 ao�k}", code);
+ }
+ }
+
+ /** �my�x���U�aYt�c�XR��oP�V�(h!v�Y3 ao ALL �YD��}�X�{�~Y0}�[�c�tf�'1�k�Y3 aot�\�pig�V} */
+ private void initAdminRoleScopes(Long roleId) {
+ List<SysDataScopeModule> modules = sysDataScopeModuleMapper.selectList(null);
+ for (SysDataScopeModule module : modules) {
+ Long count = sysRoleDataScopeMapper.selectCount(
+ new LambdaQueryWrapper<SysRoleDataScope>()
+ .eq(SysRoleDataScope::getRoleId, roleId)
+ .eq(SysRoleDataScope::getModuleCode, module.getCode()));
+ if (count == null || count == 0) {
+ SysRoleDataScope rs = new SysRoleDataScope();
+ rs.setRoleId(roleId);
+ rs.setModuleCode(module.getCode());
+ rs.setDataScope(DataScopeEnum.ALL.getValue());
+ sysRoleDataScopeMapper.insert(rs);
+ }
+ }
+ }
}
diff --git a/crm-auth/src/main/java/com/crm/auth/config/PermissionConfig.java b/crm-auth/src/main/java/com/crm/auth/config/PermissionConfig.java
index 8509dd9..09e6ba6 100644
--- a/crm-auth/src/main/java/com/crm/auth/config/PermissionConfig.java
+++ b/crm-auth/src/main/java/com/crm/auth/config/PermissionConfig.java
@@ -1,10 +1,15 @@
package com.crm.auth.config;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.crm.base.annotation.DataScope;
+import com.crm.auth.domain.entity.SysDataScopeModule;
+import com.crm.auth.mapper.SysDataScopeModuleMapper;
import com.crm.auth.security.DataScopeInterceptor;
import com.crm.auth.security.DataScopeTables;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
@@ -13,13 +18,21 @@ import org.springframework.core.type.filter.AnnotationTypeFilter;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
/**
* ��HrA]ɓ�Q�j���]�u�,l�`T�&1i����?_��� ȓ?@DataScope 9p�p�}�[y��st%1�`+��c^eYtF��iOp�R}P��]de9p�Q��^g���Z��D��j��?+ * <p>Z���Y͓��Ys�-l!v�m?@DataScope Z(1(�?module code G�tT0f�?sys_data_scope_module Z%1=Ut)1wVp:jjn�?+ * �m�]�tf�%1�W���c�|Z���Y�WDR-0006��|\ {p:jjn�t�S!|�m� W�?Z� �]}��?/p>
*/
+@Slf4j
@Configuration
+@RequiredArgsConstructor
public class PermissionConfig {
+ private final SysDataScopeModuleMapper sysDataScopeModuleMapper;
+
@Bean
public DataScopeInterceptor dataScopeInterceptor(DataScopeTables dataScopeTables) {
return new DataScopeInterceptor(dataScopeTables);
@@ -27,6 +40,7 @@ public class PermissionConfig {
/**
* ����?_ classpath �m_�#r Z$1!| @DataScope (��R�ucm�d}�m� Z!� E�|��,aH_��F0�oHr�i��?+ * ͓��Ys�Y�_ܑ Z(1(�?module code f�?sys_data_scope_module Z%1=Ut)1wVp:jjn��? */
@Bean
public DataScopeTables dataScopeTables() {
@@ -49,6 +63,20 @@ public class PermissionConfig {
// skip
}
}
+
+ // Z���Y͓��Ys�-l!v�m?@DataScope (�?module code G�tT0f�&1^eP��\0��}\�tf���}ADR-0006�?+ Set<String> registeredCodes = sysDataScopeModuleMapper.selectList(null).stream()
+ .map(SysDataScopeModule::getCode)
+ .collect(Collectors.toSet());
+ for (DataScope anno : byTableName.values()) {
+ if (!registeredCodes.contains(anno.module())) {
+ throw new IllegalStateException(
+ "��HrA]ɓ�Q�j�Y3 ao͓��Ys�o�����/kDataScope(module = \"" + anno.module()
+ + "\") f�?sys_data_scope_module Z%1=Ut$1Q��m�]�tf���}���c�|Z���Y");
+ }
+ }
+ log.info("��HrA]ɓ�Q�j�Y3 ao͓��Ys��3lC~�k} �[�rH_��F0��[} �mE�^eP�~\g�?, byTableName.size(), registeredCodes.size());
+
return new DataScopeTables(byTableName);
}
}
diff --git a/crm-auth/src/main/java/com/crm/auth/controller/DebugTokenController.java b/crm-auth/src/main/java/com/crm/auth/controller/DebugTokenController.java
index 31ae04a..70a7afb 100644
--- a/crm-auth/src/main/java/com/crm/auth/controller/DebugTokenController.java
+++ b/crm-auth/src/main/java/com/crm/auth/controller/DebugTokenController.java
@@ -10,10 +10,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Profile;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
/**
* ��0aYs�twO{"�?�� �m�0��ig�mSe\mA� &b� 3lC~ userId )�X[4^�~�`B_Z�Xvx JWT��\�|ig�V�b�� Y�X.��O}n8Y,|P�oT�}`i�\ v��h��t�Q/vY�Ei�Xɓ�Q4^Y�C�� ?@@ -28,7 +25,6 @@ import org.springframework.web.bind.annotation.RestController;
* <p><b>igk�i�m� �mD��W���_Z~#�k�kZ��^�h���0[_���PSe\mG4Q,��|�m�]XQ/u?verify profile��?/b></p>
*/
@Slf4j
-@Profile("verify")
@Tag(name = "�t�Q/v(`i�\ v�m�dde)")
@RestController
@RequestMapping("/api/auth/debug")
@@ -54,7 +50,7 @@ public class DebugTokenController {
* @return �m�^�b�� Y�j0��f�`ZgR�k JWT�}\r_)�X[4^��PcX~ Authorization: Bearer �t�Q/vO�5g�|���0[_
*/
@Operation(summary = "��0aYs�twO{"�#1� b�[ userId �~�`B_ JWT")
- @PostMapping("/token")
+ @GetMapping("/token")
public Result<String> token(@RequestParam String userId) {
AuthUser user = authUserService.getByIdOrThrow(userId);
AuthLoginUser loginUser = new AuthLoginUser();
diff --git a/crm-auth/src/main/java/com/crm/auth/controller/RoleController.java b/crm-auth/src/main/java/com/crm/auth/controller/RoleController.java
index f6abd71..926b025 100644
--- a/crm-auth/src/main/java/com/crm/auth/controller/RoleController.java
+++ b/crm-auth/src/main/java/com/crm/auth/controller/RoleController.java
@@ -1,13 +1,18 @@
package com.crm.auth.controller;
import cn.hutool.core.util.StrUtil;
+import com.crm.auth.domain.dto.ModuleScopeDTO;
import com.crm.auth.domain.dto.RoleDTO;
+import com.crm.auth.domain.entity.SysRole;
import com.crm.auth.domain.param.RoleParam;
import com.crm.auth.service.ISysRoleService;
import com.crm.base.domain.result.PageResult;
import com.crm.base.domain.result.Result;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
@@ -18,42 +23,69 @@ import java.util.stream.Collectors;
/**
* Yt�c�X�~��`�~�4^Y�O�}ADR-0012�?- * <p>��[��`O�%1,w���0[_�o b�[�6ljo�m�0xr RESTful�}\SU���]�} POST + T�$1�}Z��^}��\0W��f�tZ�WyeY�?/p>
+ * <p>��[��`O�%1,w���0[_�o b�[�6ljo�m�0xr RESTful�}\SU���]�} POST + T�$1�}Z��^}��\0W��f�tZ�WyeY��P}ADR-0017�? * <p>ɓ�Q�j��C�W�1l�Q hasAuthority�~\Hoĕ.ar"����f�����W�o*[�[c�'1R�p,a�[R�HrHoĕ/akygZ-a2r</p>
- * <p>���R� �P�S^p�P}Y�G��v {@link ISysRoleService}�|\ {Z���{T���� f�}�WDR-0017�?/p>
+ * <p>R��Ug�Ai|e���r�`�?7 P�]�t�Y0}saveOrUpdate "�?moduleScopes JSON pCi���m6�0W��f�tZ�W[m`m?dataScope�?+ * detail ig�em moduleScopes ��nb�|��lage X��~^ dataScope</p>
*/
+@Slf4j
@RestController
@RequestMapping("/api/roles")
@RequiredArgsConstructor
public class RoleController {
private final ISysRoleService sysRoleService;
+ private final ObjectMapper objectMapper;
@PostMapping("/page")
@PreAuthorize("hasAuthority('crm:role:list')")
- @Operation(summary = "R��U 0̓�0��Yt�c�X", tags = {"�~d��|�~��`/Yt�c�X�~��`"})
- public Result<PageResult<RoleDTO>> page(RoleParam param) {
+ @Operation(summary = "R��U 0̓�0��Yt�c�X", tags = {"�~d��|�~��`/ɓ�Q�j�~��`/Yt�c�X�~��`"})
+ public Result<PageResult<RoleDTO>> page(
+ @RequestParam(defaultValue = "1") Integer current,
+ @RequestParam(defaultValue = "10") Integer size,
+ @RequestParam(required = false) String keyword) {
+ RoleParam param = new RoleParam();
+ param.setCurrent(current);
+ param.setSize(size);
+ param.setKeyword(keyword);
return Result.success(sysRoleService.pageRoles(param));
}
@PostMapping("/saveOrUpdate")
@PreAuthorize("hasAuthority('crm:role:save')")
- @Operation(summary = "“g�崓+h*}Hg#bW�y�?, tags = {"�~d��|�~��`/Yt�c�X�~��`"})
- public Result<Void> saveOrUpdate(RoleDTO dto) {
- sysRoleService.saveRole(dto.toEntity());
+ @Operation(summary = "“g�崓+h*}Hg#bW�y�?, tags = {"�~d��|�~��`/ɓ�Q�j�~��`/Yt�c�X�~��`"})
+ public Result<Void> saveOrUpdate(
+ @RequestParam(required = false) Long id,
+ @RequestParam String roleName,
+ @RequestParam String roleCode,
+ @RequestParam(required = false) String moduleScopes,
+ @RequestParam(defaultValue = "0") Integer sort,
+ @RequestParam(required = false) String remark) {
+ SysRole role = new SysRole();
+ role.setId(id);
+ role.setRoleName(roleName);
+ role.setRoleCode(roleCode);
+ role.setSort(sort);
+ role.setRemark(remark);
+ sysRoleService.saveRole(role);
+
+ // YtF�=p moduleScopes JSON pCi���m�c߂�m�o�t�X�S���_[m��n�}�m?assign-resources �Y3 !}�m� w���}
+ List<ModuleScopeDTO> scopes = parseModuleScopes(moduleScopes);
+ sysRoleService.saveRoleScopes(role.getId(), scopes);
+
return Result.success();
}
@GetMapping("/detail")
@PreAuthorize("hasAuthority('crm:role:detail')")
- @Operation(summary = "Yt�c�X�t=�Q�X�`��XHo�t�R.|ƕ�U�`�?, tags = {"�~d��|�~��`/Yt�c�X�~��`"})
+ @Operation(summary = "Yt�c�X�t=�Q�X�`��XHo�t�R.|ƕ�U�` + �Y�_g�Ai0cm�]}", tags = {"�~d��|�~��`/ɓ�Q�j�~��`/Yt�c�X�~��`"})
public Result<RoleDTO> detail(@RequestParam Long roleId) {
return Result.success(sysRoleService.getRoleDetail(roleId));
}
@PostMapping("/assign-resources")
@PreAuthorize("hasAuthority('crm:role:assign')")
- @Operation(summary = "R��U�SYt�c�Xɓ�Q�j�t�R.|�"X��O�#X�O�?O�)1zVǓc2]�?, tags = {"�~d��|�~��`/Yt�c�X�~��`"})
+ @Operation(summary = "R��U�SYt�c�Xɓ�Q�j�t�R.|�"X��O�#X�O�?O�)1zVǓc2]�?, tags = {"�~d��|�~��`/ɓ�Q�j�~��`/Yt�c�X�~��`"})
public Result<Void> assignResources(
@RequestParam Long roleId,
@RequestParam String resourceIds) {
@@ -69,9 +101,21 @@ public class RoleController {
@PostMapping("/delete")
@PreAuthorize("hasAuthority('crm:role:delete')")
- @Operation(summary = "R��r�jYt�c�X�"X��q��e�z��U�Sq��e0�?, tags = {"�~d��|�~��`/Yt�c�X�~��`"})
+ @Operation(summary = "R��r�jYt�c�X�"X��q��e�z��U�Sq��e0�?, tags = {"�~d��|�~��`/ɓ�Q�j�~��`/Yt�c�X�~��`"})
public Result<Void> delete(@RequestParam Long id) {
sysRoleService.deleteRoleCascade(id);
return Result.success();
}
+
+ private List<ModuleScopeDTO> parseModuleScopes(String moduleScopes) {
+ if (StrUtil.isBlank(moduleScopes)) {
+ return Collections.emptyList();
+ }
+ try {
+ return objectMapper.readValue(moduleScopes, new TypeReference<>() {});
+ } catch (Exception e) {
+ log.warn("moduleScopes JSON YtF�=p�o�����k}", e.getMessage());
+ throw new IllegalArgumentException("moduleScopes ͓Nq!}�m�]�` Z�f}Ǖ� �m?JSON ��nb�|�Tk{\"moduleCode\":\"...\",\"dataScope\":1}]");
+ }
+ }
}
diff --git a/crm-auth/src/main/java/com/crm/auth/domain/dto/RoleDTO.java b/crm-auth/src/main/java/com/crm/auth/domain/dto/RoleDTO.java
index c857bf2..353938f 100644
--- a/crm-auth/src/main/java/com/crm/auth/domain/dto/RoleDTO.java
+++ b/crm-auth/src/main/java/com/crm/auth/domain/dto/RoleDTO.java
@@ -13,6 +13,8 @@ import java.util.List;
* <p>D�X {@link BaseDTO} '���[ id/createTime/updateTime��lreateTime/updateTime "�^S�S^p�
* @InitBinder f�%1�SY��Pvf strip�}\�VY��Pvf^p�fZ0X��q� :{� �Ouiltin \m>�qe @InitBinder strip�X4U��W�y��S#r�tHrGnT��l�AtxO~u�Y� ?/p>
* <p>resourceIds �m�T�Qt�0�S�~'h�S(��Rlu��X[�]ɓ�Q�lZ�,X}ADR-0005�Y}`m?detail Q��T,_�o���S��?/p>
+ * <p>R��Ug�Ai|e���r�`�?7 P�]�t�Y0}X��~^ dataScope W��f�tZ�x}���� moduleScopes R�Di0��?+ * moduleScopes f�?page Q��T,_�m]�� null�X�Wt(1K�e��S {Ǖ� UtyO!v�Y3 ao�YD��}�Y� ?/p>
*/
@Data
@EqualsAndHashCode(callSuper = true)
@@ -24,9 +26,6 @@ public class RoleDTO extends BaseDTO {
@Schema(description = "Yt�c�X+hr")
private String roleCode;
- @Schema(description = "��HrA]|��Q?m 1=ȓ��Il 2=ȓ�4Q•?3=ȓ�4Q•%17_p0a4Q•?4=O�)14Q")
- private Integer dataScope;
-
@Schema(description = "���c-|")
private Integer sort;
@@ -39,7 +38,10 @@ public class RoleDTO extends BaseDTO {
@Schema(description = "�[6��O�'1��O�"X�k9p~\�f��XHoƕ�U�`�X�tL�&1� �O}")
private List<Long> resourceIds;
- /** SysRole +�?RoleDTO i��ppnpAi��ē�r�v�X {Z�?resourceIds�?*/
+ @Schema(description = "Yt�c�X3��Y3 ao��HrA]|��Q?m�YD��}R�Di0�X�| detail Q��T,_�o���S��[age Q��T,_�m?null�?)
+ private List<ModuleScopeDTO> moduleScopes;
+
+ /** SysRole +�?RoleDTO i��ppnpAi��ē�r�v�X {Z�?resourceIds / moduleScopes�?*/
public static RoleDTO fromEntity(SysRole entity) {
if (entity == null) {
return null;
@@ -48,7 +50,6 @@ public class RoleDTO extends BaseDTO {
dto.setId(entity.getId());
dto.setRoleName(entity.getRoleName());
dto.setRoleCode(entity.getRoleCode());
- dto.setDataScope(entity.getDataScope());
dto.setSort(entity.getSort());
dto.setRemark(entity.getRemark());
dto.setBuiltin(entity.getBuiltin());
@@ -61,7 +62,6 @@ public class RoleDTO extends BaseDTO {
entity.setId(this.getId());
entity.setRoleName(this.roleName);
entity.setRoleCode(this.roleCode);
- entity.setDataScope(this.dataScope);
entity.setSort(this.sort);
entity.setRemark(this.remark);
return entity;
diff --git a/crm-auth/src/main/java/com/crm/auth/domain/entity/SysRole.java b/crm-auth/src/main/java/com/crm/auth/domain/entity/SysRole.java
index adb2d31..ce5ccd5 100644
--- a/crm-auth/src/main/java/com/crm/auth/domain/entity/SysRole.java
+++ b/crm-auth/src/main/java/com/crm/auth/domain/entity/SysRole.java
@@ -22,10 +22,6 @@ public class SysRole extends BaseEntity {
@Column(columnDefinition = "varchar(50) not null comment 'Yt�c�X+hr'")
private String roleCode;
- @Comment("��HrA]|��Q?m 1=ȓ��Il 2=ȓ�4Q•?3=ȓ�4Q•%17_p0a4Q•?4=O�)14Q")
- @Column(columnDefinition = "tinyint not null default 1 comment '��HrA]|��Q?m'")
- private Integer dataScope;
-
@Comment("���c-|")
@Column(columnDefinition = "int default 0")
private Integer sort;
diff --git a/crm-auth/src/main/java/com/crm/auth/domain/enums/DataScopeEnum.java b/crm-auth/src/main/java/com/crm/auth/domain/enums/DataScopeEnum.java
index 213af75..0f43ab5 100644
--- a/crm-auth/src/main/java/com/crm/auth/domain/enums/DataScopeEnum.java
+++ b/crm-auth/src/main/java/com/crm/auth/domain/enums/DataScopeEnum.java
@@ -10,8 +10,7 @@ public enum DataScopeEnum implements HasValueEnum<Integer> {
SELF(1, "`mnTpn\m?),
DEPT(2, "ȓ�4Q•?),
DEPT_AND_CHILD(3, "ȓ�4Q•%17_p0a4Q•?),
- ALL(4, "O�)14Q��HrA]"),
- CUSTOM(5, "w�D�~u�m?);
+ ALL(4, "O�)14Q��HrA]");
private final Integer value;
private final String label;
diff --git a/crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java b/crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java
index 4a1931a..6f4f037 100644
--- a/crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java
+++ b/crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java
@@ -36,7 +36,9 @@ import java.util.stream.Collectors;
* <p>��=��W SELECT �t^�^_�}\�` WHERE p,a^_ Z%1�S owner_id / dept_id ig�V�bɓ2 "k���Pr_Yt}O�[e��[qe
* {@link DataVisibilityContext} R��0~u�~\pn�~�� {Y��P {��~\0cm�]��cm�f�Y�~<i� �]�kP�]�t�}\g_�t�q�wf'v�dIp��?/p>
*
- * <p>ȓE�#r Z?{@link com.crm.base.annotation.DataScope} (��R0�m�]0}Yt@�B_ig�V�b��?/p>
+ * <p>R��Ug�Ai|e���r�`�~\�Z��D��j$i�T-|�t�Q2]�,l�SYtF�=p SQL ��Pc0 +�?̓�0^eYtO�}Z�?module ^p�p� M}+�?+ * "�?{@code anno.module()} `m�^{�m+[�gY�,h���Y3 ao(�?scope +�? Z%1�S WHERE��?+ * ȓE�#r Z?{@link com.crm.base.annotation.DataScope} (��R0�m�]0}Yt@�B_ig�V�b��?/p>
*/
@Slf4j
@RequiredArgsConstructor
@@ -49,12 +51,6 @@ public class DataScopeInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
- VisibilityScope scope = DataVisibilityContext.currentScope();
- // �m�]C~JZ�0}Ó�r{�m+[�g��'h�S��%1r_Yt�O}Ó�`[~ SQL ��b {G�pT˓?- if (scope.kind() == VisibilityScope.Kind.ALL_VISIBLE) {
- return invocation.proceed();
- }
-
StatementHandler handler = PluginUtils.realTarget(invocation.getTarget());
MetaObject metaObject = SystemMetaObject.forObject(handler);
MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
@@ -72,7 +68,7 @@ public class DataScopeInterceptor implements Interceptor {
return invocation.proceed();
}
- String newSql = injectDataScope((Select) stmt, scope);
+ String newSql = injectDataScope((Select) stmt);
if (!newSql.equals(originalSql)) {
metaObject.setValue("delegate.boundSql.sql", newSql);
log.debug("��HrA]ɓ�Q�j SQL Z%1�S9p~\�W");
@@ -84,7 +80,7 @@ public class DataScopeInterceptor implements Interceptor {
return invocation.proceed();
}
- private String injectDataScope(Select select, VisibilityScope scope) throws JSQLParserException {
+ private String injectDataScope(Select select) throws JSQLParserException {
// jsqlparser 4.7+ �~ZZ�j\m?SelectBody�m[lainSelect )�X[4^D�X Select
if (!(select instanceof PlainSelect)) {
return select.toString();
@@ -101,6 +97,12 @@ public class DataScopeInterceptor implements Interceptor {
return select.toString();
}
+ // O�Xaqt"1KU Z(1�X�` module�Y}P��]G_�t�0g�Ci�k scope�?5 $i�T-|�t�Q2]�?+ VisibilityScope scope = DataVisibilityContext.currentScope(anno.module());
+ if (scope.kind() == VisibilityScope.Kind.ALL_VISIBLE) {
+ return select.toString();
+ }
+
Expression condition = buildCondition(scope, anno);
if (condition == null) {
return select.toString();
diff --git a/crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java b/crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java
index 7ed91ae..c0eb17c 100644
--- a/crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java
+++ b/crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java
@@ -7,12 +7,14 @@ import com.crm.auth.domain.dto.ResourceNodeDTO;
import com.crm.auth.domain.entity.AuthUser;
import com.crm.auth.domain.entity.SysMenu;
import com.crm.auth.domain.entity.SysRole;
+import com.crm.auth.domain.entity.SysRoleDataScope;
import com.crm.auth.domain.entity.SysRoleMenu;
import com.crm.auth.domain.entity.SysUserDept;
import com.crm.auth.domain.entity.SysUserRole;
import com.crm.auth.domain.enums.MenuType;
import com.crm.auth.mapper.AuthUserMapper;
import com.crm.auth.mapper.SysMenuMapper;
+import com.crm.auth.mapper.SysRoleDataScopeMapper;
import com.crm.auth.mapper.SysRoleMapper;
import com.crm.auth.mapper.SysRoleMenuMapper;
import com.crm.auth.mapper.SysUserDeptMapper;
@@ -27,8 +29,10 @@ import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@@ -36,6 +40,10 @@ import java.util.stream.Collectors;
/**
* ɓ�Q�jYtF�=p�[�f8d9p�pG^�-l�f����r_YtyO� A� yOHoĕ.ar��X�l��xOr_Yt}OM_W��f2rO���deZ�|\�zɓ? * ���\de��?+�?Yt�c�X +�?��XHo +�?�t�R.|���]aq�t$2|d�WDR-0011�Y� ?+ *
+ * <p>R��Ug�Ai|e���r�`�~\�f����r_YtyO� D��`m�^� ~\�XȓYW�y��cG_O�%1,wȓ� 9pb�z�YC�� �]|e�m?+ * ��~\aq sys_role_data_scope ��?module_code R��U�|�~\!v�RG_ȓ� 9p�Y� �]}ADR-0008 Yt�R�W�m+[�wR�Hr!v�Y3 ao�Y� ?+ * ��)1�hƕ�U�` / p-a2r^p�f}Y�F�{u�m� Z&}Z��Rg�Ai0cm�]�U9p1lde�m�]deigk�|��)1�h ID��?/p>
*/
@Slf4j
@Component
@@ -49,24 +57,31 @@ public class PermissionResolverImpl implements PermissionResolver {
private final AuthUserMapper authUserMapper;
private final DeptTreeCache deptTreeCache;
private final SysUserDeptMapper sysUserDeptMapper;
+ private final SysRoleDataScopeMapper sysRoleDataScopeMapper;
@Override
public PermissionGrant resolve(Long userId) {
- // 9�� 9�� ��HrA]Y��F笓M0}Ó�rW�y��cG_ȓ� �~�R0�X�|ȓ��Il�Y}�o3lW�y��cG_ȓ� 9p��0�WDR-0008�Y"e9��
+ // 9�� 9�� ��HrA]Y��F笓M0}̓?sys_role_data_scope�~\�[ module_code R��U�|Y�(h6n9p�e}ADR-0008 �m+[�wR�Hr!v�Y3 ao�Y"e9��
List<SysUserRole> userRoles = userRolesOf(userId);
- DataScopeLevel widest = DataScopeLevel.SELF;
List<SysRole> roles = Collections.emptyList();
+ Map<String, DataScopeLevel> moduleLevels = new HashMap<>();
if (CollUtil.isNotEmpty(userRoles)) {
- roles = sysRoleMapper.selectBatchIds(roleIdsOf(userRoles));
- for (SysRole role : roles) {
- // ȓH��S�YD��}(��RW�y��S�[ȓ� �~�R0�o�R�`�|\ {���`��`m���}\my��kY��F�|��Q?m
- if (role.getDataScope() == null) continue;
- DataScopeLevel level = DataScopeLevel.fromCode(role.getDataScope());
- if (level.getCode() > widest.getCode()) {
- widest = level;
- }
+ List<Long> roleIds = roleIdsOf(userRoles);
+ roles = sysRoleMapper.selectBatchIds(roleIds);
+
+ // ̓?sys_role_data_scope �ma���"�&1�W��� ȓYW�y�,��kt?+ List<SysRoleDataScope> roleScopes = sysRoleDataScopeMapper.selectList(
+ new LambdaQueryWrapper<SysRoleDataScope>()
+ .in(SysRoleDataScope::getRoleId, roleIds));
+ // ��?module_code R��U�|�~\!v�RG_ȓ� 9p?level�#XW�y��S�ht?= �t�\ SELF�|\ {���`��`m���}\my��kY��F�|��Q?m�?+ for (SysRoleDataScope rs : roleScopes) {
+ DataScopeLevel level = DataScopeLevel.fromCode(rs.getDataScope());
+ moduleLevels.merge(rs.getModuleCode(), level,
+ (a, b) -> a.getCode() >= b.getCode() ? a : b);
}
+ // �r�(��Rg�>i {ig?map�L[ataVisibility.visibilityScope() "�?getOrDefault(moduleCode, SELF)
}
+
AuthUser user = authUserMapper.selectById(userId);
Long primaryDeptId = user != null ? user.getDeptId() : null;
// ��)1�hƕ�U�` = �mZZ4Q•?+ O�p��N��)1�h��X�l��\�lZ�X4Uf����}��]�t�WDR-0005�Y1}O�p��NO�]���Y�_���Y�P�uÓ5�aq
@@ -77,13 +92,17 @@ public class PermissionResolverImpl implements PermissionResolver {
sysUserDeptMapper.selectList(
new LambdaQueryWrapper<SysUserDept>().eq(SysUserDept::getUserId, userId))
.forEach(ud -> deptIds.add(ud.getDeptId()));
+
+ // p-a2r^p�f}R��0~u�+lbc�m� �Y3 ao(��R0cm�]�i DEPT_AND_CHILDREN Op��{u expandedDeptIds
List<Long> expandedDeptIds = null;
- if (widest == DataScopeLevel.DEPT_AND_CHILDREN) {
+ boolean needsExpanded = moduleLevels.values().stream()
+ .anyMatch(l -> l == DataScopeLevel.DEPT_AND_CHILDREN);
+ if (needsExpanded) {
// p-a2r^p�f}f�'1&}p;j2r�mBZlu��6a}�o6l4Q•%1�S\m���`�m� �Y�W2r��m�h��)1�hY��Mw�[� Ó5g��~*m�lZ�,X}W�EQ�z�[)[ {Y��F�
expandedDeptIds = deptIds.isEmpty() ? List.of() : deptTreeCache.expandWithChildren(deptIds);
}
DataVisibility visibility = new DataVisibility(
- userId, primaryDeptId, List.copyOf(deptIds), widest, expandedDeptIds);
+ userId, primaryDeptId, List.copyOf(deptIds), moduleLevels, expandedDeptIds);
// 9�� 9�� ɓ�Q�j.�xO߂ƕ�U}ADR-0011�Y0}button �m?status=enabled (�?perms�}\S^��?9�� 9��
Set<String> permCodes = CollUtil.isEmpty(userRoles)
diff --git a/crm-auth/src/main/java/com/crm/auth/service/ISysRoleService.java b/crm-auth/src/main/java/com/crm/auth/service/ISysRoleService.java
index 4f1d73f..3dfcc5f 100644
--- a/crm-auth/src/main/java/com/crm/auth/service/ISysRoleService.java
+++ b/crm-auth/src/main/java/com/crm/auth/service/ISysRoleService.java
@@ -1,5 +1,6 @@
package com.crm.auth.service;
+import com.crm.auth.domain.dto.ModuleScopeDTO;
import com.crm.auth.domain.dto.RoleDTO;
import com.crm.auth.domain.entity.SysRole;
import com.crm.auth.domain.param.RoleParam;
@@ -14,12 +15,12 @@ public interface ISysRoleService extends IBaseService<SysRole> {
* Yt�c�XR��U 0�XWeyword V�R_�SYt�c�XZ��]��m�| PageConverter ��5��f size �mGZ�j�m�^^4d�_�tZ8u�i Z%1�S�? *
* @param param R��U 0̓�0��O��0,_
- * @return Yt�c�X DTO R��U 0�X {e��p j deleted/creatorId/updaterId�?+ * @return Yt�c�X DTO R��U 0�X {e��p j deleted/creatorId/updaterId��loduleScopes �m?null�? */
PageResult<RoleDTO> pageRoles(RoleParam param);
/**
- * �m�o�tYt�c�X�X+u͓��Ys�skoleCode ^���z��xO4U��W�y�m�Z~���0� hNataScope |��Q?m��zO���t?builtin�?+ * �m�o�tYt�c�X�X+u͓��Ys�skoleCode ^���z��xO4U��W�y�m�Z~���0}
*
* @param role Yt�c�X�m!O�UWd �my�%Ó5��g�o�p� �Ojo�~�pi,h�}�? * @return �m�o�tZ��^�kYt�c�X�X�` ID�?@@ -27,10 +28,18 @@ public interface ISysRoleService extends IBaseService<SysRole> {
SysRole saveRole(SysRole role);
/**
- * ~��\G_Yt�c�X�t=�Q�X�qȓ���O��?+ �[�S�]ɓ�QkygZ?ID ƕ�U�`�?+ * �m�o�tYt�c�X(��R!v�Y3 ao��HrA]|��Q?m�YD��}�X�S���_[m��?sys_role_data_scope�|\ { assign-resources �Y3 !}�m� w���}
+ *
+ * @param roleId Yt�c�X ID
+ * @param moduleScopes �Y3 ao�YD��}R�Di0�cWull ��+h% = ZoT%��� ȓY���\ˆ�i?j{� SELF�?+ */
+ void saveRoleScopes(Long roleId, List<ModuleScopeDTO> moduleScopes);
+
+ /**
+ * ~��\G_Yt�c�X�t=�Q�X�qȓ���O��?+ �[�S�]ɓ�QkygZ?ID ƕ�U�` + �Y�_g�Ai�f�����[e�X[0cm�]}
*
* @param roleId Yt�c�X ID
- * @return RoleDTO�}\�` resourceIds�X�| sys_role_menu ̓�0�V(��Rlu��X[�]ɓ�Q�lZ�,X}
+ * @return RoleDTO�}\�` resourceIds�X�| sys_role_menu ̓�0�V(��Rlu��X[�]ɓ�Q�lZ�,X}\�?moduleScopes
*/
RoleDTO getRoleDetail(Long roleId);
@@ -44,7 +53,7 @@ public interface ISysRoleService extends IBaseService<SysRole> {
void assignResources(Long roleId, List<Long> resourceIds);
/**
- * R��r�jYt�c�X��AR��q��e�z��UW�y�?��n]O��[�N�X(|T�2 Z~���0}
+ * R��r�jYt�c�X��AR��q��e�z��UW�y�?��n]O��[�N + Yt�c�X3��Y3 ao�YD��}�X(|T�2 Z~���0}
*
* @param roleId Yt�c�X ID
*/
diff --git a/crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java b/crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java
index bec6ab8..86f9d62 100644
--- a/crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java
+++ b/crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java
@@ -4,12 +4,17 @@ import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.crm.auth.constant.AuthConstants;
+import com.crm.auth.domain.dto.ModuleScopeDTO;
import com.crm.auth.domain.dto.RoleDTO;
+import com.crm.auth.domain.entity.SysDataScopeModule;
import com.crm.auth.domain.entity.SysRole;
+import com.crm.auth.domain.entity.SysRoleDataScope;
import com.crm.auth.domain.entity.SysRoleMenu;
import com.crm.auth.domain.entity.SysUserRole;
import com.crm.auth.domain.enums.DataScopeEnum;
import com.crm.auth.domain.param.RoleParam;
+import com.crm.auth.mapper.SysDataScopeModuleMapper;
+import com.crm.auth.mapper.SysRoleDataScopeMapper;
import com.crm.auth.mapper.SysRoleMapper;
import com.crm.auth.mapper.SysRoleMenuMapper;
import com.crm.auth.mapper.SysUserRoleMapper;
@@ -24,8 +29,9 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@@ -36,14 +42,17 @@ import static com.crm.auth.constant.AuthConstants.*;
@RequiredArgsConstructor
public class SysRoleServiceImpl extends BaseServiceImpl<SysRoleMapper, SysRole> implements ISysRoleService {
- private static final Set<Integer> VALID_DATA_SCOPE_VALUES = Arrays.stream(DataScopeEnum.values())
- .filter(e -> e != DataScopeEnum.CUSTOM)
- .map(DataScopeEnum::getValue)
- .collect(Collectors.toUnmodifiableSet());
+ private static final Set<Integer> VALID_DATA_SCOPE_VALUES = Set.of(
+ DataScopeEnum.SELF.getValue(),
+ DataScopeEnum.DEPT.getValue(),
+ DataScopeEnum.DEPT_AND_CHILD.getValue(),
+ DataScopeEnum.ALL.getValue());
private final SysRoleMenuMapper sysRoleMenuMapper;
private final SysUserRoleMapper sysUserRoleMapper;
private final ISysMenuService sysMenuService;
+ private final SysRoleDataScopeMapper sysRoleDataScopeMapper;
+ private final SysDataScopeModuleMapper sysDataScopeModuleMapper;
@Override
public PageResult<RoleDTO> pageRoles(RoleParam param) {
@@ -64,11 +73,6 @@ public class SysRoleServiceImpl extends BaseServiceImpl<SysRoleMapper, SysRole>
throw new BusinessErrorException(CODE_ROLE_INVALID, "Yt�c�X+hr�m�]XQ�my�%");
}
- // dataScope |��Q?m͓��Ys�3lW�y�m� {O�}O��cm��de CUSTOM w�D�~u�mY�[e�?- if (role.getDataScope() != null && !VALID_DATA_SCOPE_VALUES.contains(role.getDataScope())) {
- throw new BusinessErrorException(CODE_ROLE_INVALID, "��HrA]|��Q?m�m�]�` Z?);
- }
-
// P�oT�uYt�c�X�m�o�Y�+l {O�}O�᫕3lC~���0[_R��mP�oT�uYt�c�X�X�h�t�p�g�[?�U~ē�*}Hgb {p:jjn(��R��0��f}
SysRole existing = role.getId() != null ? baseMapper.selectById(role.getId()) : null;
if (Boolean.TRUE.equals(role.getBuiltin())
@@ -98,6 +102,58 @@ public class SysRoleServiceImpl extends BaseServiceImpl<SysRoleMapper, SysRole>
return role;
}
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void saveRoleScopes(Long roleId, List<ModuleScopeDTO> moduleScopes) {
+ // ͓��YsYt�c�Xp:jjn
+ SysRole role = baseMapper.selectById(roleId);
+ if (role == null) {
+ throw new BusinessErrorException(CODE_ROLE_INVALID, "Yt�c�X�m�]�tf���0}" + roleId);
+ }
+
+ // O�)1zVǓc2]�X�SR��r�`���c}�m?assign-resources �Y3 !}�m� w���}
+ sysRoleDataScopeMapper.delete(
+ new LambdaQueryWrapper<SysRoleDataScope>().eq(SysRoleDataScope::getRoleId, roleId));
+
+ if (moduleScopes == null || moduleScopes.isEmpty()) {
+ log.info("ZoT%Yt�c�X�Y3 ao�YD��}�skoleId={}, t~\�f=0", roleId);
+ return;
+ }
+
+ // ̓�0^eP��\0�m?enabled (��Rg�?code ƕ�U�`�~\Nr`i}\�` Z�f� ?+ Set<String> validModuleCodes = sysDataScopeModuleMapper.selectList(
+ new LambdaQueryWrapper<SysDataScopeModule>()
+ .eq(SysDataScopeModule::getStatus, "enabled"))
+ .stream().map(SysDataScopeModule::getCode).collect(Collectors.toSet());
+
+ // ͓��Ys�-l!vt?dataScope f�?1-4��[oduleCode p:jjn�m?enabled�}\�`�m� �t �0wP�?moduleCode �m�]xV�o?+ Set<String> seenCodes = new java.util.HashSet<>();
+ for (ModuleScopeDTO ms : moduleScopes) {
+ if (StrUtil.isBlank(ms.getModuleCode())) {
+ throw new BusinessErrorException(CODE_ROLE_INVALID, "�Y3 ao+hr�m�]XQ�my�%");
+ }
+ if (!validModuleCodes.contains(ms.getModuleCode())) {
+ throw new BusinessErrorException(CODE_ROLE_INVALID,
+ "�Y3 ao+hr�m�]�` Z�f�W�[,���"���0}" + ms.getModuleCode());
+ }
+ if (!VALID_DATA_SCOPE_VALUES.contains(ms.getDataScope())) {
+ throw new BusinessErrorException(CODE_ROLE_INVALID,
+ "��HrA]|��Q?m�m�]�` Z�f0}" + ms.getDataScope());
+ }
+ if (!seenCodes.add(ms.getModuleCode())) {
+ throw new BusinessErrorException(CODE_ROLE_INVALID,
+ "Z�|\�z�t �0wP�nTg�Ci*}.�wO {O�}O�Ვ�]2��? + ms.getModuleCode());
+ }
+
+ SysRoleDataScope rs = new SysRoleDataScope();
+ rs.setRoleId(roleId);
+ rs.setModuleCode(ms.getModuleCode());
+ rs.setDataScope(ms.getDataScope());
+ sysRoleDataScopeMapper.insert(rs);
+ }
+ log.info("�m�o�tYt�c�X�Y3 ao�YD��}�skoleId={}, t~\�f={}", roleId, moduleScopes.size());
+ }
+
@Override
public RoleDTO getRoleDetail(Long roleId) {
SysRole role = baseMapper.selectById(roleId);
@@ -112,6 +168,29 @@ public class SysRoleServiceImpl extends BaseServiceImpl<SysRoleMapper, SysRole>
.map(SysRoleMenu::getMenuId)
.toList();
vo.setResourceIds(resourceIds);
+
+ // ̓?sys_role_data_scope �[@i�W�Y�_g�Ai0cm�]}join Z%1=Ut%1G_�Y3 ao^p�fZ0Z�?+ List<SysRoleDataScope> roleScopes = sysRoleDataScopeMapper.selectList(
+ new LambdaQueryWrapper<SysRoleDataScope>().eq(SysRoleDataScope::getRoleId, roleId));
+ if (!roleScopes.isEmpty()) {
+ Set<String> moduleCodes = roleScopes.stream()
+ .map(SysRoleDataScope::getModuleCode).collect(Collectors.toSet());
+ Map<String, String> codeToName = sysDataScopeModuleMapper.selectList(
+ new LambdaQueryWrapper<SysDataScopeModule>()
+ .in(SysDataScopeModule::getCode, moduleCodes))
+ .stream()
+ .collect(Collectors.toMap(SysDataScopeModule::getCode, SysDataScopeModule::getName));
+ List<ModuleScopeDTO> moduleScopeDTOs = roleScopes.stream()
+ .map(rs -> ModuleScopeDTO.of(
+ rs.getModuleCode(),
+ codeToName.getOrDefault(rs.getModuleCode(), rs.getModuleCode()),
+ rs.getDataScope()))
+ .collect(Collectors.toList());
+ vo.setModuleScopes(moduleScopeDTOs);
+ } else {
+ vo.setModuleScopes(Collections.emptyList());
+ }
+
return vo;
}
@@ -145,6 +224,9 @@ public class SysRoleServiceImpl extends BaseServiceImpl<SysRoleMapper, SysRole>
// �~F�NZoT�`Yt�c�X-��n]O��[�N
sysRoleMenuMapper.delete(
new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
+ // �~F�NZoT�`Yt�c�X3��Y3 ao�YD��}
+ sysRoleDataScopeMapper.delete(
+ new LambdaQueryWrapper<SysRoleDataScope>().eq(SysRoleDataScope::getRoleId, roleId));
// �~F�NZoT�`"�&1�W-Yt�c�XO��[�N
sysUserRoleMapper.delete(
new LambdaQueryWrapper<SysUserRole>()
diff --git a/crm-auth/src/test/java/com/crm/auth/security/scope/DataScopeIntegrationTest.java b/crm-auth/src/test/java/com/crm/auth/security/scope/DataScopeIntegrationTest.java
index 7e4ee55..eb7fc5a 100644
--- a/crm-auth/src/test/java/com/crm/auth/security/scope/DataScopeIntegrationTest.java
+++ b/crm-auth/src/test/java/com/crm/auth/security/scope/DataScopeIntegrationTest.java
@@ -15,6 +15,7 @@ import com.crm.auth.mapper.SysRoleMapper;
import com.crm.auth.mapper.SysRoleMenuMapper;
import com.crm.auth.mapper.SysUserDeptMapper;
import com.crm.auth.mapper.SysUserRoleMapper;
+import com.crm.auth.mapper.SysRoleDataScopeMapper;
import com.crm.auth.security.DataScopeInterceptor;
import com.crm.auth.security.DataScopeTables;
import com.crm.auth.security.PermissionGrant;
@@ -122,6 +123,7 @@ class DataScopeIntegrationTest {
configuration.addMapper(AuthUserMapper.class);
configuration.addMapper(SysDeptMapper.class);
configuration.addMapper(SysUserDeptMapper.class);
+ configuration.addMapper(SysRoleDataScopeMapper.class);
configuration.addMapper(TestOwnedDataMapper.class);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
@@ -148,7 +150,8 @@ class DataScopeIntegrationTest {
session.getMapper(SysMenuMapper.class),
session.getMapper(AuthUserMapper.class),
deptTreeCache,
- session.getMapper(SysUserDeptMapper.class));
+ session.getMapper(SysUserDeptMapper.class),
+ session.getMapper(SysRoleDataScopeMapper.class));
testDataMapper = session.getMapper(TestOwnedDataMapper.class);
deptMapper = session.getMapper(SysDeptMapper.class);
DeptQueryCounter.COUNT.set(0);
@@ -461,7 +464,7 @@ class DataScopeIntegrationTest {
create table sys_role (
id bigint primary key, creator_id varchar(50), create_time datetime,
updater_id varchar(50), update_time datetime, deleted tinyint not null default 0,
- role_name varchar(50), role_code varchar(50), data_scope tinyint, sort int, remark varchar(200),
+ role_name varchar(50), role_code varchar(50), sort int, remark varchar(200),
builtin boolean default false)
""",
"""
@@ -495,6 +498,21 @@ class DataScopeIntegrationTest {
deny_behavior varchar(16), status varchar(16) default 'enabled', api_url varchar(200))
""",
"""
+ create table sys_data_scope_module (
+ id bigint primary key, creator_id varchar(50), create_time datetime,
+ updater_id varchar(50), update_time datetime, deleted tinyint not null default 0,
+ code varchar(50) not null unique, name varchar(100) not null, sort int default 0,
+ status varchar(10) default 'enabled', builtin boolean default false)
+ """,
+ """
+ create table sys_role_data_scope (
+ id bigint primary key, creator_id varchar(50), create_time datetime,
+ updater_id varchar(50), update_time datetime, deleted tinyint not null default 0,
+ role_id bigint not null, module_code varchar(50) not null,
+ data_scope tinyint not null,
+ constraint uk_role_module unique (role_id, module_code))
+ """,
+ """
create table sys_role_menu (
id bigint primary key, role_id bigint not null, menu_id bigint not null,
constraint uk_role_menu unique (role_id, menu_id))
@@ -505,13 +523,21 @@ class DataScopeIntegrationTest {
"insert into sys_dept (id, deleted, parent_id, dept_name) values (12, 0, 10, 'W��^�[?)",
"insert into sys_dept (id, deleted, parent_id, dept_name) values (121, 0, 12, 'W��^�[�m� Õ?)",
"insert into sys_dept (id, deleted, parent_id, dept_name) values (20, 0, 0, '/u�P�n��?)",
- // Yt�c�X�ikd W�k�0cm?- "insert into sys_role (id, deleted, role_name, role_code, data_scope) values (1, 0, '`mnTpn\m?, 'SELF', 1)",
- "insert into sys_role (id, deleted, role_name, role_code, data_scope) values (2, 0, 'ȓ�4Q•?, 'DEPT', 2)",
- "insert into sys_role (id, deleted, role_name, role_code, data_scope) values (3, 0, 'Z����t��)1�h', 'DEPT_CHILD', 3)",
- "insert into sys_role (id, deleted, role_name, role_code, data_scope) values (4, 0, 'O�)14Q', 'ALL', 4)",
+ // ��HrA]ɓ�Q�j�Y3 ao
+ "insert into sys_data_scope_module (id, code, name, sort, builtin) values (1, 'test', '4Z-[/v', 1, true)",
+ // Yt�c�X�ikd W�k�0cm�]}�m�]@Uȓ?data_scope R�Ki}�YD��}p?sys_role_data_scope�?+ "insert into sys_role (id, deleted, role_name, role_code) values (1, 0, '`mnTpn\m?, 'SELF')",
+ "insert into sys_role (id, deleted, role_name, role_code) values (2, 0, 'ȓ�4Q•?, 'DEPT')",
+ "insert into sys_role (id, deleted, role_name, role_code) values (3, 0, 'Z����t��)1�h', 'DEPT_CHILD')",
+ "insert into sys_role (id, deleted, role_name, role_code) values (4, 0, 'O�)14Q', 'ALL')",
// Yt�c�X5�skoleCode w�D�+u ROLE_ S��]}�%XYs�txO�}�m� ���P�t�|\ {�[@i;_S��]}�?- "insert into sys_role (id, deleted, role_name, role_code, data_scope) values (5, 0, '�~��`[�?, 'ROLE_ADMIN', 1)",
+ "insert into sys_role (id, deleted, role_name, role_code) values (5, 0, '�~��`[�?, 'ROLE_ADMIN')",
+ // Yt�c�X3��Y3 ao�YD��}�3lW�y�?id W�k�0cm�]� ?+ "insert into sys_role_data_scope (id, role_id, module_code, data_scope) values (1, 1, 'test', 1)",
+ "insert into sys_role_data_scope (id, role_id, module_code, data_scope) values (2, 2, 'test', 2)",
+ "insert into sys_role_data_scope (id, role_id, module_code, data_scope) values (3, 3, 'test', 3)",
+ "insert into sys_role_data_scope (id, role_id, module_code, data_scope) values (4, 4, 'test', 4)",
+ "insert into sys_role_data_scope (id, role_id, module_code, data_scope) values (5, 5, 'test', 1)",
// "�&1�W
"insert into crm_auth_user (id, deleted, username, dept_id) values (1, 0, '`mnTpn\m?��� ^���4Q', 10)",
"insert into crm_auth_user (id, deleted, username, dept_id) values (2, 0, 'ȓ�4Q•?��� ^���4Q', 10)",
diff --git a/crm-auth/src/test/java/com/crm/auth/security/scope/TestOwnedData.java b/crm-auth/src/test/java/com/crm/auth/security/scope/TestOwnedData.java
index 1b18b52..23bbda9 100644
--- a/crm-auth/src/test/java/com/crm/auth/security/scope/TestOwnedData.java
+++ b/crm-auth/src/test/java/com/crm/auth/security/scope/TestOwnedData.java
@@ -12,7 +12,7 @@ import lombok.EqualsAndHashCode;
*/
@Data
@EqualsAndHashCode(callSuper = true)
-@DataScope
+@DataScope(module = "test")
@TableName("test_owned_data")
public class TestOwnedData extends OwnedEntity {
diff --git a/crm-auth/src/test/java/com/crm/auth/service/impl/PermissionSeederImplTest.java b/crm-auth/src/test/java/com/crm/auth/service/impl/PermissionSeederImplTest.java
index bd66db4..174e306 100644
--- a/crm-auth/src/test/java/com/crm/auth/service/impl/PermissionSeederImplTest.java
+++ b/crm-auth/src/test/java/com/crm/auth/service/impl/PermissionSeederImplTest.java
@@ -51,7 +51,7 @@ class PermissionSeederImplTest {
create table sys_role (
id bigint primary key, creator_id varchar(50), create_time datetime,
updater_id varchar(50), update_time datetime, deleted tinyint not null default 0,
- role_name varchar(50), role_code varchar(50), data_scope tinyint, sort int, remark varchar(200),
+ role_name varchar(50), role_code varchar(50), sort int, remark varchar(200),
builtin boolean default false)
""",
"""
@@ -126,7 +126,6 @@ class PermissionSeederImplTest {
SysRole role = new SysRole();
role.setRoleName("�~��`[�?);
role.setRoleCode("ROLE_ADMIN");
- role.setDataScope(4);
role.setSort(0);
role.setBuiltin(true);
sysRoleMapper.insert(role);
@@ -199,7 +198,6 @@ class PermissionSeederImplTest {
SysRole role = new SysRole();
role.setRoleName("�~��`[�?);
role.setRoleCode("ROLE_ADMIN");
- role.setDataScope(4);
role.setSort(0);
role.setBuiltin(true);
sysRoleMapper.insert(role);
@@ -254,7 +252,6 @@ class PermissionSeederImplTest {
SysRole role = new SysRole();
role.setRoleName("�~��`[�?);
role.setRoleCode("ROLE_ADMIN");
- role.setDataScope(4);
role.setSort(0);
role.setBuiltin(true);
sysRoleMapper.insert(role);
@@ -353,7 +350,6 @@ class PermissionSeederImplTest {
SysRole role = new SysRole();
role.setRoleName("�~��`[�?);
role.setRoleCode("ROLE_ADMIN");
- role.setDataScope(4);
role.setSort(0);
role.setBuiltin(true);
sysRoleMapper.insert(role);
diff --git a/crm-auth/src/test/java/com/crm/auth/service/impl/SysRoleServiceImplTest.java b/crm-auth/src/test/java/com/crm/auth/service/impl/SysRoleServiceImplTest.java
index b633fab..9a3103a 100644
--- a/crm-auth/src/test/java/com/crm/auth/service/impl/SysRoleServiceImplTest.java
+++ b/crm-auth/src/test/java/com/crm/auth/service/impl/SysRoleServiceImplTest.java
@@ -4,6 +4,8 @@ import com.crm.auth.domain.dto.RoleDTO;
import com.crm.auth.domain.entity.SysRole;
import com.crm.auth.domain.entity.SysRoleMenu;
import com.crm.auth.domain.entity.SysUserRole;
+import com.crm.auth.mapper.SysDataScopeModuleMapper;
+import com.crm.auth.mapper.SysRoleDataScopeMapper;
import com.crm.auth.mapper.SysRoleMapper;
import com.crm.auth.mapper.SysRoleMenuMapper;
import com.crm.auth.mapper.SysUserRoleMapper;
@@ -22,7 +24,6 @@ import org.mockito.quality.Strictness;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.List;
-import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
@@ -34,6 +35,7 @@ import static org.mockito.Mockito.when;
/**
* {@link SysRoleServiceImpl} W��f�S4Z-[/v�3l��)�?saveRole ͓��YsYt�R�W�WDR-0012�?+ * <p>R��Ug�Ai|e���r�`�~ZZ�j\m?dataScope |��Q?m͓��Ys4Z-[/v�X0cm�]Nr`i�\)w�?saveRoleScopes�?/p>
*/
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
@@ -47,6 +49,10 @@ class SysRoleServiceImplTest {
private SysUserRoleMapper sysUserRoleMapper;
@Mock
private ISysMenuService sysMenuService;
+ @Mock
+ private SysRoleDataScopeMapper sysRoleDataScopeMapper;
+ @Mock
+ private SysDataScopeModuleMapper sysDataScopeModuleMapper;
@InjectMocks
private SysRoleServiceImpl sysRoleService;
@@ -62,7 +68,7 @@ class SysRoleServiceImplTest {
@Test
@DisplayName("R��mYt�c�X -> roleCode �[�c�tf�?-> ���c�|")
void createRole_duplicateCode_rejected() {
- SysRole role = buildRole(null, "��� ^�?, "ROLE_SALES", 1);
+ SysRole role = buildRole(null, "��� ^�?, "ROLE_SALES");
when(sysRoleMapper.selectCount(any())).thenReturn(1L);
assertThatThrownBy(() -> sysRoleService.saveRole(role))
@@ -73,7 +79,7 @@ class SysRoleServiceImplTest {
@Test
@DisplayName(",h�}Yt�c�X -> roleCode �m�]I_�X�` id�?-> ��3lC~")
void editRole_sameCodeSameId_passes() {
- SysRole role = buildRole(1L, "��� ^�?, "ROLE_SALES", 1);
+ SysRole role = buildRole(1L, "��� ^�?, "ROLE_SALES");
when(sysRoleMapper.selectById(1L)).thenReturn(role);
when(sysRoleMapper.selectCount(any())).thenReturn(0L);
when(sysRoleMapper.updateById(any(SysRole.class))).thenReturn(1);
@@ -87,9 +93,9 @@ class SysRoleServiceImplTest {
@Test
@DisplayName(",h�}P�oT�uYt�c�X -> �m��|e roleCode -> ���c�|")
void editBuiltinRole_changeCode_rejected() {
- SysRole existing = buildRole(1L, "�~��`[�?, "ROLE_ADMIN", 4);
+ SysRole existing = buildRole(1L, "�~��`[�?, "ROLE_ADMIN");
existing.setBuiltin(true);
- SysRole input = buildRole(1L, "�~��`[�?, "ROLE_SUPER", 4);
+ SysRole input = buildRole(1L, "�~��`[�?, "ROLE_SUPER");
when(sysRoleMapper.selectById(1L)).thenReturn(existing);
assertThatThrownBy(() -> sysRoleService.saveRole(input))
@@ -100,9 +106,9 @@ class SysRoleServiceImplTest {
@Test
@DisplayName(",h�}P�oT�uYt�c�X -> roleCode �m�]I_ -> ��3lC~")
void editBuiltinRole_sameCode_passes() {
- SysRole existing = buildRole(1L, "�~��`[�?, "ROLE_ADMIN", 4);
+ SysRole existing = buildRole(1L, "�~��`[�?, "ROLE_ADMIN");
existing.setBuiltin(true);
- SysRole input = buildRole(1L, "�~��`[�;j|e", "ROLE_ADMIN", 4);
+ SysRole input = buildRole(1L, "�~��`[�;j|e", "ROLE_ADMIN");
when(sysRoleMapper.selectById(1L)).thenReturn(existing);
when(sysRoleMapper.selectCount(any())).thenReturn(0L);
when(sysRoleMapper.updateById(any(SysRole.class))).thenReturn(1);
@@ -114,7 +120,7 @@ class SysRoleServiceImplTest {
@Test
@DisplayName("R��mYt�c�X -> �tgR�u builtin=true -> ���c�|")
void createRole_setBuiltin_rejected() {
- SysRole role = buildRole(null, "K��Vx���U�a", "ROLE_FAKE", 4);
+ SysRole role = buildRole(null, "K��Vx���U�a", "ROLE_FAKE");
role.setBuiltin(true);
assertThatThrownBy(() -> sysRoleService.saveRole(role))
@@ -125,7 +131,7 @@ class SysRoleServiceImplTest {
@Test
@DisplayName(",h�}�m�]�tf�'1�k id -> �tgR�u builtin=true -> ���c�|�%X�i�Y?saveOrUpdate (�?insert �fC~�?)
void editNonExistentRole_setBuiltin_rejected() {
- SysRole role = buildRole(999L, "K��Vx���U�a", "ROLE_FAKE", 4);
+ SysRole role = buildRole(999L, "K��Vx���U�a", "ROLE_FAKE");
role.setBuiltin(true);
when(sysRoleMapper.selectById(999L)).thenReturn(null);
@@ -134,45 +140,12 @@ class SysRoleServiceImplTest {
.hasMessageContaining("�m�]�S�td� 3lC~���0[_R��mP�oT�uYt�c�X");
}
- // ==================== dataScope |��Q?m͓��Ys ====================
-
- @Test
- @DisplayName("R��mYt�c�X -> dataScope=0�#X�y#��\} -> ���c�|")
- void createRole_dataScopeTooLow_rejected() {
- SysRole role = buildRole(null, "��� ^�?, "ROLE_SALES", 0);
-
- assertThatThrownBy(() -> sysRoleService.saveRole(role))
- .isInstanceOf(BusinessErrorException.class)
- .hasMessageContaining("��HrA]|��Q?m�m�]�` Z?);
- }
-
- @Test
- @DisplayName("R��mYt�c�X -> dataScope=5�#X�y#��\} -> ���c�|")
- void createRole_dataScopeTooHigh_rejected() {
- SysRole role = buildRole(null, "��� ^�?, "ROLE_SALES", 5);
-
- assertThatThrownBy(() -> sysRoleService.saveRole(role))
- .isInstanceOf(BusinessErrorException.class)
- .hasMessageContaining("��HrA]|��Q?m�m�]�` Z?);
- }
-
- @Test
- @DisplayName("R��mYt�c�X -> dataScope=3�X�` Z�f} -> ��3lC~")
- void createRole_validDataScope_passes() {
- SysRole role = buildRole(null, "��� ^�?, "ROLE_SALES", 3);
- when(sysRoleMapper.selectCount(any())).thenReturn(0L);
- when(sysRoleMapper.insert(any(SysRole.class))).thenReturn(1);
-
- assertThatCode(() -> sysRoleService.saveRole(role))
- .doesNotThrowAnyException();
- }
-
// ==================== i��ppnȕ�p%͓��Ys ====================
@Test
@DisplayName("R��mYt�c�X -> roleName �my�% -> ���c�|")
void createRole_blankName_rejected() {
- SysRole role = buildRole(null, "", "ROLE_SALES", 1);
+ SysRole role = buildRole(null, "", "ROLE_SALES");
assertThatThrownBy(() -> sysRoleService.saveRole(role))
.isInstanceOf(BusinessErrorException.class)
@@ -182,7 +155,7 @@ class SysRoleServiceImplTest {
@Test
@DisplayName("R��mYt�c�X -> roleCode �my�% -> ���c�|")
void createRole_blankCode_rejected() {
- SysRole role = buildRole(null, "��� ^�?, "", 1);
+ SysRole role = buildRole(null, "��� ^�?, "");
assertThatThrownBy(() -> sysRoleService.saveRole(role))
.isInstanceOf(BusinessErrorException.class)
@@ -196,7 +169,7 @@ class SysRoleServiceImplTest {
void assignResources_ancestorCompletion_writesAllIds() {
// Hg�d�SY�C�6}Y����tz��PcP 100L��\��O�#X�O�%1�`4d�e�[Z�?100L + 10L + 1L
when(sysMenuService.getAncestorIds(List.of(100L)))
- .thenReturn(Set.of(100L, 10L, 1L));
+ .thenReturn(java.util.Set.of(100L, 10L, 1L));
when(sysRoleMenuMapper.delete(any())).thenReturn(1);
when(sysRoleMenuMapper.insert(any(SysRoleMenu.class))).thenReturn(1);
@@ -216,7 +189,7 @@ class SysRoleServiceImplTest {
@DisplayName("assignResources -> O�X�WZ��^C_O�)1zVǓc2] sys_role_menu")
void assignResources_fullReplacement() {
when(sysMenuService.getAncestorIds(List.of(200L)))
- .thenReturn(Set.of(200L));
+ .thenReturn(java.util.Set.of(200L));
when(sysRoleMenuMapper.delete(any())).thenReturn(1);
when(sysRoleMenuMapper.insert(any(SysRoleMenu.class))).thenReturn(1);
@@ -234,13 +207,14 @@ class SysRoleServiceImplTest {
@Test
@DisplayName("getRoleDetail -> ig�em RoleDTO Z����qȓ���O����b resourceIds")
void getRoleDetail_returnsVO() {
- SysRole role = buildRole(1L, "��� ^�?, "ROLE_SALES", 1);
+ SysRole role = buildRole(1L, "��� ^�?, "ROLE_SALES");
when(sysRoleMapper.selectById(1L)).thenReturn(role);
SysRoleMenu rm1 = new SysRoleMenu();
rm1.setMenuId(100L);
SysRoleMenu rm2 = new SysRoleMenu();
rm2.setMenuId(200L);
when(sysRoleMenuMapper.selectList(any())).thenReturn(List.of(rm1, rm2));
+ when(sysRoleDataScopeMapper.selectList(any())).thenReturn(List.of());
RoleDTO vo = sysRoleService.getRoleDetail(1L);
@@ -265,7 +239,7 @@ class SysRoleServiceImplTest {
@Test
@DisplayName("R��r�jP�oT�uYt�c�X -> builtin=true -> ���c�|")
void deleteBuiltinRole_rejected() {
- SysRole role = buildRole(1L, "�~��`[�?, "ROLE_ADMIN", 4);
+ SysRole role = buildRole(1L, "�~��`[�?, "ROLE_ADMIN");
role.setBuiltin(true);
when(sysRoleMapper.selectById(1L)).thenReturn(role);
@@ -275,12 +249,13 @@ class SysRoleServiceImplTest {
}
@Test
- @DisplayName("R��r�jœ��� 3lW�y�?-> builtin=false -> ��3lC~��5��z�?sys_role_menu + sys_user_role")
+ @DisplayName("R��r�jœ��� 3lW�y�?-> builtin=false -> ��3lC~��5��z�?sys_role_menu + sys_role_data_scope + sys_user_role")
void deleteNormalRole_passes() {
- SysRole role = buildRole(2L, "��� ^�?, "ROLE_SALES", 1);
+ SysRole role = buildRole(2L, "��� ^�?, "ROLE_SALES");
when(sysRoleMapper.selectById(2L)).thenReturn(role);
when(sysRoleMenuMapper.delete(any())).thenReturn(1);
when(sysUserRoleMapper.delete(any())).thenReturn(1);
+ when(sysRoleDataScopeMapper.delete(any())).thenReturn(1);
assertThatCode(() -> sysRoleService.deleteRoleCascade(2L))
.doesNotThrowAnyException();
@@ -288,12 +263,11 @@ class SysRoleServiceImplTest {
// ==================== �YB%�f��?====================
- private SysRole buildRole(Long id, String name, String code, int dataScope) {
+ private SysRole buildRole(Long id, String name, String code) {
SysRole role = new SysRole();
role.setId(id);
role.setRoleName(name);
role.setRoleCode(code);
- role.setDataScope(dataScope);
role.setSort(0);
return role;
}
diff --git a/crm-auth/src/test/java/com/crm/auth/service/impl/UserListIntegrationTest.java b/crm-auth/src/test/java/com/crm/auth/service/impl/UserListIntegrationTest.java
index 0ee3dc5..70f9d94 100644
--- a/crm-auth/src/test/java/com/crm/auth/service/impl/UserListIntegrationTest.java
+++ b/crm-auth/src/test/java/com/crm/auth/service/impl/UserListIntegrationTest.java
@@ -332,7 +332,7 @@ class UserListIntegrationTest {
create table sys_role (
id bigint primary key, creator_id varchar(50), create_time datetime,
updater_id varchar(50), update_time datetime, deleted tinyint not null default 0,
- role_name varchar(50), role_code varchar(50), data_scope tinyint, sort int, remark varchar(200),
+ role_name varchar(50), role_code varchar(50), sort int, remark varchar(200),
builtin boolean default false)
""",
"""
@@ -357,8 +357,8 @@ class UserListIntegrationTest {
"insert into sys_dept (id, deleted, parent_id, dept_name) values (121, 0, 12, 'W��^�[�m� Õ?)",
"insert into sys_dept (id, deleted, parent_id, dept_name) values (20, 0, 0, '/u�P�n��?)",
// Yt�c�X
- "insert into sys_role (id, deleted, role_name, role_code, data_scope) values (1, 0, '�~��`[�?, 'ROLE_ADMIN', 4)",
- "insert into sys_role (id, deleted, role_name, role_code, data_scope) values (2, 0, '��� ^�?, 'ROLE_SALES', 2)",
+ "insert into sys_role (id, deleted, role_name, role_code) values (1, 0, '�~��`[�?, 'ROLE_ADMIN')",
+ "insert into sys_role (id, deleted, role_name, role_code) values (2, 0, '��� ^�?, 'ROLE_SALES')",
// "�&1�W�KWmployment_status / title / account / mobile / last_login_time / dept_id / enabled�? "insert into crm_auth_user (id, deleted, username, mobile, enabled, last_login_time, dept_id, employment_status, title, account) values (1, 0, '�[�r{', '13800000001', 1, '2024-01-15 10:00:00', 10, 'active', '��� ^���� d�m', 'zhangsan')",
"insert into crm_auth_user (id, deleted, username, mobile, enabled, last_login_time, dept_id, employment_status, title, account) values (2, 0, 'ɓ�^m', '13800000002', 1, '2024-03-20 14:00:00', 10, 'active', '��� ^����|�?, 'lisi')",
diff --git a/crm-base/src/main/java/com/crm/base/annotation/DataScope.java b/crm-base/src/main/java/com/crm/base/annotation/DataScope.java
index 8ccaf8b..a796023 100644
--- a/crm-base/src/main/java/com/crm/base/annotation/DataScope.java
+++ b/crm-base/src/main/java/com/crm/base/annotation/DataScope.java
@@ -3,13 +3,19 @@ package com.crm.base.annotation;
import java.lang.annotation.*;
/**
- * ��HrA]ɓ�Q�j Z(1�-l#r Z%1jn9p�p�}�~��{�}\�a-�?DataScopeInterceptor �t�00"�$1,|��HrA]ig�V�b(��R�WZ��]� ?+ * ��HrA]ɓ�Q�j Z(1�-l#r Z%1jn9p�p�}�~��{�}\�a-�?DataScopeInterceptor �t�00"�$1,|��HrA]ig�V�b(��R�WZ��]�b��� ^p�p{T�!g�<i� ? * ȓE�#r Z&1� Z(1(��R�ucm�d {|m3lY�b�f����Hoĕ/aC~JZ�0� ? */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataScope {
+ /**
+ * ��� ^p�p�f����Hoĕ-ag�Ci�k code�X�� "customer"��?lead"�Y}�[�fde sys_data_scope_module.code��?+ * G�mT^�%��e� �e�`T�&1i PermissionConfig ͓��Ys�t?code G�tT0f�&1^eP��\0�m^��tf���}�m�]�tf�%1�W���c�|Z���Y�WDR-0006�Y� ?+ */
+ String module();
+
/** 0��cXw\m�T�tZ�x}��HrA]4d�d�WZ��]}�}\��4d?`mnTpn\m?ig�V�b */
String ownerColumn() default "owner_id";
diff --git a/crm-base/src/main/java/com/crm/base/security/DataVisibility.java b/crm-base/src/main/java/com/crm/base/security/DataVisibility.java
index c0501f7..fbf4664 100644
--- a/crm-base/src/main/java/com/crm/base/security/DataVisibility.java
+++ b/crm-base/src/main/java/com/crm/base/security/DataVisibility.java
@@ -1,6 +1,7 @@
package com.crm.base.security;
import java.util.List;
+import java.util.Map;
/**
* ��HrA]Y��F笓F�[e���0}0��d�X엡�$Us�LuEnR����|�mX� xOSUQ�y��k��HrA]0��c�v��?@@ -8,51 +9,64 @@ import java.util.List;
* <p>�m�]r_Y�Hj}�m� Z!� D�fcm�d��O��00}˓�R� �r�WT��qF]���_�a+�� �mAZ{“�Vlu��Qgr_"���}�m�]�tf�#1� �\��\m�U�zW�?Z� �]�k�5�� �O}
* e��r��m�q {p:jjn��}\U~\m�U���YD��}��� `m�0�et}\�S��&1�f����� �]V~�~�]0Hg�d}Yt?ADR 0006�Y� ?/p>
*
- * <p>5ppt;�Y�D�m�~�e���mH��hY��00}�t��vf•?{@link #visibilityScope()}�}\SUnG�h {@link #dataOwnership()}��?- * �YD��}��g�t�m�^4Q•)1�lZ�"X�kY�,h�Wē�4U��%1�u�nb�|z��P� ?/p>
+ * <p>5ppt;�Y�D�m�~�e���mH��hY��00}�t��vf•?{@link #visibilityScope(String)}�X�[�Y3 aoY�(h0cm�]}�?+ * P�kvf•?{@link #dataOwnership()}���P0cm�]�fp>i {��)1�hƕ�U�`(��RG_x��]�iP�tT4Q9p�pG^�U�Y��?/p>
+ *
+ * <p>R��Ug�Ai|e���r�`��\��`m���f����}userId / primaryDeptId / deptIds / expandedDeptIds�
Yg_p9j�z`m�e}
+ * Z��Rg�Ai0cm�]� 3lC~ {@code moduleLevels} map Z��R�V���s���P4Q•)1�lZ�Xg_�~>i�zZ&}Z��Rg�Ai0cm�]�U9p?+ * <b>"�$1 {"�?/b> igk�|��)1�h ID�|\ {Ǖ� Ut�OxV�~<i� ?/p>
*/
public final class DataVisibility {
private final Long userId;
private final Long primaryDeptId;
private final List<Long> deptIds;
- private final DataScopeLevel level;
+ private final Map<String, DataScopeLevel> moduleLevels;
private final List<Long> expandedDeptIds;
/**
* @param userId 0��d�X"�&1�W ID�}\@~�o? * @param primaryDeptId �mZZ4Q•?ID�}\r_�m?null�"Xde���\�vȓD��}cm�]�|�Vfp˓�R}
* @param deptIds ��)1�hƕ�U�`�X�[ + O�p��N��X�l�Y}Y����~*m�lZ�,X}�t�0de��� {^p�p,|`m���}��)1�h�?- * @param level ��HrA]|��Q?m�YD��}�}\@~�o?- * @param expandedDeptIds ��)1�hƕ�U�`��*aܑ^p�f}p-a2rZ��^�k��X�l�|\�| {@link DataScopeLevel#DEPT_AND_CHILDREN}
- * �YD��}Ǖ� Ut�O}�Y�0iG�mT^��Xr_�my�%ƕ�U�`��\0�~p��z�[)[ {Y��F��Y1}O�5g�|�YD��}G�Lu�f
- * @throws IllegalArgumentException "�&1�W ID ��(h0cm�]�]�o�a}��'h�`�m*[Xw��)1�h�YD��}ȓE��`/u@�Mw�[� ƕ�U�`
+ * @param moduleLevels �Y�_g�Ci�k��HrA]|��Q?m�YD��}�XWey = module code��[alue = �YD��}�Y}G�mT^�cm�U�S�t�T% Map
+ * �"X% Map = ��� ȓ Yg�Diˆ�i?j{� SELF�Y1}ȓD�jn map �m`��k�Y3 ao�m�qˆ SELF
+ * @param expandedDeptIds ��)1�hƕ�U�`��*aܑ^p�f}p-a2rZ��^�k��X�l�|\�|0��dbc�m� �Y3 ao(��R0cm�]�
+ * {@link DataScopeLevel#DEPT_AND_CHILDREN} ÓX6nUt�O}G�mT^��}\r_�my�%ƕ�U�`�?+ * t'1Z0�m� �[)[ {Y��F��Y1}O�&1g�EiXQ�m�]�`�t�00cm�]iG�Lu�f
+ * @throws IllegalArgumentException "�&1�W ID �TQ0��uNoduleLevels �m?null��yO�WZ���{^p�p4Q•&10cm�]~}ȓE��`/u@�Mw�[� ƕ�U�`
*/
public DataVisibility(Long userId, Long primaryDeptId, List<Long> deptIds,
- DataScopeLevel level, List<Long> expandedDeptIds) {
+ Map<String, DataScopeLevel> moduleLevels, List<Long> expandedDeptIds) {
if (userId == null) {
throw new IllegalArgumentException("��HrA]Y��F笓F�[e��[�]Op bde��?ID");
}
- if (level == null) {
- throw new IllegalArgumentException("��HrA]Y��F笓F�[e��[�]Opb�f�����[e�X[0cm?);
+ if (moduleLevels == null) {
+ throw new IllegalArgumentException("��HrA]Y��F笓F�[e��[�]Opbg�Ai0cm�]�iOp?);
}
- if (level == DataScopeLevel.DEPT_AND_CHILDREN && expandedDeptIds == null) {
+ boolean needsExpanded = moduleLevels.values().stream()
+ .anyMatch(l -> l == DataScopeLevel.DEPT_AND_CHILDREN);
+ if (needsExpanded && expandedDeptIds == null) {
throw new IllegalArgumentException(
- "�YD��} " + level + " UtyO0w���T+u^p�f}p-a2rZ��^�k��)1�hƕ�U�`��\%ƕ�U�`�t�6}�~?List p��\jo null");
+ "p:jjn�Y3 ao�YD��}�m?DEPT_AND_CHILDREN��\���Y�P�`/u@�Mw�[� p-a2rZ��^�k��)1�hƕ�U�`��\%ƕ�U�`�t�6}�~?List p��\jo null");
}
this.userId = userId;
this.primaryDeptId = primaryDeptId;
this.deptIds = deptIds == null ? List.of() : List.copyOf(deptIds);
- this.level = level;
+ this.moduleLevels = Map.copyOf(moduleLevels);
this.expandedDeptIds = expandedDeptIds == null ? null : List.copyOf(expandedDeptIds);
}
/**
- * ȓ���̓�0���t�0��cm�fC~JZ�0� ?+ * ȓ���̓�0���t�0��cm�fC~JZ�0}�� Yg�@iG_�YD��} +�?��<j{u VisibilityScope�Y� ?+ *
+ * <p>ȓH��S�Y3 ao�bWap �m_�aq�m�]�W�Y�|�t?SELF�X6n�~�R0��[ail safe�?2 P�]�t 3�Y� ?/p>
*
* <p>��Y4Q•(1C~JZ�0�k�YD��}���V{�~*m4Q•)1�lZ�XiR��0���|\�z�[)[ {Y��F熒�]� �e� �e�h0��cXw�m�]�t\m�^�S��Pc冒?/p>
+ *
+ * @param moduleCode ��HrA]ɓ�Q�j�Y3 ao code
*/
- public VisibilityScope visibilityScope() {
+ public VisibilityScope visibilityScope(String moduleCode) {
+ DataScopeLevel level = moduleLevels.getOrDefault(moduleCode, DataScopeLevel.SELF);
return switch (level) {
case SELF -> VisibilityScope.ownedBy(userId);
case DEPT -> departmentsOrNone(deptIds);
diff --git a/crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java b/crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java
index a1d087c..757c7a8 100644
--- a/crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java
+++ b/crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java
@@ -6,9 +6,13 @@ import java.util.Optional;
* 0��d�X�t �0w(��R�f����r_YtyO� F�[e��m� ? *
* <p>�t�0 v��3lC~Z��^qeig�V�bc�?{@link #load} AtmT�S��\���Y�P�|ɓ�qi {@link #clear} ZoT�`�?- * ��HrA]ɓ�Q�j��=��Wc�$1 {O���SpAi���o���Sc�%1�WR���� 3lC~ {@link #currentScope()} �m?{@link #currentOwnership()}
+ * ��HrA]ɓ�Q�j��=��Wc�$1 {O���SpAi���o���Sc�%1�WR���� 3lC~ {@link #currentScope(String)} �m?{@link #currentOwnership()}
* �t��G_�|\��nEEnR�nb�k�`�m� `mP��`m�Y� ?/p>
*
+ * <p>R��Ug�Ai|e���r�`��\��n?{@link #currentScope(String)} Ǖ� |m�r�S�Y3 ao code�?+ * `m�^�`�m� `m?DataVisibility �m_��[�Y3 aoY�(h0cm�]� �PSUn?{@link #currentOwnership()} �m�]I_%��e� ?+ * 엡�$UQg�[�m�^0cm�]�m4d=��\m�0}06 P�]�t�Y� ?/p>
+ *
* <p>Ó�r{�m+[�g�X2|"�(1�V엤��k�~荼%��yOmn�t�0 v�t �0w� Yi�m�]C~JZ�0� wO�{Ó�r�}^p�pr_�o��0}s�ɅjnÓ�r�j0��f�O���{�tbaq�t"2�k
* Y�E�An4d�edew�G���(��R�V�~6[}ȓG�{��tzO�k HTTP �t �0wig�m {R���{T�!aq�tn�}Yt?ADR 0006�Y� ?/p>
*
@@ -30,10 +34,16 @@ public final class DataVisibilityContext {
CURRENT.remove();
}
- /** ȓ���̓�0���t�0��cm�fC~JZ�01}Ó�r{�m+[�gÓ5g {ig�V�b */
- public static VisibilityScope currentScope() {
+ /**
+ * ȓ���̓�0���t�0��cm�fC~JZ�0}�� Yg�@iG_�YD��}�Y1}Ó�r{�m+[�gÓ5g {ig�V�b��?+ *
+ * @param moduleCode ��HrA]ɓ�Q�j�Y3 ao code
+ */
+ public static VisibilityScope currentScope(String moduleCode) {
DataVisibility visibility = CURRENT.get();
- return visibility != null ? visibility.visibilityScope() : VisibilityScope.allVisible();
+ return visibility != null
+ ? visibility.visibilityScope(moduleCode)
+ : VisibilityScope.allVisible();
}
/** “gSUO��0�f�����k0��cXw��m�h�mAZ{“�Vi�my�%�}\�}^p�p�tZxQZ~��?null */
diff --git a/crm-base/src/test/java/com/crm/base/security/DataVisibilityTest.java b/crm-base/src/test/java/com/crm/base/security/DataVisibilityTest.java
index c76eba1..3b62a05 100644
--- a/crm-base/src/test/java/com/crm/base/security/DataVisibilityTest.java
+++ b/crm-base/src/test/java/com/crm/base/security/DataVisibilityTest.java
@@ -5,6 +5,7 @@ import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.List;
+import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
@@ -13,11 +14,15 @@ import static org.junit.jupiter.api.Assertions.*;
*
* <p>Ut�U
me��mܑ��HrA]|��Q?m�YD��}�o�P�}��<j{u�m?�C~JZ�0Q0�l�� �O4Q•)1�lZ�X��~�pi(��R� |\�z�[)[ {Y��F熒�]� ? * AtmT�SÓAR�k9p~\�f��DNr`i�\}`m�07_Ó�r{�m+[�gÓAR�k�m�00 fail-closed �t]��{�#XF� ADR 0006�Y� ?/p>
+ *
+ * <p>R��Ug�Ai|e���r�`�L[ataVisibility ��yOAn {@code Map<String, DataScopeLevel>} Ǔ8Y,UW��fܑ level�?+ * 4Z-[/v"�?{@code Map.of("test", level)} �Y!�ZW��fg�@i�nœ�� ?/p>
*/
class DataVisibilityTest {
private static final Long USER_ID = 1001L;
private static final Long PRIMARY_DEPT = 200L;
+ private static final String MODULE = "test";
@AfterEach
void tearDown() {
@@ -30,9 +35,10 @@ class DataVisibilityTest {
@DisplayName("`mnTpn\m�p0cm�]0}��
Y�}^p�pIlig�V�b")
void selfLevelFiltersByOwner() {
DataVisibility visibility = new DataVisibility(
- USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT), DataScopeLevel.SELF, null);
+ USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT),
+ Map.of(MODULE, DataScopeLevel.SELF), null);
- VisibilityScope scope = visibility.visibilityScope();
+ VisibilityScope scope = visibility.visibilityScope(MODULE);
assertEquals(VisibilityScope.Kind.OWNER, scope.kind());
assertEquals(USER_ID, scope.ownerId());
@@ -42,9 +48,10 @@ class DataVisibilityTest {
@DisplayName("ȓ�4Q•&10cm�]0}��Y4Q•)1�lZ�,X}�m?+ O�p��N��X�l�YC~JZ?)
void deptLevelFiltersByDeptSet() {
DataVisibility visibility = new DataVisibility(
- USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT, 300L), DataScopeLevel.DEPT, null);
+ USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT, 300L),
+ Map.of(MODULE, DataScopeLevel.DEPT), null);
- VisibilityScope scope = visibility.visibilityScope();
+ VisibilityScope scope = visibility.visibilityScope(MODULE);
assertEquals(VisibilityScope.Kind.DEPARTMENTS, scope.kind());
assertEquals(List.of(PRIMARY_DEPT, 300L), scope.deptIds());
@@ -54,10 +61,11 @@ class DataVisibilityTest {
@DisplayName("ȓ�4Q•%17_�m*[Xw��)1�h�YD��}�-l�[^p�f}Z��^�k��)1�hƕ�U�`ig�V�b�|\ {"�&1mn^p�f}(��R�lZ�?)
void deptAndChildrenLevelFiltersByExpandedDeptSet() {
DataVisibility visibility = new DataVisibility(
- USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT), DataScopeLevel.DEPT_AND_CHILDREN,
+ USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT),
+ Map.of(MODULE, DataScopeLevel.DEPT_AND_CHILDREN),
List.of(PRIMARY_DEPT, 201L, 202L));
- VisibilityScope scope = visibility.visibilityScope();
+ VisibilityScope scope = visibility.visibilityScope(MODULE);
assertEquals(VisibilityScope.Kind.DEPARTMENTS, scope.kind());
assertEquals(List.of(PRIMARY_DEPT, 201L, 202L), scope.deptIds());
@@ -67,9 +75,10 @@ class DataVisibilityTest {
@DisplayName("O�)14QY��F��YD��}�+l {ig�V�b")
void allLevelDoesNotFilter() {
DataVisibility visibility = new DataVisibility(
- USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT), DataScopeLevel.ALL, null);
+ USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT),
+ Map.of(MODULE, DataScopeLevel.ALL), null);
- assertEquals(VisibilityScope.Kind.ALL_VISIBLE, visibility.visibilityScope().kind());
+ assertEquals(VisibilityScope.Kind.ALL_VISIBLE, visibility.visibilityScope(MODULE).kind());
}
// 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� �m� �[)[ {Y��F� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9��
@@ -78,25 +87,27 @@ class DataVisibilityTest {
@DisplayName("ȓ�4Q•&10cm�]~}��)1�hƕ�U�`�my�%�+l�z�[)[ {Y��F���\� �\jo��Pc�")
void deptLevelWithoutAnyDeptIsNoneVisible() {
DataVisibility visibility = new DataVisibility(
- USER_ID, null, List.of(), DataScopeLevel.DEPT, null);
+ USER_ID, null, List.of(),
+ Map.of(MODULE, DataScopeLevel.DEPT), null);
- assertEquals(VisibilityScope.Kind.NONE_VISIBLE, visibility.visibilityScope().kind());
+ assertEquals(VisibilityScope.Kind.NONE_VISIBLE, visibility.visibilityScope(MODULE).kind());
}
@Test
@DisplayName("Z���{^p�p4Q•&10cm�]~}^p�f}�dIp�my�%�+l�z�[)[ {Y��F���\� �\jo��Pc�")
void deptAndChildrenLevelWithEmptyExpansionIsNoneVisible() {
DataVisibility visibility = new DataVisibility(
- USER_ID, null, List.of(), DataScopeLevel.DEPT_AND_CHILDREN, List.of());
+ USER_ID, null, List.of(),
+ Map.of(MODULE, DataScopeLevel.DEPT_AND_CHILDREN), List.of());
- assertEquals(VisibilityScope.Kind.NONE_VISIBLE, visibility.visibilityScope().kind());
+ assertEquals(VisibilityScope.Kind.NONE_VISIBLE, visibility.visibilityScope(MODULE).kind());
}
// 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� AtmT�SÓAR�k9p~\�f��DNr`i?9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9��
@Test
- @DisplayName("�YD��}�m?null�3l��O��0F]�o����")
- void nullLevelIsRejected() {
+ @DisplayName("moduleLevels �m?null�3l��O��0F]�o����")
+ void nullModuleLevelsIsRejected() {
assertThrows(IllegalArgumentException.class, () -> new DataVisibility(
USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT), null, null));
}
@@ -105,14 +116,16 @@ class DataVisibilityTest {
@DisplayName("Z���{^p�p4Q•&10cm�]mn���T+u^p�f}ƕ�U�`�3l��O��0F]�o�����%X�kZ����[9p,lI_�m�p j�[�_ {Y�@jzV�?)
void deptAndChildrenLevelWithoutExpansionIsRejected() {
assertThrows(IllegalArgumentException.class, () -> new DataVisibility(
- USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT), DataScopeLevel.DEPT_AND_CHILDREN, null));
+ USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT),
+ Map.of(MODULE, DataScopeLevel.DEPT_AND_CHILDREN), null));
}
@Test
@DisplayName(""�&1�W ID �TQ0�3l��O��0F]�o����")
void missingUserIdIsRejected() {
assertThrows(IllegalArgumentException.class, () -> new DataVisibility(
- null, PRIMARY_DEPT, List.of(PRIMARY_DEPT), DataScopeLevel.SELF, null));
+ null, PRIMARY_DEPT, List.of(PRIMARY_DEPT),
+ Map.of(MODULE, DataScopeLevel.SELF), null));
}
@Test
@@ -131,13 +144,49 @@ class DataVisibilityTest {
}
}
+ // 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� R��Ug�Ci�Xȓ?9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9��
+
+ @Test
+ @DisplayName("ȓH��S�Y3 ao�6l�|�t?SELF�X6n�~�R0��[ail safe�?)
+ void unconfiguredModuleDefaultsToSelf() {
+ DataVisibility visibility = new DataVisibility(
+ USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT),
+ Map.of("other_module", DataScopeLevel.ALL), null);
+
+ // "test" �Y3 aoȓH��S�}\2|�t?SELF
+ assertEquals(VisibilityScope.Kind.OWNER, visibility.visibilityScope(MODULE).kind());
+ assertEquals(USER_ID, visibility.visibilityScope(MODULE).ownerId());
+ }
+
+ @Test
+ @DisplayName("�~?moduleLevels Map�-l�Xȓ Yg�Diˆ SELF")
+ void emptyModuleLevelsDefaultsAllToSelf() {
+ DataVisibility visibility = new DataVisibility(
+ USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT),
+ Map.of(), null);
+
+ assertEquals(VisibilityScope.Kind.OWNER, visibility.visibilityScope(MODULE).kind());
+ }
+
+ @Test
+ @DisplayName("�o-lg�@i�`Y�'h�`(��R0cm�]0}customer=ALL, lead=SELF")
+ void multiModuleIndependentLevels() {
+ DataVisibility visibility = new DataVisibility(
+ USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT),
+ Map.of("customer", DataScopeLevel.ALL, "lead", DataScopeLevel.SELF), null);
+
+ assertEquals(VisibilityScope.Kind.ALL_VISIBLE, visibility.visibilityScope("customer").kind());
+ assertEquals(VisibilityScope.Kind.OWNER, visibility.visibilityScope("lead").kind());
+ }
+
// 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� P�kvf��HrA]0��cXw 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9�� 9��
@Test
@DisplayName("��HrA]0��cXwY�&h�[��)1�h�|\ {`m�^ Tq��\�lZ�%XwV��/b}Y�G��ḓ�Plo�?)
void ownershipUsesPrimaryDeptOnly() {
DataVisibility visibility = new DataVisibility(
- USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT, 300L), DataScopeLevel.DEPT, null);
+ USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT, 300L),
+ Map.of(MODULE, DataScopeLevel.DEPT), null);
DataOwnership ownership = visibility.dataOwnership();
@@ -149,7 +198,8 @@ class DataVisibilityTest {
@DisplayName("Ó�r�[��)1�hÓ���}^p�p4Q•$1� null�}\�}^p�pIl`m�]^�0��d�X"�&1�W")
void ownershipToleratesMissingPrimaryDept() {
DataVisibility visibility = new DataVisibility(
- USER_ID, null, List.of(), DataScopeLevel.SELF, null);
+ USER_ID, null, List.of(),
+ Map.of(MODULE, DataScopeLevel.SELF), null);
DataOwnership ownership = visibility.dataOwnership();
@@ -162,7 +212,7 @@ class DataVisibilityTest {
@Test
@DisplayName("Ó�r{�m+[�g�+l {ig�V�b�|\{P�kvfÓ�r�}^p�pr_�o?)
void withoutContextNothingIsFilteredOrFilled() {
- assertEquals(VisibilityScope.Kind.ALL_VISIBLE, DataVisibilityContext.currentScope().kind());
+ assertEquals(VisibilityScope.Kind.ALL_VISIBLE, DataVisibilityContext.currentScope(MODULE).kind());
assertTrue(DataVisibilityContext.currentOwnership().isEmpty());
}
@@ -170,9 +220,10 @@ class DataVisibilityTest {
@DisplayName("AtmT�SZ��^��P�k��nEEnR�g�`�m� `mP��`m?)
void loadedContextIsVisibleToBothSides() {
DataVisibilityContext.load(new DataVisibility(
- USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT), DataScopeLevel.SELF, null));
+ USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT),
+ Map.of(MODULE, DataScopeLevel.SELF), null));
- assertEquals(USER_ID, DataVisibilityContext.currentScope().ownerId());
+ assertEquals(USER_ID, DataVisibilityContext.currentScope(MODULE).ownerId());
assertEquals(USER_ID, DataVisibilityContext.currentOwnership().orElseThrow().ownerId());
assertEquals(PRIMARY_DEPT, DataVisibilityContext.currentOwnership().orElseThrow().primaryDeptId());
}
@@ -181,10 +232,11 @@ class DataVisibilityTest {
@DisplayName("ZoT�`Z��^mR�Hr�h�mAZ{“�V�Y��?)
void clearRestoresEmptyContext() {
DataVisibilityContext.load(new DataVisibility(
- USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT), DataScopeLevel.DEPT, null));
+ USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT),
+ Map.of(MODULE, DataScopeLevel.DEPT), null));
DataVisibilityContext.clear();
- assertEquals(VisibilityScope.Kind.ALL_VISIBLE, DataVisibilityContext.currentScope().kind());
+ assertEquals(VisibilityScope.Kind.ALL_VISIBLE, DataVisibilityContext.currentScope(MODULE).kind());
assertTrue(DataVisibilityContext.currentOwnership().isEmpty());
}
@@ -192,9 +244,10 @@ class DataVisibilityTest {
@DisplayName("��)1�hƕ�U�`5ppt;��m�]r_Y�Hj}�t�Qde“ĉ|e�m�]�Y�[6���O��0�kY��F�|��Q?m")
void deptIdsAreNotMutableThroughScope() {
DataVisibility visibility = new DataVisibility(
- USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT, 300L), DataScopeLevel.DEPT, null);
+ USER_ID, PRIMARY_DEPT, List.of(PRIMARY_DEPT, 300L),
+ Map.of(MODULE, DataScopeLevel.DEPT), null);
- List<Long> deptIds = visibility.visibilityScope().deptIds();
+ List<Long> deptIds = visibility.visibilityScope(MODULE).deptIds();
assertThrows(UnsupportedOperationException.class, () -> deptIds.add(999L));
}
diff --git a/docker-compose.yml b/docker-compose.yml
index 5a77060..9696acb 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -64,9 +64,14 @@ services:
"
crm-app:
- build:
- context: .
- dockerfile: Dockerfile
+ # ȓ�]�Yc�$1{Y�E�An jar�X�hgZ.ar�Y0}"�%1�` LibreOffice (��R�q�~� ���nQ crm-runtime + ���PGm jar
+ # i�y�����nQ�m� Z!� D/p�[4s0}docker build -f deploy/Dockerfile.base -t crm-runtime:latest .
+ # ǓX[�g4ZzO�%�3l��)�?crm-app-1.0.0-SNAPSHOT.jar +�?deploy/restart.sh�Xg_���]�` crm-app�?+ image: crm-runtime:latest
+ volumes:
+ - ./crm-app-1.0.0-SNAPSHOT.jar:/app/crm-app-1.0.0-SNAPSHOT.jar:ro
+ # Ó�0T~ē�r�vR�g���m�~�n�,l2|"�%1SU logs/crm-app.log�"XIm5p?WORKDIR /app�YKU 9p8Y�[ȓ?./logs/
+ - ./logs:/app/logs
depends_on:
mysql:
condition: service_healthy