/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
nosetests.xml
.pytest_cache
cmdb-api/test-output
# Translations
*.mo

View File

@ -23,6 +23,7 @@ from api.models.cmdb import CITypeGroupItem
from api.models.cmdb import CITypeRelation
from api.models.cmdb import PreferenceShowAttributes
from api.models.cmdb import PreferenceTreeView
from api.tasks.cmdb import ci_type_attribute_order_rebuild
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))
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
@kwargs_required("name")
def add(cls, **kwargs):
unique_key = kwargs.pop("unique_key", None)
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"]
cls._validate_unique(name=kwargs['name'])
cls._validate_unique(alias=kwargs['alias'])
kwargs["unique_id"] = unique_key.id
ci_type = CIType.create(**kwargs)
@ -88,6 +105,9 @@ class CITypeManager(object):
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 = AttributeCache.get(unique_key)
if unique_key is not None:
@ -305,6 +325,31 @@ class CITypeAttributeManager(object):
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):
"""
@ -455,3 +500,86 @@ class CITypeAttributeGroupManager(object):
item.soft_delete()
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 es
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 REDIS_PREFIX_CI
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)
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)
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):
url_prefix = ("/ci_types/<int:type_id>/attribute_groups",
"/ci_types/attribute_groups/<int:group_id>")