mirror of
				https://github.com/veops/cmdb.git
				synced 2025-11-04 05:36:17 +08:00 
			
		
		
		
	feat(api): build relation by attributes (#461)
This commit is contained in:
		@@ -1086,6 +1086,31 @@ class CIRelationManager(object):
 | 
			
		||||
                for ci_id in ci_ids:
 | 
			
		||||
                    cls.delete_2(parent_id, ci_id, ancestor_ids=ancestor_ids)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def build_by_attribute(cls, ci_dict):
 | 
			
		||||
        type_id = ci_dict['_type']
 | 
			
		||||
        child_items = CITypeRelation.get_by(parent_id=type_id, only_query=True).filter(
 | 
			
		||||
            CITypeRelation.parent_attr_id.isnot(None))
 | 
			
		||||
        for item in child_items:
 | 
			
		||||
            parent_attr = AttributeCache.get(item.parent_attr_id)
 | 
			
		||||
            child_attr = AttributeCache.get(item.child_attr_id)
 | 
			
		||||
            attr_value = ci_dict.get(parent_attr.name)
 | 
			
		||||
            value_table = TableMap(attr=child_attr).table
 | 
			
		||||
            for child in value_table.get_by(attr_id=child_attr.id, value=attr_value, only_query=True).join(
 | 
			
		||||
                    CI, CI.id == value_table.ci_id).filter(CI.type_id == item.child_id):
 | 
			
		||||
                CIRelationManager.add(ci_dict['_id'], child.ci_id)
 | 
			
		||||
 | 
			
		||||
        parent_items = CITypeRelation.get_by(child_id=type_id, only_query=True).filter(
 | 
			
		||||
            CITypeRelation.child_attr_id.isnot(None))
 | 
			
		||||
        for item in parent_items:
 | 
			
		||||
            parent_attr = AttributeCache.get(item.parent_attr_id)
 | 
			
		||||
            child_attr = AttributeCache.get(item.child_attr_id)
 | 
			
		||||
            attr_value = ci_dict.get(child_attr.name)
 | 
			
		||||
            value_table = TableMap(attr=parent_attr).table
 | 
			
		||||
            for parent in value_table.get_by(attr_id=parent_attr.id, value=attr_value, only_query=True).join(
 | 
			
		||||
                    CI, CI.id == value_table.ci_id).filter(CI.type_id == item.parent_id):
 | 
			
		||||
                CIRelationManager.add(parent.ci_id, ci_dict['_id'])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CITriggerManager(object):
 | 
			
		||||
    @staticmethod
 | 
			
		||||
 
 | 
			
		||||
@@ -672,6 +672,10 @@ class CITypeAttributeManager(object):
 | 
			
		||||
                    item = CITypeTrigger.get_by(type_id=_type_id, attr_id=attr_id, to_dict=False, first=True)
 | 
			
		||||
                    item and item.soft_delete(commit=False)
 | 
			
		||||
 | 
			
		||||
                for item in (CITypeRelation.get_by(parent_id=type_id, parent_attr_id=attr_id, to_dict=False) +
 | 
			
		||||
                             CITypeRelation.get_by(child_id=type_id, child_attr_id=attr_id, to_dict=False)):
 | 
			
		||||
                    item.soft_delete(commit=False)
 | 
			
		||||
 | 
			
		||||
                db.session.commit()
 | 
			
		||||
 | 
			
		||||
                CITypeAttributeCache.clean(type_id, attr_id)
 | 
			
		||||
@@ -813,7 +817,8 @@ class CITypeRelationManager(object):
 | 
			
		||||
        return "{} -> {}".format(first_name, second_name)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def add(cls, parent, child, relation_type_id, constraint=ConstraintEnum.One2Many):
 | 
			
		||||
    def add(cls, parent, child, relation_type_id, constraint=ConstraintEnum.One2Many,
 | 
			
		||||
            parent_attr_id=None, child_attr_id=None):
 | 
			
		||||
        p = CITypeManager.check_is_existed(parent)
 | 
			
		||||
        c = CITypeManager.check_is_existed(child)
 | 
			
		||||
 | 
			
		||||
@@ -828,24 +833,18 @@ class CITypeRelationManager(object):
 | 
			
		||||
            current_app.logger.warning(str(e))
 | 
			
		||||
            return abort(400, ErrFormat.circular_dependency_error)
 | 
			
		||||
 | 
			
		||||
        # if constraint == ConstraintEnum.Many2Many:
 | 
			
		||||
        #     other_c = CITypeRelation.get_by(parent_id=p.id, constraint=ConstraintEnum.Many2Many,
 | 
			
		||||
        #                                     to_dict=False, first=True)
 | 
			
		||||
        #     other_p = CITypeRelation.get_by(child_id=c.id, constraint=ConstraintEnum.Many2Many,
 | 
			
		||||
        #                                     to_dict=False, first=True)
 | 
			
		||||
        #     if other_c and other_c.child_id != c.id:
 | 
			
		||||
        #         return abort(400, ErrFormat.m2m_relation_constraint.format(p.name, other_c.child.name))
 | 
			
		||||
        #     if other_p and other_p.parent_id != p.id:
 | 
			
		||||
        #         return abort(400, ErrFormat.m2m_relation_constraint.format(other_p.parent.name, c.name))
 | 
			
		||||
 | 
			
		||||
        existed = cls._get(p.id, c.id)
 | 
			
		||||
        if existed is not None:
 | 
			
		||||
            existed.update(relation_type_id=relation_type_id,
 | 
			
		||||
                           constraint=constraint)
 | 
			
		||||
                           constraint=constraint,
 | 
			
		||||
                           parent_attr_id=parent_attr_id,
 | 
			
		||||
                           child_attr_id=child_attr_id)
 | 
			
		||||
        else:
 | 
			
		||||
            existed = CITypeRelation.create(parent_id=p.id,
 | 
			
		||||
                                            child_id=c.id,
 | 
			
		||||
                                            relation_type_id=relation_type_id,
 | 
			
		||||
                                            parent_attr_id=parent_attr_id,
 | 
			
		||||
                                            child_attr_id=child_attr_id,
 | 
			
		||||
                                            constraint=constraint)
 | 
			
		||||
 | 
			
		||||
            if current_app.config.get("USE_ACL"):
 | 
			
		||||
 
 | 
			
		||||
