mirror of
				https://github.com/veops/cmdb.git
				synced 2025-10-31 19:39:24 +08:00 
			
		
		
		
	feat: Predefined values support executing scripts (#227)
This commit is contained in:
		cmdb-api/api/lib/cmdb
| @@ -60,10 +60,11 @@ class AttributeManager(object): | ||||
|             return [] | ||||
|  | ||||
|     @staticmethod | ||||
|     def _get_choice_values_from_other_ci(choice_other): | ||||
|     def _get_choice_values_from_other(choice_other): | ||||
|         from api.lib.cmdb.search import SearchError | ||||
|         from api.lib.cmdb.search.ci import search | ||||
|  | ||||
|         if choice_other.get('type_ids'): | ||||
|             type_ids = choice_other.get('type_ids') | ||||
|             attr_id = choice_other.get('attr_id') | ||||
|             other_filter = choice_other.get('filter') or '' | ||||
| @@ -77,6 +78,16 @@ class AttributeManager(object): | ||||
|                 current_app.logger.error("get choice values from other ci failed: {}".format(e)) | ||||
|                 return [] | ||||
|  | ||||
|         elif choice_other.get('script'): | ||||
|             try: | ||||
|                 x = compile(choice_other['script'], '', "exec") | ||||
|                 exec(x) | ||||
|                 res = locals()['ChoiceValue']().values() or [] | ||||
|                 return [[i, {}] for i in res] | ||||
|             except Exception as e: | ||||
|                 current_app.logger.error("get choice values from script: {}".format(e)) | ||||
|                 return [] | ||||
|  | ||||
|     @classmethod | ||||
|     def get_choice_values(cls, attr_id, value_type, choice_web_hook, choice_other, | ||||
|                           choice_web_hook_parse=True, choice_other_parse=True): | ||||
| @@ -87,7 +98,7 @@ class AttributeManager(object): | ||||
|                 return [] | ||||
|         elif choice_other: | ||||
|             if choice_other_parse and isinstance(choice_other, dict): | ||||
|                 return cls._get_choice_values_from_other_ci(choice_other) | ||||
|                 return cls._get_choice_values_from_other(choice_other) | ||||
|             else: | ||||
|                 return [] | ||||
|  | ||||
| @@ -96,7 +107,8 @@ class AttributeManager(object): | ||||
|             return [] | ||||
|         choice_values = choice_table.get_by(fl=["value", "option"], attr_id=attr_id) | ||||
|  | ||||
|         return [[choice_value['value'], choice_value['option']] for choice_value in choice_values] | ||||
|         return [[ValueTypeMap.serialize[value_type](choice_value['value']), choice_value['option']] | ||||
|                 for choice_value in choice_values] | ||||
|  | ||||
|     @staticmethod | ||||
|     def add_choice_values(_id, value_type, choice_values): | ||||
| @@ -218,9 +230,14 @@ class AttributeManager(object): | ||||
|         if name in BUILTIN_KEYWORDS: | ||||
|             return abort(400, ErrFormat.attribute_name_cannot_be_builtin) | ||||
|  | ||||
|         if kwargs.get('choice_other'): | ||||
|             if (not isinstance(kwargs['choice_other'], dict) or not kwargs['choice_other'].get('type_ids') or | ||||
|                     not kwargs['choice_other'].get('attr_id')): | ||||
|         while kwargs.get('choice_other'): | ||||
|             if isinstance(kwargs['choice_other'], dict): | ||||
|                 if kwargs['choice_other'].get('script'): | ||||
|                     break | ||||
|  | ||||
|                 if kwargs['choice_other'].get('type_ids') and kwargs['choice_other'].get('attr_id'): | ||||
|                     break | ||||
|  | ||||
|             return abort(400, ErrFormat.attribute_choice_other_invalid) | ||||
|  | ||||
|         alias = kwargs.pop("alias", "") | ||||
| @@ -232,6 +249,8 @@ class AttributeManager(object): | ||||
|  | ||||
|         kwargs.get('is_computed') and cls.can_create_computed_attribute() | ||||
|  | ||||
|         kwargs.get('choice_other') and kwargs['choice_other'].get('script') and cls.can_create_computed_attribute() | ||||
|  | ||||
|         attr = Attribute.create(flush=True, | ||||
|                                 name=name, | ||||
|                                 alias=alias, | ||||
| @@ -337,9 +356,14 @@ class AttributeManager(object): | ||||
|  | ||||
|             self._change_index(attr, attr.is_index, kwargs['is_index']) | ||||
|  | ||||
|         if kwargs.get('choice_other'): | ||||
|             if (not isinstance(kwargs['choice_other'], dict) or not kwargs['choice_other'].get('type_ids') or | ||||
|                     not kwargs['choice_other'].get('attr_id')): | ||||
|         while kwargs.get('choice_other'): | ||||
|             if isinstance(kwargs['choice_other'], dict): | ||||
|                 if kwargs['choice_other'].get('script'): | ||||
|                     break | ||||
|  | ||||
|                 if kwargs['choice_other'].get('type_ids') and kwargs['choice_other'].get('attr_id'): | ||||
|                     break | ||||
|  | ||||
|             return abort(400, ErrFormat.attribute_choice_other_invalid) | ||||
|  | ||||
|         existed2 = attr.to_dict() | ||||
|   | ||||
| @@ -28,6 +28,7 @@ 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_TYPE | ||||
| from api.lib.cmdb.search.ci.db.query_sql import QUERY_UNION_CI_ATTRIBUTE_IS_NULL | ||||
| from api.lib.cmdb.utils import TableMap | ||||
| from api.lib.cmdb.utils import ValueTypeMap | ||||
| from api.lib.perm.acl.acl import ACLManager | ||||
| from api.lib.perm.acl.acl import is_app_admin | ||||
| from api.lib.utils import handle_arg_list | ||||
| @@ -524,15 +525,15 @@ class Search(object): | ||||
|             if k: | ||||
|                 table_name = TableMap(attr=attr).table_name | ||||
|                 query_sql = FACET_QUERY.format(table_name, self.query_sql, attr.id) | ||||
|                 # current_app.logger.warning(query_sql) | ||||
|                 result = db.session.execute(query_sql).fetchall() | ||||
|                 facet[k] = result | ||||
|  | ||||
|         facet_result = dict() | ||||
|         for k, v in facet.items(): | ||||
|             if not k.startswith('_'): | ||||
|                 a = getattr(AttributeCache.get(k), self.ret_key) | ||||
|                 facet_result[a] = [(f[0], f[1], a) for f in v] | ||||
|                 attr = AttributeCache.get(k) | ||||
|                 a = getattr(attr, self.ret_key) | ||||
|                 facet_result[a] = [(ValueTypeMap.serialize[attr.value_type](f[0]), f[1], a) for f in v] | ||||
|  | ||||
|         return facet_result | ||||
|  | ||||
|   | ||||
| @@ -12,7 +12,7 @@ import api.models.cmdb as model | ||||
| from api.lib.cmdb.cache import AttributeCache | ||||
| from api.lib.cmdb.const import ValueTypeEnum | ||||
|  | ||||
| TIME_RE = re.compile(r"^(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d$") | ||||
| TIME_RE = re.compile(r"^20|21|22|23|[0-1]\d:[0-5]\d:[0-5]\d$") | ||||
|  | ||||
|  | ||||
| def string2int(x): | ||||
| @@ -21,7 +21,7 @@ def string2int(x): | ||||
|  | ||||
| def str2datetime(x): | ||||
|     try: | ||||
|         return datetime.datetime.strptime(x, "%Y-%m-%d") | ||||
|         return datetime.datetime.strptime(x, "%Y-%m-%d").date() | ||||
|     except ValueError: | ||||
|         pass | ||||
|  | ||||
| @@ -44,8 +44,8 @@ class ValueTypeMap(object): | ||||
|         ValueTypeEnum.FLOAT: float, | ||||
|         ValueTypeEnum.TEXT: lambda x: x if isinstance(x, six.string_types) else str(x), | ||||
|         ValueTypeEnum.TIME: lambda x: x if isinstance(x, six.string_types) else str(x), | ||||
|         ValueTypeEnum.DATE: lambda x: x.strftime("%Y-%m-%d"), | ||||
|         ValueTypeEnum.DATETIME: lambda x: x.strftime("%Y-%m-%d %H:%M:%S"), | ||||
|         ValueTypeEnum.DATE: lambda x: x.strftime("%Y-%m-%d") if not isinstance(x, six.string_types) else x, | ||||
|         ValueTypeEnum.DATETIME: lambda x: x.strftime("%Y-%m-%d %H:%M:%S") if not isinstance(x, six.string_types) else x, | ||||
|         ValueTypeEnum.JSON: lambda x: json.loads(x) if isinstance(x, six.string_types) and x else x, | ||||
|     } | ||||
|  | ||||
| @@ -64,6 +64,8 @@ class ValueTypeMap(object): | ||||
|         ValueTypeEnum.FLOAT: model.FloatChoice, | ||||
|         ValueTypeEnum.TEXT: model.TextChoice, | ||||
|         ValueTypeEnum.TIME: model.TextChoice, | ||||
|         ValueTypeEnum.DATE: model.TextChoice, | ||||
|         ValueTypeEnum.DATETIME: model.TextChoice, | ||||
|     } | ||||
|  | ||||
|     table = { | ||||
| @@ -97,7 +99,7 @@ class ValueTypeMap(object): | ||||
|         ValueTypeEnum.DATE: 'text', | ||||
|         ValueTypeEnum.TIME: 'text', | ||||
|         ValueTypeEnum.FLOAT: 'float', | ||||
|         ValueTypeEnum.JSON: 'object' | ||||
|         ValueTypeEnum.JSON: 'object', | ||||
|     } | ||||
|  | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user