resolve conflict
This commit is contained in:
commit
e598f8aabe
|
@ -75,7 +75,7 @@ class InventoryView(LoginMixin, SnapshotMixin):
|
|||
self.response = jsonify(
|
||||
{
|
||||
'url': snapshot.device.url.to_text(),
|
||||
'dhid': snapshot.device.devicehub_id,
|
||||
'dhid': snapshot.device.dhid,
|
||||
'sid': snapshot.sid,
|
||||
}
|
||||
)
|
||||
|
|
|
@ -110,7 +110,13 @@ class AdvancedSearchForm(FlaskForm):
|
|||
self.search(dhids)
|
||||
|
||||
def search(self, dhids):
|
||||
self.devices = Device.query.filter(Device.devicehub_id.in_(dhids))
|
||||
query = Device.query.filter(Device.owner_id == g.user.id)
|
||||
self.devices = query.join(Device.placeholder).filter(
|
||||
or_(
|
||||
Device.devicehub_id.in_(dhids),
|
||||
Placeholder.phid.in_(dhids),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class FilterForm(FlaskForm):
|
||||
|
@ -137,11 +143,11 @@ class FilterForm(FlaskForm):
|
|||
self.lot = self.lots.filter(Lot.id == self.lot_id).one()
|
||||
device_ids = (d.id for d in self.lot.devices)
|
||||
self.devices = Device.query.filter(Device.id.in_(device_ids)).filter(
|
||||
Device.binding == None
|
||||
Device.binding == None # noqa: E711
|
||||
)
|
||||
else:
|
||||
self.devices = Device.query.filter(Device.owner_id == g.user.id).filter(
|
||||
Device.binding == None
|
||||
Device.binding == None # noqa: E711
|
||||
)
|
||||
if self.only_unassigned:
|
||||
self.devices = self.devices.filter_by(lots=None)
|
||||
|
@ -364,18 +370,6 @@ class NewDeviceForm(FlaskForm):
|
|||
if not self.generation.data:
|
||||
self.generation.data = 1
|
||||
|
||||
if not self.weight.data:
|
||||
self.weight.data = 0.1
|
||||
|
||||
if not self.height.data:
|
||||
self.height.data = 0.1
|
||||
|
||||
if not self.width.data:
|
||||
self.width.data = 0.1
|
||||
|
||||
if not self.depth.data:
|
||||
self.depth.data = 0.1
|
||||
|
||||
def reset_from_obj(self):
|
||||
if not self._obj:
|
||||
return
|
||||
|
@ -449,24 +443,28 @@ class NewDeviceForm(FlaskForm):
|
|||
error = ["Not a correct value"]
|
||||
is_valid = super().validate(extra_validators)
|
||||
|
||||
if self.generation.data < 1:
|
||||
if self.generation.data and self.generation.data < 1:
|
||||
self.generation.errors = error
|
||||
is_valid = False
|
||||
|
||||
if self.weight.data < 0.1:
|
||||
self.weight.errors = error
|
||||
if self.weight.data and not (0.1 <= self.weight.data <= 5):
|
||||
txt = ["Supported values between 0.1 and 5"]
|
||||
self.weight.errors = txt
|
||||
is_valid = False
|
||||
|
||||
if self.height.data < 0.1:
|
||||
self.height.errors = error
|
||||
if self.height.data and not (0.1 <= self.height.data <= 5):
|
||||
txt = ["Supported values between 0.1 and 5"]
|
||||
self.height.errors = txt
|
||||
is_valid = False
|
||||
|
||||
if self.width.data < 0.1:
|
||||
self.width.errors = error
|
||||
if self.width.data and not (0.1 <= self.width.data <= 5):
|
||||
txt = ["Supported values between 0.1 and 5"]
|
||||
self.width.errors = txt
|
||||
is_valid = False
|
||||
|
||||
if self.depth.data < 0.1:
|
||||
self.depth.errors = error
|
||||
if self.depth.data and not (0.1 <= self.depth.data <= 5):
|
||||
txt = ["Supported values between 0.1 and 5"]
|
||||
self.depth.errors = txt
|
||||
is_valid = False
|
||||
|
||||
if self.imei.data and self.amount.data == 1:
|
||||
|
@ -655,19 +653,30 @@ class NewDeviceForm(FlaskForm):
|
|||
|
||||
|
||||
class TagDeviceForm(FlaskForm):
|
||||
tag = SelectField('Tag', choices=[])
|
||||
device = StringField('Device', [validators.Optional()])
|
||||
tag = SelectField(
|
||||
'Tag',
|
||||
choices=[],
|
||||
render_kw={
|
||||
'class': 'form-control selectpicker',
|
||||
'data-live-search': 'true',
|
||||
},
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.delete = kwargs.pop('delete', None)
|
||||
self.device_id = kwargs.pop('device', None)
|
||||
self.dhid = kwargs.pop('dhid', None)
|
||||
self._device = (
|
||||
Device.query.filter(Device.devicehub_id == self.dhid)
|
||||
.filter(Device.owner_id == g.user.id)
|
||||
.one()
|
||||
)
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
if self.delete:
|
||||
tags = (
|
||||
Tag.query.filter(Tag.owner_id == g.user.id)
|
||||
.filter_by(device_id=self.device_id)
|
||||
.filter_by(device_id=self._device.id)
|
||||
.order_by(Tag.id)
|
||||
)
|
||||
else:
|
||||
|
@ -695,20 +704,6 @@ class TagDeviceForm(FlaskForm):
|
|||
self.tag.errors = [("This tag is actualy in use.")]
|
||||
return False
|
||||
|
||||
if self.device.data:
|
||||
try:
|
||||
self.device.data = int(self.device.data.split(',')[-1])
|
||||
except: # noqa: E722
|
||||
self.device.data = None
|
||||
|
||||
if self.device_id or self.device.data:
|
||||
self.device_id = self.device_id or self.device.data
|
||||
self._device = (
|
||||
Device.query.filter(Device.id == self.device_id)
|
||||
.filter(Device.owner_id == g.user.id)
|
||||
.one()
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
def save(self):
|
||||
|
@ -1667,8 +1662,8 @@ class BindingForm(FlaskForm):
|
|||
self.phid.errors = [txt]
|
||||
return False
|
||||
|
||||
if self.device.is_abstract() != 'Abstract':
|
||||
txt = "This is not a abstract device."
|
||||
if self.device.is_abstract() not in ['Abstract', 'Real']:
|
||||
txt = "This is not a Abstract or Real device."
|
||||
self.phid.errors = [txt]
|
||||
return False
|
||||
|
||||
|
@ -1682,7 +1677,7 @@ class BindingForm(FlaskForm):
|
|||
self.phid.errors = [txt]
|
||||
return False
|
||||
|
||||
if self.placeholder.binding:
|
||||
if self.placeholder.status not in ['Abstract', 'Real']:
|
||||
txt = "This placeholder have a binding with other device. "
|
||||
txt += "Before you need to do an unbinding with this other device."
|
||||
self.phid.errors = [txt]
|
||||
|
|
|
@ -80,7 +80,6 @@ class DeviceListMixin(GenericMixin):
|
|||
self.context.update(
|
||||
{
|
||||
'devices': devices,
|
||||
'form_tag_device': TagDeviceForm(),
|
||||
'form_new_action': form_new_action,
|
||||
'form_new_allocate': AllocateForm(lot=lot_id),
|
||||
'form_new_datawipe': DataWipeForm(lot=lot_id),
|
||||
|
@ -148,27 +147,51 @@ class DeviceDetailView(GenericMixin):
|
|||
.one()
|
||||
)
|
||||
|
||||
form_binding = BindingForm(device=device)
|
||||
|
||||
form_tags = TagDeviceForm(dhid=id)
|
||||
self.context.update(
|
||||
{
|
||||
'device': device,
|
||||
'placeholder': device.binding or device.placeholder,
|
||||
'page_title': 'Device {}'.format(device.devicehub_id),
|
||||
'form_tag_device': form_tags,
|
||||
}
|
||||
)
|
||||
|
||||
return flask.render_template(self.template_name, **self.context)
|
||||
|
||||
|
||||
class BindingSearchView(GenericMixin):
|
||||
methods = ['GET', 'POST']
|
||||
decorators = [login_required]
|
||||
template_name = 'inventory/binding_search.html'
|
||||
|
||||
def dispatch_request(self, dhid):
|
||||
self.get_context()
|
||||
device = (
|
||||
Device.query.filter(Device.owner_id == current_user.id)
|
||||
.filter(Device.devicehub_id == dhid)
|
||||
.one()
|
||||
)
|
||||
|
||||
form_binding = BindingForm(device=device)
|
||||
|
||||
self.context.update(
|
||||
{
|
||||
'page_title': 'Search a Device for to do a binding from {}'.format(
|
||||
device.devicehub_id
|
||||
),
|
||||
'form_binding': form_binding,
|
||||
'active_binding': False,
|
||||
'device': device,
|
||||
}
|
||||
)
|
||||
|
||||
if form_binding.validate_on_submit():
|
||||
next_url = url_for(
|
||||
'inventory.binding',
|
||||
dhid=form_binding.device.devicehub_id,
|
||||
dhid=dhid,
|
||||
phid=form_binding.placeholder.phid,
|
||||
)
|
||||
return flask.redirect(next_url)
|
||||
elif form_binding.phid.data:
|
||||
self.context['active_binding'] = True
|
||||
|
||||
return flask.render_template(self.template_name, **self.context)
|
||||
|
||||
|
@ -179,71 +202,113 @@ class BindingView(GenericMixin):
|
|||
template_name = 'inventory/binding.html'
|
||||
|
||||
def dispatch_request(self, dhid, phid):
|
||||
self.phid = phid
|
||||
self.dhid = dhid
|
||||
self.next_url = url_for('inventory.device_details', id=dhid)
|
||||
self.get_context()
|
||||
device = (
|
||||
Device.query.filter(Device.owner_id == g.user.id)
|
||||
.filter(Device.devicehub_id == dhid)
|
||||
.one()
|
||||
)
|
||||
placeholder = (
|
||||
Placeholder.query.filter(Placeholder.owner_id == g.user.id)
|
||||
.filter(Placeholder.phid == phid)
|
||||
.one()
|
||||
)
|
||||
|
||||
if device.is_abstract() != 'Abstract':
|
||||
next_url = url_for('inventory.device_details', id=dhid)
|
||||
messages.error('Device "{}" not is a Abstract device!'.format(dhid))
|
||||
return flask.redirect(next_url)
|
||||
|
||||
if device.placeholder:
|
||||
device = device.placeholder.binding
|
||||
dhid = device.devicehub_id
|
||||
self.get_objects()
|
||||
if self.check_errors():
|
||||
return flask.redirect(self.next_url)
|
||||
|
||||
if request.method == 'POST':
|
||||
old_placeholder = device.binding
|
||||
old_device_placeholder = old_placeholder.device
|
||||
|
||||
if old_placeholder.is_abstract:
|
||||
for plog in PlaceholdersLog.query.filter_by(
|
||||
placeholder_id=old_placeholder.id
|
||||
):
|
||||
db.session.delete(plog)
|
||||
|
||||
for ac in old_device_placeholder.actions:
|
||||
ac.devices.add(placeholder.device)
|
||||
ac.devices.remove(old_device_placeholder)
|
||||
for act in ac.actions_device:
|
||||
if act.device == old_device_placeholder:
|
||||
db.session.delete(act)
|
||||
|
||||
for tag in list(old_device_placeholder.tags):
|
||||
tag.device = placeholder.device
|
||||
|
||||
db.session.delete(old_device_placeholder)
|
||||
|
||||
device.binding = placeholder
|
||||
db.session.commit()
|
||||
next_url = url_for('inventory.device_details', id=dhid)
|
||||
messages.success(
|
||||
'Device "{}" bind successfully with {}!'.format(dhid, phid)
|
||||
)
|
||||
return flask.redirect(next_url)
|
||||
return self.post()
|
||||
|
||||
self.context.update(
|
||||
{
|
||||
'device': device.binding.device,
|
||||
'placeholder': placeholder,
|
||||
'new_placeholder': self.new_placeholder,
|
||||
'old_placeholder': self.old_placeholder,
|
||||
'page_title': 'Binding confirm',
|
||||
'actions': list(device.binding.device.actions)
|
||||
+ list(placeholder.device.actions),
|
||||
'tags': list(device.binding.device.tags)
|
||||
+ list(placeholder.device.tags),
|
||||
'actions': list(self.old_device.actions)
|
||||
+ list(self.new_device.actions),
|
||||
'tags': list(self.old_device.tags) + list(self.new_device.tags),
|
||||
'dhid': self.dhid,
|
||||
}
|
||||
)
|
||||
|
||||
return flask.render_template(self.template_name, **self.context)
|
||||
|
||||
def check_errors(self):
|
||||
if not self.new_placeholder:
|
||||
messages.error('Device Phid: "{}" not exist!'.format(self.phid))
|
||||
return True
|
||||
|
||||
if self.old_device.placeholder.status != 'Abstract':
|
||||
messages.error(
|
||||
'Device Dhid: "{}" is not a Abstract device!'.format(self.dhid)
|
||||
)
|
||||
return True
|
||||
|
||||
if self.new_placeholder.status == 'Twin':
|
||||
messages.error('Device Phid: "{}" is a Twin device!'.format(self.phid))
|
||||
return True
|
||||
|
||||
if self.new_placeholder.status == self.old_placeholder.status:
|
||||
txt = 'Device Phid: "{}" and device Dhid: "{}" have the same status, "{}"!'.format(
|
||||
self.phid, self.dhid, self.new_placeholder.status
|
||||
)
|
||||
messages.error(txt)
|
||||
return True
|
||||
|
||||
def get_objects(self):
|
||||
self.old_device = (
|
||||
Device.query.filter(Device.owner_id == g.user.id)
|
||||
.filter(Device.devicehub_id == self.dhid)
|
||||
.one()
|
||||
)
|
||||
self.new_placeholder = (
|
||||
Placeholder.query.filter(Placeholder.owner_id == g.user.id)
|
||||
.filter(Placeholder.phid == self.phid)
|
||||
.first()
|
||||
)
|
||||
|
||||
if not self.new_placeholder:
|
||||
return
|
||||
|
||||
if self.old_device.placeholder.status == 'Abstract':
|
||||
self.new_device = self.new_placeholder.device
|
||||
self.old_placeholder = self.old_device.placeholder
|
||||
elif self.old_device.placeholder.status == 'Real':
|
||||
self.new_device = self.old_device
|
||||
self.old_placeholder = self.new_placeholder
|
||||
self.old_device = self.old_placeholder.device
|
||||
self.new_placeholder = self.new_device.placeholder
|
||||
|
||||
self.abstract_device = self.old_placeholder.binding
|
||||
self.real_dhid = self.new_device.devicehub_id
|
||||
self.real_phid = self.new_placeholder.phid
|
||||
self.abstract_dhid = self.old_device.devicehub_id
|
||||
self.abstract_phid = self.old_placeholder.phid
|
||||
|
||||
def post(self):
|
||||
for plog in PlaceholdersLog.query.filter_by(
|
||||
placeholder_id=self.old_placeholder.id
|
||||
):
|
||||
db.session.delete(plog)
|
||||
|
||||
for ac in self.old_device.actions:
|
||||
ac.devices.add(self.new_device)
|
||||
ac.devices.remove(self.old_device)
|
||||
for act in ac.actions_device:
|
||||
if act.device == self.old_device:
|
||||
db.session.delete(act)
|
||||
|
||||
for tag in list(self.old_device.tags):
|
||||
tag.device = self.new_device
|
||||
|
||||
db.session.delete(self.old_device)
|
||||
self.abstract_device.binding = self.new_placeholder
|
||||
db.session.commit()
|
||||
|
||||
next_url = url_for('inventory.device_details', id=self.real_dhid)
|
||||
txt = 'Device real with PHID: {} and DHID: {} bind successfully with '
|
||||
txt += 'device abstract PHID: {} DHID: {}.'
|
||||
messages.success(
|
||||
txt.format(
|
||||
self.real_phid, self.real_dhid, self.abstract_phid, self.abstract_dhid
|
||||
)
|
||||
)
|
||||
return flask.redirect(next_url)
|
||||
|
||||
|
||||
class UnBindingView(GenericMixin):
|
||||
methods = ['GET', 'POST']
|
||||
|
@ -256,31 +321,33 @@ class UnBindingView(GenericMixin):
|
|||
.filter(Placeholder.phid == phid)
|
||||
.one()
|
||||
)
|
||||
if not placeholder.binding:
|
||||
if not placeholder.binding or placeholder.status != 'Twin':
|
||||
next_url = url_for(
|
||||
'inventory.device_details', id=placeholder.device.devicehub_id
|
||||
)
|
||||
return flask.redirect(next_url)
|
||||
|
||||
device = placeholder.binding
|
||||
|
||||
if device.is_abstract() != 'Twin':
|
||||
dhid = device.devicehub_id
|
||||
if placeholder.status != 'Twin':
|
||||
dhid = placeholder.device.devicehub_id
|
||||
next_url = url_for('inventory.device_details', id=dhid)
|
||||
messages.error('Device "{}" not is a Twin device!'.format(dhid))
|
||||
messages.error('Device Dhid: "{}" not is a Twin device!'.format(dhid))
|
||||
return flask.redirect(next_url)
|
||||
|
||||
self.get_context()
|
||||
|
||||
if request.method == 'POST':
|
||||
new_device = self.clone_device(device)
|
||||
next_url = url_for('inventory.device_details', id=new_device.devicehub_id)
|
||||
messages.success('Device "{}" unbind successfully!'.format(phid))
|
||||
dhid = placeholder.device.devicehub_id
|
||||
self.clone_device(placeholder.binding)
|
||||
next_url = url_for('inventory.device_details', id=dhid)
|
||||
messages.success(
|
||||
'Device with PHID:"{}" and DHID: {} unbind successfully!'.format(
|
||||
phid, dhid
|
||||
)
|
||||
)
|
||||
return flask.redirect(next_url)
|
||||
|
||||
self.context.update(
|
||||
{
|
||||
'device': device,
|
||||
'placeholder': placeholder,
|
||||
'page_title': 'Unbinding confirm',
|
||||
}
|
||||
|
@ -476,12 +543,15 @@ class TagLinkDeviceView(View):
|
|||
methods = ['POST']
|
||||
decorators = [login_required]
|
||||
|
||||
def dispatch_request(self):
|
||||
form = TagDeviceForm()
|
||||
def dispatch_request(self, dhid):
|
||||
form = TagDeviceForm(dhid=dhid)
|
||||
if form.validate_on_submit():
|
||||
tag = form.tag.data
|
||||
form.save()
|
||||
|
||||
return flask.redirect(request.referrer)
|
||||
next_url = url_for('inventory.device_details', id=dhid)
|
||||
messages.success('Tag {} was linked successfully!'.format(tag))
|
||||
return flask.redirect(next_url)
|
||||
|
||||
|
||||
class TagUnlinkDeviceView(GenericMixin):
|
||||
|
@ -489,19 +559,20 @@ class TagUnlinkDeviceView(GenericMixin):
|
|||
decorators = [login_required]
|
||||
template_name = 'inventory/tag_unlink_device.html'
|
||||
|
||||
def dispatch_request(self, id):
|
||||
def dispatch_request(self, dhid):
|
||||
self.get_context()
|
||||
form = TagDeviceForm(delete=True, device=id)
|
||||
form = TagDeviceForm(delete=True, dhid=dhid)
|
||||
if form.validate_on_submit():
|
||||
form.remove()
|
||||
|
||||
next_url = url_for('inventory.devicelist')
|
||||
next_url = url_for('inventory.device_details', id=dhid)
|
||||
messages.success('Tag {} was unlinked successfully!'.format(form.tag.data))
|
||||
return flask.redirect(next_url)
|
||||
|
||||
self.context.update(
|
||||
{
|
||||
'form': form,
|
||||
'referrer': request.referrer,
|
||||
'dhid': dhid,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -1145,10 +1216,11 @@ devices.add_url_rule(
|
|||
'/device/edit/<string:id>/', view_func=DeviceEditView.as_view('device_edit')
|
||||
)
|
||||
devices.add_url_rule(
|
||||
'/tag/devices/add/', view_func=TagLinkDeviceView.as_view('tag_devices_add')
|
||||
'/tag/devices/<string:dhid>/add/',
|
||||
view_func=TagLinkDeviceView.as_view('tag_devices_add'),
|
||||
)
|
||||
devices.add_url_rule(
|
||||
'/tag/devices/<int:id>/del/',
|
||||
'/tag/devices/<string:dhid>/del/',
|
||||
view_func=TagUnlinkDeviceView.as_view('tag_devices_del'),
|
||||
)
|
||||
devices.add_url_rule(
|
||||
|
@ -1192,3 +1264,7 @@ devices.add_url_rule(
|
|||
devices.add_url_rule(
|
||||
'/unbinding/<string:phid>/', view_func=UnBindingView.as_view('unbinding')
|
||||
)
|
||||
devices.add_url_rule(
|
||||
'/device/<string:dhid>/binding/',
|
||||
view_func=BindingSearchView.as_view('binding_search'),
|
||||
)
|
||||
|
|
|
@ -63,6 +63,9 @@ def clone_device(device):
|
|||
|
||||
if device.type == "Battery":
|
||||
device.size
|
||||
|
||||
old_devicehub_id = device.devicehub_id
|
||||
|
||||
dict_device = copy.copy(device.__dict__)
|
||||
dict_device.pop('_sa_instance_state')
|
||||
dict_device.pop('id', None)
|
||||
|
@ -73,6 +76,8 @@ def clone_device(device):
|
|||
dict_device.pop('tags', None)
|
||||
dict_device.pop('system_uuid', None)
|
||||
new_device = device.__class__(**dict_device)
|
||||
new_device.devicehub_id = old_devicehub_id
|
||||
device.devicehub_id = None
|
||||
db.session.add(new_device)
|
||||
|
||||
if hasattr(device, 'components'):
|
||||
|
|
|
@ -330,7 +330,7 @@ class Device(Thing):
|
|||
@property
|
||||
def url(self) -> urlutils.URL:
|
||||
"""The URL where to GET this device."""
|
||||
return urlutils.URL(url_for_resource(Device, item_id=self.devicehub_id))
|
||||
return urlutils.URL(url_for_resource(Device, item_id=self.dhid))
|
||||
|
||||
@property
|
||||
def rate(self):
|
||||
|
@ -615,6 +615,14 @@ class Device(Thing):
|
|||
model = self.model or ''
|
||||
return f'{type} {manufacturer} {model}'
|
||||
|
||||
@property
|
||||
def dhid(self):
|
||||
if self.placeholder:
|
||||
return self.placeholder.device.devicehub_id
|
||||
if self.binding:
|
||||
return self.binding.device.devicehub_id
|
||||
return self.devicehub_id
|
||||
|
||||
@declared_attr
|
||||
def __mapper_args__(cls):
|
||||
"""Defines inheritance.
|
||||
|
@ -924,6 +932,25 @@ class Placeholder(Thing):
|
|||
)
|
||||
owner = db.relationship(User, primaryjoin=owner_id == User.id)
|
||||
|
||||
@property
|
||||
def actions(self):
|
||||
actions = list(self.device.actions) or []
|
||||
|
||||
if self.binding:
|
||||
actions.extend(list(self.binding.actions))
|
||||
|
||||
actions = sorted(actions, key=lambda x: x.created)
|
||||
actions.reverse()
|
||||
return actions
|
||||
|
||||
@property
|
||||
def status(self):
|
||||
if self.is_abstract:
|
||||
return 'Abstract'
|
||||
if self.binding:
|
||||
return 'Twin'
|
||||
return 'Real'
|
||||
|
||||
|
||||
class Computer(Device):
|
||||
"""A chassis with components inside that can be processed
|
||||
|
@ -1022,10 +1049,14 @@ class Computer(Device):
|
|||
"""Returns the privacy of all ``DataStorage`` components when
|
||||
it is not None.
|
||||
"""
|
||||
components = self.components
|
||||
if self.placeholder and self.placeholder.binding:
|
||||
components = self.placeholder.binding.components
|
||||
|
||||
return set(
|
||||
privacy
|
||||
for privacy in (
|
||||
hdd.privacy for hdd in self.components if isinstance(hdd, DataStorage)
|
||||
hdd.privacy for hdd in components if isinstance(hdd, DataStorage)
|
||||
)
|
||||
if privacy
|
||||
)
|
||||
|
|
|
@ -114,7 +114,7 @@ class Device(Thing):
|
|||
sku = SanitizedStr(description=m.Device.sku.comment)
|
||||
image = URL(description=m.Device.image.comment)
|
||||
allocated = Boolean(description=m.Device.allocated.comment)
|
||||
devicehub_id = SanitizedStr(
|
||||
dhid = SanitizedStr(
|
||||
data_key='devicehubID', description=m.Device.devicehub_id.comment
|
||||
)
|
||||
|
||||
|
|
|
@ -41,8 +41,8 @@
|
|||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="page-header col-md-6 col-md-offset-3">
|
||||
<h1>{{ device.__format__('t') }}<br>
|
||||
<small>{{ device.__format__('s') }}</small>
|
||||
<h1>{% if abstract %}Real device {% endif %}{{ device.__format__('t') or '' }}<br>
|
||||
<small>{{ device.__format__('s') or '' }}</small>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -52,7 +52,7 @@
|
|||
<div class="col-md-6">
|
||||
<ul>
|
||||
{% for key, value in device.public_properties.items() %}
|
||||
<li>{{ key }}: {{ value }}</li>
|
||||
<li>{{ key }}: {{ value or '' }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% if isinstance(device, d.Computer) %}
|
||||
|
@ -140,17 +140,6 @@
|
|||
<td></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if device.rate %}
|
||||
<tr class="active">
|
||||
<td class="text-right">
|
||||
Total rate
|
||||
</td>
|
||||
<td>
|
||||
{{ device.rate.rating_range }}
|
||||
({{ device.rate.rating }})
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -222,6 +211,181 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if abstract %}
|
||||
<div class="row">
|
||||
<div class="page-header col-md-6 col-md-offset-3">
|
||||
<hr />
|
||||
<h1>Abstract device {{ abstract.__format__('t') or '' }}<br>
|
||||
<small>{{ abstract.__format__('s') or '' }}</small>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<ul>
|
||||
{% for key, value in abstract.public_properties.items() %}
|
||||
<li>{{ key }}: {{ value or '' }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% if isinstance(abstract, d.Computer) %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Range</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if abstract.processor_model %}
|
||||
<tr>
|
||||
<td>
|
||||
CPU – {{ abstract.processor_model }}
|
||||
</td>
|
||||
<td>
|
||||
Processor Rate = {% if abstract.rate %}
|
||||
{{ abstract.rate.processor_range }}
|
||||
({{ abstract.rate.processor }})
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if abstract.ram_size %}
|
||||
<tr>
|
||||
<td>
|
||||
RAM – {{ abstract.ram_size // 1000 }} GB
|
||||
{{ macros.component_type(abstract.components, 'RamModule') }}
|
||||
</td>
|
||||
<td>
|
||||
RAM Rate = {% if abstract.rate %}
|
||||
{{ abstract.rate.ram_range }}
|
||||
({{ abstract.rate.ram }})
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if abstract.data_storage_size %}
|
||||
<tr>
|
||||
<td>
|
||||
Data Storage – {{ abstract.data_storage_size // 1000 }} GB
|
||||
{{ macros.component_type(abstract.components, 'SolidStateDrive') }}
|
||||
{{ macros.component_type(abstract.components, 'HardDrive') }}
|
||||
</td>
|
||||
<td>
|
||||
Data Storage Rate = {% if abstract.rate %}
|
||||
{{ abstract.rate.data_storage_range }}
|
||||
({{ abstract.rate.data_storage }})
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if abstract.graphic_card_model %}
|
||||
<tr>
|
||||
<td>
|
||||
Graphics – {{ abstract.graphic_card_model }}
|
||||
{{ macros.component_type(abstract.components, 'GraphicCard') }}
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if abstract.network_speeds %}
|
||||
<tr>
|
||||
<td>
|
||||
Network –
|
||||
{% if abstract.network_speeds[0] %}
|
||||
Ethernet
|
||||
{% if abstract.network_speeds[0] != None %}
|
||||
max. {{ abstract.network_speeds[0] }} Mbps
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if abstract.network_speeds[0] and abstract.network_speeds[1] %}
|
||||
+
|
||||
{% endif %}
|
||||
{% if abstract.network_speeds[1] %}
|
||||
WiFi
|
||||
{% if abstract.network_speeds[1] != None %}
|
||||
max. {{ abstract.network_speeds[1] }} Mbps
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{{ macros.component_type(abstract.components, 'NetworkAdapter') }}
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<h4>Actual Status</h4>
|
||||
<ol>
|
||||
<li>
|
||||
<strong>
|
||||
Lifecycle Status
|
||||
</strong>
|
||||
—
|
||||
{% if abstract.status %}
|
||||
{{ abstract.status.type }}
|
||||
{% endif %}
|
||||
</li>
|
||||
<li>
|
||||
<strong>
|
||||
Allocate Status
|
||||
</strong>
|
||||
—
|
||||
{% if abstract.allocated_status %}
|
||||
{{ abstract.allocated_status.type }}
|
||||
{% endif %}
|
||||
</li>
|
||||
<li>
|
||||
<strong>
|
||||
Physical Status
|
||||
</strong>
|
||||
—
|
||||
{% if abstract.physical_status %}
|
||||
{{ abstract.physical_status.type }}
|
||||
{% endif %}
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<h4>Public traceability log of the abstract</h4>
|
||||
<div class="text-right">
|
||||
<small>Latest one.</small>
|
||||
</div>
|
||||
<ol>
|
||||
{% for action in abstract.public_actions %}
|
||||
<li>
|
||||
<strong>
|
||||
{{ abstract.is_status(action) }}
|
||||
{% if not abstract.is_status(action) %}
|
||||
{{ action.type }}
|
||||
{% endif %}
|
||||
</strong>
|
||||
—
|
||||
{% if abstract.is_status(action) %}
|
||||
{{ action }} {{ action.type }}
|
||||
{% else %}
|
||||
{{ action }}
|
||||
{% endif %}
|
||||
<br>
|
||||
<div class="text-muted">
|
||||
<small>
|
||||
{{ action._date_str }}
|
||||
</small>
|
||||
</div>
|
||||
{% if action.certificate %}
|
||||
<a href="{{ action.certificate.to_text() }}">See the certificate</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
<div class="text-right">
|
||||
<small>Oldest one.</small>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<footer class="container-fluid footer">
|
||||
<div class="row">
|
||||
|
|
|
@ -2,6 +2,7 @@ import datetime
|
|||
import uuid
|
||||
from itertools import filterfalse
|
||||
|
||||
import flask
|
||||
import marshmallow
|
||||
from flask import Response
|
||||
from flask import current_app as app
|
||||
|
@ -110,9 +111,7 @@ class DeviceView(View):
|
|||
return super().get(id)
|
||||
|
||||
def patch(self, id):
|
||||
dev = Device.query.filter_by(
|
||||
id=id, owner_id=g.user.id, active=True
|
||||
).one()
|
||||
dev = Device.query.filter_by(id=id, owner_id=g.user.id, active=True).one()
|
||||
if isinstance(dev, Computer):
|
||||
resource_def = app.resources['Computer']
|
||||
# TODO check how to handle the 'actions_one'
|
||||
|
@ -138,10 +137,17 @@ class DeviceView(View):
|
|||
return self.one_private(id)
|
||||
|
||||
def one_public(self, id: int):
|
||||
device = Device.query.filter_by(
|
||||
devicehub_id=id, active=True
|
||||
).one()
|
||||
return render_template('devices/layout.html', device=device, states=states)
|
||||
device = Device.query.filter_by(devicehub_id=id, active=True).one()
|
||||
abstract = None
|
||||
if device.binding:
|
||||
return flask.redirect(device.public_link)
|
||||
|
||||
if device.is_abstract() == 'Twin':
|
||||
abstract = device.placeholder.binding
|
||||
|
||||
return render_template(
|
||||
'devices/layout.html', device=device, states=states, abstract=abstract
|
||||
)
|
||||
|
||||
@auth.Auth.requires_auth
|
||||
def one_private(self, id: str):
|
||||
|
|
|
@ -276,10 +276,10 @@ class DeviceRow(BaseDeviceRow):
|
|||
software=snapshot.software.name, version=snapshot.version
|
||||
)
|
||||
# General information about device
|
||||
self['DHID'] = device.devicehub_id
|
||||
self['DHID'] = self.placeholder.device.dhid
|
||||
self['DocumentID'] = self.document_id
|
||||
self['Public Link'] = '{url}{id}'.format(
|
||||
url=url_for('Device.main', _external=True), id=device.devicehub_id
|
||||
url=url_for('Device.main', _external=True), id=device.dhid
|
||||
)
|
||||
self['Lots'] = ', '.join([x.name for x in self.device.lots])
|
||||
for i, tag in zip(range(1, 3), device.tags):
|
||||
|
|
|
@ -42,13 +42,13 @@
|
|||
|
||||
<dt>Computer where was erase:</dt>
|
||||
<dd>Title: {{ erasure.parent.__format__('ts') }}</dd>
|
||||
<dd>DevicehubID: {{ erasure.parent.devicehub_id }}</dd>
|
||||
<dd>DevicehubID: {{ erasure.parent.dhid }}</dd>
|
||||
<dd>Hid: {{ erasure.parent.hid }}</dd>
|
||||
<dd>Tags: {{ erasure.parent.tags }}</dd>
|
||||
|
||||
<dt>Computer where it resides:</dt>
|
||||
<dd>Title: {{ erasure.device.parent.__format__('ts') }}</dd>
|
||||
<dd>DevicehubID: {{ erasure.device.parent.devicehub_id }}</dd>
|
||||
<dd>DevicehubID: {{ erasure.device.parent.dhid }}</dd>
|
||||
<dd>Hid: {{ erasure.device.parent.hid }}</dd>
|
||||
<dd>Tags: {{ erasure.device.parent.tags }}</dd>
|
||||
|
||||
|
|
|
@ -178,8 +178,6 @@ function deviceSelect() {
|
|||
$("#addingLotModal .btn-primary").hide();
|
||||
$("#removeLotModal .pol").show();
|
||||
$("#removeLotModal .btn-primary").hide();
|
||||
$("#addingTagModal .pol").show();
|
||||
$("#addingTagModal .btn-primary").hide();
|
||||
$("#actionModal .pol").show();
|
||||
$("#actionModal .btn-primary").hide();
|
||||
$("#allocateModal .pol").show();
|
||||
|
@ -197,8 +195,6 @@ function deviceSelect() {
|
|||
$("#allocateModal .btn-primary").show();
|
||||
$("#datawipeModal .pol").hide();
|
||||
$("#datawipeModal .btn-primary").show();
|
||||
$("#addingTagModal .pol").hide();
|
||||
$("#addingTagModal .btn-primary").show();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,33 +210,6 @@ function removeLot() {
|
|||
$("#activeRemoveLotModal").click();
|
||||
}
|
||||
|
||||
function removeTag() {
|
||||
const devices = TableController.getSelectedDevices();
|
||||
const devices_id = devices.map(dev => $(dev).attr('data'));
|
||||
|
||||
if (devices_id.length == 1) {
|
||||
const url = "/inventory/tag/devices/".concat(devices_id[0], "/del/");
|
||||
window.location.href = url;
|
||||
} else {
|
||||
$("#unlinkTagAlertModal").click();
|
||||
}
|
||||
}
|
||||
|
||||
function addTag() {
|
||||
const devices = TableController.getSelectedDevices();
|
||||
const devices_id = devices.map(dev => $(dev).attr('data'));
|
||||
|
||||
if (devices_id.length == 1) {
|
||||
$("#addingTagModal .pol").hide();
|
||||
$("#addingTagModal .btn-primary").show();
|
||||
} else {
|
||||
$("#addingTagModal .pol").show();
|
||||
$("#addingTagModal .btn-primary").hide();
|
||||
}
|
||||
|
||||
$("#addTagAlertModal").click();
|
||||
}
|
||||
|
||||
function select_shift() {
|
||||
const chkboxes = $('.deviceSelect');
|
||||
var lastChecked = null;
|
||||
|
|
|
@ -163,9 +163,6 @@ function deviceSelect() {
|
|||
$("#removeLotModal .pol").show();
|
||||
$("#removeLotModal .btn-primary").hide();
|
||||
|
||||
$("#addingTagModal .pol").show();
|
||||
$("#addingTagModal .btn-primary").hide();
|
||||
|
||||
$("#actionModal .pol").show();
|
||||
$("#actionModal .btn-primary").hide();
|
||||
|
||||
|
@ -189,9 +186,6 @@ function deviceSelect() {
|
|||
|
||||
$("#datawipeModal .pol").hide();
|
||||
$("#datawipeModal .btn-primary").show();
|
||||
|
||||
$("#addingTagModal .pol").hide();
|
||||
$("#addingTagModal .btn-primary").show();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,31 +199,6 @@ function removeLot() {
|
|||
$("#activeRemoveLotModal").click();
|
||||
}
|
||||
|
||||
function removeTag() {
|
||||
const devices = TableController.getSelectedDevices();
|
||||
const devices_id = devices.map(dev => $(dev).attr("data"));
|
||||
if (devices_id.length == 1) {
|
||||
const url = `/inventory/tag/devices/${devices_id[0]}/del/`;
|
||||
window.location.href = url;
|
||||
} else {
|
||||
$("#unlinkTagAlertModal").click();
|
||||
}
|
||||
}
|
||||
|
||||
function addTag() {
|
||||
const devices = TableController.getSelectedDevices();
|
||||
const devices_id = devices.map(dev => $(dev).attr("data"));
|
||||
if (devices_id.length == 1) {
|
||||
$("#addingTagModal .pol").hide();
|
||||
$("#addingTagModal .btn-primary").show();
|
||||
} else {
|
||||
$("#addingTagModal .pol").show();
|
||||
$("#addingTagModal .btn-primary").hide();
|
||||
}
|
||||
|
||||
$("#addTagAlertModal").click();
|
||||
}
|
||||
|
||||
function select_shift() {
|
||||
const chkboxes = $(".deviceSelect");
|
||||
let lastChecked = null;
|
||||
|
|
|
@ -256,6 +256,14 @@
|
|||
</ul>
|
||||
</li><!-- End Temporal Lots Nav -->
|
||||
|
||||
<li class="nav-heading">Unique Identifiers (Tags)</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link collapsed" href="{{ url_for('labels.label_list') }}">
|
||||
<i class="bi bi-tag"></i><span>UI Management</span>
|
||||
</a>
|
||||
</li><!-- End Unique Identifiers -->
|
||||
|
||||
</ul>
|
||||
|
||||
</aside><!-- End Sidebar-->
|
||||
|
|
|
@ -7,16 +7,12 @@
|
|||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<form action="{{ url_for('inventory.tag_devices_add') }}" method="post">
|
||||
{{ form_tag_device.csrf_token }}
|
||||
<form action="{{ url_for('inventory.tag_devices_add', dhid=device.devicehub_id) }}" method="post">
|
||||
<div class="modal-body">
|
||||
Please write a name of a unique identifier
|
||||
<select class="form-control selectpicker" id="selectTag" name="tag" data-live-search="true">
|
||||
{% for tag in tags %}
|
||||
<option value="{{ tag.id }}">{{ tag.id }}</option>
|
||||
{% for f in form_tag_device %}
|
||||
{{ f }}
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input class="devicesList" type="hidden" name="device" />
|
||||
<p class="text-danger pol">
|
||||
You need select first one device and only one for add this in a unique identifier
|
||||
</p>
|
||||
|
|
|
@ -20,115 +20,126 @@
|
|||
<div class="pt-4 pb-2">
|
||||
<h5 class="card-title text-center pb-0 fs-4">{{ title }}</h5>
|
||||
<p class="text-center">Please check that the information is correct.</p>
|
||||
<p>This is a binding between:
|
||||
<ul>
|
||||
{% if new_placeholder.is_abstract %}
|
||||
<li>1. Device abstract with DHID:<b>{{ new_placeholder.device.devicehub_id }}</b> and PHID: <b>{{ new_placeholder.phid }}</b></li>
|
||||
<li>2. Device real with DHID: <b>{{ old_placeholder.device.devicehub_id }}</b> and PHID:<b>{{ old_placeholder.phid }}</b></li>
|
||||
{% else %}
|
||||
<li>1. Device abstract with DHID:<b>{{ old_placeholder.device.devicehub_id }}</b> and PHID: <b>{{ old_placeholder.phid }}</b></li>
|
||||
<li>2. Device real with DHID: <b>{{ new_placeholder.device.devicehub_id }}</b> and PHID:<b>{{ new_placeholder.phid }}</b></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</p>
|
||||
<p>The DHID and PHID information of the abstract will be lost.</p>
|
||||
<p>The information in <span class="text-danger">red colour</span> will be losted and replaced by the information in <span class="text-success">green colour</span>.<br />
|
||||
The information in <span class="text-warning">orange</span> will be replaced by the information in <span class="text-success">green</span> and you always can recover
|
||||
it by doing an unbinding action or find this information into device details web.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="text-center">
|
||||
<th scope="col">Basic Data</th>
|
||||
<th scope="col">Info to be Entered</th>
|
||||
<th scope="col">Info to be Decoupled</th>
|
||||
<th scope="col">Info Twin device</th>
|
||||
<th scope="col">Info Abstract device</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">PHID:</th>
|
||||
<td class="table-success text-right">{{ placeholder.phid or '' }}</td>
|
||||
<td class="table-danger">{{ device.placeholder.phid or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Manufacturer:</th>
|
||||
<td class="table-success text-right">{{ placeholder.device.manufacturer or '' }}</td>
|
||||
<td class="table-danger">{{ device.manufacturer or '' }}</td>
|
||||
<td class="table-success text-right">{{ new_placeholder.device.manufacturer or '' }}</td>
|
||||
<td class="table-warning">{{ old_placeholder.device.manufacturer or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Model:</th>
|
||||
<td class="table-success">{{ placeholder.device.model or '' }}</td>
|
||||
<td class="table-danger">{{ device.model or '' }}</td>
|
||||
<td class="table-success">{{ new_placeholder.device.model or '' }}</td>
|
||||
<td class="table-warning">{{ old_placeholder.device.model or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Serial Number:</th>
|
||||
<td class="table-success">{{ placeholder.device.serial_number or '' }}</td>
|
||||
<td class="table-danger">{{ device.serial_number or '' }}</td>
|
||||
<td class="table-success">{{ new_placeholder.device.serial_number or '' }}</td>
|
||||
<td class="table-warning">{{ old_placeholder.device.serial_number or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Brand:</th>
|
||||
<td class="table-success">{{ placeholder.device.brand or '' }}</td>
|
||||
<td class="table-danger">{{ device.brand or '' }}</td>
|
||||
<td class="table-success">{{ new_placeholder.device.brand or '' }}</td>
|
||||
<td class="table-warning">{{ old_placeholder.device.brand or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Sku:</th>
|
||||
<td class="table-success">{{ placeholder.device.sku or '' }}</td>
|
||||
<td class="table-danger">{{ device.sku or '' }}</td>
|
||||
<td class="table-success">{{ new_placeholder.device.sku or '' }}</td>
|
||||
<td class="table-warning">{{ old_placeholder.device.sku or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Generation:</th>
|
||||
<td class="table-success">{{ placeholder.device.generation or '' }}</td>
|
||||
<td class="table-danger">{{ device.generation or '' }}</td>
|
||||
<td class="table-success">{{ new_placeholder.device.generation or '' }}</td>
|
||||
<td class="table-warning">{{ old_placeholder.device.generation or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Version:</th>
|
||||
<td class="table-success">{{ placeholder.device.version or '' }}</td>
|
||||
<td class="table-danger">{{ device.version or '' }}</td>
|
||||
<td class="table-success">{{ new_placeholder.device.version or '' }}</td>
|
||||
<td class="table-warning">{{ old_placeholder.device.version or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Weight:</th>
|
||||
<td class="table-success">{{ placeholder.device.weight or '' }}</td>
|
||||
<td class="table-danger">{{ device.weight or '' }}</td>
|
||||
<td class="table-success">{{ new_placeholder.device.weight or '' }}</td>
|
||||
<td class="table-warning">{{ old_placeholder.device.weight or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Width:</th>
|
||||
<td class="table-success">{{ placeholder.device.width or '' }}</td>
|
||||
<td class="table-danger">{{ device.width or '' }}</td>
|
||||
<td class="table-success">{{ new_placeholder.device.width or '' }}</td>
|
||||
<td class="table-warning">{{ old_placeholder.device.width or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Height:</th>
|
||||
<td class="table-success">{{ placeholder.device.height or '' }}</td>
|
||||
<td class="table-danger">{{ device.height or '' }}</td>
|
||||
<td class="table-success">{{ new_placeholder.device.height or '' }}</td>
|
||||
<td class="table-warning">{{ old_placeholder.device.height or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Depth:</th>
|
||||
<td class="table-success">{{ placeholder.device.depth or '' }}</td>
|
||||
<td class="table-danger">{{ device.depth or '' }}</td>
|
||||
<td class="table-success">{{ new_placeholder.device.depth or '' }}</td>
|
||||
<td class="table-warning">{{ old_placeholder.device.depth or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Color:</th>
|
||||
<td class="table-success">{{ placeholder.device.color or '' }}</td>
|
||||
<td class="table-danger">{{ device.color or '' }}</td>
|
||||
<td class="table-success">{{ new_placeholder.device.color or '' }}</td>
|
||||
<td class="table-warning">{{ old_placeholder.device.color or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Production date:</th>
|
||||
<td class="table-success">{{ placeholder.device.production_date or '' }}</td>
|
||||
<td class="table-danger">{{ device.production_date or '' }}</td>
|
||||
<td class="table-success">{{ new_placeholder.device.production_date or '' }}</td>
|
||||
<td class="table-warning">{{ old_placeholder.device.production_date or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Variant:</th>
|
||||
<td class="table-success">{{ placeholder.device.variant or '' }}</td>
|
||||
<td class="table-danger">{{ device.variant or '' }}</td>
|
||||
<td class="table-success">{{ new_placeholder.device.variant or '' }}</td>
|
||||
<td class="table-warning">{{ old_placeholder.device.variant or '' }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
{% if placeholder.device.components or device.components %}
|
||||
{% if new_placeholder.device.components or old_placeholder.device.components %}
|
||||
<h2>Components</h2>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="text-center">
|
||||
<th scope="col">Info to be Entered</th>
|
||||
<th scope="col">Info to be Decoupled</th>
|
||||
<th scope="col">Info Twin device</th>
|
||||
<th scope="col">Info Abstract device</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="table-success text-right">
|
||||
{% for c in placeholder.device.components %}
|
||||
{% for c in new_placeholder.device.components %}
|
||||
* {{ c.verbose_name }}<br />
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td class="table-danger">
|
||||
{% for c in device.components %}
|
||||
<td class="table-warning">
|
||||
{% for c in old_placeholder.device.components %}
|
||||
* {{ c.verbose_name }}<br />
|
||||
{% endfor %}
|
||||
</td>
|
||||
|
@ -141,11 +152,14 @@
|
|||
|
||||
{% if actions %}
|
||||
<h2>Actions</h2>
|
||||
<p>
|
||||
The actions will become real device and will no longer be in the abstract
|
||||
</p>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="text-center">
|
||||
<th scope="col">Info to be Entered</th>
|
||||
<th scope="col">Info to be Decoupled</th>
|
||||
<th scope="col">Info Twin device</th>
|
||||
<th scope="col">Info Abstract device</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -166,11 +180,14 @@
|
|||
|
||||
{% if tags %}
|
||||
<h2>Tags</h2>
|
||||
<p>
|
||||
The tags will become real device and will no longer be in the abstract
|
||||
</p>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="text-center">
|
||||
<th scope="col">Info to be Entered</th>
|
||||
<th scope="col">Info to be Decoupled</th>
|
||||
<th scope="col">Info Twin device</th>
|
||||
<th scope="col">Info Abstract device</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -189,7 +206,7 @@
|
|||
|
||||
<div>
|
||||
<form method="post">
|
||||
<a href="{{ url_for('inventory.device_details', id=device.placeholder.binding.devicehub_id) }}" class="btn btn-danger">Cancel</a>
|
||||
<a href="{{ url_for('inventory.device_details', id=dhid) }}" class="btn btn-danger">Cancel</a>
|
||||
<button class="btn btn-primary" type="submit">Confirm</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
74
ereuse_devicehub/templates/inventory/binding_search.html
Normal file
74
ereuse_devicehub/templates/inventory/binding_search.html
Normal file
|
@ -0,0 +1,74 @@
|
|||
{% extends "ereuse_devicehub/base_site.html" %}
|
||||
{% block main %}
|
||||
|
||||
<div class="pagetitle">
|
||||
<h1>Inventory</h1>
|
||||
<nav>
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{{ url_for('inventory.devicelist')}}">Inventory</a></li>
|
||||
<li class="breadcrumb-item active">{{ page_title }}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div><!-- End Page Title -->
|
||||
|
||||
<section class="section profile">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-xl-12">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body pt-3">
|
||||
<h3>{{ device.devicehub_id }}</h3>
|
||||
<!-- Bordered Tabs -->
|
||||
<div class="tab-content pt-2">
|
||||
|
||||
<div class="tab-pane fade show active">
|
||||
<h5 class="card-title">Binding</h5>
|
||||
{% if device.is_abstract() == 'Twin' or not device.placeholder %}
|
||||
<div class="list-group col-6">
|
||||
<p>
|
||||
Device with Dhid: {{ device.devicehub_id }} is a Twin device.<br />
|
||||
If you want to do a binding with this device, you need todo an Unbinding first.<br />
|
||||
You can to do this in <a href="{{ url_for('inventory.unbinding', phid=device.placeholder.phid) }}" class="help">here</a>.
|
||||
</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="list-group col-6">
|
||||
<p>
|
||||
Be careful, binding implies changes in the data of a device that affect its traceability.
|
||||
</p>
|
||||
</div>
|
||||
<div class="list-group col-6">
|
||||
<form action="{{ url_for('inventory.binding_search', dhid=device.devicehub_id) }}" method="post">
|
||||
{{ form_binding.csrf_token }}
|
||||
{% for field in form_binding %}
|
||||
{% if field != form_binding.csrf_token %}
|
||||
|
||||
<div class="col-12">
|
||||
{{ field.label(class_="form-label") }}:
|
||||
{{ field }}
|
||||
{% if field.errors %}
|
||||
<p class="text-danger">
|
||||
{% for error in field.errors %}
|
||||
{{ error }}<br/>
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<div class="col-12 mt-2">
|
||||
<input type="submit" class="btn btn-primary" value="Search" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock main %}
|
|
@ -18,25 +18,48 @@
|
|||
|
||||
<div class="card">
|
||||
<div class="card-body pt-3">
|
||||
<h3>{{ device.devicehub_id }}</h3>
|
||||
<h3>{{ placeholder.device.devicehub_id }}</h3>
|
||||
<div class="tab-pane active show mb-5">
|
||||
<div class="btn-group dropdown" uib-dropdown="" style="float: right; margin-right: 15px;">
|
||||
<button id="btnUniqueID" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-tag"></i>
|
||||
Unique Identifiers (Tags)
|
||||
</button>
|
||||
<span class="d-none" id="unlinkTagAlertModal" data-bs-toggle="modal" data-bs-target="#unlinkTagErrorModal"></span>
|
||||
<span class="d-none" id="addTagAlertModal" data-bs-toggle="modal" data-bs-target="#addingTagModal"></span>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnUniqueID">
|
||||
<li>
|
||||
<a href="javascript:addTag()" class="dropdown-item">
|
||||
<i class="bi bi-plus"></i>
|
||||
Add Unique Identifier
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ url_for('inventory.tag_devices_del', dhid=placeholder.device.devicehub_id) }}" class="dropdown-item">
|
||||
<i class="bi bi-x"></i>
|
||||
Remove Unique Identifier
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{% if placeholder.status in ['Abstract', 'Real'] %}
|
||||
<a type="button" href="{{ url_for('inventory.binding_search', dhid=placeholder.device.devicehub_id) }}" class="btn btn-primary" style="float: right; margin-right: 15px;">
|
||||
Binding
|
||||
</a>
|
||||
{% elif placeholder.status == 'Twin' %}
|
||||
<a type="button" href="{{ url_for('inventory.unbinding', phid=placeholder.phid) }}" class="btn btn-primary" style="float: right; margin-right: 15px;">
|
||||
Unbinding
|
||||
</a>
|
||||
{% endif %}
|
||||
<div style="display: block;"></div>
|
||||
|
||||
</div>
|
||||
<!-- Bordered Tabs -->
|
||||
<ul class="nav nav-tabs nav-tabs-bordered">
|
||||
|
||||
{% if placeholder %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('inventory.device_details', id=placeholder.device.devicehub_id) }}">Placeholder device</a>
|
||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#details">General details</button>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#type">General details</button>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% if placeholder.binding %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('inventory.device_details', id=placeholder.binding.devicehub_id) }}">Workbench device</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ device.public_link }}" target="_blank">Web</a>
|
||||
|
@ -50,10 +73,6 @@
|
|||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#status">Status</button>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#rate">Rate</button>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#traceability">Traceability log</button>
|
||||
</li>
|
||||
|
@ -62,65 +81,72 @@
|
|||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#components">Components</button>
|
||||
</li>
|
||||
|
||||
{% if device.is_abstract() == 'Abstract' %}
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#binding">Binding</button>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% if device.is_abstract() == 'Twin' %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('inventory.unbinding', phid=placeholder.phid) }}">Unbinding</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
</ul>
|
||||
<div class="tab-content pt-2">
|
||||
|
||||
<div class="tab-pane fade {% if active_binding %}profile-overview{% else %}show active{% endif %}" id="type">
|
||||
<h5 class="card-title">Details</h5>
|
||||
{% if device.placeholder %}
|
||||
<div class="tab-pane fade show active" id="details">
|
||||
<h5 class="card-title">Details Real parth</h5>
|
||||
<div class="row mb-3">
|
||||
<div class="col-lg-3 col-md-4 label ">
|
||||
(<a href="{{ url_for('inventory.device_edit', id=device.devicehub_id)}}">Edit Device</a>)
|
||||
(<a href="{{ url_for('inventory.device_edit', id=placeholder.device.devicehub_id)}}">Edit Device</a>)
|
||||
</div>
|
||||
<div class="col-lg-9 col-md-8">{{ device.is_abstract() }}</div>
|
||||
<div class="col-lg-9 col-md-8">{{ placeholder.status }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if device.placeholder %}
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label ">Phid</div>
|
||||
<div class="col-lg-9 col-md-8">{{ device.placeholder.phid }}</div>
|
||||
<div class="col-lg-9 col-md-8">{{ placeholder.phid }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label ">Type</div>
|
||||
<div class="col-lg-9 col-md-8">{{ device.type }}</div>
|
||||
<div class="col-lg-9 col-md-8">{{ placeholder.device.type }}</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Manufacturer</div>
|
||||
<div class="col-lg-9 col-md-8">{{ device.manufacturer or ''}}</div>
|
||||
<div class="col-lg-9 col-md-8">{{ placeholder.device.manufacturer or ''}}</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Model</div>
|
||||
<div class="col-lg-9 col-md-8">{{ device.model or ''}}</div>
|
||||
<div class="col-lg-9 col-md-8">{{ placeholder.device.model or ''}}</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Serial Number</div>
|
||||
<div class="col-lg-9 col-md-8">{{ device.serial_number or ''}}</div>
|
||||
<div class="col-lg-9 col-md-8">{{ placeholder.device.serial_number or ''}}</div>
|
||||
</div>
|
||||
|
||||
{% if placeholder.binding %}
|
||||
<h5 class="card-title">Details Abstract parth</h5>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label ">Type</div>
|
||||
<div class="col-lg-9 col-md-8">{{ placeholder.binding.type }}</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Manufacturer</div>
|
||||
<div class="col-lg-9 col-md-8">{{ placeholder.binding.manufacturer or ''}}</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Model</div>
|
||||
<div class="col-lg-9 col-md-8">{{ placeholder.binding.model or ''}}</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Serial Number</div>
|
||||
<div class="col-lg-9 col-md-8">{{ placeholder.binding.serial_number or ''}}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade profile-overview" id="lots">
|
||||
<h5 class="card-title">Incoming Lots</h5>
|
||||
|
||||
<div class="row">
|
||||
{% for lot in device.lots %}
|
||||
{% for lot in placeholder.device.lots %}
|
||||
{% if lot.is_incoming %}
|
||||
<div class="col">
|
||||
<a class="ms-3" href="{{ url_for('inventory.lotdevicelist', lot_id=lot.id) }}">
|
||||
|
@ -134,7 +160,7 @@
|
|||
<h5 class="card-title">Outgoing Lots</h5>
|
||||
|
||||
<div class="row">
|
||||
{% for lot in device.lots %}
|
||||
{% for lot in placeholder.device.lots %}
|
||||
{% if lot.is_outgoing %}
|
||||
<div class="col">
|
||||
<a class="ms-3" href="{{ url_for('inventory.lotdevicelist', lot_id=lot.id) }}">
|
||||
|
@ -148,7 +174,7 @@
|
|||
<h5 class="card-title">Temporary Lots</h5>
|
||||
|
||||
<div class="row">
|
||||
{% for lot in device.lots %}
|
||||
{% for lot in placeholder.device.lots %}
|
||||
{% if lot.is_temporary %}
|
||||
<div class="col">
|
||||
<a class="ms-3" href="{{ url_for('inventory.lotdevicelist', lot_id=lot.id) }}">
|
||||
|
@ -165,53 +191,33 @@
|
|||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Physical State</div>
|
||||
<div class="col-lg-9 col-md-8">
|
||||
{% if device.physical_status %}
|
||||
{{ device.physical_status.type }}
|
||||
{% if placeholder.device.physical_status %}
|
||||
{{ placeholder.device.physical_status.type }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Lifecycle State</div>
|
||||
<div class="col-lg-9 col-md-8">
|
||||
{% if device.status %}
|
||||
{{ device.status.type }}
|
||||
{% if placeholder.device.status %}
|
||||
{{ placeholder.device.status.type }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Allocated State</div>
|
||||
<div class="col-lg-9 col-md-8">
|
||||
{% if device.allocated_status %}
|
||||
{{ device.allocated_status.type }}
|
||||
{% if placeholder.device.allocated_status %}
|
||||
{{ placeholder.device.allocated_status.type }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade profile-overview" id="rate">
|
||||
<h5 class="card-title">Rate Details</h5>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Rating</div>
|
||||
<div class="col-lg-9 col-md-8">{{ device.rate or '' }}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Processor</div>
|
||||
<div class="col-lg-9 col-md-8">{{ device.rate.processor or '' }}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">RAM</div>
|
||||
<div class="col-lg-9 col-md-8">{{ device.rate.ram or '' }}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Data storage</div>
|
||||
<div class="col-lg-9 col-md-8">{{ device.rate.data_storage or '' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade profile-overview" id="traceability">
|
||||
<h5 class="card-title">Traceability log Details</h5>
|
||||
<div class="list-group col-6">
|
||||
{% for action in device.reverse_actions %}
|
||||
{% for action in placeholder.actions %}
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center">
|
||||
{{ action.type }} {{ action.severity }}
|
||||
<small class="text-muted">{{ action.created.strftime('%H:%M %d-%m-%Y') }}</small>
|
||||
|
@ -221,10 +227,15 @@
|
|||
</div>
|
||||
|
||||
<div class="tab-pane fade profile-overview" id="components">
|
||||
<h5 class="card-title">Components Details</h5>
|
||||
{% if device.binding %}
|
||||
<h5 class="card-title">Components Real parth</h5>
|
||||
<div class="list-group col-6">
|
||||
{% for component in device.components|sort(attribute='type') %}
|
||||
{{ placeholder.components or '' }}
|
||||
</div>
|
||||
|
||||
{% if placeholder.binding %}
|
||||
<h5 class="card-title">Components Abstract parth</h5>
|
||||
<div class="list-group col-6">
|
||||
{% for component in placeholder.binding.components|sort(attribute='type') %}
|
||||
<div class="list-group-item">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">{{ component.type }}</h5>
|
||||
|
@ -242,52 +253,27 @@
|
|||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col-6">
|
||||
{{ device.placeholder.components or '' }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if device.is_abstract() %}
|
||||
<div class="tab-pane fade {% if active_binding %}show active{% else %}profile-overview{% endif %}" id="binding">
|
||||
<h5 class="card-title">Binding</h5>
|
||||
<div class="list-group col-6">
|
||||
<p>
|
||||
Be careful, binding implies changes in the data of a device that affect its
|
||||
traceability.
|
||||
</p>
|
||||
</div>
|
||||
<div class="list-group col-6">
|
||||
<form action="{{ url_for('inventory.device_details', id=device.devicehub_id) }}" method="post">
|
||||
{{ form_binding.csrf_token }}
|
||||
{% for field in form_binding %}
|
||||
{% if field != form_binding.csrf_token %}
|
||||
|
||||
<div class="col-12">
|
||||
{{ field.label(class_="form-label") }}:
|
||||
{{ field }}
|
||||
{% if field.errors %}
|
||||
<p class="text-danger">
|
||||
{% for error in field.errors %}
|
||||
{{ error }}<br/>
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<div class="col-12 mt-2">
|
||||
<input type="submit" class="btn btn-primary" value="Search" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
function addTag() {
|
||||
const devices_id = [{{ placeholder.device.id }}];
|
||||
if (devices_id.length == 1) {
|
||||
$("#addingTagModal .pol").hide();
|
||||
$("#addingTagModal .btn-primary").show();
|
||||
} else {
|
||||
$("#addingTagModal .pol").show();
|
||||
$("#addingTagModal .btn-primary").hide();
|
||||
}
|
||||
|
||||
$("#addTagAlertModal").click();
|
||||
}
|
||||
</script>
|
||||
{% include "inventory/addDevicestag.html" %}
|
||||
{% endblock main %}
|
||||
|
|
|
@ -268,42 +268,11 @@
|
|||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="btn-group dropdown m-1" uib-dropdown="">
|
||||
<button id="btnUniqueID" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-tag"></i>
|
||||
Unique Identifiers (Tags)
|
||||
</button>
|
||||
<span class="d-none" id="unlinkTagAlertModal" data-bs-toggle="modal" data-bs-target="#unlinkTagErrorModal"></span>
|
||||
<span class="d-none" id="addTagAlertModal" data-bs-toggle="modal" data-bs-target="#addingTagModal"></span>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnUniqueID">
|
||||
<li>
|
||||
<a href="javascript:addTag()" class="dropdown-item">
|
||||
<i class="bi bi-plus"></i>
|
||||
Add Unique Identifier to selected Device
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:removeTag()" class="dropdown-item">
|
||||
<i class="bi bi-x"></i>
|
||||
Remove Unique Identifier from selected Device
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="{{ url_for('labels.label_list')}}">
|
||||
<i class="bi bi-tools"></i>
|
||||
Unique Identifier Management
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="btn-group dropdown m-1" uib-dropdown="">
|
||||
<button id="btnTags" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-tag"></i>
|
||||
Labels
|
||||
</button>
|
||||
<span class="d-none" id="unlinkTagAlertModal" data-bs-toggle="modal" data-bs-target="#unlinkTagErrorModal"></span>
|
||||
<span class="d-none" id="addTagAlertModal" data-bs-toggle="modal" data-bs-target="#addingTagModal"></span>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnTags">
|
||||
<li>
|
||||
<form id="print_labels" method="post" action="{{ url_for('labels.print_labels') }}">
|
||||
|
@ -322,19 +291,9 @@
|
|||
<div class="btn-group dropdown m-1" uib-dropdown="">
|
||||
<button id="btnSnapshot" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-laptop"></i>
|
||||
New Devices
|
||||
New Devices Real
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnSnapshot">
|
||||
<li>
|
||||
{% if lot %}
|
||||
<a href="{{ url_for('inventory.lot_upload_snapshot', lot_id=lot.id) }}" class="dropdown-item">
|
||||
{% else %}
|
||||
<a href="{{ url_for('inventory.upload_snapshot') }}" class="dropdown-item">
|
||||
{% endif %}
|
||||
<i class="bi bi-upload"></i>
|
||||
Upload Snapshot files
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
{% if lot %}
|
||||
<a href="{{ url_for('inventory.lot_upload_placeholder', lot_id=lot.id) }}" class="dropdown-item">
|
||||
|
@ -358,6 +317,25 @@
|
|||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="btn-group dropdown m-1" uib-dropdown="">
|
||||
<button id="btnSnapshot" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-laptop"></i>
|
||||
New Devices Abstract
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnSnapshot">
|
||||
<li>
|
||||
{% if lot %}
|
||||
<a href="{{ url_for('inventory.lot_upload_snapshot', lot_id=lot.id) }}" class="dropdown-item">
|
||||
{% else %}
|
||||
<a href="{{ url_for('inventory.upload_snapshot') }}" class="dropdown-item">
|
||||
{% endif %}
|
||||
<i class="bi bi-upload"></i>
|
||||
Upload Snapshot files
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{% if lot and not lot.is_temporary %}
|
||||
<div class="btn-group dropdown ml-1" uib-dropdown="">
|
||||
<button id="btnSnapshot" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
|
@ -610,14 +588,12 @@
|
|||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% include "inventory/addDevicestag.html" %}
|
||||
{% include "inventory/lot_delete_modal.html" %}
|
||||
{% include "inventory/actions.html" %}
|
||||
{% include "inventory/allocate.html" %}
|
||||
{% include "inventory/data_wipe.html" %}
|
||||
{% include "inventory/trade.html" %}
|
||||
{% include "inventory/alert_export_error.html" %}
|
||||
{% include "inventory/alert_unlink_tag_error.html" %}
|
||||
{% include "inventory/alert_lots_changes.html" %}
|
||||
|
||||
<!-- Custom Code -->
|
||||
|
|
|
@ -40,18 +40,6 @@
|
|||
<dt>Data storage:</dt>
|
||||
<dd>{{ erasure.device.__format__('ts') }}</dd>
|
||||
|
||||
<dt>Computer where was erase:</dt>
|
||||
<dd>Title: {{ erasure.parent.__format__('ts') }}</dd>
|
||||
<dd>DevicehubID: {{ erasure.parent.devicehub_id }}</dd>
|
||||
<dd>Hid: {{ erasure.parent.hid }}</dd>
|
||||
<dd>Tags: {{ erasure.parent.tags }}</dd>
|
||||
|
||||
<dt>Computer where it resides:</dt>
|
||||
<dd>Title: {{ erasure.device.parent.__format__('ts') }}</dd>
|
||||
<dd>DevicehubID: {{ erasure.device.parent.devicehub_id }}</dd>
|
||||
<dd>Hid: {{ erasure.device.parent.hid }}</dd>
|
||||
<dd>Tags: {{ erasure.device.parent.tags }}</dd>
|
||||
|
||||
<dt>Erasure:</dt>
|
||||
<dd>{{ erasure.__format__('ts') }}</dd>
|
||||
{% if erasure.steps %}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if devices %}
|
||||
{% if devices.count() %}
|
||||
<div class="card">
|
||||
<div class="card-body pt-3" style="min-height: 650px;">
|
||||
<!-- Bordered Tabs -->
|
||||
|
@ -178,42 +178,11 @@
|
|||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="btn-group dropdown m-1" uib-dropdown="">
|
||||
<button id="btnUniqueID" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-tag"></i>
|
||||
Unique Identifiers (Tags)
|
||||
</button>
|
||||
<span class="d-none" id="unlinkTagAlertModal" data-bs-toggle="modal" data-bs-target="#unlinkTagErrorModal"></span>
|
||||
<span class="d-none" id="addTagAlertModal" data-bs-toggle="modal" data-bs-target="#addingTagModal"></span>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnUniqueID">
|
||||
<li>
|
||||
<a href="javascript:addTag()" class="dropdown-item">
|
||||
<i class="bi bi-plus"></i>
|
||||
Add Unique Identifier to selected Device
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:removeTag()" class="dropdown-item">
|
||||
<i class="bi bi-x"></i>
|
||||
Remove Unique Identifier from selected Device
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="{{ url_for('labels.label_list')}}">
|
||||
<i class="bi bi-tools"></i>
|
||||
Unique Identifier Management
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="btn-group dropdown m-1" uib-dropdown="">
|
||||
<button id="btnTags" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-tag"></i>
|
||||
Labels
|
||||
</button>
|
||||
<span class="d-none" id="unlinkTagAlertModal" data-bs-toggle="modal" data-bs-target="#unlinkTagErrorModal"></span>
|
||||
<span class="d-none" id="addTagAlertModal" data-bs-toggle="modal" data-bs-target="#addingTagModal"></span>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnTags">
|
||||
<li>
|
||||
<form id="print_labels" method="post" action="{{ url_for('labels.print_labels') }}">
|
||||
|
@ -232,17 +201,17 @@
|
|||
<div class="btn-group dropdown m-1" uib-dropdown="">
|
||||
<button id="btnSnapshot" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-laptop"></i>
|
||||
New Device
|
||||
New Device Real
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnSnapshot">
|
||||
<li>
|
||||
{% if lot %}
|
||||
<a href="{{ url_for('inventory.lot_upload_snapshot', lot_id=lot.id) }}" class="dropdown-item">
|
||||
<a href="{{ url_for('inventory.lot_upload_placeholder', lot_id=lot.id) }}" class="dropdown-item">
|
||||
{% else %}
|
||||
<a href="{{ url_for('inventory.upload_snapshot') }}" class="dropdown-item">
|
||||
<a href="{{ url_for('inventory.upload_placeholder') }}" class="dropdown-item">
|
||||
{% endif %}
|
||||
<i class="bi bi-upload"></i>
|
||||
Upload a new Snapshot
|
||||
Upload Placeholder Spreadsheet
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
|
@ -252,7 +221,26 @@
|
|||
<a href="{{ url_for('inventory.device_add') }}" class="dropdown-item">
|
||||
{% endif %}
|
||||
<i class="bi bi-plus"></i>
|
||||
Create a new Device
|
||||
Create a new Placeholder
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="btn-group dropdown m-1" uib-dropdown="">
|
||||
<button id="btnSnapshot" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-laptop"></i>
|
||||
New Device Abstract
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnSnapshot">
|
||||
<li>
|
||||
{% if lot %}
|
||||
<a href="{{ url_for('inventory.lot_upload_snapshot', lot_id=lot.id) }}" class="dropdown-item">
|
||||
{% else %}
|
||||
<a href="{{ url_for('inventory.upload_snapshot') }}" class="dropdown-item">
|
||||
{% endif %}
|
||||
<i class="bi bi-upload"></i>
|
||||
Upload Snapshot files
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -287,6 +275,8 @@
|
|||
<th scope="col">Select</th>
|
||||
<th scope="col">Title</th>
|
||||
<th scope="col">DHID</th>
|
||||
<th scope="col">PHID</th>
|
||||
<th scope="col">Type</th>
|
||||
<th scope="col">Unique Identifiers</th>
|
||||
<th scope="col">Lifecycle Status</th>
|
||||
<th scope="col">Allocated Status</th>
|
||||
|
@ -328,6 +318,12 @@
|
|||
{{ dev.devicehub_id }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ dev.binding and dev.binding.phid or dev.placeholder and dev.placeholder.phid or '' }}
|
||||
</td>
|
||||
<td>
|
||||
{{ dev.is_abstract() }}
|
||||
</td>
|
||||
<td>
|
||||
{% for t in dev.tags | sort(attribute="id") %}
|
||||
<a href="{{ url_for('labels.label_details', id=t.id)}}">{{ t.id }}</a>
|
||||
|
@ -392,14 +388,12 @@
|
|||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% include "inventory/addDevicestag.html" %}
|
||||
{% include "inventory/lot_delete_modal.html" %}
|
||||
{% include "inventory/actions.html" %}
|
||||
{% include "inventory/allocate.html" %}
|
||||
{% include "inventory/data_wipe.html" %}
|
||||
{% include "inventory/trade.html" %}
|
||||
{% include "inventory/alert_export_error.html" %}
|
||||
{% include "inventory/alert_unlink_tag_error.html" %}
|
||||
{% include "inventory/alert_lots_changes.html" %}
|
||||
|
||||
<!-- Custom Code -->
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
<input class="devicesList" type="hidden" name="device" />
|
||||
|
||||
<div>
|
||||
<a href="{{ referrer }}" class="btn btn-danger">Cancel</a>
|
||||
<a href="{{ url_for('inventory.device_details', id=dhid) }}" class="btn btn-danger">Cancel</a>
|
||||
<button class="btn btn-primary" type="submit">Unlink</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -26,111 +26,101 @@
|
|||
<thead>
|
||||
<tr class="text-center">
|
||||
<th scope="col">Basic Data</th>
|
||||
<th scope="col">Info to be Entered</th>
|
||||
<th scope="col">Info to be Decoupled</th>
|
||||
<th scope="col">Info Abstract device</th>
|
||||
<th scope="col">Info Real device</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">PHID:</th>
|
||||
<td class="table-success"></td>
|
||||
<td class="table-danger text-right">{{ placeholder.phid or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Manufacturer:</th>
|
||||
<td class="table-success">{{ device.manufacturer or '' }}</td>
|
||||
<td class="table-danger text-right">{{ placeholder.device.manufacturer or '' }}</td>
|
||||
<td class="table-success">{{ placeholder.binding.manufacturer or '' }}</td>
|
||||
<td class="table-warning text-right">{{ placeholder.device.manufacturer or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Model:</th>
|
||||
<td class="table-success">{{ device.model or '' }}</td>
|
||||
<td class="table-danger">{{ placeholder.device.model or '' }}</td>
|
||||
<td class="table-success">{{ placeholder.binding.model or '' }}</td>
|
||||
<td class="table-warning">{{ placeholder.device.model or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Serial Number:</th>
|
||||
<td class="table-success">{{ device.serial_number or '' }}</td>
|
||||
<td class="table-danger">{{ placeholder.device.serial_number or '' }}</td>
|
||||
<td class="table-success">{{ placeholder.binding.serial_number or '' }}</td>
|
||||
<td class="table-warning">{{ placeholder.device.serial_number or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Brand:</th>
|
||||
<td class="table-success">{{ device.brand or '' }}</td>
|
||||
<td class="table-danger">{{ placeholder.device.brand or '' }}</td>
|
||||
<td class="table-success">{{ placeholder.binding.brand or '' }}</td>
|
||||
<td class="table-warning">{{ placeholder.device.brand or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Sku:</th>
|
||||
<td class="table-success">{{ device.sku or '' }}</td>
|
||||
<td class="table-danger">{{ placeholder.device.sku or '' }}</td>
|
||||
<td class="table-success">{{ placeholder.binding.sku or '' }}</td>
|
||||
<td class="table-warning">{{ placeholder.device.sku or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Generation:</th>
|
||||
<td class="table-success">{{ device.generation or '' }}</td>
|
||||
<td class="table-danger">{{ placeholder.device.generation or '' }}</td>
|
||||
<td class="table-success">{{ placeholder.binding.generation or '' }}</td>
|
||||
<td class="table-warning">{{ placeholder.device.generation or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Version:</th>
|
||||
<td class="table-success">{{ device.version or '' }}</td>
|
||||
<td class="table-danger">{{ placeholder.device.version or '' }}</td>
|
||||
<td class="table-success">{{ placeholder.binding.version or '' }}</td>
|
||||
<td class="table-warning">{{ placeholder.device.version or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Weight:</th>
|
||||
<td class="table-success">{{ device.weight or '' }}</td>
|
||||
<td class="table-danger">{{ placeholder.device.weight or '' }}</td>
|
||||
<td class="table-success">{{ placeholder.binding.weight or '' }}</td>
|
||||
<td class="table-warning">{{ placeholder.device.weight or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Width:</th>
|
||||
<td class="table-success">{{ device.width or '' }}</td>
|
||||
<td class="table-danger">{{ placeholder.device.width or '' }}</td>
|
||||
<td class="table-success">{{ placeholder.binding.width or '' }}</td>
|
||||
<td class="table-warning">{{ placeholder.device.width or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Height:</th>
|
||||
<td class="table-success">{{ device.height or '' }}</td>
|
||||
<td class="table-danger">{{ placeholder.device.height or '' }}</td>
|
||||
<td class="table-success">{{ placeholder.binding.height or '' }}</td>
|
||||
<td class="table-warning">{{ placeholder.device.height or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Depth:</th>
|
||||
<td class="table-success">{{ device.depth or '' }}</td>
|
||||
<td class="table-danger">{{ placeholder.device.depth or '' }}</td>
|
||||
<td class="table-success">{{ placeholder.binding.depth or '' }}</td>
|
||||
<td class="table-warning">{{ placeholder.device.depth or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Color:</th>
|
||||
<td class="table-success">{{ device.color or '' }}</td>
|
||||
<td class="table-danger">{{ placeholder.device.color or '' }}</td>
|
||||
<td class="table-success">{{ placeholder.binding.color or '' }}</td>
|
||||
<td class="table-warning">{{ placeholder.device.color or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Production date:</th>
|
||||
<td class="table-success">{{ device.production_date or '' }}</td>
|
||||
<td class="table-danger">{{ placeholder.device.production_date or '' }}</td>
|
||||
<td class="table-success">{{ placeholder.binding.production_date or '' }}</td>
|
||||
<td class="table-warning">{{ placeholder.device.production_date or '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Variant:</th>
|
||||
<td class="table-success">{{ device.variant or '' }}</td>
|
||||
<td class="table-danger">{{ placeholder.device.variant or '' }}</td>
|
||||
<td class="table-success">{{ placeholder.binding.variant or '' }}</td>
|
||||
<td class="table-warning">{{ placeholder.device.variant or '' }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
{% if placeholder.device.components or device.components %}
|
||||
{% if placeholder.components %}
|
||||
<h2>Components</h2>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="text-center">
|
||||
<th scope="col">Info to be Entered</th>
|
||||
<th scope="col">Info to be Decoupled</th>
|
||||
<th scope="col">Info Abstract device</th>
|
||||
<th scope="col">Info Real device</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="table-success">
|
||||
{% for c in device.components %}
|
||||
* {{ c.verbose_name }}<br />
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td class="table-danger text-right">
|
||||
{% for c in placeholder.device.components %}
|
||||
* {{ c.verbose_name }}<br />
|
||||
{% endfor %}
|
||||
<td class="table-warning text-right">
|
||||
{{ placeholder.components or ''}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -139,19 +129,22 @@
|
|||
|
||||
<br />
|
||||
|
||||
{% if placeholder.device.manual_actions or device.manual_actions %}
|
||||
{% if placeholder.device.manual_actions or placeholder.binding.manual_actions %}
|
||||
<h2>Actions</h2>
|
||||
<p>
|
||||
The actions will become real device and will no longer be in the abstract
|
||||
</p>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="text-center">
|
||||
<th scope="col">Info to be Entered</th>
|
||||
<th scope="col">Info to be Decoupled</th>
|
||||
<th scope="col">Info Abstract device</th>
|
||||
<th scope="col">Info Real device</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="table-success">
|
||||
{% for a in device.manual_actions %}
|
||||
{% for a in placeholder.binding.manual_actions %}
|
||||
* {{ a.t }}<br />
|
||||
{% endfor %}
|
||||
</td>
|
||||
|
@ -165,6 +158,32 @@
|
|||
</table>
|
||||
{% endif %}
|
||||
|
||||
{% if placeholder.device.tags %}
|
||||
<h2>Tags</h2>
|
||||
<p>
|
||||
The tags will become real device and will no longer be in the abstract
|
||||
</p>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="text-center">
|
||||
<th scope="col">Info Abstract device</th>
|
||||
<th scope="col">Info Real device</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="table-success">
|
||||
</td>
|
||||
<td class="table-danger text-right">
|
||||
{% for a in placeholder.device.tags %}
|
||||
* {{ a.t }}<br />
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
<div>
|
||||
<form method="post">
|
||||
<a href="{{ url_for('inventory.device_details', id=placeholder.device.devicehub_id) }}" class="btn btn-danger">Cancel</a>
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -251,6 +251,7 @@ def test_update_parent():
|
|||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.auth_app_context.__name__)
|
||||
@pytest.mark.parametrize(
|
||||
'action_model_state',
|
||||
(
|
||||
|
@ -264,15 +265,18 @@ def test_update_parent():
|
|||
),
|
||||
)
|
||||
def test_generic_action(
|
||||
action_model_state: Tuple[models.Action, states.Trading], user: UserClient
|
||||
action_model_state: Tuple[models.ToPrepare, states.Trading], user2: UserClient
|
||||
):
|
||||
"""Tests POSTing all generic actions."""
|
||||
user = user2
|
||||
action_model, state = action_model_state
|
||||
snapshot, _ = user.post(file('basic.snapshot'), res=models.Snapshot)
|
||||
action = {'type': action_model.t, 'devices': [snapshot['device']['id']]}
|
||||
abstract = Device.query.filter(Device.id == snapshot['device']['id']).one()
|
||||
real = abstract.binding.device
|
||||
action = {'type': action_model.t, 'devices': [real.id]}
|
||||
action, _ = user.post(action, res=models.Action)
|
||||
assert action['devices'][0]['id'] == snapshot['device']['id']
|
||||
device, _ = user.get(res=Device, item=snapshot['device']['devicehubID'])
|
||||
assert action['devices'][0]['id'] == real.id
|
||||
device, _ = user.get(res=Device, item=real.dhid)
|
||||
assert device['actions'][-1]['id'] == action['id']
|
||||
assert device['physical'] == state.name
|
||||
# Check if the update of device is changed
|
||||
|
@ -280,6 +284,7 @@ def test_generic_action(
|
|||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.auth_app_context.__name__)
|
||||
@pytest.mark.parametrize(
|
||||
'action_model',
|
||||
(
|
||||
|
@ -288,14 +293,17 @@ def test_generic_action(
|
|||
),
|
||||
)
|
||||
def test_simple_status_actions(
|
||||
action_model: models.Action, user: UserClient, user2: UserClient
|
||||
action_model: models.Action, user2: UserClient
|
||||
):
|
||||
"""Simple test of status action."""
|
||||
user = user2
|
||||
snap, _ = user.post(file('basic.snapshot'), res=models.Snapshot)
|
||||
abstract = Device.query.filter(Device.id == snap['device']['id']).one()
|
||||
real = abstract.binding.device
|
||||
|
||||
action = {'type': action_model.t, 'devices': [snap['device']['id']]}
|
||||
action = {'type': action_model.t, 'devices': [real.id]}
|
||||
action, _ = user.post(action, res=models.Action)
|
||||
device, _ = user.get(res=Device, item=snap['device']['devicehubID'])
|
||||
device, _ = user.get(res=Device, item=real.dhid)
|
||||
assert device['actions'][-1]['id'] == action['id']
|
||||
assert action['author']['id'] == user.user['id']
|
||||
assert action['rol_user']['id'] == user.user['id']
|
||||
|
@ -518,6 +526,7 @@ def test_recycling_container(user: UserClient):
|
|||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||
@pytest.mark.parametrize(
|
||||
'action_model',
|
||||
(
|
||||
|
@ -528,13 +537,16 @@ def test_recycling_container(user: UserClient):
|
|||
def test_status_without_lot(action_model: models.Action, user: UserClient):
|
||||
"""Test of status actions for devices without lot."""
|
||||
snap, _ = user.post(file('basic.snapshot'), res=models.Snapshot)
|
||||
action = {'type': action_model.t, 'devices': [snap['device']['id']]}
|
||||
abstract = Device.query.filter_by(id=snap['device']['id']).first()
|
||||
device_id = abstract.binding.device.id
|
||||
action = {'type': action_model.t, 'devices': [device_id]}
|
||||
action, _ = user.post(action, res=models.Action)
|
||||
device, _ = user.get(res=Device, item=snap['device']['devicehubID'])
|
||||
device, _ = user.get(res=Device, item=abstract.dhid)
|
||||
assert device['actions'][-1]['id'] == action['id']
|
||||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||
@pytest.mark.parametrize(
|
||||
'action_model',
|
||||
(
|
||||
|
@ -542,17 +554,18 @@ def test_status_without_lot(action_model: models.Action, user: UserClient):
|
|||
for ams in [models.Recycling, models.Use, models.Refurbish, models.Management]
|
||||
),
|
||||
)
|
||||
def test_status_in_temporary_lot(action_model: models.Action, user: UserClient):
|
||||
def test_status_in_temporary_lot(action_model: models.Action, user: UserClient, app: Devicehub):
|
||||
"""Test of status actions for devices in a temporary lot."""
|
||||
snap, _ = user.post(file('basic.snapshot'), res=models.Snapshot)
|
||||
device_id = snap['device']['id']
|
||||
abstract = Device.query.filter_by(id=snap['device']['id']).first()
|
||||
device_id = abstract.binding.device.id
|
||||
lot, _ = user.post({'name': 'MyLotOut'}, res=Lot)
|
||||
lot, _ = user.post(
|
||||
{}, res=Lot, item='{}/devices'.format(lot['id']), query=[('id', device_id)]
|
||||
)
|
||||
action = {'type': action_model.t, 'devices': [device_id]}
|
||||
action, _ = user.post(action, res=models.Action)
|
||||
device, _ = user.get(res=Device, item=snap['device']['devicehubID'])
|
||||
device, _ = user.get(res=Device, item=abstract.dhid)
|
||||
assert device['actions'][-1]['id'] == action['id']
|
||||
|
||||
|
||||
|
@ -991,8 +1004,9 @@ def test_licences(client: Client):
|
|||
def test_allocate(user: UserClient):
|
||||
"""Tests allocate"""
|
||||
snapshot, _ = user.post(file('basic.snapshot'), res=models.Snapshot)
|
||||
device_id = snapshot['device']['id']
|
||||
devicehub_id = snapshot['device']['devicehubID']
|
||||
abstract = Device.query.filter_by(id=snapshot['device']['id']).one()
|
||||
device_id = abstract.binding.device.id
|
||||
devicehub_id = abstract.dhid
|
||||
post_request = {
|
||||
"transaction": "ccc",
|
||||
"finalUserCode": "aabbcc",
|
||||
|
@ -1060,8 +1074,9 @@ def test_allocate_bad_dates(user: UserClient):
|
|||
def test_deallocate(user: UserClient):
|
||||
"""Tests deallocate"""
|
||||
snapshot, _ = user.post(file('basic.snapshot'), res=models.Snapshot)
|
||||
device_id = snapshot['device']['id']
|
||||
devicehub_id = snapshot['device']['devicehubID']
|
||||
abstract = Device.query.filter_by(id=snapshot['device']['id']).one()
|
||||
device_id = abstract.binding.device.id
|
||||
devicehub_id = abstract.dhid
|
||||
post_deallocate = {
|
||||
"startTime": "2020-11-01T02:00:00+00:00",
|
||||
"transaction": "ccc",
|
||||
|
@ -1393,27 +1408,6 @@ def test_price_custom():
|
|||
assert c['price']['id'] == p['id']
|
||||
|
||||
|
||||
@pytest.mark.mvp
|
||||
def test_price_custom_client(user: UserClient):
|
||||
"""As test_price_custom but creating the price through the API."""
|
||||
s = file('basic.snapshot')
|
||||
snapshot, _ = user.post(s, res=models.Snapshot)
|
||||
price, _ = user.post(
|
||||
{
|
||||
'type': 'Price',
|
||||
'price': 25,
|
||||
'currency': Currency.EUR.name,
|
||||
'device': snapshot['device']['id'],
|
||||
},
|
||||
res=models.Action,
|
||||
)
|
||||
assert 25 == price['price']
|
||||
assert Currency.EUR.name == price['currency']
|
||||
|
||||
device, _ = user.get(res=Device, item=price['device']['devicehubID'])
|
||||
assert 25 == device['price']['price']
|
||||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.auth_app_context.__name__)
|
||||
def test_erase_physical():
|
||||
|
|
|
@ -54,6 +54,7 @@ def test_api_docs(client: Client):
|
|||
'/inventory/device/',
|
||||
'/inventory/device/add/',
|
||||
'/inventory/device/{id}/',
|
||||
'/inventory/device/{dhid}/binding/',
|
||||
'/inventory/export/{export_id}/',
|
||||
'/inventory/lot/add/',
|
||||
'/inventory/lot/{id}/',
|
||||
|
@ -68,8 +69,8 @@ def test_api_docs(client: Client):
|
|||
'/inventory/lot/{lot_id}/upload-snapshot/',
|
||||
'/inventory/snapshots/{snapshot_uuid}/',
|
||||
'/inventory/snapshots/',
|
||||
'/inventory/tag/devices/add/',
|
||||
'/inventory/tag/devices/{id}/del/',
|
||||
'/inventory/tag/devices/{dhid}/add/',
|
||||
'/inventory/tag/devices/{dhid}/del/',
|
||||
'/inventory/upload-snapshot/',
|
||||
'/inventory/device/edit/{id}/',
|
||||
'/inventory/upload-placeholder/',
|
||||
|
|
|
@ -473,6 +473,7 @@ def test_get_devices(app: Devicehub, user: UserClient):
|
|||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||
def test_get_device_permissions(app: Devicehub, user: UserClient, user2: UserClient,
|
||||
client: Client):
|
||||
"""Checks GETting a d.Desktop with its components."""
|
||||
|
@ -480,7 +481,9 @@ def test_get_device_permissions(app: Devicehub, user: UserClient, user2: UserCli
|
|||
s, _ = user.post(file('asus-eee-1000h.snapshot.11'), res=m.Snapshot)
|
||||
pc, res = user.get(res=d.Device, item=s['device']['devicehubID'])
|
||||
assert res.status_code == 200
|
||||
assert len(pc['actions']) == 7
|
||||
assert len(pc['actions']) == 0
|
||||
pc = d.Device.query.filter_by(devicehub_id=s['device']['devicehubID']).one()
|
||||
assert len(pc.placeholder.binding.actions) == 7
|
||||
|
||||
html, _ = client.get(res=d.Device, item=s['device']['devicehubID'], accept=ANY)
|
||||
assert 'intel atom cpu n270 @ 1.60ghz' in html
|
||||
|
@ -660,12 +663,15 @@ def test_cooking_mixer_api(user: UserClient):
|
|||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||
def test_hid_with_mac(app: Devicehub, user: UserClient):
|
||||
"""Checks hid with mac."""
|
||||
snapshot = file('asus-eee-1000h.snapshot.11')
|
||||
snap, _ = user.post(snapshot, res=m.Snapshot)
|
||||
pc, _ = user.get(res=d.Device, item=snap['device']['devicehubID'])
|
||||
assert pc['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d'
|
||||
assert pc['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116'
|
||||
pc = d.Device.query.filter_by(devicehub_id=snap['device']['devicehubID']).one()
|
||||
assert pc.placeholder.binding.hid == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d'
|
||||
|
||||
|
||||
@pytest.mark.mvp
|
||||
|
@ -706,6 +712,7 @@ def test_hid_with_2networkadapters(app: Devicehub, user: UserClient):
|
|||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||
def test_hid_with_2network_and_drop_no_mac_in_hid(app: Devicehub, user: UserClient):
|
||||
"""Checks hid with 2 networks adapters and next drop the network is not used in hid"""
|
||||
snapshot = yaml2json('asus-eee-1000h.snapshot.11')
|
||||
|
@ -715,19 +722,22 @@ def test_hid_with_2network_and_drop_no_mac_in_hid(app: Devicehub, user: UserClie
|
|||
network['serialNumber'] = 'a0:24:8c:7f:cf:2d'
|
||||
snap, _ = user.post(json_encode(snapshot), res=m.Snapshot)
|
||||
pc, _ = user.get(res=d.Device, item=snap['device']['devicehubID'])
|
||||
assert pc['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d'
|
||||
assert pc['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116'
|
||||
pc = d.Device.query.filter_by(devicehub_id=snap['device']['devicehubID']).one()
|
||||
assert pc.placeholder.binding.hid == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d'
|
||||
|
||||
snapshot['uuid'] = 'd1b70cb8-8929-4f36-99b7-fe052cec0abb'
|
||||
snapshot['components'] = [c for c in snapshot['components'] if c != network]
|
||||
user.post(json_encode(snapshot), res=m.Snapshot)
|
||||
devices, _ = user.get(res=d.Device)
|
||||
laptop = devices['items'][0]
|
||||
assert laptop['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d'
|
||||
assert pc.placeholder.binding.hid == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d'
|
||||
assert len([c for c in devices['items'] if c['type'] == 'Laptop']) == 2
|
||||
assert len([c for c in laptop['components'] if c['type'] == 'NetworkAdapter']) == 1
|
||||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||
def test_hid_with_2network_and_drop_mac_in_hid(app: Devicehub, user: UserClient):
|
||||
"""Checks hid with 2 networks adapters and next drop the network is used in hid"""
|
||||
# One tipical snapshot with 2 network cards
|
||||
|
@ -738,7 +748,9 @@ def test_hid_with_2network_and_drop_mac_in_hid(app: Devicehub, user: UserClient)
|
|||
network['serialNumber'] = 'a0:24:8c:7f:cf:2d'
|
||||
snap, _ = user.post(json_encode(snapshot), res=m.Snapshot)
|
||||
pc, _ = user.get(res=d.Device, item=snap['device']['devicehubID'])
|
||||
assert pc['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d'
|
||||
assert pc['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116'
|
||||
pc = d.Device.query.filter_by(devicehub_id=snap['device']['devicehubID']).one()
|
||||
assert pc.placeholder.binding.hid == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d'
|
||||
|
||||
# we drop the network card then is used for to build the hid
|
||||
snapshot['uuid'] = 'd1b70cb8-8929-4f36-99b7-fe052cec0abb'
|
||||
|
|
|
@ -238,18 +238,22 @@ def test_device_search_regenerate_table(app: DeviceSearch, user: UserClient):
|
|||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||
def test_device_query_search(user: UserClient):
|
||||
# todo improve
|
||||
snapshot, _ = user.post(file('basic.snapshot'), res=Snapshot)
|
||||
dev = Device.query.filter_by(id=snapshot['device']['id']).one()
|
||||
user.post(file('computer-monitor.snapshot'), res=Snapshot)
|
||||
user.post(file('real-eee-1001pxd.snapshot.11'), res=Snapshot)
|
||||
i, _ = user.get(res=Device, query=[('search', 'desktop')])
|
||||
assert i['items'][0]['id'] == snapshot['device']['id']
|
||||
assert i['items'][0]['id'] == dev.id
|
||||
i, _ = user.get(res=Device, query=[('search', 'intel')])
|
||||
assert len(i['items']) == 1
|
||||
i, _ = user.get(res=Device, query=[('search', i['items'][0]['devicehubID'])])
|
||||
dev1 = Device.query.filter_by(id=i['items'][0]['id']).one()
|
||||
i, _ = user.get(res=Device, query=[('search', dev1.devicehub_id)])
|
||||
assert len(i['items']) == 1
|
||||
i, _ = user.get(res=Device, query=[('search', snapshot['device']['id'])])
|
||||
dev2 = Device.query.filter_by(id=i['items'][0]['id']).one()
|
||||
i, _ = user.get(res=Device, query=[('search', dev2.devicehub_id)])
|
||||
assert len(i['items']) == 1
|
||||
|
||||
|
||||
|
|
|
@ -319,16 +319,16 @@ def test_link_tag_to_device(user3: UserClientFlask):
|
|||
}
|
||||
user3.post(uri, data=data)
|
||||
|
||||
body, status = user3.get('/inventory/device/')
|
||||
body, status = user3.get('/inventory/device/{}/'.format(dev.dhid))
|
||||
assert "tag1" in body
|
||||
|
||||
data = {
|
||||
'tag': "tag1",
|
||||
'device': dev.id,
|
||||
'device': dev.dhid,
|
||||
'csrf_token': generate_csrf(),
|
||||
}
|
||||
|
||||
uri = '/inventory/tag/devices/add/'
|
||||
uri = '/inventory/tag/devices/{}/add/'.format(dev.dhid)
|
||||
user3.post(uri, data=data)
|
||||
assert len(list(dev.tags)) == 1
|
||||
tags = [tag.id for tag in dev.tags]
|
||||
|
@ -405,7 +405,7 @@ def test_print_labels(user3: UserClientFlask):
|
|||
'csrf_token': generate_csrf(),
|
||||
}
|
||||
|
||||
uri = '/inventory/tag/devices/add/'
|
||||
uri = '/inventory/tag/devices/{}/add/'.format(dev.dhid)
|
||||
user3.post(uri, data=data)
|
||||
|
||||
assert len(list(dev.tags)) == 1
|
||||
|
@ -418,7 +418,7 @@ def test_print_labels(user3: UserClientFlask):
|
|||
body, status = user3.post(uri, data=data)
|
||||
|
||||
assert status == '200 OK'
|
||||
path = "/devices/{}".format(dev.devicehub_id)
|
||||
path = "/devices/{}".format(dev.dhid)
|
||||
assert path in body
|
||||
assert "tag1" in body
|
||||
|
||||
|
@ -2020,7 +2020,6 @@ def test_manual_binding(user3: UserClientFlask):
|
|||
'model': "LC27T55",
|
||||
'manufacturer': "Samsung",
|
||||
'generation': 1,
|
||||
'weight': 0.1,
|
||||
'height': 0.1,
|
||||
'depth': 0.1,
|
||||
'id_device_supplier': "b2",
|
||||
|
@ -2046,17 +2045,24 @@ def test_manual_binding(user3: UserClientFlask):
|
|||
old_placeholder = dev_wb.binding
|
||||
|
||||
# page binding
|
||||
dhid = dev_wb.devicehub_id
|
||||
dhid = dev_wb.dhid
|
||||
uri = f'/inventory/binding/{dhid}/sid/'
|
||||
body, status = user3.get(uri)
|
||||
assert status == '200 OK'
|
||||
assert 'sid' in body
|
||||
assert 'Confirm' in body
|
||||
|
||||
phid_real = dev.placeholder.phid
|
||||
phid_abstract = dev_wb.binding.phid
|
||||
dhid_real = dev.dhid
|
||||
dhid_abstract = dev_wb.dhid
|
||||
|
||||
# action binding
|
||||
body, status = user3.post(uri, data={})
|
||||
assert status == '200 OK'
|
||||
assert f"Device "{dhid}" bind successfully with sid!" in body
|
||||
txt = f"Device real with PHID: {phid_real} and DHID: {dhid_real} "
|
||||
txt += f"bind successfully with device abstract PHID: {phid_abstract} DHID: {dhid_abstract}."
|
||||
assert txt in body
|
||||
|
||||
# check new structure
|
||||
assert dev_wb.binding.phid == 'sid'
|
||||
|
@ -2144,7 +2150,7 @@ def test_unbinding(user3: UserClientFlask):
|
|||
old_placeholder = dev_wb.binding
|
||||
|
||||
# page binding
|
||||
dhid = dev_wb.devicehub_id
|
||||
dhid = dev_wb.dhid
|
||||
uri = f'/inventory/binding/{dhid}/sid/'
|
||||
user3.get(uri)
|
||||
|
||||
|
@ -2153,11 +2159,14 @@ def test_unbinding(user3: UserClientFlask):
|
|||
user3.post(uri, data={})
|
||||
assert dev.placeholder.binding == dev_wb
|
||||
|
||||
dhid = dev.dhid
|
||||
# action unbinding
|
||||
uri = '/inventory/unbinding/sid/'
|
||||
body, status = user3.post(uri, data={})
|
||||
assert status == '200 OK'
|
||||
assert 'Device "sid" unbind successfully!' in body
|
||||
txt = f'Device with PHID:"sid" and DHID: {dhid} unbind successfully!'
|
||||
assert txt in body
|
||||
# assert 'Device "sid" unbind successfully!' in body
|
||||
|
||||
# check new structure
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ from ereuse_devicehub.resources.action.models import (
|
|||
from ereuse_devicehub.resources.action.views.snapshot import save_json
|
||||
from ereuse_devicehub.resources.device import models as m
|
||||
from ereuse_devicehub.resources.device.exceptions import NeedsId
|
||||
from ereuse_devicehub.resources.device.models import SolidStateDrive
|
||||
from ereuse_devicehub.resources.device.models import SolidStateDrive, Device
|
||||
from ereuse_devicehub.resources.device.sync import (
|
||||
MismatchBetweenProperties,
|
||||
MismatchBetweenTagsAndHid,
|
||||
|
@ -91,6 +91,7 @@ def test_snapshot_schema(app: Devicehub):
|
|||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||
def test_snapshot_post(user: UserClient):
|
||||
"""Tests the post snapshot endpoint (validation, etc), data correctness,
|
||||
and relationship correctness.
|
||||
|
@ -108,11 +109,12 @@ def test_snapshot_post(user: UserClient):
|
|||
assert snapshot['author']['id'] == user.user['id']
|
||||
assert 'actions' not in snapshot['device']
|
||||
assert 'author' not in snapshot['device']
|
||||
device, _ = user.get(res=m.Device, item=snapshot['device']['devicehubID'])
|
||||
dev = m.Device.query.filter_by(id=snapshot['device']['id']).one()
|
||||
device, _ = user.get(res=m.Device, item=dev.devicehub_id)
|
||||
key = itemgetter('serialNumber')
|
||||
snapshot['components'].sort(key=key)
|
||||
device['components'].sort(key=key)
|
||||
assert snapshot['components'] == device['components']
|
||||
assert {(x['id'], x['type']) for x in device['components']} == {(x['id'], x['type']) for x in snapshot['components']}
|
||||
|
||||
assert {c['type'] for c in snapshot['components']} == {
|
||||
m.GraphicCard.t,
|
||||
|
@ -190,7 +192,6 @@ def test_snapshot_power_on_hours(user: UserClient):
|
|||
)
|
||||
|
||||
errors = SnapshotsLog.query.filter().all()
|
||||
snap_log = errors[1]
|
||||
assert len(errors) == 2
|
||||
assert str(errors[0].snapshot_uuid) == snap['uuid']
|
||||
assert str(errors[1].snapshot.uuid) == snap['uuid']
|
||||
|
@ -199,6 +200,7 @@ def test_snapshot_power_on_hours(user: UserClient):
|
|||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||
def test_snapshot_component_add_remove(user: UserClient):
|
||||
"""Tests adding and removing components and some don't generate HID.
|
||||
All computers generate HID.
|
||||
|
@ -221,7 +223,8 @@ def test_snapshot_component_add_remove(user: UserClient):
|
|||
# RateComputer.t),
|
||||
# perform_second_snapshot=False)
|
||||
pc1_id = snapshot1['device']['id']
|
||||
pc1_devicehub_id = snapshot1['device']['devicehubID']
|
||||
pc1_dev = m.Device.query.filter_by(id=pc1_id).one()
|
||||
pc1_devicehub_id = pc1_dev.devicehub_id
|
||||
pc1, _ = user.get(res=m.Device, item=pc1_devicehub_id)
|
||||
update1_pc1 = pc1['updated']
|
||||
# Parent contains components
|
||||
|
@ -229,14 +232,15 @@ def test_snapshot_component_add_remove(user: UserClient):
|
|||
'p1c1s',
|
||||
'p1c2s',
|
||||
'p1c3s',
|
||||
)
|
||||
) == tuple(x.serial_number for x in pc1_dev.binding.device.components)
|
||||
# Components contain parent
|
||||
assert all(c['parent'] == pc1_id for c in pc1['components'])
|
||||
# pc has three actions: Snapshot, BenchmarkProcessor and RateComputer
|
||||
assert len(pc1['actions']) == 2
|
||||
assert pc1['actions'][1]['type'] == Snapshot.t
|
||||
# p1c1s has Snapshot
|
||||
p1c1s, _ = user.get(res=m.Device, item=pc1['components'][0]['devicehubID'])
|
||||
p1c1s_dev = m.Device.query.filter_by(id=pc1['components'][0]['id']).one()
|
||||
p1c1s, _ = user.get(res=m.Device, item=p1c1s_dev.devicehub_id)
|
||||
assert tuple(e['type'] for e in p1c1s['actions']) == ('Snapshot',)
|
||||
|
||||
# We register a new device
|
||||
|
@ -249,7 +253,8 @@ def test_snapshot_component_add_remove(user: UserClient):
|
|||
# snapshot2 = snapshot_and_check(user, s2, action_types=('Remove', 'RateComputer'),
|
||||
# perform_second_snapshot=False)
|
||||
pc2_id = snapshot2['device']['id']
|
||||
pc2_devicehub_id = snapshot2['device']['devicehubID']
|
||||
pc2_dev = m.Device.query.filter_by(id=pc2_id).one()
|
||||
pc2_devicehub_id = pc2_dev.devicehub_id
|
||||
pc1, _ = user.get(res=m.Device, item=pc1_devicehub_id)
|
||||
pc2, _ = user.get(res=m.Device, item=pc2_devicehub_id)
|
||||
# Check if the update_timestamp is updated
|
||||
|
@ -269,7 +274,8 @@ def test_snapshot_component_add_remove(user: UserClient):
|
|||
assert all(c['parent'] == pc2_id for c in pc2['components'])
|
||||
assert tuple(e['type'] for e in pc2['actions']) == ('Snapshot',)
|
||||
# p1c2s has two Snapshots, a Remove and an Add
|
||||
p1c2s, _ = user.get(res=m.Device, item=pc2['components'][0]['devicehubID'])
|
||||
p1c2s_dev = m.Device.query.filter_by(id=pc2['components'][0]['id']).one()
|
||||
p1c2s, _ = user.get(res=m.Device, item=p1c2s_dev.devicehub_id)
|
||||
assert tuple(e['type'] for e in p1c2s['actions']) == (
|
||||
'BenchmarkProcessor',
|
||||
'Snapshot',
|
||||
|
@ -299,8 +305,8 @@ def test_snapshot_component_add_remove(user: UserClient):
|
|||
assert tuple(get_actions_info(pc1['actions'])) == (
|
||||
# id, type, components, snapshot
|
||||
('BenchmarkProcessor', []), # first BenchmarkProcessor
|
||||
('Snapshot', ['p1c1s', 'p1c2s', 'p1c3s']), # first Snapshot1
|
||||
('Remove', ['p1c2s']), # Remove Processor in Snapshot2
|
||||
('Snapshot', ['p1c1s', 'p1c2s', 'p1c3s', 'p1c2s']), # first Snapshot1
|
||||
('Remove', ['p1c2s', 'p1c2s']), # Remove Processor in Snapshot2
|
||||
('Snapshot', ['p1c2s', 'p1c3s']), # This Snapshot3
|
||||
)
|
||||
# PC2
|
||||
|
@ -311,12 +317,13 @@ def test_snapshot_component_add_remove(user: UserClient):
|
|||
'Remove', # the processor we added in 2.
|
||||
)
|
||||
# p1c2s has Snapshot, Remove and Add
|
||||
p1c2s, _ = user.get(res=m.Device, item=pc1['components'][0]['devicehubID'])
|
||||
p1c2s_dev = m.Device.query.filter_by(id=pc1['components'][0]['id']).one()
|
||||
p1c2s, _ = user.get(res=m.Device, item=p1c2s_dev.devicehub_id)
|
||||
assert tuple(get_actions_info(p1c2s['actions'])) == (
|
||||
('BenchmarkProcessor', []), # first BenchmarkProcessor
|
||||
('Snapshot', ['p1c1s', 'p1c2s', 'p1c3s']), # First Snapshot to PC1
|
||||
('Snapshot', ['p1c1s', 'p1c2s', 'p1c3s', 'p1c2s']), # First Snapshot to PC1
|
||||
('Snapshot', ['p1c2s', 'p2c1s']), # Second Snapshot to PC2
|
||||
('Remove', ['p1c2s']), # ...which caused p1c2s to be removed form PC1
|
||||
('Remove', ['p1c2s', 'p1c2s']), # ...which caused p1c2s to be removed form PC1
|
||||
('Snapshot', ['p1c2s', 'p1c3s']), # The third Snapshot to PC1
|
||||
('Remove', ['p1c2s']), # ...which caused p1c2 to be removed from PC2
|
||||
)
|
||||
|
@ -482,6 +489,7 @@ def test_not_remove_ram_in_same_computer(user: UserClient):
|
|||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||
def test_erase_privacy_standards_endtime_sort(user: UserClient):
|
||||
"""Tests a Snapshot with EraseSectors and the resulting privacy
|
||||
properties.
|
||||
|
@ -520,8 +528,9 @@ def test_erase_privacy_standards_endtime_sort(user: UserClient):
|
|||
|
||||
# The actual test
|
||||
storage = next(e for e in snapshot['components'] if e['type'] == SolidStateDrive.t)
|
||||
db_storage = m.Device.query.filter_by(id=storage['id']).one()
|
||||
storage, _ = user.get(
|
||||
res=m.Device, item=storage['devicehubID']
|
||||
res=m.Device, item=db_storage.devicehub_id
|
||||
) # Let's get storage actions too
|
||||
# order: endTime ascending
|
||||
# erasure1/2 have an user defined time and others actions endTime = created
|
||||
|
@ -555,17 +564,22 @@ def test_erase_privacy_standards_endtime_sort(user: UserClient):
|
|||
assert 'num' not in step2
|
||||
assert ['HMG_IS5'] == erasure['standards']
|
||||
assert storage['privacy']['type'] == 'EraseSectors'
|
||||
pc, _ = user.get(res=m.Device, item=snapshot['device']['devicehubID'])
|
||||
dev = m.Device.query.filter_by(id=snapshot['device']['id']).one()
|
||||
pc, _ = user.get(res=m.Device, item=dev.devicehub_id)
|
||||
# pc, _ = user.get(res=m.Device, item=snapshot['device']['devicehubID'])
|
||||
assert pc['privacy'] == [storage['privacy']]
|
||||
|
||||
# Let's try a second erasure with an error
|
||||
s['uuid'] = uuid4()
|
||||
s['components'][0]['actions'][0]['severity'] = 'Error'
|
||||
snapshot, _ = user.post(json_encode(s), res=Snapshot)
|
||||
storage, _ = user.get(res=m.Device, item=storage['devicehubID'])
|
||||
storage, _ = user.get(res=m.Device, item=db_storage.devicehub_id)
|
||||
assert storage['hid'] == 'solidstatedrive-c1mr-c1ml-c1s'
|
||||
assert dev.components[0].privacy.type == 'EraseSectors'
|
||||
assert storage['privacy']['type'] == 'EraseSectors'
|
||||
pc, _ = user.get(res=m.Device, item=snapshot['device']['devicehubID'])
|
||||
dev = m.Device.query.filter_by(id=snapshot['device']['id']).one()
|
||||
pc, _ = user.get(res=m.Device, item=dev.devicehub_id)
|
||||
# import pdb; pdb.set_trace()
|
||||
assert pc['privacy'] == [storage['privacy']]
|
||||
|
||||
|
||||
|
@ -889,23 +903,26 @@ def test_snapshot_failed_missing_chassis(app: Devicehub, user: UserClient):
|
|||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||
def test_snapshot_failed_end_time_bug(app: Devicehub, user: UserClient):
|
||||
"""This test check if the end_time = 0001-01-01 00:00:00+00:00
|
||||
and then we get a /devices, this create a crash
|
||||
"""
|
||||
snapshot_file = file('asus-end_time_bug88.snapshot')
|
||||
snapshot, _ = user.post(res=Snapshot, data=snapshot_file)
|
||||
device, _ = user.get(res=m.Device, item=snapshot['device']['devicehubID'])
|
||||
dev = m.Device.query.filter_by(id=snapshot['device']['id']).one()
|
||||
device, _ = user.get(res=m.Device, item=dev.devicehub_id)
|
||||
end_times = [x['endTime'] for x in device['actions']]
|
||||
|
||||
assert '1970-01-02T00:00:00+00:00' in end_times
|
||||
assert not '0001-01-01T00:00:00+00:00' in end_times
|
||||
assert '0001-01-01T00:00:00+00:00' not in end_times
|
||||
|
||||
tmp_snapshots = app.config['TMP_SNAPSHOTS']
|
||||
shutil.rmtree(tmp_snapshots)
|
||||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||
def test_snapshot_not_failed_end_time_bug(app: Devicehub, user: UserClient):
|
||||
"""This test check if the end_time != 0001-01-01 00:00:00+00:00
|
||||
and then we get a /devices, this create a crash
|
||||
|
@ -913,7 +930,8 @@ def test_snapshot_not_failed_end_time_bug(app: Devicehub, user: UserClient):
|
|||
snapshot_file = yaml2json('asus-end_time_bug88.snapshot')
|
||||
snapshot_file['endTime'] = '2001-01-01 00:00:00+00:00'
|
||||
snapshot, _ = user.post(res=Snapshot, data=json_encode(snapshot_file))
|
||||
device, _ = user.get(res=m.Device, item=snapshot['device']['devicehubID'])
|
||||
db_dev = Device.query.filter_by(id=snapshot['device']['id']).one()
|
||||
device, _ = user.get(res=m.Device, item=db_dev.devicehub_id)
|
||||
end_times = [x['endTime'] for x in device['actions']]
|
||||
|
||||
assert not '1970-01-02T00:00:00+00:00' in end_times
|
||||
|
@ -974,6 +992,7 @@ def test_snapshot_wb_lite(user: UserClient):
|
|||
body, res = user.post(snapshot, uri="/api/inventory/")
|
||||
|
||||
dev = m.Device.query.filter_by(devicehub_id=body['dhid']).one()
|
||||
dev = dev.placeholder.binding
|
||||
ssd = [x for x in dev.components if x.type == 'SolidStateDrive'][0]
|
||||
|
||||
assert dev.manufacturer == 'lenovo'
|
||||
|
@ -1000,6 +1019,7 @@ def test_snapshot_wb_lite_qemu(user: UserClient):
|
|||
assert res.status == '201 CREATED'
|
||||
|
||||
dev = m.Device.query.filter_by(devicehub_id=body['dhid']).one()
|
||||
dev = dev.placeholder.binding
|
||||
assert dev.manufacturer == 'qemu'
|
||||
assert dev.model == 'standard'
|
||||
assert dev.serial_number is None
|
||||
|
@ -1235,6 +1255,7 @@ def test_snapshot_errors(user: UserClient):
|
|||
assert len(SnapshotsLog.query.all()) == 1
|
||||
bodyLite, res = user.post(snapshot_lite, uri="/api/inventory/")
|
||||
dev = m.Device.query.filter_by(devicehub_id=bodyLite['dhid']).one()
|
||||
dev = dev.placeholder.binding
|
||||
assert len(SnapshotsLog.query.all()) == 4
|
||||
|
||||
assert body11['device'].get('hid') == dev.hid
|
||||
|
@ -1276,6 +1297,7 @@ def test_snapshot_errors_no_serial_number(user: UserClient):
|
|||
assert len(logs) == 1
|
||||
assert logs[0].description == 'Ok'
|
||||
dev = m.Device.query.filter_by(devicehub_id=bodyLite['dhid']).one()
|
||||
dev = dev.placeholder.binding
|
||||
assert not dev.model
|
||||
assert not dev.manufacturer
|
||||
assert not dev.serial_number
|
||||
|
|
|
@ -364,13 +364,12 @@ def test_tag_secondary_workbench_link_find(user: UserClient):
|
|||
s = yaml2json('basic.snapshot')
|
||||
s['device']['tags'] = [{'id': 'foo', 'secondary': 'bar', 'type': 'Tag'}]
|
||||
snapshot, _ = user.post(json_encode(s), res=Snapshot)
|
||||
device, _ = user.get(res=Device, item=snapshot['device']['devicehubID'])
|
||||
desktop = Device.query.filter_by(
|
||||
devicehub_id=snapshot['device']['devicehubID']
|
||||
).one()
|
||||
dev = Device.query.filter_by(id=snapshot['device']['id']).one()
|
||||
device, _ = user.get(res=Device, item=dev.devicehub_id)
|
||||
desktop = dev.binding.device
|
||||
assert [] == [x['id'] for x in device['tags']]
|
||||
assert 'foo' in [x.id for x in desktop.binding.device.tags]
|
||||
assert 'bar' in [x.secondary for x in desktop.binding.device.tags]
|
||||
assert 'foo' in [x.id for x in desktop.tags]
|
||||
assert 'bar' in [x.secondary for x in desktop.tags]
|
||||
|
||||
r, _ = user.get(
|
||||
res=Device, query=[('search', 'foo'), ('filter', {'type': ['Computer']})]
|
||||
|
|
|
@ -16,9 +16,11 @@ from ereuse_devicehub.resources.device.exceptions import NeedsId
|
|||
from ereuse_devicehub.resources.device.models import Device
|
||||
from ereuse_devicehub.resources.tag.model import Tag
|
||||
from tests.conftest import file, file_workbench, json_encode, yaml2json
|
||||
from tests import conftest
|
||||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||
def test_workbench_server_condensed(user: UserClient):
|
||||
"""As :def:`.test_workbench_server_phases` but all the actions
|
||||
condensed in only one big ``Snapshot`` file, as described
|
||||
|
@ -54,7 +56,8 @@ def test_workbench_server_condensed(user: UserClient):
|
|||
}
|
||||
assert snapshot['closed']
|
||||
assert snapshot['severity'] == 'Info'
|
||||
device, _ = user.get(res=Device, item=snapshot['device']['devicehubID'])
|
||||
db_dev = Device.query.filter_by(id=snapshot['device']['id']).one()
|
||||
device, _ = user.get(res=Device, item=db_dev.devicehub_id)
|
||||
assert device['dataStorageSize'] == 1100
|
||||
assert device['chassis'] == 'Tower'
|
||||
assert device['hid'] == 'desktop-d1mr-d1ml-d1s-na1-s'
|
||||
|
@ -175,13 +178,15 @@ def test_real_toshiba_11(user: UserClient):
|
|||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||
def test_snapshot_real_eee_1001pxd_with_rate(user: UserClient):
|
||||
"""Checks the values of the device, components,
|
||||
actions and their relationships of a real pc.
|
||||
"""
|
||||
s = file('real-eee-1001pxd.snapshot.11')
|
||||
snapshot, _ = user.post(res=em.Snapshot, data=s)
|
||||
pc, _ = user.get(res=Device, item=snapshot['device']['devicehubID'])
|
||||
dev = Device.query.filter_by(id=snapshot['device']['id']).one()
|
||||
pc, _ = user.get(res=Device, item=dev.devicehub_id)
|
||||
assert pc['type'] == 'Laptop'
|
||||
assert pc['chassis'] == 'Netbook'
|
||||
assert pc['model'] == '1001pxd'
|
||||
|
@ -222,7 +227,8 @@ def test_snapshot_real_eee_1001pxd_with_rate(user: UserClient):
|
|||
assert cpu['speed'] == 1.667
|
||||
assert 'hid' not in cpu
|
||||
assert pc['processorModel'] == cpu['model'] == 'intel atom cpu n455 @ 1.66ghz'
|
||||
cpu, _ = user.get(res=Device, item=cpu['devicehubID'])
|
||||
db_cpu = Device.query.filter_by(id=cpu['id']).one()
|
||||
cpu, _ = user.get(res=Device, item=db_cpu.devicehub_id)
|
||||
actions = cpu['actions']
|
||||
sysbench = next(e for e in actions if e['type'] == em.BenchmarkProcessorSysbench.t)
|
||||
assert sysbench['elapsed'] == 164
|
||||
|
@ -245,7 +251,8 @@ def test_snapshot_real_eee_1001pxd_with_rate(user: UserClient):
|
|||
)
|
||||
assert gpu['manufacturer'] == 'intel corporation'
|
||||
assert gpu['memory'] == 256
|
||||
gpu, _ = user.get(res=Device, item=gpu['devicehubID'])
|
||||
db_gpu = Device.query.filter_by(id=gpu['id']).one()
|
||||
gpu, _ = user.get(res=Device, item=db_gpu.devicehub_id)
|
||||
action_types = tuple(e['type'] for e in gpu['actions'])
|
||||
assert em.BenchmarkRamSysbench.t in action_types
|
||||
assert em.StressTest.t in action_types
|
||||
|
@ -264,7 +271,8 @@ def test_snapshot_real_eee_1001pxd_with_rate(user: UserClient):
|
|||
assert hdd['hid'] == 'harddrive-hitachi-hts54322-e2024242cv86hj'
|
||||
assert hdd['interface'] == 'ATA'
|
||||
assert hdd['size'] == 238475
|
||||
hdd, _ = user.get(res=Device, item=hdd['devicehubID'])
|
||||
db_hdd = Device.query.filter_by(id=hdd['id']).one()
|
||||
hdd, _ = user.get(res=Device, item=db_hdd.devicehub_id)
|
||||
action_types = tuple(e['type'] for e in hdd['actions'])
|
||||
assert em.BenchmarkRamSysbench.t in action_types
|
||||
assert em.StressTest.t in action_types
|
||||
|
|
Reference in a new issue