/ci_types/<int:type_id>/attributes/transfer and /ci_types/<int:type_id>/attribute_groups/transfer

This commit is contained in:
pycook 2020-01-19 17:59:32 +08:00
parent 28ff27c019
commit 356cf58135
4 changed files with 180 additions and 2 deletions

1
.gitignore vendored
View File

@ -38,6 +38,7 @@ pip-log.txt
.tox .tox
nosetests.xml nosetests.xml
.pytest_cache .pytest_cache
cmdb-api/test-output
# Translations # Translations
*.mo *.mo

View File

@ -23,6 +23,7 @@ from api.models.cmdb import CITypeGroupItem
from api.models.cmdb import CITypeRelation from api.models.cmdb import CITypeRelation
from api.models.cmdb import PreferenceShowAttributes from api.models.cmdb import PreferenceShowAttributes
from api.models.cmdb import PreferenceTreeView from api.models.cmdb import PreferenceTreeView
from api.tasks.cmdb import ci_type_attribute_order_rebuild
class CITypeManager(object): class CITypeManager(object):
@ -55,16 +56,32 @@ class CITypeManager(object):
ci_type = CITypeCache.get(_type) or abort(404, "CIType <{0}> is not found".format(_type)) ci_type = CITypeCache.get(_type) or abort(404, "CIType <{0}> is not found".format(_type))
return ci_type.to_dict() return ci_type.to_dict()
@staticmethod
def _validate_unique(type_id=None, name=None, alias=None):
if name is not None:
ci_type = CIType.get_by(name=name, first=True, to_dict=False)
elif alias is not None:
ci_type = CIType.get_by(alias=alias, first=True, to_dict=False)
else:
return
if type_id is not None and ci_type.id != type_id:
return abort(400, "CIType <{0}> is already existed".format(name or alias))
if type_id is None and ci_type is not None:
return abort(400, "CIType <{0}> is already existed".format(name or alias))
@classmethod @classmethod
@kwargs_required("name") @kwargs_required("name")
def add(cls, **kwargs): def add(cls, **kwargs):
unique_key = kwargs.pop("unique_key", None) unique_key = kwargs.pop("unique_key", None)
unique_key = AttributeCache.get(unique_key) or abort(404, "Unique key is not defined") unique_key = AttributeCache.get(unique_key) or abort(404, "Unique key is not defined")
CIType.get_by(name=kwargs['name']) and abort(404, "CIType <{0}> is already existed".format(kwargs.get("name")))
kwargs["alias"] = kwargs["name"] if not kwargs.get("alias") else kwargs["alias"] kwargs["alias"] = kwargs["name"] if not kwargs.get("alias") else kwargs["alias"]
cls._validate_unique(name=kwargs['name'])
cls._validate_unique(alias=kwargs['alias'])
kwargs["unique_id"] = unique_key.id kwargs["unique_id"] = unique_key.id
ci_type = CIType.create(**kwargs) ci_type = CIType.create(**kwargs)
@ -88,6 +105,9 @@ class CITypeManager(object):
ci_type = cls.check_is_existed(type_id) ci_type = cls.check_is_existed(type_id)
cls._validate_unique(type_id=type_id, name=kwargs.get('name'))
cls._validate_unique(type_id=type_id, alias=kwargs.get('alias'))
unique_key = kwargs.pop("unique_key", None) unique_key = kwargs.pop("unique_key", None)
unique_key = AttributeCache.get(unique_key) unique_key = AttributeCache.get(unique_key)
if unique_key is not None: if unique_key is not None:
@ -305,6 +325,31 @@ class CITypeAttributeManager(object):
CITypeAttributesCache.clean(type_id) CITypeAttributesCache.clean(type_id)
@classmethod
def transfer(cls, type_id, _from, _to):
current_app.logger.info("[{0}] {1} -> {2}".format(type_id, _from, _to))
attr_id = _from.get('attr_id')
from_group_id = _from.get('group_id')
to_group_id = _to.get('group_id')
order = _to.get('order')
if from_group_id != to_group_id:
if from_group_id is not None:
CITypeAttributeGroupManager.delete_item(from_group_id, attr_id)
if to_group_id is not None:
CITypeAttributeGroupManager.add_item(to_group_id, attr_id, order)
elif from_group_id:
CITypeAttributeGroupManager.update_item(from_group_id, attr_id, order)
else: # other attribute transfer
return abort(400, "invalid operation!!!")
CITypeAttributesCache.clean(type_id)
ci_type_attribute_order_rebuild.apply_async(args=(type_id,), queue=CMDB_QUEUE)
class CITypeRelationManager(object): class CITypeRelationManager(object):
""" """
@ -455,3 +500,86 @@ class CITypeAttributeGroupManager(object):
item.soft_delete() item.soft_delete()
return group_id return group_id
@classmethod
def add_item(cls, group_id, attr_id, order):
db.session.remove()
existed = CITypeAttributeGroupItem.get_by(group_id=group_id,
attr_id=attr_id,
first=True,
to_dict=False)
if existed is not None:
existed.update(order=order)
else:
CITypeAttributeGroupItem.create(group_id=group_id, attr_id=attr_id, order=order)
gt_items = db.session.query(CITypeAttributeGroupItem).filter(
CITypeAttributeGroupItem.deleted.is_(False)).filter(CITypeAttributeGroupItem.order > order)
for _item in gt_items:
_order = _item.order
_item.update(order=_order + 1)
@classmethod
def update_item(cls, group_id, attr_id, order):
db.session.remove()
existed = CITypeAttributeGroupItem.get_by(group_id=group_id,
attr_id=attr_id,
first=True,
to_dict=False)
existed or abort(404, "Group<{0}> - Attribute<{1}> is not found".format(group_id, attr_id))
if existed.order > order: # forward, +1
items = db.session.query(CITypeAttributeGroupItem).filter(
CITypeAttributeGroupItem.deleted.is_(False)).filter(
CITypeAttributeGroupItem.order >= order).filter(
CITypeAttributeGroupItem.order < existed.order)
for item in items:
item.update(order=item.order + 1)
elif existed.order < order: # backward, -1
items = db.session.query(CITypeAttributeGroupItem).filter(
CITypeAttributeGroupItem.deleted.is_(False)).filter(
CITypeAttributeGroupItem.order > existed.order).filter(
CITypeAttributeGroupItem.order <= order)
for item in items:
item.update(order=item.order - 1)
existed.update(order=order)
@classmethod
def delete_item(cls, group_id, attr_id):
db.session.remove()
item = CITypeAttributeGroupItem.get_by(group_id=group_id,
attr_id=attr_id,
first=True,
to_dict=False)
if item is not None:
item.soft_delete()
order = item.order
gt_items = db.session.query(CITypeAttributeGroupItem).filter(
CITypeAttributeGroupItem.deleted.is_(False)).filter(CITypeAttributeGroupItem.order > order)
for _item in gt_items:
_order = _item.order
_item.update(order=_order - 1)
@classmethod
def transfer(cls, type_id, _from, _to):
current_app.logger.info("CIType[{0}] {1} -> {2}".format(type_id, _from, _to))
from_group = CITypeAttributeGroup.get_by_id(_from)
from_group or abort(404, "Group <{0}> is not found".format(_from))
to_group = CITypeAttributeGroup.get_by_id(_to)
to_group or abort(404, "Group <{0}> is not found".format(_to))
from_order, to_order = from_group.order, to_group.order
from_group.update(order=to_order)
to_group.update(order=from_order)
CITypeAttributesCache.clean(type_id)
ci_type_attribute_order_rebuild.apply_async(args=(type_id,), queue=CMDB_QUEUE)

