diff --git a/cmdb-api/api/lib/cmdb/attribute.py b/cmdb-api/api/lib/cmdb/attribute.py index 83f2029..4a8e265 100644 --- a/cmdb-api/api/lib/cmdb/attribute.py +++ b/cmdb-api/api/lib/cmdb/attribute.py @@ -8,6 +8,7 @@ from flask_login import current_user from api.extensions import db 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 PermEnum, ResourceTypeEnum, RoleEnum 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: 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) if attr.is_choice: @@ -331,9 +337,6 @@ class AttributeManager(object): 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): i.soft_delete() diff --git a/cmdb-api/api/lib/cmdb/ci.py b/cmdb-api/api/lib/cmdb/ci.py index a51bac0..b70f4d2 100644 --- a/cmdb-api/api/lib/cmdb/ci.py +++ b/cmdb-api/api/lib/cmdb/ci.py @@ -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 is_app_admin 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 handle_arg_list from api.models.cmdb import CI from api.models.cmdb import CIRelation 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_delete +PRIVILEGED_USERS = {"worker", "cmdb_agent", "agent"} + class CIManager(object): """ 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 = 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): existed = cls.ci_is_exist(unique_key, unique_value, ci_type.id) 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 {} - 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): self._valid_unique_constraint(ci.type_id, ci_dict, ci_id) diff --git a/cmdb-api/api/lib/cmdb/resp_format.py b/cmdb-api/api/lib/cmdb/resp_format.py index 7474c48..27208ad 100644 --- a/cmdb-api/api/lib/cmdb/resp_format.py +++ b/cmdb-api/api/lib/cmdb/resp_format.py @@ -11,6 +11,7 @@ class ErrFormat(CommonErrFormat): attribute_not_found = "属性 {} 不存在!" attribute_is_unique_id = "该属性是模型的唯一标识,不能被删除!" + attribute_is_ref_by_type = "该属性被模型 {} 引用, 不能删除!" attribute_value_type_cannot_change = "属性的值类型不允许修改!" attribute_list_value_cannot_change = "多值不被允许修改!" attribute_index_cannot_change = "修改索引 非管理员不被允许!" @@ -20,7 +21,7 @@ class ErrFormat(CommonErrFormat): add_attribute_failed = "创建属性 {} 失败!" update_attribute_failed = "修改属性 {} 失败!" cannot_edit_attribute = "您没有权限修改该属性!" - cannot_delete_attribute = "您没有权限删除该属性!" + cannot_delete_attribute = "目前只允许 属性创建人、管理员 删除属性!" attribute_name_cannot_be_builtin = "属性字段名不能是内置字段: id, _id, ci_id, type, _type, ci_type" ci_not_found = "CI {} 不存在" diff --git a/cmdb-api/api/lib/database.py b/cmdb-api/api/lib/database.py index 5145bd4..dfe1fb1 100644 --- a/cmdb-api/api/lib/database.py +++ b/cmdb-api/api/lib/database.py @@ -80,10 +80,10 @@ class CRUDMixin(FormatMixin): db.session.rollback() 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_at", datetime.datetime.now()) - self.save(flush=flush) + self.save(flush=flush, commit=commit) @classmethod 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) @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) + if hasattr(cls, "deleted") and deleted is not None: + query = query.filter(cls.deleted.is_(deleted)) + for k, v in kwargs.items(): query = query.filter(getattr(cls, k).ilike('%{0}%'.format(v))) return [i.to_dict() if to_dict else i for i in query] diff --git a/cmdb-api/api/lib/perm/acl/resp_format.py b/cmdb-api/api/lib/perm/acl/resp_format.py index 114010d..25f6bdc 100644 --- a/cmdb-api/api/lib/perm/acl/resp_format.py +++ b/cmdb-api/api/lib/perm/acl/resp_format.py @@ -17,6 +17,7 @@ class ErrFormat(CommonErrFormat): role_exists = "角色 {} 已经存在!" global_role_not_found = "全局角色 {} 不存在!" global_role_exists = "全局角色 {} 已经存在!" + user_role_delete_invalid = "删除用户角色, 请在 用户管理 页面操作!" resource_no_permission = "您没有资源: {} 的 {} 权限" admin_required = "需要管理员权限" diff --git a/cmdb-api/api/lib/perm/acl/role.py b/cmdb-api/api/lib/perm/acl/role.py index 712c7d5..9649913 100644 --- a/cmdb-api/api/lib/perm/acl/role.py +++ b/cmdb-api/api/lib/perm/acl/role.py @@ -285,11 +285,13 @@ class RoleCRUD(object): return role @classmethod - def delete_role(cls, rid): + def delete_role(cls, rid, force=False): 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))) + not force and role.uid and abort(400, ErrFormat.user_role_delete_invalid) + if not role.app_id and not is_admin(): 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): 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): parent_ids.append(i.parent_id) - i.soft_delete() + i.soft_delete(commit=False) role_permissions = [] for i in RolePermission.get_by(rid=rid, to_dict=False): 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) diff --git a/cmdb-api/api/lib/perm/acl/user.py b/cmdb-api/api/lib/perm/acl/user.py index 9c9141d..942fae7 100644 --- a/cmdb-api/api/lib/perm/acl/user.py +++ b/cmdb-api/api/lib/perm/acl/user.py @@ -107,6 +107,10 @@ class UserCRUD(object): 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, AuditScope.user, user.uid, origin, {}, {}, {}) diff --git a/cmdb-api/api/views/cmdb/attribute.py b/cmdb-api/api/views/cmdb/attribute.py index 08864f1..c48de55 100644 --- a/cmdb-api/api/views/cmdb/attribute.py +++ b/cmdb-api/api/views/cmdb/attribute.py @@ -63,6 +63,7 @@ class AttributeView(APIView): current_app.logger.debug(params) attr_id = AttributeManager.add(**params) + return self.jsonify(attr_id=attr_id) @args_validate(AttributeManager.cls) @@ -72,8 +73,10 @@ class AttributeView(APIView): params["choice_value"] = choice_value current_app.logger.debug(params) AttributeManager().update(attr_id, **params) + return self.jsonify(attr_id=attr_id) def delete(self, attr_id): attr_name = AttributeManager.delete(attr_id) + return self.jsonify(message="attribute {0} deleted".format(attr_name)) diff --git a/cmdb-api/api/views/cmdb/auto_discovery.py b/cmdb-api/api/views/cmdb/auto_discovery.py index d10b1c2..958d831 100644 --- a/cmdb-api/api/views/cmdb/auto_discovery.py +++ b/cmdb-api/api/views/cmdb/auto_discovery.py @@ -75,9 +75,9 @@ class AutoDiscoveryRuleTemplateFileView(APIView): return self.send_file(bf, as_attachment=True, - attachment_filename="cmdb_auto_discovery.json", + download_name="cmdb_auto_discovery.json", mimetype='application/json', - cache_timeout=0) + max_age=0) def post(self): f = request.files.get('file') diff --git a/cmdb-api/api/views/cmdb/ci_type.py b/cmdb-api/api/views/cmdb/ci_type.py index 7d748e1..ba2686f 100644 --- a/cmdb-api/api/views/cmdb/ci_type.py +++ b/cmdb-api/api/views/cmdb/ci_type.py @@ -350,9 +350,9 @@ class CITypeTemplateFileView(APIView): return self.send_file(bf, as_attachment=True, - attachment_filename="cmdb_template.json", + download_name="cmdb_template.json", mimetype='application/json', - cache_timeout=0) + max_age=0) @role_required(RoleEnum.CONFIG) def post(self): # import