diff --git a/cmdb-api/.ruff.toml b/cmdb-api/.ruff.toml new file mode 100644 index 0000000..9b8290e --- /dev/null +++ b/cmdb-api/.ruff.toml @@ -0,0 +1,79 @@ +line-length = 120 +cache-dir = ".ruff_cache" +target-version = "py310" +unsafe-fixes = true +show-fixes = true + +[lint] +select = [ + "E", + "F", + "I", + "TCH", + # W + "W505", + # PT + "PT018", + # SIM + "SIM101", + "SIM114", + # PGH + "PGH004", + # PL + "PLE1142", + # RUF + "RUF100", + # UP + "UP007" +] +preview = true +ignore = ["FURB101"] + +[lint.flake8-pytest-style] +mark-parentheses = false +parametrize-names-type = "list" +parametrize-values-row-type = "list" +parametrize-values-type = "tuple" + +[lint.flake8-unused-arguments] +ignore-variadic-names = true + +[lint.isort] +lines-between-types = 1 +order-by-type = true + +[lint.per-file-ignores] +"**/api/v1/*.py" = ["TCH"] +"**/model/*.py" = ["TCH003"] +"**/models/__init__.py" = ["F401", "F403"] +"**/tests/*.py" = ["E402"] +"celery_worker.py" = ["F401"] +"api/views/entry.py" = ["I001"] +"migrations/*.py" = ["I001", "E402"] +"*.py" = ["I001"] +"api/views/common_setting/department.py" = ["F841"] +"api/lib/common_setting/upload_file.py" = ["F841"] +"api/lib/common_setting/acl.py" = ["F841"] +"**/__init__.py" = ["F822"] +"api/tasks/*.py" = ["E722"] +"api/views/cmdb/*.py" = ["E722"] +"api/views/acl/*.py" = ["E722"] +"api/lib/secrets/*.py" = ["E722", "F841"] +"api/lib/utils.py" = ["E722", "E731"] +"api/lib/perm/authentication/cas/*" = ["E113", "F841"] +"api/lib/perm/acl/*" = ["E722"] +"api/lib/*" = ["E721", "F722"] +"api/lib/cmdb/*" = ["F722", "E722"] +"api/lib/cmdb/search/ci/es/search.py" = ["F841", "SIM114"] +"api/lib/cmdb/search/ci/db/search.py" = ["F841"] +"api/lib/cmdb/value.py" = ["F841"] +"api/lib/cmdb/history.py" = ["E501"] +"api/commands/common.py" = ["E722"] +"api/commands/click_cmdb.py" = ["E722"] +"api/lib/perm/auth.py" = ["SIM114"] + +[format] +preview = true +quote-style = "single" +docstring-code-format = true +skip-magic-trailing-comma = false diff --git a/cmdb-api/api/commands/click_cmdb.py b/cmdb-api/api/commands/click_cmdb.py index 9482068..9c9ab11 100644 --- a/cmdb-api/api/commands/click_cmdb.py +++ b/cmdb-api/api/commands/click_cmdb.py @@ -346,7 +346,7 @@ def cmdb_inner_secrets_init(address): if valid_address(address): token = current_app.config.get("INNER_TRIGGER_TOKEN", "") if not token else token if not token: - token = click.prompt(f'Enter root token', hide_input=True, confirmation_prompt=False) + token = click.prompt('Enter root token', hide_input=True, confirmation_prompt=False) assert token is not None resp = requests.post("{}/api/v0.1/secrets/auto_seal".format(address.strip("/")), headers={"Inner-Token": token}) diff --git a/cmdb-api/api/lib/cmdb/attribute.py b/cmdb-api/api/lib/cmdb/attribute.py index 2fc9be6..77175b0 100644 --- a/cmdb-api/api/lib/cmdb/attribute.py +++ b/cmdb-api/api/lib/cmdb/attribute.py @@ -415,7 +415,7 @@ class AttributeManager(object): db.session.rollback() current_app.logger.error("update attribute error, {0}".format(str(e))) - return abort(400, ErrFormat.update_attribute_failed.format(("id=".format(_id)))) + return abort(400, ErrFormat.update_attribute_failed.format(("id={}".format(_id)))) new = attr.to_dict() if not new['choice_web_hook'] and new['is_choice']: diff --git a/cmdb-api/api/lib/cmdb/ci_type.py b/cmdb-api/api/lib/cmdb/ci_type.py index 222d96f..83f3f11 100644 --- a/cmdb-api/api/lib/cmdb/ci_type.py +++ b/cmdb-api/api/lib/cmdb/ci_type.py @@ -862,15 +862,15 @@ class CITypeRelationManager(object): graph = nx.DiGraph() - def get_children(_id): + def get_children(_id, _graph): children = CITypeRelation.get_by(parent_id=_id, to_dict=False) for i in children: if i.child_id != _id: - graph.add_edge(i.parent_id, i.child_id) - get_children(i.child_id) + _graph.add_edge(i.parent_id, i.child_id) + get_children(i.child_id, _graph) - get_children(source_type_id) + get_children(source_type_id, graph) paths = list(nx.all_simple_paths(graph, source_type_id, target_type_ids)) diff --git a/cmdb-api/api/lib/cmdb/resp_format.py b/cmdb-api/api/lib/cmdb/resp_format.py index 71f1236..881fd31 100644 --- a/cmdb-api/api/lib/cmdb/resp_format.py +++ b/cmdb-api/api/lib/cmdb/resp_format.py @@ -16,8 +16,9 @@ class ErrFormat(CommonErrFormat): argument_file_not_found = _l("The file doesn't seem to be uploaded") # 文件似乎并未上传 attribute_not_found = _l("Attribute {} does not exist!") # 属性 {} 不存在! + # 该属性是模型的唯一标识,不能被删除! attribute_is_unique_id = _l( - "This attribute is the unique identifier of the model and cannot be deleted!") # 该属性是模型的唯一标识,不能被删除! + "This attribute is the unique identifier of the model and cannot be deleted!") attribute_is_ref_by_type = _l( "This attribute is referenced by model {} and cannot be deleted!") # 该属性被模型 {} 引用, 不能删除! attribute_value_type_cannot_change = _l( @@ -129,7 +130,8 @@ class ErrFormat(CommonErrFormat): adr_default_ref_once = _l("The default auto-discovery rule is already referenced by model {}!") # unique_key方法必须返回非空字符串! adr_unique_key_required = _l("The unique_key method must return a non-empty string!") - adr_plugin_attributes_list_required = _l("The attributes method must return a list") # attributes方法必须返回的是list + # attributes方法必须返回的是list + adr_plugin_attributes_list_required = _l("The attributes method must return a list") # attributes方法返回的list不能为空! adr_plugin_attributes_list_no_empty = _l("The list returned by the attributes method cannot be empty!") # 只有管理员才可以定义执行机器为: 所有节点! diff --git a/cmdb-api/api/lib/cmdb/search/ci/db/query_sql.py b/cmdb-api/api/lib/cmdb/search/ci/db/query_sql.py index df61745..8ca41ad 100644 --- a/cmdb-api/api/lib/cmdb/search/ci/db/query_sql.py +++ b/cmdb-api/api/lib/cmdb/search/ci/db/query_sql.py @@ -107,3 +107,12 @@ FROM WHERE c_value_index_datetime.value LIKE "{0}") AS {1} GROUP BY {1}.ci_id """ + +QUERY_CI_BY_NO_ATTR_IN = """ +SELECT * +FROM + (SELECT c_value_index_texts.ci_id + FROM c_value_index_texts + WHERE c_value_index_texts.value in ({0})) AS {1} +GROUP BY {1}.ci_id +""" \ No newline at end of file diff --git a/cmdb-api/api/lib/cmdb/search/ci/db/search.py b/cmdb-api/api/lib/cmdb/search/ci/db/search.py index e4e4154..e50958e 100644 --- a/cmdb-api/api/lib/cmdb/search/ci/db/search.py +++ b/cmdb-api/api/lib/cmdb/search/ci/db/search.py @@ -27,6 +27,7 @@ from api.lib.cmdb.search.ci.db.query_sql import FACET_QUERY from api.lib.cmdb.search.ci.db.query_sql import QUERY_CI_BY_ATTR_NAME from api.lib.cmdb.search.ci.db.query_sql import QUERY_CI_BY_ID from api.lib.cmdb.search.ci.db.query_sql import QUERY_CI_BY_NO_ATTR +from api.lib.cmdb.search.ci.db.query_sql import QUERY_CI_BY_NO_ATTR_IN from api.lib.cmdb.search.ci.db.query_sql import QUERY_CI_BY_TYPE from api.lib.cmdb.search.ci.db.query_sql import QUERY_UNION_CI_ATTRIBUTE_IS_NULL from api.lib.cmdb.utils import TableMap @@ -527,10 +528,15 @@ class Search(object): for q in queries: _query_sql = "" if isinstance(q, dict): - alias, _query_sql, operator = self.__query_build_by_field(q['queries'], True, True, alias, is_sub=True) - # current_app.logger.info(_query_sql) - # current_app.logger.info((operator, is_first, alias)) - operator = q['operator'] + current_app.logger.debug("Dict query content: queries=%s, operator=%s", q['queries'], q['operator']) + if len(q['queries']) == 1 and ";" in q['queries'][0]: + values = q['queries'][0].split(";") + in_values = ",".join("'{0}'".format(v) for v in values) + _query_sql = QUERY_CI_BY_NO_ATTR_IN.format(in_values, alias) + operator = q['operator'] + else: + alias, _query_sql, operator = self.__query_build_by_field(q['queries'], True, True, alias, is_sub=True) + operator = q['operator'] elif ":" in q and not q.startswith("*"): alias, _query_sql, operator = self.__query_by_attr(q, queries, alias, is_sub) diff --git a/cmdb-api/api/lib/cmdb/utils.py b/cmdb-api/api/lib/cmdb/utils.py index 7ea7e2a..f924037 100644 --- a/cmdb-api/api/lib/cmdb/utils.py +++ b/cmdb-api/api/lib/cmdb/utils.py @@ -55,7 +55,6 @@ def str2datetime(x): return datetime.datetime.strptime(x, "%Y-%m-%d %H:%M") - class ValueTypeMap(object): deserialize = { ValueTypeEnum.INT: string2int, diff --git a/cmdb-api/api/lib/common_setting/decorator.py b/cmdb-api/api/lib/common_setting/decorator.py index 30106e1..d55b6fe 100644 --- a/cmdb-api/api/lib/common_setting/decorator.py +++ b/cmdb-api/api/lib/common_setting/decorator.py @@ -1,6 +1,6 @@ import functools -from flask import abort, session +from flask import abort, session, current_app from api.lib.common_setting.acl import ACLManager from api.lib.common_setting.resp_format import ErrFormat from api.lib.perm.acl.acl import is_app_admin @@ -15,6 +15,7 @@ def perms_role_required(app_name, resource_type_name, resource_name, perm, role_ try: has_perms = acl.role_has_perms(session["acl"]['rid'], resource_name, resource_type_name, perm) except Exception as e: + current_app.logger.error(f"acl role_has_perms err: {e}") # resource_type not exist, continue check role if role_name: if role_name not in session.get("acl", {}).get("parentRoles", []) and not is_app_admin(app_name): diff --git a/cmdb-api/api/lib/common_setting/department.py b/cmdb-api/api/lib/common_setting/department.py index 7d72bc6..61d5d58 100644 --- a/cmdb-api/api/lib/common_setting/department.py +++ b/cmdb-api/api/lib/common_setting/department.py @@ -476,7 +476,7 @@ class EditDepartmentInACL(object): for employee in e_list: employee_acl_rid = employee.get('e_acl_rid') if employee_acl_rid == 0: - result.append(f"employee_acl_rid == 0") + result.append("employee_acl_rid == 0") continue cls.remove_single_employee_from_old_department(acl, employee, result) @@ -501,8 +501,8 @@ class EditDepartmentInACL(object): acl.remove_user_from_role(employee.get('e_acl_rid'), payload) current_app.logger.info(f"remove {employee.get('e_acl_rid')} from {d_acl_rid}") except Exception as e: - result.append( - f"remove_user_from_role employee_acl_rid: {employee.get('e_acl_rid')}, parent_id: {d_acl_rid}, err: {e}") + err = f"remove_user_from_role e_acl_rid: {employee.get('e_acl_rid')}, parent_id: {d_acl_rid}, err: {e}" + result.append(err) return True @@ -548,7 +548,7 @@ class EditDepartmentInACL(object): for employee in e_list: employee_acl_rid = employee.get('e_acl_rid') if employee_acl_rid == 0: - result.append(f"employee_acl_rid == 0") + result.append("employee_acl_rid == 0") continue cls.remove_single_employee_from_old_department(acl, employee, result) diff --git a/cmdb-api/api/lib/common_setting/employee.py b/cmdb-api/api/lib/common_setting/employee.py index ca7173f..5dbeeb2 100644 --- a/cmdb-api/api/lib/common_setting/employee.py +++ b/cmdb-api/api/lib/common_setting/employee.py @@ -4,7 +4,7 @@ import traceback from datetime import datetime import requests -from flask import abort +from flask import abort, current_app from flask_login import current_user from sqlalchemy import or_, literal_column, func, not_, and_ from werkzeug.datastructures import MultiDict @@ -478,7 +478,7 @@ class EmployeeCRUD(object): Employee.deleted == 0, Employee.block == block, ] - if type(department_id) == list: + if isinstance(department_id, list): if len(department_id) == 0: return [] else: @@ -702,6 +702,7 @@ class EmployeeCRUD(object): try: last_login = datetime.strptime(last_login, '%Y-%m-%d %H:%M:%S') except Exception as e: + current_app.logger.error(f"strptime {last_login} err: {e}") last_login = datetime.now() else: last_login = datetime.now() @@ -712,6 +713,7 @@ class EmployeeCRUD(object): ) return last_login except Exception as e: + current_app.logger.error(f"update last_login err: {e}") return diff --git a/cmdb-api/api/lib/common_setting/notice_config.py b/cmdb-api/api/lib/common_setting/notice_config.py index 152eb53..6246962 100644 --- a/cmdb-api/api/lib/common_setting/notice_config.py +++ b/cmdb-api/api/lib/common_setting/notice_config.py @@ -2,7 +2,7 @@ import requests from api.lib.common_setting.const import BotNameMap from api.lib.common_setting.resp_format import ErrFormat -from api.models.common_setting import CompanyInfo, NoticeConfig +from api.models.common_setting import NoticeConfig from wtforms import Form from wtforms import StringField from wtforms import validators diff --git a/cmdb-api/api/lib/common_setting/role_perm_base.py b/cmdb-api/api/lib/common_setting/role_perm_base.py index 7a210a5..a508b06 100644 --- a/cmdb-api/api/lib/common_setting/role_perm_base.py +++ b/cmdb-api/api/lib/common_setting/role_perm_base.py @@ -48,7 +48,9 @@ class CMDBApp(BaseApp): {"page": "Model_Relationships", "page_cn": "模型关系", "perms": ["read"]}, {"page": "Operation_Audit", "page_cn": "操作审计", "perms": ["read"]}, {"page": "Relationship_Types", "page_cn": "关系类型", "perms": ["read"]}, - {"page": "Auto_Discovery", "page_cn": "自动发现", "perms": ["read", "create_plugin", "update_plugin", "delete_plugin"]}, + {"page": "Auto_Discovery", "page_cn": "自动发现", + "perms": ["read", "create_plugin", "update_plugin", "delete_plugin"] + }, {"page": "TopologyView", "page_cn": "拓扑视图", "perms": ["read", "create_topology_group", "update_topology_group", "delete_topology_group", "create_topology_view"], diff --git a/cmdb-api/api/lib/perm/acl/__init__.py b/cmdb-api/api/lib/perm/acl/__init__.py index a44fc64..2185830 100644 --- a/cmdb-api/api/lib/perm/acl/__init__.py +++ b/cmdb-api/api/lib/perm/acl/__init__.py @@ -6,7 +6,7 @@ from functools import wraps from flask import abort from flask import request -from api.lib.perm.acl.cache import AppCache, AppAccessTokenCache +from api.lib.perm.acl.cache import AppCache from api.lib.perm.acl.resp_format import ErrFormat diff --git a/cmdb-api/api/lib/perm/acl/role.py b/cmdb-api/api/lib/perm/acl/role.py index 2faacbb..e08207d 100644 --- a/cmdb-api/api/lib/perm/acl/role.py +++ b/cmdb-api/api/lib/perm/acl/role.py @@ -1,8 +1,5 @@ # -*- coding:utf-8 -*- - -import time - import redis_lock import six from flask import abort diff --git a/cmdb-api/api/lib/utils.py b/cmdb-api/api/lib/utils.py index 8f79358..f1b397c 100644 --- a/cmdb-api/api/lib/utils.py +++ b/cmdb-api/api/lib/utils.py @@ -1,7 +1,6 @@ # -*- coding:utf-8 -*- import base64 -from typing import Set import elasticsearch import redis diff --git a/cmdb-api/api/views/common_setting/employee.py b/cmdb-api/api/views/common_setting/employee.py index 173dc13..06e947b 100644 --- a/cmdb-api/api/views/common_setting/employee.py +++ b/cmdb-api/api/views/common_setting/employee.py @@ -131,7 +131,7 @@ class EmployeeChangePasswordWithACLID(APIView): if not password: abort(400, ErrFormat.password_is_required) - data = EmployeeCRUD.change_password_by_uid(_uid, password) + EmployeeCRUD.change_password_by_uid(_uid, password) return self.jsonify(200) diff --git a/cmdb-api/api/views/common_setting/file_manage.py b/cmdb-api/api/views/common_setting/file_manage.py index fb304df..35f24e8 100644 --- a/cmdb-api/api/views/common_setting/file_manage.py +++ b/cmdb-api/api/views/common_setting/file_manage.py @@ -6,7 +6,7 @@ import magic from api.lib.common_setting.const import MIMEExtMap from api.lib.common_setting.resp_format import ErrFormat -from api.lib.common_setting.upload_file import allowed_file, generate_new_file_name, CommonFileCRUD +from api.lib.common_setting.upload_file import generate_new_file_name, CommonFileCRUD from api.resource import APIView prefix = '/file' diff --git a/cmdb-api/requirements.txt b/cmdb-api/requirements.txt index 33fe829..5f256c1 100644 --- a/cmdb-api/requirements.txt +++ b/cmdb-api/requirements.txt @@ -58,3 +58,4 @@ python-magic==0.4.27 jsonpath==0.82.2 networkx>=3.1 ipaddress>=1.0.23 +ruff==0.8.3 diff --git a/cmdb-ui/src/modules/cmdb/lang/en.js b/cmdb-ui/src/modules/cmdb/lang/en.js index 090d8ba..0549a80 100644 --- a/cmdb-ui/src/modules/cmdb/lang/en.js +++ b/cmdb-ui/src/modules/cmdb/lang/en.js @@ -314,6 +314,9 @@ const cmdb_en = { enum: 'Enum', ciGrantTip: `Filter conditions can be changed dynamically using {{}} referenced variables, currently user variables are supported, such as {{user.uid}},{{user.username}},{{user.email}},{{user.nickname}}`, searchInputTip: 'Please search for resource keywords', + columnSearchInputTip: '192.168.1.1\n192.168.1.2\n192.168.1.3', + rowSearchMode: 'Single Row Search', + columnSearchMode: 'Multi Row Search', resourceSearch: 'Resource Search', recentSearch: 'Recent Search', myCollection: 'My Collection', diff --git a/cmdb-ui/src/modules/cmdb/lang/zh.js b/cmdb-ui/src/modules/cmdb/lang/zh.js index f55e392..f2f11d4 100644 --- a/cmdb-ui/src/modules/cmdb/lang/zh.js +++ b/cmdb-ui/src/modules/cmdb/lang/zh.js @@ -314,6 +314,9 @@ const cmdb_zh = { enum: '枚举', ciGrantTip: `筛选条件可使用{{}}引用变量实现动态变化,目前支持用户变量,如{{user.uid}},{{user.username}},{{user.email}},{{user.nickname}}`, searchInputTip: '请搜索资源关键字', + columnSearchInputTip: '192.168.1.1\n192.168.1.2\n192.168.1.3', + rowSearchMode: '单行搜索', + columnSearchMode: '多行搜索', resourceSearch: '资源搜索', recentSearch: '最近搜索', myCollection: '我的收藏', diff --git a/cmdb-ui/src/modules/cmdb/views/ci/modules/createInstanceFormByGroup.vue b/cmdb-ui/src/modules/cmdb/views/ci/modules/createInstanceFormByGroup.vue index 8b0e8d2..bbed6e3 100644 --- a/cmdb-ui/src/modules/cmdb/views/ci/modules/createInstanceFormByGroup.vue +++ b/cmdb-ui/src/modules/cmdb/views/ci/modules/createInstanceFormByGroup.vue @@ -95,7 +95,7 @@ attr.name, { rules: [{ required: attr.is_required, message: $t('placeholder1') + `${attr.alias || attr.name}` }], - initialValue: attr.default && attr.default.default ? attr.default.default : null, + initialValue: attr.default && attr.default.default !== undefined && attr.default.default !== null ? attr.default.default : null, }, ]" style="width: 100%" @@ -148,6 +148,7 @@