[update] delete roles, users, attributes

This commit is contained in:
pycook 2023-08-15 19:47:59 +08:00
parent ff061d4d2e
commit 1de8b492ea
10 changed files with 41 additions and 20 deletions

View File

@ -8,6 +8,7 @@ from flask_login import current_user
from api.extensions import db from api.extensions import db
from api.lib.cmdb.cache import AttributeCache from api.lib.cmdb.cache import AttributeCache
from api.lib.cmdb.cache import CITypeCache
from api.lib.cmdb.const import CITypeOperateType from api.lib.cmdb.const import CITypeOperateType
from api.lib.cmdb.const import PermEnum, ResourceTypeEnum, RoleEnum from api.lib.cmdb.const import PermEnum, ResourceTypeEnum, RoleEnum
from api.lib.cmdb.const import ValueTypeEnum from api.lib.cmdb.const import ValueTypeEnum
@ -319,7 +320,12 @@ class AttributeManager(object):
if CIType.get_by(unique_id=attr.id, first=True, to_dict=False) is not None: if CIType.get_by(unique_id=attr.id, first=True, to_dict=False) is not None:
return abort(400, ErrFormat.attribute_is_unique_id) return abort(400, ErrFormat.attribute_is_unique_id)
if attr.uid and attr.uid != current_user.uid: ref = CITypeAttribute.get_by(attr_id=_id, to_dict=False, first=True)
if ref is not None:
ci_type = CITypeCache.get(ref.type_id)
return abort(400, ErrFormat.attribute_is_ref_by_type.format(ci_type.alias))
if attr.uid != current_user.uid and not is_app_admin('cmdb'):
return abort(403, ErrFormat.cannot_delete_attribute) return abort(403, ErrFormat.cannot_delete_attribute)
if attr.is_choice: if attr.is_choice:
@ -331,9 +337,6 @@ class AttributeManager(object):
attr.soft_delete() attr.soft_delete()
for i in CITypeAttribute.get_by(attr_id=_id, to_dict=False):
i.soft_delete()
for i in PreferenceShowAttributes.get_by(attr_id=_id, to_dict=False): for i in PreferenceShowAttributes.get_by(attr_id=_id, to_dict=False):
i.soft_delete() i.soft_delete()

View File

@ -38,8 +38,8 @@ from api.lib.decorator import kwargs_required
from api.lib.perm.acl.acl import ACLManager from api.lib.perm.acl.acl import ACLManager
from api.lib.perm.acl.acl import is_app_admin from api.lib.perm.acl.acl import is_app_admin
from api.lib.perm.acl.acl import validate_permission from api.lib.perm.acl.acl import validate_permission
from api.lib.utils import handle_arg_list
from api.lib.utils import Lock from api.lib.utils import Lock
from api.lib.utils import handle_arg_list
from api.models.cmdb import CI from api.models.cmdb import CI
from api.models.cmdb import CIRelation from api.models.cmdb import CIRelation
from api.models.cmdb import CITypeAttribute from api.models.cmdb import CITypeAttribute
@ -49,6 +49,8 @@ from api.tasks.cmdb import ci_delete
from api.tasks.cmdb import ci_relation_cache from api.tasks.cmdb import ci_relation_cache
from api.tasks.cmdb import ci_relation_delete from api.tasks.cmdb import ci_relation_delete
PRIVILEGED_USERS = {"worker", "cmdb_agent", "agent"}
class CIManager(object): class CIManager(object):
""" manage CI interface """ manage CI interface
@ -316,7 +318,7 @@ class CIManager(object):
ci_attr2type_attr = {type_attr.attr_id: type_attr for type_attr, _ in attrs} ci_attr2type_attr = {type_attr.attr_id: type_attr for type_attr, _ in attrs}
ci = None ci = None
need_lock = current_user.username not in ("worker", "cmdb_agent", "agent") need_lock = current_user.username not in current_app.config.get('PRIVILEGED_USERS', PRIVILEGED_USERS)
with Lock(ci_type_name, need_lock=need_lock): with Lock(ci_type_name, need_lock=need_lock):
existed = cls.ci_is_exist(unique_key, unique_value, ci_type.id) existed = cls.ci_is_exist(unique_key, unique_value, ci_type.id)
if existed is not None: if existed is not None:
@ -411,7 +413,7 @@ class CIManager(object):
limit_attrs = self._valid_ci_for_no_read(ci) if not _is_admin else {} limit_attrs = self._valid_ci_for_no_read(ci) if not _is_admin else {}
need_lock = current_user.username not in ("worker", "cmdb_agent", "agent") need_lock = current_user.username not in current_app.config.get('PRIVILEGED_USERS', PRIVILEGED_USERS)
with Lock(ci.ci_type.name, need_lock=need_lock): with Lock(ci.ci_type.name, need_lock=need_lock):
self._valid_unique_constraint(ci.type_id, ci_dict, ci_id) self._valid_unique_constraint(ci.type_id, ci_dict, ci_id)

