feat(plugin): 实体级 data_scope + scope_role + data_scope_levels 声明

- PluginEntity 新增 data_scope: Option<bool> 字段,控制是否启用行级数据权限
- PluginField 新增 scope_role: Option<String> 字段,标记数据权限的"所有者"字段
- PluginPermission 新增 data_scope_levels: Option<Vec<String>> 字段,声明支持的数据范围等级
- 更新 default_for_field() 测试辅助和 dynamic_table.rs 中的 PluginEntity 构造
- 新增 parse_entity_with_data_scope 和 parse_permission_with_data_scope_levels 测试
This commit is contained in:
iven
2026-04-17 10:45:49 +08:00
parent 89684313d9
commit 41a0dc8bd6
2 changed files with 53 additions and 0 deletions

View File

@@ -1019,6 +1019,7 @@ mod tests {
],
indexes: vec![],
relations: vec![],
data_scope: None,
};
let sql = DynamicTableManager::build_create_table_sql("erp_crm", &entity);
@@ -1060,6 +1061,7 @@ mod tests {
}],
indexes: vec![],
relations: vec![],
data_scope: None,
};
let sql = DynamicTableManager::build_create_table_sql("erp_crm", &entity);

View File

@@ -45,6 +45,8 @@ pub struct PluginEntity {
pub indexes: Vec<PluginIndex>,
#[serde(default)]
pub relations: Vec<PluginRelation>,
#[serde(default)]
pub data_scope: Option<bool>, // 是否启用行级数据权限
}
/// 字段校验规则
@@ -79,6 +81,8 @@ pub struct PluginField {
pub validation: Option<FieldValidation>, // 字段校验规则
#[serde(default)]
pub no_cycle: Option<bool>, // 禁止循环引用
#[serde(default)]
pub scope_role: Option<String>, // 标记为数据权限的"所有者"字段
}
/// 字段类型
@@ -145,6 +149,7 @@ impl PluginField {
ref_entity: None,
validation: None,
no_cycle: None,
scope_role: None,
}
}
}
@@ -272,6 +277,8 @@ pub struct PluginPermission {
pub name: String,
#[serde(default)]
pub description: String,
#[serde(default)]
pub data_scope_levels: Option<Vec<String>>, // 支持的数据范围等级
}
/// 从 TOML 字符串解析插件清单
@@ -746,4 +753,48 @@ on_delete = "cascade"
assert_eq!(entity.relations[0].foreign_key, "customer_id");
assert!(matches!(entity.relations[0].on_delete, OnDeleteStrategy::Cascade));
}
#[test]
fn parse_entity_with_data_scope() {
let toml = r#"
[metadata]
id = "test"
name = "Test"
version = "0.1.0"
[schema]
[[schema.entities]]
name = "customer"
display_name = "客户"
data_scope = true
[[schema.entities.fields]]
name = "owner_id"
field_type = "uuid"
display_name = "负责人"
scope_role = "owner"
"#;
let manifest = parse_manifest(toml).unwrap();
let entity = &manifest.schema.unwrap().entities[0];
assert_eq!(entity.data_scope, Some(true));
assert_eq!(entity.fields[0].scope_role.as_deref(), Some("owner"));
}
#[test]
fn parse_permission_with_data_scope_levels() {
let toml = r#"
[metadata]
id = "test"
name = "Test"
version = "0.1.0"
[[permissions]]
code = "customer.list"
name = "查看客户"
data_scope_levels = ["self", "department", "department_tree", "all"]
"#;
let manifest = parse_manifest(toml).unwrap();
let perm = &manifest.permissions.unwrap()[0];
assert_eq!(perm.data_scope_levels.as_ref().unwrap().len(), 4);
}
}