feat: enforce field-level permissions for material creation and update
Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
This commit is contained in:
@ -170,7 +170,37 @@ def create():
|
|||||||
if not data:
|
if not data:
|
||||||
return jsonify({"code": 400, "msg": "No data provided"}), 400
|
return jsonify({"code": 400, "msg": "No data provided"}), 400
|
||||||
|
|
||||||
MaterialBaseService.create_material(data)
|
# 获取当前用户权限
|
||||||
|
user_permissions = get_current_user_permissions()
|
||||||
|
# 字段到权限码的映射(与 filter_item_by_permissions 一致)
|
||||||
|
field_to_perm = {
|
||||||
|
'id': 'material_list:id',
|
||||||
|
'companyName': 'material_list:companyName',
|
||||||
|
'name': 'material_list:name',
|
||||||
|
'commonName': 'material_list:commonName',
|
||||||
|
'category': 'material_list:category',
|
||||||
|
'type': 'material_list:type',
|
||||||
|
'spec': 'material_list:spec',
|
||||||
|
'unit': 'material_list:unit',
|
||||||
|
'inventoryCount': 'material_list:inventoryCount',
|
||||||
|
'availableCount': 'material_list:availableCount',
|
||||||
|
'generalManual': 'material_list:files',
|
||||||
|
'generalImage': 'material_list:files',
|
||||||
|
'isEnabled': 'material_list:isEnabled'
|
||||||
|
}
|
||||||
|
# 过滤用户没有权限的字段
|
||||||
|
filtered_data = {}
|
||||||
|
for key, value in data.items():
|
||||||
|
if key in field_to_perm:
|
||||||
|
perm_code = field_to_perm[key]
|
||||||
|
if perm_code in user_permissions:
|
||||||
|
filtered_data[key] = value
|
||||||
|
# 没有权限则跳过,不包含在 filtered_data 中
|
||||||
|
else:
|
||||||
|
# 不在映射中的字段,默认允许(例如 visibilityLevel)
|
||||||
|
filtered_data[key] = value
|
||||||
|
|
||||||
|
MaterialBaseService.create_material(filtered_data)
|
||||||
return jsonify({"code": 200, "msg": "新增成功"})
|
return jsonify({"code": 200, "msg": "新增成功"})
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
# 捕获业务逻辑验证错误 (如名称为空)
|
# 捕获业务逻辑验证错误 (如名称为空)
|
||||||
@ -189,7 +219,37 @@ def create():
|
|||||||
def update(id):
|
def update(id):
|
||||||
try:
|
try:
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
MaterialBaseService.update_material(id, data)
|
# 获取当前用户权限
|
||||||
|
user_permissions = get_current_user_permissions()
|
||||||
|
# 字段到权限码的映射(与 filter_item_by_permissions 一致)
|
||||||
|
field_to_perm = {
|
||||||
|
'id': 'material_list:id',
|
||||||
|
'companyName': 'material_list:companyName',
|
||||||
|
'name': 'material_list:name',
|
||||||
|
'commonName': 'material_list:commonName',
|
||||||
|
'category': 'material_list:category',
|
||||||
|
'type': 'material_list:type',
|
||||||
|
'spec': 'material_list:spec',
|
||||||
|
'unit': 'material_list:unit',
|
||||||
|
'inventoryCount': 'material_list:inventoryCount',
|
||||||
|
'availableCount': 'material_list:availableCount',
|
||||||
|
'generalManual': 'material_list:files',
|
||||||
|
'generalImage': 'material_list:files',
|
||||||
|
'isEnabled': 'material_list:isEnabled'
|
||||||
|
}
|
||||||
|
# 过滤用户没有权限的字段
|
||||||
|
filtered_data = {}
|
||||||
|
for key, value in data.items():
|
||||||
|
if key in field_to_perm:
|
||||||
|
perm_code = field_to_perm[key]
|
||||||
|
if perm_code in user_permissions:
|
||||||
|
filtered_data[key] = value
|
||||||
|
# 没有权限则跳过,不包含在 filtered_data 中
|
||||||
|
else:
|
||||||
|
# 不在映射中的字段,默认允许(例如 visibilityLevel)
|
||||||
|
filtered_data[key] = value
|
||||||
|
# 使用过滤后的数据调用服务
|
||||||
|
MaterialBaseService.update_material(id, filtered_data)
|
||||||
return jsonify({"code": 200, "msg": "修改成功"})
|
return jsonify({"code": 200, "msg": "修改成功"})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|||||||
@ -247,12 +247,12 @@
|
|||||||
|
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="名称" prop="name">
|
<el-form-item label="名称" prop="name" v-if="hasFieldPermission('name')">
|
||||||
<el-input v-model="form.name" placeholder="内部名称" />
|
<el-input v-model="form.name" placeholder="内部名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="俗名" prop="commonName">
|
<el-form-item label="俗名" prop="commonName" v-if="hasFieldPermission('commonName')">
|
||||||
<el-input v-model="form.commonName" placeholder="标准名称" />
|
<el-input v-model="form.commonName" placeholder="标准名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -260,7 +260,7 @@
|
|||||||
|
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="所属公司" prop="companyName">
|
<el-form-item label="所属公司" prop="companyName" v-if="hasFieldPermission('companyName')">
|
||||||
<el-autocomplete
|
<el-autocomplete
|
||||||
v-model="form.companyName"
|
v-model="form.companyName"
|
||||||
:fetch-suggestions="querySearchCompany"
|
:fetch-suggestions="querySearchCompany"
|
||||||
@ -271,7 +271,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="类别" prop="category">
|
<el-form-item label="类别" prop="category" v-if="hasFieldPermission('category')">
|
||||||
<div style="display: flex; width: 100%; align-items: center;">
|
<div style="display: flex; width: 100%; align-items: center;">
|
||||||
<el-cascader
|
<el-cascader
|
||||||
v-model="tempCategoryPrefix"
|
v-model="tempCategoryPrefix"
|
||||||
@ -299,7 +299,7 @@
|
|||||||
|
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="类型" prop="type">
|
<el-form-item label="类型" prop="type" v-if="hasFieldPermission('type')">
|
||||||
<el-autocomplete
|
<el-autocomplete
|
||||||
v-model="form.type"
|
v-model="form.type"
|
||||||
:fetch-suggestions="querySearchType"
|
:fetch-suggestions="querySearchType"
|
||||||
@ -310,7 +310,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="规格型号" prop="spec">
|
<el-form-item label="规格型号" prop="spec" v-if="hasFieldPermission('spec')">
|
||||||
<el-input v-model="form.spec" placeholder="请输入规格型号" />
|
<el-input v-model="form.spec" placeholder="请输入规格型号" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -318,7 +318,7 @@
|
|||||||
|
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="计量单位" prop="unit">
|
<el-form-item label="计量单位" prop="unit" v-if="hasFieldPermission('unit')">
|
||||||
<el-input v-model="form.unit" placeholder="如: 个, 台, 米" />
|
<el-input v-model="form.unit" placeholder="如: 个, 台, 米" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -330,7 +330,7 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-form-item label="产品图" prop="generalImage">
|
<el-form-item label="产品图" prop="generalImage" v-if="hasFieldPermission('files')">
|
||||||
<div class="upload-container">
|
<div class="upload-container">
|
||||||
<el-upload
|
<el-upload
|
||||||
v-model:file-list="fileListImage"
|
v-model:file-list="fileListImage"
|
||||||
@ -358,7 +358,7 @@
|
|||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="说明书" prop="generalManual">
|
<el-form-item label="说明书" prop="generalManual" v-if="hasFieldPermission('files')">
|
||||||
<div class="upload-container">
|
<div class="upload-container">
|
||||||
<el-upload
|
<el-upload
|
||||||
v-model:file-list="fileListManual"
|
v-model:file-list="fileListManual"
|
||||||
@ -386,7 +386,7 @@
|
|||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="状态" prop="isEnabled">
|
<el-form-item label="状态" prop="isEnabled" v-if="hasFieldPermission('isEnabled')">
|
||||||
<el-radio-group v-model="form.isEnabled">
|
<el-radio-group v-model="form.isEnabled">
|
||||||
<el-radio :value="1">启用</el-radio>
|
<el-radio :value="1">启用</el-radio>
|
||||||
<el-radio :value="0">禁用</el-radio>
|
<el-radio :value="0">禁用</el-radio>
|
||||||
@ -538,6 +538,19 @@ const initColumnPermissions = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 检查字段权限(用于表单)
|
||||||
|
const hasFieldPermission = (field: string) => {
|
||||||
|
if (userStore.role === 'SUPER_ADMIN' || userStore.username === 'IRIS') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const code = permissionMap[field];
|
||||||
|
// 如果permissionMap中没有该字段,默认允许
|
||||||
|
if (!code) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return userStore.hasPermission(code);
|
||||||
|
};
|
||||||
|
|
||||||
const companyOptions = ref<string[]>([]);
|
const companyOptions = ref<string[]>([]);
|
||||||
const categoryOptions = ref<string[]>([]);
|
const categoryOptions = ref<string[]>([]);
|
||||||
const typeOptions = ref<string[]>([]);
|
const typeOptions = ref<string[]>([]);
|
||||||
|
|||||||
Reference in New Issue
Block a user