View File

@ -11,6 +11,7 @@ from api.extensions import celery
from api.extensions import db from api.extensions import db
from api.extensions import es from api.extensions import es
from api.extensions import rd from api.extensions import rd
from api.lib.cmdb.cache import CITypeAttributeCache
from api.lib.cmdb.const import CMDB_QUEUE from api.lib.cmdb.const import CMDB_QUEUE
from api.lib.cmdb.const import REDIS_PREFIX_CI from api.lib.cmdb.const import REDIS_PREFIX_CI
from api.lib.cmdb.const import REDIS_PREFIX_CI_RELATION from api.lib.cmdb.const import REDIS_PREFIX_CI_RELATION
@ -71,3 +72,23 @@ def ci_relation_delete(parent_id, child_id):
rd.create_or_update({parent_id: json.dumps(children)}, REDIS_PREFIX_CI_RELATION) rd.create_or_update({parent_id: json.dumps(children)}, REDIS_PREFIX_CI_RELATION)
current_app.logger.info("DELETE ci relation cache: {0} -> {1}".format(parent_id, child_id)) current_app.logger.info("DELETE ci relation cache: {0} -> {1}".format(parent_id, child_id))
@celery.task(name="cmdb.ci_type_attribute_order_rebuild", queue=CMDB_QUEUE)
def ci_type_attribute_order_rebuild(type_id):
current_app.logger.info('rebuild attribute order')
db.session.remove()
from api.lib.cmdb.ci_type import CITypeAttributeGroupManager
attrs = CITypeAttributeCache.get(type_id)
id2attr = {attr.attr_id: attr for attr in attrs}
res = CITypeAttributeGroupManager.get_by_type_id(type_id, True)
order = 0
for group in res:
for _attr in group.get('attributes'):
if order != id2attr.get(_attr['id']) and id2attr.get(_attr['id']):
id2attr.get(_attr['id']).update(order=order)
order += 1

View File

@ -164,6 +164,34 @@ class CITypeAttributeView(APIView):
return self.jsonify(attributes=attr_id_list) return self.jsonify(attributes=attr_id_list)
class CITypeAttributeTransferView(APIView):
url_prefix = "/ci_types/<int:type_id>/attributes/transfer"
@args_required('from')
@args_required('to')
def post(self, type_id):
_from = request.values.get('from') # {'attr_id': xx, 'group_id': xx}
_to = request.values.get('to') # {'group_id': xx, 'order': xxx}
CITypeAttributeManager.transfer(type_id, _from, _to)
return self.jsonify(code=200)
class CITypeAttributeGroupTransferView(APIView):
url_prefix = "/ci_types/<int:type_id>/attribute_groups/transfer"
@args_required('from')
@args_required('to')
def post(self, type_id):
_from = request.values.get('from') # group_id
_to = request.values.get('to') # group_id
CITypeAttributeGroupManager.transfer(type_id, _from, _to)
return self.jsonify(code=200)
class CITypeAttributeGroupView(APIView): class CITypeAttributeGroupView(APIView):
url_prefix = ("/ci_types/<int:type_id>/attribute_groups", url_prefix = ("/ci_types/<int:type_id>/attribute_groups",
"/ci_types/attribute_groups/<int:group_id>") "/ci_types/attribute_groups/<int:group_id>")