Merge branch 'master' of github.com:veops/cmdb into dev_ui

This commit is contained in:
wang-liang0615 2023-08-16 10:09:47 +08:00
commit 7110b4bcb3
11 changed files with 60 additions and 22 deletions

View File

@ -22,13 +22,24 @@ class InitEmployee(object):
Import users from ACL Import users from ACL
""" """
InitDepartment().init()
acl = ACLManager('acl') acl = ACLManager('acl')
user_list = acl.get_all_users() user_list = acl.get_all_users()
username_list = [e['username'] for e in Employee.get_by()] username_list = [e['username'] for e in Employee.get_by()]
for user in user_list: for user in user_list:
acl_uid = user['uid']
block = 1 if user['block'] else 0
acl_rid = self.get_rid_by_uid(acl_uid)
if user['username'] in username_list: if user['username'] in username_list:
existed = Employee.get_by(first=True, username=user['username'], to_dict=False)
if existed:
existed.update(
acl_uid=acl_uid,
acl_rid=acl_rid,
block=block,
)
continue continue
try: try:
form = EmployeeAddForm(MultiDict(user)) form = EmployeeAddForm(MultiDict(user))
@ -36,8 +47,9 @@ class InitEmployee(object):
raise Exception( raise Exception(
','.join(['{}: {}'.format(filed, ','.join(msg)) for filed, msg in form.errors.items()])) ','.join(['{}: {}'.format(filed, ','.join(msg)) for filed, msg in form.errors.items()]))
data = form.data data = form.data
data['acl_uid'] = user['uid'] data['acl_uid'] = acl_uid
data['block'] = 1 if user['block'] else 0 data['acl_rid'] = acl_rid
data['block'] = block
data.pop('password') data.pop('password')
Employee.create( Employee.create(
**data **data
@ -46,6 +58,11 @@ class InitEmployee(object):
self.log.error(ErrFormat.acl_import_user_failed.format(user['username'], str(e))) self.log.error(ErrFormat.acl_import_user_failed.format(user['username'], str(e)))
self.log.error(e) self.log.error(e)
def get_rid_by_uid(self, uid):
from api.models.acl import Role
role = Role.get_by(first=True, uid=uid)
return role['id'] if role is not None else 0
class InitDepartment(object): class InitDepartment(object):
def __init__(self): def __init__(self):

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