View File

@ -11,6 +11,7 @@ class ErrFormat(CommonErrFormat):
attribute_not_found = "属性 {} 不存在!" attribute_not_found = "属性 {} 不存在!"
attribute_is_unique_id = "该属性是模型的唯一标识,不能被删除!" attribute_is_unique_id = "该属性是模型的唯一标识,不能被删除!"
attribute_is_ref_by_type = "该属性被模型 {} 引用, 不能删除!"
attribute_value_type_cannot_change = "属性的值类型不允许修改!" attribute_value_type_cannot_change = "属性的值类型不允许修改!"
attribute_list_value_cannot_change = "多值不被允许修改!" attribute_list_value_cannot_change = "多值不被允许修改!"
attribute_index_cannot_change = "修改索引 非管理员不被允许!" attribute_index_cannot_change = "修改索引 非管理员不被允许!"
@ -20,7 +21,7 @@ class ErrFormat(CommonErrFormat):
add_attribute_failed = "创建属性 {} 失败!" add_attribute_failed = "创建属性 {} 失败!"
update_attribute_failed = "修改属性 {} 失败!" update_attribute_failed = "修改属性 {} 失败!"
cannot_edit_attribute = "您没有权限修改该属性!" cannot_edit_attribute = "您没有权限修改该属性!"
cannot_delete_attribute = "您没有权限删除该属性!" cannot_delete_attribute = "目前只允许 属性创建人、管理员 删除属性!"
attribute_name_cannot_be_builtin = "属性字段名不能是内置字段: id, _id, ci_id, type, _type, ci_type" attribute_name_cannot_be_builtin = "属性字段名不能是内置字段: id, _id, ci_id, type, _type, ci_type"
ci_not_found = "CI {} 不存在" ci_not_found = "CI {} 不存在"

View File

@ -80,10 +80,10 @@ class CRUDMixin(FormatMixin):
db.session.rollback() db.session.rollback()
raise CommitException(str(e)) raise CommitException(str(e))
def soft_delete(self, flush=False): def soft_delete(self, flush=False, commit=True):
setattr(self, "deleted", True) setattr(self, "deleted", True)
setattr(self, "deleted_at", datetime.datetime.now()) setattr(self, "deleted_at", datetime.datetime.now())
self.save(flush=flush) self.save(flush=flush, commit=commit)
@classmethod @classmethod
def get_by_id(cls, _id): def get_by_id(cls, _id):
@ -138,8 +138,11 @@ class CRUDMixin(FormatMixin):
return result[0] if first and result else (None if first else result) return result[0] if first and result else (None if first else result)
@classmethod @classmethod
def get_by_like(cls, to_dict=True, **kwargs): def get_by_like(cls, to_dict=True, deleted=False, **kwargs):
query = db.session.query(cls) query = db.session.query(cls)
if hasattr(cls, "deleted") and deleted is not None:
query = query.filter(cls.deleted.is_(deleted))
for k, v in kwargs.items(): for k, v in kwargs.items():
query = query.filter(getattr(cls, k).ilike('%{0}%'.format(v))) query = query.filter(getattr(cls, k).ilike('%{0}%'.format(v)))
return [i.to_dict() if to_dict else i for i in query] return [i.to_dict() if to_dict else i for i in query]

View File

@ -17,6 +17,7 @@ class ErrFormat(CommonErrFormat):
role_exists = "角色 {} 已经存在!" role_exists = "角色 {} 已经存在!"
global_role_not_found = "全局角色 {} 不存在!" global_role_not_found = "全局角色 {} 不存在!"
global_role_exists = "全局角色 {} 已经存在!" global_role_exists = "全局角色 {} 已经存在!"
user_role_delete_invalid = "删除用户角色, 请在 用户管理 页面操作!"
resource_no_permission = "您没有资源: {}{} 权限" resource_no_permission = "您没有资源: {}{} 权限"
admin_required = "需要管理员权限" admin_required = "需要管理员权限"

View File

