clean sync class

This commit is contained in:
Cayo Puigdefabregas 2022-12-13 20:40:28 +01:00
parent da1feef746
commit 1b11162522

View file

@ -30,13 +30,6 @@ DEVICES_ALLOW_DUPLICITY = [
'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:
"""Synchronizes the device and components with the database."""
@ -74,18 +67,10 @@ class Sync:
of the passed-in components.
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)
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()
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
# non-computers with components
raise ValidationError('Only computers can have components.')
blacklist = set() # type: Set[int]
not_new_components = set()
for component in components:
db_component, is_new = self.execute_register_component(
component, blacklist, parent=db_device
)
db_component, is_new = self.execute_register_component(component)
db_components.add(db_component)
if not is_new:
not_new_components.add(db_component)
@ -109,9 +91,7 @@ class Sync:
self.create_placeholder(db_device)
return db_device, actions
def execute_register_component(
self, component: Component, blacklist: Set[int], parent: Computer
):
def execute_register_component(self, component: Component):
"""Synchronizes one component to the DB.
This method is a specialization of :meth:`.execute_register`
@ -141,30 +121,18 @@ class Sync:
is_new = True
return component, is_new
# if not, then continue with the traditional behaviour
try:
if component.hid:
db_component = Device.query.filter_by(
hid=component.hid, owner_id=g.user.id, placeholder=None
).one()
assert isinstance(
db_component, Device
), '{} must be a component'.format(db_component)
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:
if component.hid:
db_component = Device.query.filter_by(
hid=component.hid, owner_id=g.user.id, placeholder=None
).first()
assert isinstance(db_component, Device), '{} must be a component'.format(
db_component
)
is_new = False
else:
db.session.add(component)
# db.session.flush()
db_component = component
is_new = True
else:
self.merge(component, db_component)
is_new = False
return db_component, is_new
def execute_register(self, device: Device) -> Device:
@ -194,53 +162,15 @@ class Sync:
:raise DatabaseError: Any other error from the DB.
: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()
if db_device and db_device.allocated:
raise ResourceNotFound('device is actually allocated {}'.format(device))
try:
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
if not db_device:
device.tags.clear() # We don't want to add the transient dummy tags
db.session.add(device)
db_device = device
db_device.tags |= (
tags # Union of tags the device had plus the (potentially) new ones
)
try:
db.session.flush()
except IntegrityError as e:
@ -258,29 +188,6 @@ class Sync:
assert db_device is not None
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
def create_placeholder(device: Device):
"""If the device is new, we need create automaticaly a new placeholder"""