clean sync class

This commit is contained in:
Cayo Puigdefabregas 2022-12-13 20:40:28 +01:00
parent da1feef746
commit 1b11162522
1 changed files with 15 additions and 108 deletions

View File

@ -30,13 +30,6 @@ DEVICES_ALLOW_DUPLICITY = [
'GraphicCard', 'GraphicCard',
] ]
err_motherboard = "Error: We have detected that a there is a device"
err_motherboard += " in your inventory with this system UUID. "
err_motherboard += "We proceed to block this snapshot to prevent its"
err_motherboard += " information from being updated incorrectly."
err_motherboard += " The solution we offer you to inventory this device "
err_motherboard += "is to do it by creating a placeholder."
class Sync: class Sync:
"""Synchronizes the device and components with the database.""" """Synchronizes the device and components with the database."""
@ -74,18 +67,10 @@ class Sync:
of the passed-in components. of the passed-in components.
2. A list of Add / Remove (not yet added to session). 2. A list of Add / Remove (not yet added to session).
""" """
device.components = OrderedSet(components)
device.set_hid()
device.components = OrderedSet()
db_device = self.execute_register(device) db_device = self.execute_register(device)
motherboard = None
if components:
for c in components:
if c.type == "Motherboard":
motherboard = c
if motherboard:
for c in db_device.components:
if c.type == "Motherboard" and motherboard.hid != c.hid:
# import pdb; pdb.set_trace()
raise ValidationError(err_motherboard)
db_components, actions = OrderedSet(), OrderedSet() db_components, actions = OrderedSet(), OrderedSet()
if components is not None: # We have component info (see above) if components is not None: # We have component info (see above)
@ -93,12 +78,9 @@ class Sync:
# Until a good reason is given, we synthetically forbid # Until a good reason is given, we synthetically forbid
# non-computers with components # non-computers with components
raise ValidationError('Only computers can have components.') raise ValidationError('Only computers can have components.')
blacklist = set() # type: Set[int]
not_new_components = set() not_new_components = set()
for component in components: for component in components:
db_component, is_new = self.execute_register_component( db_component, is_new = self.execute_register_component(component)
component, blacklist, parent=db_device
)
db_components.add(db_component) db_components.add(db_component)
if not is_new: if not is_new:
not_new_components.add(db_component) not_new_components.add(db_component)
@ -109,9 +91,7 @@ class Sync:
self.create_placeholder(db_device) self.create_placeholder(db_device)
return db_device, actions return db_device, actions
def execute_register_component( def execute_register_component(self, component: Component):
self, component: Component, blacklist: Set[int], parent: Computer
):
"""Synchronizes one component to the DB. """Synchronizes one component to the DB.
This method is a specialization of :meth:`.execute_register` This method is a specialization of :meth:`.execute_register`
@ -141,30 +121,18 @@ class Sync:
is_new = True is_new = True
return component, is_new return component, is_new
# if not, then continue with the traditional behaviour
try:
if component.hid: if component.hid:
db_component = Device.query.filter_by( db_component = Device.query.filter_by(
hid=component.hid, owner_id=g.user.id, placeholder=None hid=component.hid, owner_id=g.user.id, placeholder=None
).one() ).first()
assert isinstance( assert isinstance(db_component, Device), '{} must be a component'.format(
db_component, Device db_component
), '{} must be a component'.format(db_component) )
is_new = False
else: else:
# Is there a component similar to ours?
db_component = component.similar_one(parent, blacklist)
# We blacklist this component so we
# ensure we don't get it again for another component
# with the same physical properties
blacklist.add(db_component.id)
except ResourceNotFound:
db.session.add(component) db.session.add(component)
# db.session.flush()
db_component = component db_component = component
is_new = True is_new = True
else:
self.merge(component, db_component)
is_new = False
return db_component, is_new return db_component, is_new
def execute_register(self, device: Device) -> Device: def execute_register(self, device: Device) -> Device:
@ -194,53 +162,15 @@ class Sync:
:raise DatabaseError: Any other error from the DB. :raise DatabaseError: Any other error from the DB.
:return: The synced device from the db with the tags linked. :return: The synced device from the db with the tags linked.
""" """
assert inspect(device).transient, 'Device cannot be already synced from DB'
assert all(
inspect(tag).transient for tag in device.tags
), 'Tags cannot be synced from DB'
db_device = device.get_from_db() db_device = device.get_from_db()
if db_device and db_device.allocated: if db_device and db_device.allocated:
raise ResourceNotFound('device is actually allocated {}'.format(device)) raise ResourceNotFound('device is actually allocated {}'.format(device))
try: if not db_device:
tags = {
Tag.from_an_id(tag.id).one() for tag in device.tags
} # type: Set[Tag]
except ResourceNotFound:
raise ResourceNotFound('tag you are linking to device {}'.format(device))
linked_tags = {tag for tag in tags if tag.device_id} # type: Set[Tag]
if linked_tags:
sample_tag = next(iter(linked_tags))
for tag in linked_tags:
if tag.device_id != sample_tag.device_id:
raise MismatchBetweenTags(
tag, sample_tag
) # Tags linked to different devices
if db_device: # Device from hid
if (
sample_tag.device_id != db_device.id
): # Device from hid != device from tags
raise MismatchBetweenTagsAndHid(db_device.id, db_device.hid)
else: # There was no device from hid
if sample_tag.device.physical_properties != device.physical_properties:
# Incoming physical props of device != props from tag's device
# which means that the devices are not the same
raise MismatchBetweenProperties(
sample_tag.device.physical_properties,
device.physical_properties,
)
db_device = sample_tag.device
if db_device: # Device from hid or tags
self.merge(device, db_device)
else: # Device is new and tags are not linked to a device
device.tags.clear() # We don't want to add the transient dummy tags device.tags.clear() # We don't want to add the transient dummy tags
db.session.add(device) db.session.add(device)
db_device = device db_device = device
db_device.tags |= (
tags # Union of tags the device had plus the (potentially) new ones
)
try: try:
db.session.flush() db.session.flush()
except IntegrityError as e: except IntegrityError as e:
@ -258,29 +188,6 @@ class Sync:
assert db_device is not None assert db_device is not None
return db_device return db_device
@staticmethod
def merge(device: Device, db_device: Device):
"""Copies the physical properties of the device to the db_device.
This method mutates db_device.
"""
if db_device.owner_id != g.user.id:
return
if device.placeholder and not db_device.placeholder:
return
for field_name, value in device.physical_properties.items():
if value is not None:
setattr(db_device, field_name, value)
# if device.system_uuid and db_device.system_uuid and device.system_uuid != db_device.system_uuid:
# TODO @cayop send error to sentry.io
# there are 2 computers duplicate get db_device for hid
if hasattr(device, 'system_uuid') and device.system_uuid:
db_device.system_uuid = device.system_uuid
@staticmethod @staticmethod
def create_placeholder(device: Device): def create_placeholder(device: Device):
"""If the device is new, we need create automaticaly a new placeholder""" """If the device is new, we need create automaticaly a new placeholder"""