@ -285,11 +285,13 @@ class RoleCRUD(object):
return role return role
@classmethod @classmethod
def delete_role(cls, rid): def delete_role(cls, rid, force=False):
from api.lib.perm.acl.acl import is_admin from api.lib.perm.acl.acl import is_admin
role = Role.get_by_id(rid) or abort(404, ErrFormat.role_not_found.format("rid={}".format(rid))) role = Role.get_by_id(rid) or abort(404, ErrFormat.role_not_found.format("rid={}".format(rid)))
not force and role.uid and abort(400, ErrFormat.user_role_delete_invalid)
if not role.app_id and not is_admin(): if not role.app_id and not is_admin():
return abort(403, ErrFormat.admin_required) return abort(403, ErrFormat.admin_required)
@ -301,18 +303,20 @@ class RoleCRUD(object):
for i in RoleRelation.get_by(parent_id=rid, to_dict=False): for i in RoleRelation.get_by(parent_id=rid, to_dict=False):
child_ids.append(i.child_id) child_ids.append(i.child_id)
i.soft_delete() i.soft_delete(commit=False)
for i in RoleRelation.get_by(child_id=rid, to_dict=False): for i in RoleRelation.get_by(child_id=rid, to_dict=False):
parent_ids.append(i.parent_id) parent_ids.append(i.parent_id)
i.soft_delete() i.soft_delete(commit=False)
role_permissions = [] role_permissions = []
for i in RolePermission.get_by(rid=rid, to_dict=False): for i in RolePermission.get_by(rid=rid, to_dict=False):
role_permissions.append(i.to_dict()) role_permissions.append(i.to_dict())
i.soft_delete() i.soft_delete(commit=False)
role.soft_delete() role.soft_delete(commit=False)
db.session.commit()
role_rebuild.apply_async(args=(recursive_child_ids, role.app_id), queue=ACL_QUEUE) role_rebuild.apply_async(args=(recursive_child_ids, role.app_id), queue=ACL_QUEUE)

View File

@ -107,6 +107,10 @@ class UserCRUD(object):
UserCache.clean(user) UserCache.clean(user)
role = RoleCRUD.get_by_name(user.username, app_id=None)
if role:
RoleCRUD.delete_role(role[0]['id'], force=True)
AuditCRUD.add_role_log(None, AuditOperateType.delete, AuditCRUD.add_role_log(None, AuditOperateType.delete,
AuditScope.user, user.uid, origin, {}, {}, {}) AuditScope.user, user.uid, origin, {}, {}, {})

View File

@ -63,6 +63,7 @@ class AttributeView(APIView):
current_app.logger.debug(params) current_app.logger.debug(params)
attr_id = AttributeManager.add(**params) attr_id = AttributeManager.add(**params)
return self.jsonify(attr_id=attr_id) return self.jsonify(attr_id=attr_id)
@args_validate(AttributeManager.cls) @args_validate(AttributeManager.cls)
@ -72,8 +73,10 @@ class AttributeView(APIView):
params["choice_value"] = choice_value params["choice_value"] = choice_value
current_app.logger.debug(params) current_app.logger.debug(params)
AttributeManager().update(attr_id, **params) AttributeManager().update(attr_id, **params)
return self.jsonify(attr_id=attr_id) return self.jsonify(attr_id=attr_id)
def delete(self, attr_id): def delete(self, attr_id):
attr_name = AttributeManager.delete(attr_id) attr_name = AttributeManager.delete(attr_id)
return self.jsonify(message="attribute {0} deleted".format(attr_name)) return self.jsonify(message="attribute {0} deleted".format(attr_name))

View File

@ -75,9 +75,9 @@ class AutoDiscoveryRuleTemplateFileView(APIView):
return self.send_file(bf, return self.send_file(bf,
as_attachment=True, as_attachment=True,
attachment_filename="cmdb_auto_discovery.json", download_name="cmdb_auto_discovery.json",
mimetype='application/json', mimetype='application/json',
cache_timeout=0) max_age=0)
def post(self): def post(self):
f = request.files.get('file') f = request.files.get('file')

View File

@ -350,9 +350,9 @@ class CITypeTemplateFileView(APIView):
return self.send_file(bf, return self.send_file(bf,
as_attachment=True, as_attachment=True,
attachment_filename="cmdb_template.json", download_name="cmdb_template.json",
mimetype='application/json', mimetype='application/json',
cache_timeout=0) max_age=0)
@role_required(RoleEnum.CONFIG) @role_required(RoleEnum.CONFIG)
def post(self): # import def post(self): # import