@@ -75,6 +75,9 @@ class CITypeRelation(Model):
 | 
			
		||||
    relation_type_id = db.Column(db.Integer, db.ForeignKey("c_relation_types.id"), nullable=False)
 | 
			
		||||
    constraint = db.Column(db.Enum(*ConstraintEnum.all()), default=ConstraintEnum.One2Many)
 | 
			
		||||
 | 
			
		||||
    parent_attr_id = db.Column(db.Integer, db.ForeignKey("c_attributes.id"))
 | 
			
		||||
    child_attr_id = db.Column(db.Integer, db.ForeignKey("c_attributes.id"))
 | 
			
		||||
 | 
			
		||||
    parent = db.relationship("CIType", primaryjoin="CIType.id==CITypeRelation.parent_id")
 | 
			
		||||
    child = db.relationship("CIType", primaryjoin="CIType.id==CITypeRelation.child_id")
 | 
			
		||||
    relation_type = db.relationship("RelationType", backref="c_ci_type_relations.relation_type_id")
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
import redis_lock
 | 
			
		||||
from flask import current_app
 | 
			
		||||
@@ -33,8 +32,7 @@ from api.models.cmdb import CITypeAttribute
 | 
			
		||||
@reconnect_db
 | 
			
		||||
def ci_cache(ci_id, operate_type, record_id):
 | 
			
		||||
    from api.lib.cmdb.ci import CITriggerManager
 | 
			
		||||
 | 
			
		||||
    time.sleep(0.01)
 | 
			
		||||
    from api.lib.cmdb.ci import CIRelationManager
 | 
			
		||||
 | 
			
		||||
    m = api.lib.cmdb.ci.CIManager()
 | 
			
		||||
    ci_dict = m.get_ci_by_id_from_db(ci_id, need_children=False, use_master=False)
 | 
			
		||||
@@ -52,13 +50,13 @@ def ci_cache(ci_id, operate_type, record_id):
 | 
			
		||||
 | 
			
		||||
        CITriggerManager.fire(operate_type, ci_dict, record_id)
 | 
			
		||||
 | 
			
		||||
    ci_dict and CIRelationManager.build_by_attribute(ci_dict)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@celery.task(name="cmdb.batch_ci_cache", queue=CMDB_QUEUE)
 | 
			
		||||
@flush_db
 | 
			
		||||
@reconnect_db
 | 
			
		||||
def batch_ci_cache(ci_ids, ):  # only for attribute change index
 | 
			
		||||
    time.sleep(1)
 | 
			
		||||
 | 
			
		||||
    for ci_id in ci_ids:
 | 
			
		||||
        m = api.lib.cmdb.ci.CIManager()
 | 
			
		||||
        ci_dict = m.get_ci_by_id_from_db(ci_id, need_children=False, use_master=False)
 | 
			
		||||
@@ -87,7 +85,6 @@ def ci_delete(ci_id):
 | 
			
		||||
@celery.task(name="cmdb.delete_id_filter", queue=CMDB_QUEUE)
 | 
			
		||||
@reconnect_db
 | 
			
		||||
def delete_id_filter(ci_id):
 | 
			
		||||
 | 
			
		||||
    CIFilterPermsCRUD().delete_id_filter_by_ci_id(ci_id)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,10 @@ class CITypeRelationView(APIView):
 | 
			
		||||
    def post(self, parent_id, child_id):
 | 
			
		||||
        relation_type_id = request.values.get("relation_type_id")
 | 
			
		||||
        constraint = request.values.get("constraint")
 | 
			
		||||
        ctr_id = CITypeRelationManager.add(parent_id, child_id, relation_type_id, constraint)
 | 
			
		||||
        parent_attr_id = request.values.get("parent_attr_id")
 | 
			
		||||
        child_attr_id = request.values.get("child_attr_id")
 | 
			
		||||
        ctr_id = CITypeRelationManager.add(parent_id, child_id, relation_type_id, constraint,
 | 
			
		||||
                                           parent_attr_id, child_attr_id)
 | 
			
		||||
 | 
			
		||||
        return self.jsonify(ctr_id=ctr_id)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user