merge testing
This commit is contained in:
commit
327e5f20cb
|
@ -230,7 +230,7 @@ class Dummy:
|
||||||
user1.get(res=Device, item=sample_pc_devicehub_id) # Test
|
user1.get(res=Device, item=sample_pc_devicehub_id) # Test
|
||||||
anonymous = self.app.test_client()
|
anonymous = self.app.test_client()
|
||||||
html, _ = anonymous.get(res=Device, item=sample_pc_devicehub_id, accept=ANY)
|
html, _ = anonymous.get(res=Device, item=sample_pc_devicehub_id, accept=ANY)
|
||||||
assert 'intel core2 duo cpu' in html
|
assert 'hewlett-packard' in html
|
||||||
|
|
||||||
# For netbook: to preapre -> torepair -> to dispose -> disposed
|
# For netbook: to preapre -> torepair -> to dispose -> disposed
|
||||||
print('⭐ Done.')
|
print('⭐ Done.')
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
|
from boltons.urlutils import URL
|
||||||
from flask import current_app as app
|
from flask import current_app as app
|
||||||
from flask import g, session
|
from flask import g, session
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from werkzeug.security import generate_password_hash
|
from werkzeug.security import generate_password_hash
|
||||||
from wtforms import BooleanField, EmailField, PasswordField, validators
|
from wtforms import (
|
||||||
|
BooleanField,
|
||||||
|
EmailField,
|
||||||
|
PasswordField,
|
||||||
|
StringField,
|
||||||
|
URLField,
|
||||||
|
validators,
|
||||||
|
)
|
||||||
|
|
||||||
from ereuse_devicehub.db import db
|
from ereuse_devicehub.db import db
|
||||||
from ereuse_devicehub.resources.user.models import User
|
from ereuse_devicehub.resources.user.models import SanitizationEntity, User
|
||||||
|
|
||||||
|
|
||||||
class LoginForm(FlaskForm):
|
class LoginForm(FlaskForm):
|
||||||
|
@ -107,7 +115,7 @@ class PasswordForm(FlaskForm):
|
||||||
g.user.reset_dlt_keys(self.newpassword.data, keys_dlt)
|
g.user.reset_dlt_keys(self.newpassword.data, keys_dlt)
|
||||||
|
|
||||||
token_dlt = (
|
token_dlt = (
|
||||||
user.get_dlt_keys(self.password.data).get('data', {}).get('api_token')
|
g.user.get_dlt_keys(self.password.data).get('data', {}).get('api_token')
|
||||||
)
|
)
|
||||||
session['token_dlt'] = token_dlt
|
session['token_dlt'] = token_dlt
|
||||||
|
|
||||||
|
@ -117,3 +125,48 @@ class PasswordForm(FlaskForm):
|
||||||
if commit:
|
if commit:
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class SanitizationEntityForm(FlaskForm):
|
||||||
|
|
||||||
|
logo = URLField(
|
||||||
|
'Logo',
|
||||||
|
[validators.Optional(), validators.URL()],
|
||||||
|
render_kw={'class': "form-control"},
|
||||||
|
)
|
||||||
|
company_name = StringField('Company Name', render_kw={'class': "form-control"})
|
||||||
|
location = StringField('Location', render_kw={'class': "form-control"})
|
||||||
|
responsable_person = StringField(
|
||||||
|
'Responsable person', render_kw={'class': "form-control"}
|
||||||
|
)
|
||||||
|
supervisor_person = StringField(
|
||||||
|
'Supervisor person', render_kw={'class': "form-control"}
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
if isinstance(self.logo.data, URL):
|
||||||
|
self.logo.data = self.logo.data.to_text()
|
||||||
|
|
||||||
|
def validate(self, extra_validators=None):
|
||||||
|
is_valid = super().validate(extra_validators)
|
||||||
|
|
||||||
|
if not is_valid:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def save(self, commit=True):
|
||||||
|
sanitation_data = SanitizationEntity(
|
||||||
|
logo=URL(self.logo.data),
|
||||||
|
company_name=self.company_name.data,
|
||||||
|
location=self.location.data,
|
||||||
|
responsable_person=self.responsable_person.data,
|
||||||
|
supervisor_person=self.supervisor_person.data,
|
||||||
|
user=g.user,
|
||||||
|
)
|
||||||
|
db.session.add(sanitation_data)
|
||||||
|
|
||||||
|
if commit:
|
||||||
|
db.session.commit()
|
||||||
|
return
|
||||||
|
|
|
@ -30,7 +30,12 @@ from wtforms import (
|
||||||
from wtforms.fields import FormField
|
from wtforms.fields import FormField
|
||||||
|
|
||||||
from ereuse_devicehub.db import db
|
from ereuse_devicehub.db import db
|
||||||
from ereuse_devicehub.inventory.models import DeliveryNote, ReceiverNote, Transfer
|
from ereuse_devicehub.inventory.models import (
|
||||||
|
DeliveryNote,
|
||||||
|
ReceiverNote,
|
||||||
|
Transfer,
|
||||||
|
TransferCustomerDetails,
|
||||||
|
)
|
||||||
from ereuse_devicehub.parser.models import PlaceholdersLog, SnapshotsLog
|
from ereuse_devicehub.parser.models import PlaceholdersLog, SnapshotsLog
|
||||||
from ereuse_devicehub.parser.parser import ParseSnapshotLsHw
|
from ereuse_devicehub.parser.parser import ParseSnapshotLsHw
|
||||||
from ereuse_devicehub.parser.schemas import Snapshot_lite
|
from ereuse_devicehub.parser.schemas import Snapshot_lite
|
||||||
|
@ -44,6 +49,7 @@ from ereuse_devicehub.resources.action.views.snapshot import (
|
||||||
from ereuse_devicehub.resources.device.models import (
|
from ereuse_devicehub.resources.device.models import (
|
||||||
SAI,
|
SAI,
|
||||||
Cellphone,
|
Cellphone,
|
||||||
|
Computer,
|
||||||
ComputerMonitor,
|
ComputerMonitor,
|
||||||
Desktop,
|
Desktop,
|
||||||
Device,
|
Device,
|
||||||
|
@ -297,7 +303,7 @@ class UploadSnapshotForm(SnapshotMixin, FlaskForm):
|
||||||
|
|
||||||
return is_lite
|
return is_lite
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True, user_trusts=True):
|
||||||
if any([x == 'Error' for x in self.result.values()]):
|
if any([x == 'Error' for x in self.result.values()]):
|
||||||
return
|
return
|
||||||
schema = SnapshotSchema()
|
schema = SnapshotSchema()
|
||||||
|
@ -333,6 +339,8 @@ class UploadSnapshotForm(SnapshotMixin, FlaskForm):
|
||||||
self.result[filename] = 'Error'
|
self.result[filename] = 'Error'
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if isinstance(response.device, Computer):
|
||||||
|
response.device.user_trusts = user_trusts
|
||||||
db.session.add(response)
|
db.session.add(response)
|
||||||
devices.append(response.device.binding.device)
|
devices.append(response.device.binding.device)
|
||||||
|
|
||||||
|
@ -1516,6 +1524,54 @@ class NotesForm(FlaskForm):
|
||||||
return self._obj
|
return self._obj
|
||||||
|
|
||||||
|
|
||||||
|
class CustomerDetailsForm(FlaskForm):
|
||||||
|
company_name = StringField(
|
||||||
|
'Company name',
|
||||||
|
[validators.Optional()],
|
||||||
|
render_kw={'class': "form-control"},
|
||||||
|
description="Name of the company",
|
||||||
|
)
|
||||||
|
location = StringField(
|
||||||
|
'Location',
|
||||||
|
[validators.Optional()],
|
||||||
|
render_kw={'class': "form-control"},
|
||||||
|
description="""Location where is the company""",
|
||||||
|
)
|
||||||
|
logo = URLField(
|
||||||
|
'Logo',
|
||||||
|
[validators.Optional()],
|
||||||
|
render_kw={'class': "form-control"},
|
||||||
|
description="Url where is the logo",
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
lot_id = kwargs.pop('lot_id', None)
|
||||||
|
self._tmp_lot = Lot.query.filter(Lot.id == lot_id).one()
|
||||||
|
self._obj = self._tmp_lot.transfer.customer_details
|
||||||
|
if self._obj:
|
||||||
|
kwargs['obj'] = self._obj
|
||||||
|
if not self._obj:
|
||||||
|
self._obj = TransferCustomerDetails(transfer_id=self._tmp_lot.transfer.id)
|
||||||
|
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
if isinstance(self.logo.data, URL):
|
||||||
|
self.logo.data = URL(self.logo.data).to_text()
|
||||||
|
|
||||||
|
def validate(self, extra_validators=None):
|
||||||
|
is_valid = super().validate(extra_validators)
|
||||||
|
return is_valid
|
||||||
|
|
||||||
|
def save(self, commit=True):
|
||||||
|
self.populate_obj(self._obj)
|
||||||
|
self._obj.logo = URL(self._obj.logo)
|
||||||
|
db.session.add(self._obj)
|
||||||
|
|
||||||
|
if commit:
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
return self._obj
|
||||||
|
|
||||||
|
|
||||||
class UploadPlaceholderForm(FlaskForm):
|
class UploadPlaceholderForm(FlaskForm):
|
||||||
type = StringField('Type', [validators.DataRequired()])
|
type = StringField('Type', [validators.DataRequired()])
|
||||||
placeholder_file = FileField(
|
placeholder_file = FileField(
|
||||||
|
|
|
@ -5,7 +5,7 @@ from flask import g
|
||||||
from sqlalchemy import Column, Integer
|
from sqlalchemy import Column, Integer
|
||||||
from sqlalchemy.dialects.postgresql import UUID
|
from sqlalchemy.dialects.postgresql import UUID
|
||||||
from sqlalchemy.orm import backref, relationship
|
from sqlalchemy.orm import backref, relationship
|
||||||
from teal.db import CASCADE_OWN
|
from teal.db import CASCADE_OWN, URL
|
||||||
|
|
||||||
from ereuse_devicehub.db import db
|
from ereuse_devicehub.db import db
|
||||||
from ereuse_devicehub.resources.models import Thing
|
from ereuse_devicehub.resources.models import Thing
|
||||||
|
@ -90,3 +90,23 @@ class ReceiverNote(Thing):
|
||||||
backref=backref('receiver_note', lazy=True, uselist=False, cascade=CASCADE_OWN),
|
backref=backref('receiver_note', lazy=True, uselist=False, cascade=CASCADE_OWN),
|
||||||
primaryjoin='ReceiverNote.transfer_id == Transfer.id',
|
primaryjoin='ReceiverNote.transfer_id == Transfer.id',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TransferCustomerDetails(Thing):
|
||||||
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
|
||||||
|
company_name = Column(CIText(), nullable=True)
|
||||||
|
location = Column(CIText(), nullable=True)
|
||||||
|
logo = Column(URL(), nullable=True)
|
||||||
|
|
||||||
|
transfer_id = db.Column(
|
||||||
|
UUID(as_uuid=True),
|
||||||
|
db.ForeignKey('transfer.id'),
|
||||||
|
nullable=False,
|
||||||
|
)
|
||||||
|
transfer = relationship(
|
||||||
|
'Transfer',
|
||||||
|
backref=backref(
|
||||||
|
'customer_details', lazy=True, uselist=False, cascade=CASCADE_OWN
|
||||||
|
),
|
||||||
|
primaryjoin='TransferCustomerDetails.transfer_id == Transfer.id',
|
||||||
|
)
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import copy
|
import copy
|
||||||
import csv
|
import csv
|
||||||
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import uuid
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
@ -20,6 +22,7 @@ from ereuse_devicehub.inventory.forms import (
|
||||||
AdvancedSearchForm,
|
AdvancedSearchForm,
|
||||||
AllocateForm,
|
AllocateForm,
|
||||||
BindingForm,
|
BindingForm,
|
||||||
|
CustomerDetailsForm,
|
||||||
DataWipeForm,
|
DataWipeForm,
|
||||||
EditTransferForm,
|
EditTransferForm,
|
||||||
FilterForm,
|
FilterForm,
|
||||||
|
@ -79,6 +82,7 @@ class DeviceListMixin(GenericMixin):
|
||||||
form_transfer = ''
|
form_transfer = ''
|
||||||
form_delivery = ''
|
form_delivery = ''
|
||||||
form_receiver = ''
|
form_receiver = ''
|
||||||
|
form_customer_details = ''
|
||||||
|
|
||||||
if lot_id:
|
if lot_id:
|
||||||
lot = lots.filter(Lot.id == lot_id).one()
|
lot = lots.filter(Lot.id == lot_id).one()
|
||||||
|
@ -86,6 +90,7 @@ class DeviceListMixin(GenericMixin):
|
||||||
form_transfer = EditTransferForm(lot_id=lot.id)
|
form_transfer = EditTransferForm(lot_id=lot.id)
|
||||||
form_delivery = NotesForm(lot_id=lot.id, type='Delivery')
|
form_delivery = NotesForm(lot_id=lot.id, type='Delivery')
|
||||||
form_receiver = NotesForm(lot_id=lot.id, type='Receiver')
|
form_receiver = NotesForm(lot_id=lot.id, type='Receiver')
|
||||||
|
form_customer_details = CustomerDetailsForm(lot_id=lot.id)
|
||||||
|
|
||||||
form_new_action = NewActionForm(lot=lot_id)
|
form_new_action = NewActionForm(lot=lot_id)
|
||||||
self.context.update(
|
self.context.update(
|
||||||
|
@ -97,6 +102,7 @@ class DeviceListMixin(GenericMixin):
|
||||||
'form_transfer': form_transfer,
|
'form_transfer': form_transfer,
|
||||||
'form_delivery': form_delivery,
|
'form_delivery': form_delivery,
|
||||||
'form_receiver': form_receiver,
|
'form_receiver': form_receiver,
|
||||||
|
'form_customer_details': form_customer_details,
|
||||||
'form_filter': form_filter,
|
'form_filter': form_filter,
|
||||||
'form_print_labels': PrintLabelsForm(),
|
'form_print_labels': PrintLabelsForm(),
|
||||||
'lot': lot,
|
'lot': lot,
|
||||||
|
@ -1039,7 +1045,7 @@ class ExportsView(View):
|
||||||
|
|
||||||
return self.response_csv(data, "Erasures.csv")
|
return self.response_csv(data, "Erasures.csv")
|
||||||
|
|
||||||
def build_erasure_certificate(self):
|
def get_datastorages(self):
|
||||||
erasures = []
|
erasures = []
|
||||||
for device in self.find_devices():
|
for device in self.find_devices():
|
||||||
if device.placeholder and device.placeholder.binding:
|
if device.placeholder and device.placeholder.binding:
|
||||||
|
@ -1050,11 +1056,66 @@ class ExportsView(View):
|
||||||
elif isinstance(device, DataStorage):
|
elif isinstance(device, DataStorage):
|
||||||
if device.privacy:
|
if device.privacy:
|
||||||
erasures.append(device.privacy)
|
erasures.append(device.privacy)
|
||||||
|
return erasures
|
||||||
|
|
||||||
|
def get_costum_details(self):
|
||||||
|
my_data = None
|
||||||
|
customer_details = None
|
||||||
|
if hasattr(g.user, 'sanitization_entity'):
|
||||||
|
if g.user.sanitization_entity:
|
||||||
|
my_data = list(g.user.sanitization_entity)[0]
|
||||||
|
|
||||||
|
try:
|
||||||
|
if len(request.referrer.split('/lot/')) > 1:
|
||||||
|
lot_id = request.referrer.split('/lot/')[-1].split('/')[0]
|
||||||
|
lot = Lot.query.filter_by(owner=g.user).filter_by(id=lot_id).first()
|
||||||
|
customer_details = lot.transfer.customer_details
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return my_data, customer_details
|
||||||
|
|
||||||
|
def get_server_erasure_hosts(self, erasures):
|
||||||
|
erasures_host = []
|
||||||
|
erasures_on_server = []
|
||||||
|
for erase in erasures:
|
||||||
|
try:
|
||||||
|
if erase.parent.binding.kangaroo:
|
||||||
|
erasures_host.append(erase.parent)
|
||||||
|
erasures_on_server.append(erase)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return erasures_host, erasures_on_server
|
||||||
|
|
||||||
|
def build_erasure_certificate(self):
|
||||||
|
erasures = self.get_datastorages()
|
||||||
|
software = 'USODY DRIVE ERASURE'
|
||||||
|
if erasures and erasures[0].snapshot:
|
||||||
|
software += ' {}'.format(
|
||||||
|
erasures[0].snapshot.version,
|
||||||
|
)
|
||||||
|
|
||||||
|
my_data, customer_details = self.get_costum_details()
|
||||||
|
|
||||||
|
a, b = self.get_server_erasure_hosts(erasures)
|
||||||
|
erasures_host, erasures_on_server = a, b
|
||||||
|
|
||||||
|
result = 'Success'
|
||||||
|
if "Failed" in [e.severity.get_public_name() for e in erasures]:
|
||||||
|
result = 'Failed'
|
||||||
|
|
||||||
params = {
|
params = {
|
||||||
'title': 'Erasure Certificate',
|
'title': 'Erasure Certificate',
|
||||||
'erasures': tuple(erasures),
|
'erasures': tuple(erasures),
|
||||||
'url_pdf': '',
|
'url_pdf': '',
|
||||||
|
'date_report': '{:%c}'.format(datetime.datetime.now()),
|
||||||
|
'uuid_report': '{}'.format(uuid.uuid4()),
|
||||||
|
'software': software,
|
||||||
|
'my_data': my_data,
|
||||||
|
'n_computers': len(set([x.parent for x in erasures])),
|
||||||
|
'result': result,
|
||||||
|
'customer_details': customer_details,
|
||||||
|
'erasure_hosts': erasures_host,
|
||||||
|
'erasures_normal': list(set(erasures) - set(erasures_on_server)),
|
||||||
}
|
}
|
||||||
return flask.render_template('inventory/erasure.html', **params)
|
return flask.render_template('inventory/erasure.html', **params)
|
||||||
|
|
||||||
|
@ -1257,6 +1318,28 @@ class SnapshotDetailView(GenericMixin):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CustomerDetailsView(GenericMixin):
|
||||||
|
methods = ['POST']
|
||||||
|
form_class = CustomerDetailsForm
|
||||||
|
|
||||||
|
def dispatch_request(self, lot_id):
|
||||||
|
self.get_context()
|
||||||
|
form = self.form_class(request.form, lot_id=lot_id)
|
||||||
|
next_url = url_for('inventory.lotdevicelist', lot_id=lot_id)
|
||||||
|
|
||||||
|
if form.validate_on_submit():
|
||||||
|
form.save()
|
||||||
|
messages.success('Customer details updated successfully!')
|
||||||
|
return flask.redirect(next_url)
|
||||||
|
|
||||||
|
messages.error('Customer details updated error!')
|
||||||
|
for k, v in form.errors.items():
|
||||||
|
value = ';'.join(v)
|
||||||
|
key = form[k].label.text
|
||||||
|
messages.error('Error {key}: {value}!'.format(key=key, value=value))
|
||||||
|
return flask.redirect(next_url)
|
||||||
|
|
||||||
|
|
||||||
class DeliveryNoteView(GenericMixin):
|
class DeliveryNoteView(GenericMixin):
|
||||||
methods = ['POST']
|
methods = ['POST']
|
||||||
form_class = NotesForm
|
form_class = NotesForm
|
||||||
|
@ -1448,6 +1531,10 @@ devices.add_url_rule(
|
||||||
'/lot/<string:lot_id>/transfer/',
|
'/lot/<string:lot_id>/transfer/',
|
||||||
view_func=EditTransferView.as_view('edit_transfer'),
|
view_func=EditTransferView.as_view('edit_transfer'),
|
||||||
)
|
)
|
||||||
|
devices.add_url_rule(
|
||||||
|
'/lot/<string:lot_id>/customerdetails/',
|
||||||
|
view_func=CustomerDetailsView.as_view('customer_details'),
|
||||||
|
)
|
||||||
devices.add_url_rule(
|
devices.add_url_rule(
|
||||||
'/lot/<string:lot_id>/deliverynote/',
|
'/lot/<string:lot_id>/deliverynote/',
|
||||||
view_func=DeliveryNoteView.as_view('delivery_note'),
|
view_func=DeliveryNoteView.as_view('delivery_note'),
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
"""sanitization
|
||||||
|
|
||||||
|
Revision ID: 4f33137586dd
|
||||||
|
Revises: 8334535d56fa
|
||||||
|
Create Date: 2023-02-13 18:01:00.092527
|
||||||
|
|
||||||
|
"""
|
||||||
|
import citext
|
||||||
|
import sqlalchemy as sa
|
||||||
|
import teal
|
||||||
|
from alembic import context, op
|
||||||
|
from sqlalchemy.dialects import postgresql
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '4f33137586dd'
|
||||||
|
down_revision = '8334535d56fa'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_inv():
|
||||||
|
INV = context.get_x_argument(as_dictionary=True).get('inventory')
|
||||||
|
if not INV:
|
||||||
|
raise ValueError("Inventory value is not specified")
|
||||||
|
return INV
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.create_table(
|
||||||
|
'sanitization_entity',
|
||||||
|
sa.Column('id', sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column(
|
||||||
|
'updated',
|
||||||
|
sa.TIMESTAMP(timezone=True),
|
||||||
|
server_default=sa.text('CURRENT_TIMESTAMP'),
|
||||||
|
nullable=False,
|
||||||
|
),
|
||||||
|
sa.Column(
|
||||||
|
'created',
|
||||||
|
sa.TIMESTAMP(timezone=True),
|
||||||
|
server_default=sa.text('CURRENT_TIMESTAMP'),
|
||||||
|
nullable=False,
|
||||||
|
),
|
||||||
|
sa.Column('company_name', sa.String(), nullable=True),
|
||||||
|
sa.Column('logo', teal.db.URL(), nullable=True),
|
||||||
|
sa.Column('responsable_person', sa.String(), nullable=True),
|
||||||
|
sa.Column('supervisor_person', sa.String(), nullable=True),
|
||||||
|
sa.Column('location', sa.String(), nullable=True),
|
||||||
|
sa.Column('user_id', postgresql.UUID(as_uuid=True), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
['user_id'],
|
||||||
|
['common.user.id'],
|
||||||
|
),
|
||||||
|
schema=f'{get_inv()}',
|
||||||
|
)
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
'transfer_customer_details',
|
||||||
|
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
|
||||||
|
sa.Column(
|
||||||
|
'updated',
|
||||||
|
sa.TIMESTAMP(timezone=True),
|
||||||
|
server_default=sa.text('CURRENT_TIMESTAMP'),
|
||||||
|
nullable=False,
|
||||||
|
),
|
||||||
|
sa.Column(
|
||||||
|
'created',
|
||||||
|
sa.TIMESTAMP(timezone=True),
|
||||||
|
server_default=sa.text('CURRENT_TIMESTAMP'),
|
||||||
|
nullable=False,
|
||||||
|
),
|
||||||
|
sa.Column('company_name', citext.CIText(), nullable=True),
|
||||||
|
sa.Column('logo', teal.db.URL(), nullable=True),
|
||||||
|
sa.Column('location', citext.CIText(), nullable=True),
|
||||||
|
sa.Column('transfer_id', postgresql.UUID(as_uuid=True), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['transfer_id'], [f'{get_inv()}.transfer.id']),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
schema=f'{get_inv()}',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_table('sanitization_entity', schema=f'{get_inv()}')
|
||||||
|
op.drop_table('transfer_customer_details', schema=f'{get_inv()}')
|
|
@ -527,6 +527,9 @@ class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice):
|
||||||
proof = Proof(**d)
|
proof = Proof(**d)
|
||||||
db.session.add(proof)
|
db.session.add(proof)
|
||||||
|
|
||||||
|
def get_public_name(self):
|
||||||
|
return "Basic"
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return '{} on {}.'.format(self.severity, self.date_str)
|
return '{} on {}.'.format(self.severity, self.date_str)
|
||||||
|
|
||||||
|
@ -556,12 +559,32 @@ class EraseSectors(EraseBasic):
|
||||||
|
|
||||||
method = 'Badblocks'
|
method = 'Badblocks'
|
||||||
|
|
||||||
|
def get_public_name(self):
|
||||||
|
steps_random = 0
|
||||||
|
steps_zeros = 0
|
||||||
|
for s in self.steps:
|
||||||
|
if s.type == 'StepRandom':
|
||||||
|
steps_random += 1
|
||||||
|
if s.type == 'StepZero':
|
||||||
|
steps_zeros += 1
|
||||||
|
if steps_zeros < 1:
|
||||||
|
return "Basic"
|
||||||
|
if 0 < steps_random < 3:
|
||||||
|
return "Baseline"
|
||||||
|
if steps_random > 2:
|
||||||
|
return "Enhanced"
|
||||||
|
|
||||||
|
return "Basic"
|
||||||
|
|
||||||
|
|
||||||
class ErasePhysical(EraseBasic):
|
class ErasePhysical(EraseBasic):
|
||||||
"""The act of physically destroying a data storage unit."""
|
"""The act of physically destroying a data storage unit."""
|
||||||
|
|
||||||
method = Column(DBEnum(PhysicalErasureMethod))
|
method = Column(DBEnum(PhysicalErasureMethod))
|
||||||
|
|
||||||
|
def get_public_name(self):
|
||||||
|
return "Physical"
|
||||||
|
|
||||||
|
|
||||||
class Step(db.Model):
|
class Step(db.Model):
|
||||||
erasure_id = Column(
|
erasure_id = Column(
|
||||||
|
|
|
@ -758,6 +758,24 @@ class Device(Thing):
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
def get_exist_untrusted_device(self):
|
||||||
|
if isinstance(self, Computer):
|
||||||
|
if not self.system_uuid:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return (
|
||||||
|
Computer.query.filter_by(
|
||||||
|
hid=self.hid,
|
||||||
|
user_trusts=False,
|
||||||
|
owner_id=g.user.id,
|
||||||
|
active=True,
|
||||||
|
placeholder=None,
|
||||||
|
).first()
|
||||||
|
or False
|
||||||
|
)
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
def get_from_db(self):
|
def get_from_db(self):
|
||||||
if 'property_hid' in app.blueprints.keys():
|
if 'property_hid' in app.blueprints.keys():
|
||||||
try:
|
try:
|
||||||
|
@ -939,7 +957,7 @@ class Device(Thing):
|
||||||
if not snapshot1:
|
if not snapshot1:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.create_new_device(snapshots.values())
|
self.create_new_device(snapshots.values(), user_trusts=self.user_trusts)
|
||||||
self.remove_snapshot(snapshots.keys())
|
self.remove_snapshot(snapshots.keys())
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -956,7 +974,7 @@ class Device(Thing):
|
||||||
snapshot = file_snapshot.read()
|
snapshot = file_snapshot.read()
|
||||||
return json.loads(snapshot)
|
return json.loads(snapshot)
|
||||||
|
|
||||||
def create_new_device(self, snapshots):
|
def create_new_device(self, snapshots, user_trusts=True):
|
||||||
from ereuse_devicehub.inventory.forms import UploadSnapshotForm
|
from ereuse_devicehub.inventory.forms import UploadSnapshotForm
|
||||||
|
|
||||||
new_snapshots = []
|
new_snapshots = []
|
||||||
|
@ -969,7 +987,7 @@ class Device(Thing):
|
||||||
form.result = {}
|
form.result = {}
|
||||||
form.snapshots = new_snapshots
|
form.snapshots = new_snapshots
|
||||||
form.create_new_devices = True
|
form.create_new_devices = True
|
||||||
form.save(commit=False)
|
form.save(commit=False, user_trusts=user_trusts)
|
||||||
|
|
||||||
def remove_snapshot(self, snapshots):
|
def remove_snapshot(self, snapshots):
|
||||||
from ereuse_devicehub.parser.models import SnapshotsLog
|
from ereuse_devicehub.parser.models import SnapshotsLog
|
||||||
|
|
|
@ -16,19 +16,20 @@ from ereuse_devicehub.resources.action.models import Remove
|
||||||
from ereuse_devicehub.resources.device.models import (
|
from ereuse_devicehub.resources.device.models import (
|
||||||
Component,
|
Component,
|
||||||
Computer,
|
Computer,
|
||||||
|
DataStorage,
|
||||||
Device,
|
Device,
|
||||||
Placeholder,
|
Placeholder,
|
||||||
)
|
)
|
||||||
from ereuse_devicehub.resources.tag.model import Tag
|
from ereuse_devicehub.resources.tag.model import Tag
|
||||||
|
|
||||||
DEVICES_ALLOW_DUPLICITY = [
|
# DEVICES_ALLOW_DUPLICITY = [
|
||||||
'RamModule',
|
# 'RamModule',
|
||||||
'Display',
|
# 'Display',
|
||||||
'SoundCard',
|
# 'SoundCard',
|
||||||
'Battery',
|
# 'Battery',
|
||||||
'Camera',
|
# 'Camera',
|
||||||
'GraphicCard',
|
# 'GraphicCard',
|
||||||
]
|
# ]
|
||||||
|
|
||||||
|
|
||||||
class Sync:
|
class Sync:
|
||||||
|
@ -119,7 +120,7 @@ class Sync:
|
||||||
"""
|
"""
|
||||||
assert inspect(component).transient, 'Component should not be synced from DB'
|
assert inspect(component).transient, 'Component should not be synced from DB'
|
||||||
# if not is a DataStorage, then need build a new one
|
# if not is a DataStorage, then need build a new one
|
||||||
if component.t in DEVICES_ALLOW_DUPLICITY:
|
if not isinstance(component, DataStorage):
|
||||||
db.session.add(component)
|
db.session.add(component)
|
||||||
is_new = True
|
is_new = True
|
||||||
return component, is_new
|
return component, is_new
|
||||||
|
@ -171,6 +172,8 @@ class Sync:
|
||||||
|
|
||||||
if not db_device or create_new_device:
|
if not db_device or create_new_device:
|
||||||
device.tags.clear() # We don't want to add the transient dummy tags
|
device.tags.clear() # We don't want to add the transient dummy tags
|
||||||
|
if create_new_device or device.get_exist_untrusted_device():
|
||||||
|
device.user_trusts = False
|
||||||
db.session.add(device)
|
db.session.add(device)
|
||||||
db_device = device
|
db_device = device
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,400 +1,220 @@
|
||||||
{% import 'devices/macros.html' as macros %}
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
<link href="https://stackpath.bootstrapcdn.com/bootswatch/3.3.7/flatly/bootstrap.min.css"
|
|
||||||
rel="stylesheet"
|
|
||||||
integrity="sha384-+ENW/yibaokMnme+vBLnHMphUYxHs34h9lpdbSLuAwGkOKFRl4C34WkjazBtb7eT"
|
|
||||||
crossorigin="anonymous">
|
|
||||||
<script src="https://use.fontawesome.com/7553aecc27.js"></script>
|
|
||||||
<title>Devicehub | {{ device.__format__('t') }}</title>
|
|
||||||
<style>
|
|
||||||
/*Sticky footer*/
|
|
||||||
html {
|
|
||||||
position: relative;
|
|
||||||
min-height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
<title>Device {{ device_real.dhid }} - Usody</title>
|
||||||
margin-bottom: 60px; /* Margin bottom by footer height */
|
<meta content="" name="description">
|
||||||
}
|
<meta content="" name="keywords">
|
||||||
|
|
||||||
.footer {
|
<!-- Favicons -->
|
||||||
position: absolute;
|
<link href="{{ url_for('static', filename='img/favicon.png') }}" rel="icon">
|
||||||
bottom: 0;
|
<link href="{{ url_for('static', filename='img/apple-touch-icon.png') }}" rel="apple-touch-icon">
|
||||||
width: 100%;
|
|
||||||
height: 6em;
|
<!-- Google Fonts -->
|
||||||
}
|
<link href="https://fonts.gstatic.com" rel="preconnect">
|
||||||
</style>
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i|Nunito:300,300i,400,400i,600,600i,700,700i|Poppins:300,300i,400,400i,500,500i,600,600i,700,700i" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- JS Files -->
|
||||||
|
<script src="{{ url_for('static', filename='js/jquery-3.6.0.min.js') }}"></script>
|
||||||
|
|
||||||
|
<!-- Vendor CSS Files -->
|
||||||
|
<link href="{{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
|
||||||
|
<link href="{{ url_for('static', filename='vendor/bootstrap-icons/bootstrap-icons.css') }}" rel="stylesheet">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Template Main CSS File -->
|
||||||
|
<link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet">
|
||||||
|
<link href="{{ url_for('static', filename='css/devicehub.css') }}" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- =======================================================
|
||||||
|
* Template Name: NiceAdmin - v2.2.0
|
||||||
|
* Template URL: https://bootstrapmade.com/nice-admin-bootstrap-admin-html-template/
|
||||||
|
* Author: BootstrapMade.com
|
||||||
|
* License: https://bootstrapmade.com/license/
|
||||||
|
======================================================== -->
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<nav class="navbar navbar-default" style="background-color: gainsboro; margin: 0 !important">
|
<main>
|
||||||
<div class="container-fluid">
|
|
||||||
<a href="https://www.usody.com/" target="_blank">
|
|
||||||
<h1 align="center">Usody Public Link</h1>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row">
|
|
||||||
<div class="page-header col-md-6 col-md-offset-3">
|
|
||||||
<h1>{% if abstract %}Real device {% endif %}{{ device.__format__('t') or '' }}<br>
|
|
||||||
<small>{{ device.__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 device.public_properties.items() %}
|
|
||||||
<li>{{ key }}: {{ value or '' }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% if isinstance(device, d.Computer) %}
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-striped">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th></th>
|
|
||||||
<th>Range</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% if device.processor_model %}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
CPU – {{ device.processor_model }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
Processor Rate = {% if device.rate %}
|
|
||||||
{{ device.rate.processor_range }}
|
|
||||||
({{ device.rate.processor }})
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
{% if device.ram_size %}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
RAM – {{ device.ram_size // 1000 }} GB
|
|
||||||
{{ macros.component_type(device.components, 'RamModule') }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
RAM Rate = {% if device.rate %}
|
|
||||||
{{ device.rate.ram_range }}
|
|
||||||
({{ device.rate.ram }})
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
{% if device.data_storage_size %}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
Data Storage – {{ device.data_storage_size // 1000 }} GB
|
|
||||||
{{ macros.component_type(device.components, 'SolidStateDrive') }}
|
|
||||||
{{ macros.component_type(device.components, 'HardDrive') }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
Data Storage Rate = {% if device.rate %}
|
|
||||||
{{ device.rate.data_storage_range }}
|
|
||||||
({{ device.rate.data_storage }})
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
{% if device.graphic_card_model %}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
Graphics – {{ device.graphic_card_model }}
|
|
||||||
{{ macros.component_type(device.components, 'GraphicCard') }}
|
|
||||||
</td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
{% if device.network_speeds %}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
Network –
|
|
||||||
{% if device.network_speeds[0] %}
|
|
||||||
Ethernet
|
|
||||||
{% if device.network_speeds[0] != None %}
|
|
||||||
max. {{ device.network_speeds[0] }} Mbps
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% if device.network_speeds[0] and device.network_speeds[1] %}
|
|
||||||
+
|
|
||||||
{% endif %}
|
|
||||||
{% if device.network_speeds[1] %}
|
|
||||||
WiFi
|
|
||||||
{% if device.network_speeds[1] != None %}
|
|
||||||
max. {{ device.network_speeds[1] }} Mbps
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{{ macros.component_type(device.components, 'NetworkAdapter') }}
|
|
||||||
</td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<h4>Actual Status</h4>
|
|
||||||
<ol>
|
|
||||||
<li>
|
|
||||||
<strong>
|
|
||||||
Lifecycle Status
|
|
||||||
</strong>
|
|
||||||
—
|
|
||||||
{% if device.status %}
|
|
||||||
{{ device.status.type }}
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<strong>
|
|
||||||
Allocate Status
|
|
||||||
</strong>
|
|
||||||
—
|
|
||||||
{% if device.allocated_status %}
|
|
||||||
{{ device.allocated_status.type }}
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<strong>
|
|
||||||
Physical Status
|
|
||||||
</strong>
|
|
||||||
—
|
|
||||||
{% if device.physical_status %}
|
|
||||||
{{ device.physical_status.type }}
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<h4>Public traceability log of the device</h4>
|
<section class="container mt-3">
|
||||||
<div class="text-right">
|
<div class="row">
|
||||||
<small>Latest one.</small>
|
|
||||||
</div>
|
|
||||||
<ol>
|
|
||||||
{% for action in device.public_actions %}
|
|
||||||
<li>
|
|
||||||
<strong>
|
|
||||||
{{ device.is_status(action) }}
|
|
||||||
{% if not device.is_status(action) %}
|
|
||||||
{{ action.type }}
|
|
||||||
{% endif %}
|
|
||||||
</strong>
|
|
||||||
—
|
|
||||||
{% if device.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>
|
|
||||||
{% 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="col">
|
||||||
<div class="text-right">
|
<div class="col-xl-12">
|
||||||
<small>Latest one.</small>
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h3 class="nav-link mt-5" style="color: #993365">{{ device_real.type }} - {{ device_real.verbose_name }}</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6">
|
||||||
|
<h5 class="card-title">Basic</h5>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
Usody Identifier (DHID)
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
{{ device_real.dhid }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
Inventory Identifier (PHID)
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
{{ device_real.phid() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
Type
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
{{ device_real.type or '- not detected -' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
Manufacturer
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
{{ device_real.manufacturer or '- not detected -' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
Model
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
{{ device_real.model or '- not detected -' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
Part Number
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
{{ device_real.part_number or '- not detected -' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
Serial Number
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
- anonymized -
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ol>
|
<div class="col-1">
|
||||||
{% 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>
|
</div>
|
||||||
{% endif %}
|
<div class="col-5">
|
||||||
|
<h5 class="card-title">Status</h5>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div class="label"><b>Physical</b></div>
|
||||||
|
<div>{{ device_real.physical_status and device.physical_status.type or '- not status -' }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div class="label"><b>Lifecycle</b></div>
|
||||||
|
<div>{{ device_real.status and device_real.status.type or '- not status -' }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div class="label"><b>Allocation</b></div>
|
||||||
|
<div>
|
||||||
|
{% if device_real.allocated %}
|
||||||
|
Allocated
|
||||||
|
{% else %}
|
||||||
|
Not allocated
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mt-3">
|
||||||
|
<div class="col-6">
|
||||||
|
<h5 class="card-title">Components</h5>
|
||||||
|
<div class="row">
|
||||||
|
{% if placeholder.binding %}
|
||||||
|
<div class="list-group col">
|
||||||
|
{% 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>
|
||||||
|
<small class="text-muted">{{ component.created.strftime('%H:%M %d-%m-%Y') }}</small>
|
||||||
|
</div>
|
||||||
|
<p class="mb-1">
|
||||||
|
{{ component.manufacturer or '- not detected -' }}<br />
|
||||||
|
{{ component.model or '- not detected -' }}<br />
|
||||||
|
</p>
|
||||||
|
<small class="text-muted">
|
||||||
|
{% if component.type in ['RamModule', 'HardDrive', 'SolidStateDrive'] %}
|
||||||
|
{{ component.size }}MB
|
||||||
|
{% endif %}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="list-group col">
|
||||||
|
<div class="list-group-item">
|
||||||
|
- not detected -
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-6">
|
||||||
|
<h5 class="card-title">Repair history</h5>
|
||||||
|
<div class="row">
|
||||||
|
<div class="list-group col">
|
||||||
|
{% 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>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
<!-- ======= Footer ======= -->
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="copyright">
|
||||||
|
© Copyright <strong><span>Usody</span></strong>. All Rights Reserved
|
||||||
|
</div>
|
||||||
|
<div class="credits">
|
||||||
|
<a href="https://help.usody.com/en/" target="_blank">Help</a> |
|
||||||
|
<a href="https://www.usody.com/legal/privacy-policy" target="_blank">Privacy</a> |
|
||||||
|
<a href="https://www.usody.com/legal/terms" target="_blank">Terms</a>
|
||||||
|
</div>
|
||||||
|
<div class="credits">
|
||||||
|
DeviceHub
|
||||||
|
</div>
|
||||||
|
</footer><!-- End Footer -->
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<footer class="container-fluid footer">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
Page generated by:<br>
|
|
||||||
<img style="height: 9em"
|
|
||||||
src="{{ url_for('Device.static', filename='usody-logo-v4.png') }}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -148,8 +148,17 @@ class DeviceView(View):
|
||||||
if device.is_abstract() == 'Twin':
|
if device.is_abstract() == 'Twin':
|
||||||
abstract = device.placeholder.binding
|
abstract = device.placeholder.binding
|
||||||
|
|
||||||
|
placeholder = device.binding or device.placeholder
|
||||||
|
device_abstract = placeholder and placeholder.binding or device
|
||||||
|
device_real = placeholder and placeholder.device or device
|
||||||
return render_template(
|
return render_template(
|
||||||
'devices/layout.html', device=device, states=states, abstract=abstract
|
'devices/layout.html',
|
||||||
|
placeholder=placeholder,
|
||||||
|
device=device,
|
||||||
|
device_abstract=device_abstract,
|
||||||
|
device_real=device_real,
|
||||||
|
states=states,
|
||||||
|
abstract=abstract,
|
||||||
)
|
)
|
||||||
|
|
||||||
@auth.Auth.requires_auth
|
@auth.Auth.requires_auth
|
||||||
|
|
|
@ -334,6 +334,12 @@ class Severity(IntEnum):
|
||||||
def __format__(self, format_spec):
|
def __format__(self, format_spec):
|
||||||
return str(self)
|
return str(self)
|
||||||
|
|
||||||
|
def get_public_name(self):
|
||||||
|
if self.value == 3:
|
||||||
|
return "Failed"
|
||||||
|
|
||||||
|
return "Success"
|
||||||
|
|
||||||
|
|
||||||
class PhysicalErasureMethod(Enum):
|
class PhysicalErasureMethod(Enum):
|
||||||
"""Methods of physically erasing the data-storage, usually
|
"""Methods of physically erasing the data-storage, usually
|
||||||
|
|
|
@ -8,7 +8,7 @@ from flask_login import UserMixin
|
||||||
from sqlalchemy import BigInteger, Boolean, Column, Sequence
|
from sqlalchemy import BigInteger, Boolean, Column, Sequence
|
||||||
from sqlalchemy.dialects.postgresql import UUID
|
from sqlalchemy.dialects.postgresql import UUID
|
||||||
from sqlalchemy_utils import EmailType, PasswordType
|
from sqlalchemy_utils import EmailType, PasswordType
|
||||||
from teal.db import IntEnum
|
from teal.db import URL, IntEnum
|
||||||
|
|
||||||
from ereuse_devicehub.db import db
|
from ereuse_devicehub.db import db
|
||||||
from ereuse_devicehub.resources.enums import SessionType
|
from ereuse_devicehub.resources.enums import SessionType
|
||||||
|
@ -178,3 +178,22 @@ class Session(Thing):
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return '{0.token}'.format(self)
|
return '{0.token}'.format(self)
|
||||||
|
|
||||||
|
|
||||||
|
class SanitizationEntity(Thing):
|
||||||
|
id = Column(BigInteger, primary_key=True)
|
||||||
|
company_name = Column(db.String, nullable=True)
|
||||||
|
location = Column(db.String, nullable=True)
|
||||||
|
logo = Column(db.String, nullable=True)
|
||||||
|
logo = Column(URL(), nullable=True)
|
||||||
|
responsable_person = Column(db.String, nullable=True)
|
||||||
|
supervisor_person = Column(db.String, nullable=True)
|
||||||
|
user_id = db.Column(db.UUID(as_uuid=True), db.ForeignKey(User.id))
|
||||||
|
user = db.relationship(
|
||||||
|
User,
|
||||||
|
backref=db.backref('sanitization_entity', lazy=True, collection_class=set),
|
||||||
|
collection_class=set,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return '{0.company_name}'.format(self)
|
||||||
|
|
|
@ -1,182 +0,0 @@
|
||||||
.dataTable-wrapper.no-header .dataTable-container {
|
|
||||||
border-top: 1px solid #d9d9d9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-wrapper.no-footer .dataTable-container {
|
|
||||||
border-bottom: 1px solid #d9d9d9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-top,
|
|
||||||
.dataTable-bottom {
|
|
||||||
padding: 8px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-top > nav:first-child,
|
|
||||||
.dataTable-top > div:first-child,
|
|
||||||
.dataTable-bottom > nav:first-child,
|
|
||||||
.dataTable-bottom > div:first-child {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-top > nav:last-child,
|
|
||||||
.dataTable-top > div:last-child,
|
|
||||||
.dataTable-bottom > nav:last-child,
|
|
||||||
.dataTable-bottom > div:last-child {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-selector {
|
|
||||||
padding: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-input {
|
|
||||||
padding: 6px 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-info {
|
|
||||||
margin: 7px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* PAGER */
|
|
||||||
.dataTable-pagination ul {
|
|
||||||
margin: 0;
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-pagination li {
|
|
||||||
list-style: none;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-pagination a {
|
|
||||||
border: 1px solid transparent;
|
|
||||||
float: left;
|
|
||||||
margin-left: 2px;
|
|
||||||
padding: 6px 12px;
|
|
||||||
position: relative;
|
|
||||||
text-decoration: none;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-pagination a:hover {
|
|
||||||
background-color: #d9d9d9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-pagination .active a,
|
|
||||||
.dataTable-pagination .active a:focus,
|
|
||||||
.dataTable-pagination .active a:hover {
|
|
||||||
background-color: #d9d9d9;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-pagination .ellipsis a,
|
|
||||||
.dataTable-pagination .disabled a,
|
|
||||||
.dataTable-pagination .disabled a:focus,
|
|
||||||
.dataTable-pagination .disabled a:hover {
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-pagination .disabled a,
|
|
||||||
.dataTable-pagination .disabled a:focus,
|
|
||||||
.dataTable-pagination .disabled a:hover {
|
|
||||||
cursor: not-allowed;
|
|
||||||
opacity: 0.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-pagination .pager a {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TABLE */
|
|
||||||
.dataTable-table {
|
|
||||||
max-width: 100%;
|
|
||||||
width: 100%;
|
|
||||||
border-spacing: 0;
|
|
||||||
border-collapse: separate;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-table > tbody > tr > td,
|
|
||||||
.dataTable-table > tbody > tr > th,
|
|
||||||
.dataTable-table > tfoot > tr > td,
|
|
||||||
.dataTable-table > tfoot > tr > th,
|
|
||||||
.dataTable-table > thead > tr > td,
|
|
||||||
.dataTable-table > thead > tr > th {
|
|
||||||
vertical-align: top;
|
|
||||||
padding: 8px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-table > thead > tr > th {
|
|
||||||
vertical-align: bottom;
|
|
||||||
text-align: left;
|
|
||||||
border-bottom: 1px solid #d9d9d9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-table > tfoot > tr > th {
|
|
||||||
vertical-align: bottom;
|
|
||||||
text-align: left;
|
|
||||||
border-top: 1px solid #d9d9d9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-table th {
|
|
||||||
vertical-align: bottom;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-table th a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-sorter {
|
|
||||||
display: inline-block;
|
|
||||||
height: 100%;
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-sorter::before,
|
|
||||||
.dataTable-sorter::after {
|
|
||||||
content: "";
|
|
||||||
height: 0;
|
|
||||||
width: 0;
|
|
||||||
position: absolute;
|
|
||||||
right: 4px;
|
|
||||||
border-left: 4px solid transparent;
|
|
||||||
border-right: 4px solid transparent;
|
|
||||||
opacity: 0.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-sorter::before {
|
|
||||||
border-top: 4px solid #000;
|
|
||||||
bottom: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-sorter::after {
|
|
||||||
border-bottom: 4px solid #000;
|
|
||||||
border-top: 4px solid transparent;
|
|
||||||
top: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asc .dataTable-sorter::after,
|
|
||||||
.desc .dataTable-sorter::before {
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTables-empty {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataTable-top::after, .dataTable-bottom::after {
|
|
||||||
clear: both;
|
|
||||||
content: " ";
|
|
||||||
display: table;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.dataTable-table:focus tr.dataTable-cursor > td:first-child {
|
|
||||||
border-left: 3px blue solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.dataTable-table:focus {
|
|
||||||
outline: solid 1px black;
|
|
||||||
outline-offset: -1px;
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
|
@ -19,12 +19,14 @@
|
||||||
|
|
||||||
<!-- JS Files -->
|
<!-- JS Files -->
|
||||||
<script src="{{ url_for('static', filename='js/jquery-3.6.0.min.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/jquery-3.6.0.min.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/simple-datatables-5.0.3.js') }}"></script>
|
<script src="https://cdn.jsdelivr.net/npm/simple-datatables@5.0.3" type="text/javascript"></script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Vendor CSS Files -->
|
<!-- Vendor CSS Files -->
|
||||||
<link href="{{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
|
<link href="{{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
|
||||||
<link href="{{ url_for('static', filename='vendor/bootstrap-icons/bootstrap-icons.css') }}" rel="stylesheet">
|
<link href="{{ url_for('static', filename='vendor/bootstrap-icons/bootstrap-icons.css') }}" rel="stylesheet">
|
||||||
<link href="{{ url_for('static', filename='css/simple-datatables.css') }}" rel="stylesheet" type="text/css">
|
<link href="https://cdn.jsdelivr.net/npm/simple-datatables@5.0.3/dist/style.css" rel="stylesheet" type="text/css">
|
||||||
|
|
||||||
|
|
||||||
<!-- Template Main CSS File -->
|
<!-- Template Main CSS File -->
|
||||||
|
|
|
@ -309,8 +309,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="credits">
|
<div class="credits">
|
||||||
<a href="https://help.usody.com/en/" target="_blank">Help</a> |
|
<a href="https://help.usody.com/en/" target="_blank">Help</a> |
|
||||||
<a href="https://pangea.org/es/politica-de-privacidad/" target="_blank">Privacy</a> |
|
<a href="https://www.usody.com/legal/privacy-policy" target="_blank">Privacy</a> |
|
||||||
<a href="https://pangea.org/aviso-legal/" target="_blank">Terms</a>
|
<a href="https://www.usody.com/legal/terms" target="_blank">Terms</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="credits">
|
<div class="credits">
|
||||||
DeviceHub {{ version }}
|
DeviceHub {{ version }}
|
||||||
|
|
|
@ -71,8 +71,8 @@
|
||||||
|
|
||||||
<div class="credits">
|
<div class="credits">
|
||||||
<a href="https://help.usody.com/en/getting-started/login-usody/" target="_blank">Help</a> |
|
<a href="https://help.usody.com/en/getting-started/login-usody/" target="_blank">Help</a> |
|
||||||
<a href="https://pangea.org/es/politica-de-privacidad/" target="_blank">Privacy</a> |
|
<a href="https://www.usody.com/legal/privacy-policy" target="_blank">Privacy</a> |
|
||||||
<a href="https://pangea.org/aviso-legal/" target="_blank">Terms</a>
|
<a href="https://www.usody.com/legal/terms" target="_blank">Terms</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -34,7 +34,10 @@
|
||||||
<!-- Bordered Tabs -->
|
<!-- Bordered Tabs -->
|
||||||
<ul class="nav nav-tabs nav-tabs-bordered">
|
<ul class="nav nav-tabs nav-tabs-bordered">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#profile-change-password">Change Password</button>
|
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#profile-change-password">Change Password</button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#profile-sanitization-entity">Sanitization Entity</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content pt-2">
|
<div class="tab-content pt-2">
|
||||||
|
@ -65,7 +68,34 @@
|
||||||
<button type="submit" class="btn btn-primary">Change Password</button>
|
<button type="submit" class="btn btn-primary">Change Password</button>
|
||||||
</div>
|
</div>
|
||||||
</form><!-- End Change Password Form -->
|
</form><!-- End Change Password Form -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-pane fade pt-3" id="profile-sanitization-entity">
|
||||||
|
<!-- Sanitization Entity datas Form -->
|
||||||
|
<form action="{{ url_for('core.set-sanitization') }}" method="post">
|
||||||
|
{% for f in sanitization_form %}
|
||||||
|
{% if f == sanitization_form.csrf_token %}
|
||||||
|
{{ f }}
|
||||||
|
{% else %}
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label class="col-md-4 col-lg-3 col-form-label">{{ f.label }}</label>
|
||||||
|
<div class="col-md-8 col-lg-9">
|
||||||
|
{{ f }}
|
||||||
|
{% if f.errors %}
|
||||||
|
<p class="text-danger">
|
||||||
|
{% for error in f.errors %}
|
||||||
|
{{ error }}<br/>
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<div class="text-center">
|
||||||
|
<button type="submit" class="btn btn-primary">Change sanitization data</button>
|
||||||
|
</div>
|
||||||
|
</form><!-- End Sanitization Entity datas Form -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div><!-- End Bordered Tabs -->
|
</div><!-- End Bordered Tabs -->
|
||||||
|
|
|
@ -93,6 +93,11 @@
|
||||||
Receiver Note
|
Receiver Note
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#edit-customer-details">
|
||||||
|
Customer Details
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
@ -656,6 +661,37 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="edit-customer-details" class="tab-pane fade edit-customer-details">
|
||||||
|
<h5 class="card-title">Customer Details</h5>
|
||||||
|
<form method="post" action="{{ url_for('inventory.customer_details', lot_id=lot.id) }}" class="row g-3 needs-validation" novalidate>
|
||||||
|
{{ form_customer_details.csrf_token }}
|
||||||
|
|
||||||
|
{% for field in form_customer_details %}
|
||||||
|
{% if field != form_customer_details.csrf_token %}
|
||||||
|
<div class="col-12">
|
||||||
|
{% if field != form_customer_details.type %}
|
||||||
|
{{ field.label(class_="form-label") }}
|
||||||
|
{{ field }}
|
||||||
|
<small class="text-muted">{{ field.description }}</small>
|
||||||
|
{% if field.errors %}
|
||||||
|
<p class="text-danger">
|
||||||
|
{% for error in field.errors %}
|
||||||
|
{{ error }}<br/>
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<a href="{{ url_for('inventory.lotdevicelist', lot_id=lot.id) }}" class="btn btn-danger">Cancel</a>
|
||||||
|
<button class="btn btn-primary" type="submit">Save</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</div><!-- End Bordered Tabs -->
|
</div><!-- End Bordered Tabs -->
|
||||||
|
|
|
@ -1,80 +1,398 @@
|
||||||
{% extends "documents/layout.html" %}
|
<!DOCTYPE html>
|
||||||
{% block body %}
|
<html>
|
||||||
<div>
|
<head>
|
||||||
<h2>Summary</h2>
|
<title>Data Sanitization Certificate</title>
|
||||||
<table class="table table-bordered">
|
<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
|
||||||
<thead>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
<tr>
|
<link href="https://stackpath.bootstrapcdn.com/bootswatch/3.3.7/flatly/bootstrap.min.css"
|
||||||
<th>S/N Data Storage</th>
|
rel="stylesheet"
|
||||||
<th>Type of erasure</th>
|
integrity="sha384-+ENW/yibaokMnme+vBLnHMphUYxHs34h9lpdbSLuAwGkOKFRl4C34WkjazBtb7eT"
|
||||||
<th>Result</th>
|
crossorigin="anonymous">
|
||||||
<th>Date</th>
|
<style type="text/css" media="all">
|
||||||
</tr>
|
@page {
|
||||||
</thead>
|
size: A4 portrait; /* can use also 'landscape' for orientation */
|
||||||
<tbody>
|
margin: 1.0cm 1.5cm 3.5cm 1.5cm;
|
||||||
{% for erasure in erasures %}
|
font-family: "Source Sans Pro", Calibri, Candra, Sans serif;
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
{{ erasure.device.serial_number.upper() }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ erasure.type }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ erasure.severity }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ erasure.date_str }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="page-break row">
|
|
||||||
<h2>Details</h2>
|
|
||||||
{% for erasure in erasures %}
|
|
||||||
<div class="col-md-6 no-page-break">
|
|
||||||
<h4>{{ erasure.device.__format__('t') }}</h4>
|
|
||||||
<dl>
|
|
||||||
<dt>Data storage:</dt>
|
|
||||||
<dd>{{ erasure.device.__format__('ts') }}</dd>
|
|
||||||
|
|
||||||
<dt>Erasure:</dt>
|
@top {
|
||||||
<dd>{{ erasure.__format__('ts') }}</dd>
|
content: element(header);
|
||||||
{% if erasure.steps %}
|
}
|
||||||
<dt>Erasure steps:</dt>
|
|
||||||
<dd>
|
@bottom {
|
||||||
<ol>
|
content: element(footer);
|
||||||
{% for step in erasure.steps %}
|
}
|
||||||
<li>{{ step.__format__('') }}</li>
|
|
||||||
{% endfor %}
|
}
|
||||||
</ol>
|
body {
|
||||||
</dd>
|
width: 100% !important;
|
||||||
{% endif %}
|
height: 100%;
|
||||||
</dl>
|
background: #fff;
|
||||||
</div>
|
color: black;
|
||||||
{% endfor %}
|
font-size: 100%;
|
||||||
|
line-height: 1.65;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-webkit-text-size-adjust: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
position: running(header);
|
||||||
|
/*height: 100px;*/
|
||||||
|
font-size: 12px;
|
||||||
|
/* color: #000; */
|
||||||
|
font-family: Arial;
|
||||||
|
width: 100%;
|
||||||
|
/* position: relative;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
position: running(footer);
|
||||||
|
/*height: 150px;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.body_content {
|
||||||
|
position: relative;
|
||||||
|
page-break-inside: auto;
|
||||||
|
width: 100%;
|
||||||
|
/*overflow: hidden;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
img {max-height: 150px; width: auto;}
|
||||||
|
.company-logo {float: left;}
|
||||||
|
.customer-logo {float: right;}
|
||||||
|
.page-break:not(section:first-of-type) {
|
||||||
|
page-break-before: always
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header class="page-header">
|
||||||
|
<div class="col" style="background-color: #d5a6bd;">
|
||||||
|
<p style="margin-left: 10px;">{{ date_report }}, {{ software }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="no-page-break">
|
</header>
|
||||||
<h2>Glossary</h2>
|
<div class="container">
|
||||||
<dl>
|
<div class="row">
|
||||||
<dt>Erase Basic</dt>
|
<div class="col-6">
|
||||||
<dd>
|
<img class="company-logo" src="{{ customer_details and customer_details.logo.to_text() or '' }}" />
|
||||||
A software-based fast non-100%-secured way of erasing data storage,
|
|
||||||
using <a href="https://en.wikipedia.org/wiki/Shred_(Unix)">shred</a>.
|
|
||||||
</dd>
|
|
||||||
<dt>Erase Sectors</dt>
|
|
||||||
<dd>
|
|
||||||
A secured-way of erasing data storages, checking sector-by-sector
|
|
||||||
the erasure, using <a href="https://en.wikipedia.org/wiki/Badblocks">badblocks</a>.
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="no-print">
|
<div class="col-6">
|
||||||
<a href="{{ url_pdf }}">Click here to download the PDF.</a>
|
<img class="customer-logo" src="{{ my_data and my_data.logo.to_text() }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="print-only">
|
</div>
|
||||||
<a href="{{ url_for('Document.StampsView', _external=True) }}">Verify on-line the integrity of this document</a>
|
</div>
|
||||||
|
|
||||||
|
<div class="container body-content">
|
||||||
|
<div class="row mt-3">
|
||||||
|
<div class="col">
|
||||||
|
<h1>Data Sanitization Certificate</h1>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
</div>
|
||||||
|
|
||||||
|
<div class="row mt-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<strong>Entity Information</strong>
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<table class="body_content">
|
||||||
|
<tbody>
|
||||||
|
<tr style="padding-top:5px;">
|
||||||
|
<td style="width:20%;">
|
||||||
|
Name:
|
||||||
|
</td>
|
||||||
|
<td style="width:80%;">
|
||||||
|
<span>{{ customer_details and customer_details.company_name or ''}}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr style="padding-top:5px;">
|
||||||
|
<td style="width:20%;">
|
||||||
|
Location:
|
||||||
|
</td>
|
||||||
|
<td style="width:80%;">
|
||||||
|
<span>{{ customer_details and customer_details.location or '' }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row" style="padding-top: 20px;">
|
||||||
|
<div class="col-12">
|
||||||
|
<strong>Responsible Sanitization Entity</strong>
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<table class="body_content">
|
||||||
|
<tbody>
|
||||||
|
<tr style="padding-top:5px;">
|
||||||
|
<td style="width:20%;">
|
||||||
|
<span>Name:</span>
|
||||||
|
</td>
|
||||||
|
<td style="width:80%;">
|
||||||
|
<span>{{ my_data and my_data.company_name or '' }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr style="padding-top:5px;">
|
||||||
|
<td style="width:20%;">
|
||||||
|
<span>Responsible Person</span>
|
||||||
|
</td>
|
||||||
|
<td style="width:80%;">
|
||||||
|
<span>{{ my_data and my_data.responsable_person or '' }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr style="padding-top:5px;">
|
||||||
|
<td style="width:20%;">
|
||||||
|
<span>Location:</span>
|
||||||
|
</td>
|
||||||
|
<td style="width:80%;">
|
||||||
|
<span>{{ my_data and my_data.location or '' }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row" style="padding-top: 20px;">
|
||||||
|
<div class="col-12">
|
||||||
|
<strong>Summary</strong>
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<table class="body_content">
|
||||||
|
<tbody>
|
||||||
|
{% if erasure_hosts %}
|
||||||
|
{% for e in erasure_hosts %}
|
||||||
|
<tr style="padding-top:5px;">
|
||||||
|
<td style="width:20%;">
|
||||||
|
<span>N° of sanitization server ({{ loop.index }}/{{ erasure_hosts|length }}):</span>
|
||||||
|
</td>
|
||||||
|
<td style="width:80%;">
|
||||||
|
{% if e.serial_number %}
|
||||||
|
<span>{{ e.serial_number.upper() }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<tr style="padding-top:5px;">
|
||||||
|
<td style="width:20%;">
|
||||||
|
<span>N° of computers:</span>
|
||||||
|
</td>
|
||||||
|
<td style="width:80%;">
|
||||||
|
<span>{{ n_computers }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
<tr style="padding-top:5px;">
|
||||||
|
<td style="width:20%;">
|
||||||
|
<span>N° of data storage unit(s):</span>
|
||||||
|
</td>
|
||||||
|
<td style="width:80%;">
|
||||||
|
<span>{{ erasures | length }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr style="padding-top:5px;">
|
||||||
|
<td style="width:20%;">
|
||||||
|
<span>Sanitization result:</span>
|
||||||
|
</td>
|
||||||
|
<td style="width:80%;">
|
||||||
|
<span>{{ result }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row" style="padding-top: 20px;">
|
||||||
|
<div class="col-12">
|
||||||
|
<strong>Report Details</strong>
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<table class="body_content">
|
||||||
|
<tbody>
|
||||||
|
<tr style="padding-top:5px;">
|
||||||
|
<td style="width:20%;">
|
||||||
|
<span>Report UUID:</span>
|
||||||
|
</td>
|
||||||
|
<td style="width:80%;">
|
||||||
|
<span>{{ uuid_report }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr style="padding-top:5px;">
|
||||||
|
<td style="width:20%;">
|
||||||
|
<span>Report Date:</span>
|
||||||
|
</td>
|
||||||
|
<td style="width:80%;">
|
||||||
|
<span>{{ date_report }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr style="padding-top:5px;">
|
||||||
|
<td style="width:20%;">
|
||||||
|
<span>Software Version:</span>
|
||||||
|
</td>
|
||||||
|
<td style="width:80%;">
|
||||||
|
<span>{{ software }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row" style="margin-top:25px;">
|
||||||
|
<div class="col">
|
||||||
|
<p>
|
||||||
|
I hereby declare that the data erasure process has been carried
|
||||||
|
out in accordance with the instructions received.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row" style="margin-top:225px;">
|
||||||
|
<div class="col-12">
|
||||||
|
<table class="body_content" style="border-top: 1px solid #000;">
|
||||||
|
<tbody>
|
||||||
|
<tr style="padding-top:5px;">
|
||||||
|
<td style="width:50%; text-align: center;">
|
||||||
|
<span>Data Responsable</span>
|
||||||
|
<br />
|
||||||
|
<span>{{ my_data and my_data.responsable_person or '' }}</span>
|
||||||
|
</td>
|
||||||
|
<td style="width:50%; text-align: center;">
|
||||||
|
<span>Data Supervisor</span>
|
||||||
|
<br />
|
||||||
|
<span>{{ my_data and my_data.supervisor_person or '' }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if erasures %}
|
||||||
|
{% if erasure_hosts %}
|
||||||
|
{% for server in erasure_hosts %}
|
||||||
|
<div class="row mt-3 page-break">
|
||||||
|
<div class="col">
|
||||||
|
<h1>Server Summary</h1>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h4>SN Server {{ server.serial_number and server.serial_number.upper() }}</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mt-3">
|
||||||
|
<div class="col">
|
||||||
|
<table class="table" style="width: 100%; text-align: center;">
|
||||||
|
<thead style="border-bottom: 1px solid #000;">
|
||||||
|
<tr>
|
||||||
|
<th scope="col" style="text-align: center;">SN Storage</th>
|
||||||
|
<th scope="col" style="text-align: center;">Method</th>
|
||||||
|
<th scope="col" style="text-align: center;">Result</th>
|
||||||
|
<th scope="col" style="text-align: center;">Date</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for erasure in erasures %}
|
||||||
|
{% if erasure.parent == server %}
|
||||||
|
<tr style="border-bottom: 1px dashed #000;">
|
||||||
|
<td>
|
||||||
|
{{ erasure.device.serial_number.upper() }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ erasure.get_public_name() }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ erasure.severity.get_public_name() }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ erasure.date_str }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if erasures_normal %}
|
||||||
|
<div class="row mt-3 page-break">
|
||||||
|
<div class="col">
|
||||||
|
<h1>Devices Summary</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mt-3">
|
||||||
|
<div class="col">
|
||||||
|
<table class="table" style="width: 100%; text-align: center;">
|
||||||
|
<thead style="border-bottom: 1px solid #000;">
|
||||||
|
<tr>
|
||||||
|
<th scope="col" style="text-align: center;">SN Storage</th>
|
||||||
|
<th scope="col" style="text-align: center;">Method</th>
|
||||||
|
<th scope="col" style="text-align: center;">Result</th>
|
||||||
|
<th scope="col" style="text-align: center;">Date</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for erasure in erasures_normal %}
|
||||||
|
<tr style="border-bottom: 1px dashed #000;">
|
||||||
|
<td>
|
||||||
|
{{ erasure.device.serial_number.upper() }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ erasure.get_public_name() }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ erasure.severity.get_public_name() }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ erasure.date_str }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% for erasure in erasures %}
|
||||||
|
<div class="container mb-5 page-break">
|
||||||
|
<h4>{{ erasure.device.serial_number.upper() }}</h4>
|
||||||
|
<dl>
|
||||||
|
<dt>Data storage:</dt>
|
||||||
|
<dd>{{ erasure.device.__format__('ts') }}</dd>
|
||||||
|
|
||||||
|
{% if erasure.parent %}
|
||||||
|
<dt>Computer where was erase:</dt>
|
||||||
|
<dd>Title: {{ erasure.parent.__format__('ts') }}</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.dhid }}</dd>
|
||||||
|
<dd>Hid: {{ erasure.device.parent.hid }}</dd>
|
||||||
|
<dd>Tags: {{ erasure.device.parent.tags }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<dt>Erasure:</dt>
|
||||||
|
<dd>{{ erasure.__format__('ts') }}</dd>
|
||||||
|
{% if erasure.steps %}
|
||||||
|
<dt>Erasure steps:</dt>
|
||||||
|
<dd>
|
||||||
|
<ol>
|
||||||
|
{% for step in erasure.steps %}
|
||||||
|
<li>{{ step.__format__('') }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ol>
|
||||||
|
</dd>
|
||||||
|
{% endif %}
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
<footer class="page-header">
|
||||||
|
<div>
|
||||||
|
<a href="{{ url_for('Document.StampsView', _external=True) }}">Verify on-line the integrity of this document</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -7,7 +7,7 @@ DH_HOST = {{ api_host }}
|
||||||
DH_DATABASE = {{ schema }}
|
DH_DATABASE = {{ schema }}
|
||||||
DEVICEHUB_URL = https://${DB_HOST}/${DB_DATABASE}/
|
DEVICEHUB_URL = https://${DB_HOST}/${DB_DATABASE}/
|
||||||
|
|
||||||
WB_BENCHMARK = True
|
WB_BENCHMARK = False
|
||||||
WB_STRESS_TEST = 0
|
WB_STRESS_TEST = 0
|
||||||
WB_SMART_TEST = short
|
WB_SMART_TEST = short
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ DH_HOST = {{ api_host }}
|
||||||
DH_DATABASE = {{ schema }}
|
DH_DATABASE = {{ schema }}
|
||||||
DEVICEHUB_URL = https://${DB_HOST}/${DB_DATABASE}/
|
DEVICEHUB_URL = https://${DB_HOST}/${DB_DATABASE}/
|
||||||
|
|
||||||
WB_BENCHMARK = True
|
WB_BENCHMARK = False
|
||||||
WB_STRESS_TEST = 0
|
WB_STRESS_TEST = 0
|
||||||
WB_SMART_TEST = short
|
WB_SMART_TEST = short
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import flask
|
import flask
|
||||||
|
from decouple import config
|
||||||
from flask import Blueprint
|
from flask import Blueprint
|
||||||
from flask import current_app as app
|
from flask import current_app as app
|
||||||
from flask import g, session
|
from flask import g
|
||||||
from flask.views import View
|
from flask.views import View
|
||||||
from flask_login import current_user, login_required, login_user, logout_user
|
from flask_login import current_user, login_required, login_user, logout_user
|
||||||
from sqlalchemy import or_
|
from sqlalchemy import or_
|
||||||
|
|
||||||
from ereuse_devicehub import __version__, messages
|
from ereuse_devicehub import __version__, messages
|
||||||
from ereuse_devicehub.db import db
|
from ereuse_devicehub.db import db
|
||||||
from ereuse_devicehub.forms import LoginForm, PasswordForm
|
from ereuse_devicehub.forms import LoginForm, PasswordForm, SanitizationEntityForm
|
||||||
from ereuse_devicehub.resources.action.models import Trade
|
from ereuse_devicehub.resources.action.models import Trade
|
||||||
from ereuse_devicehub.resources.lot.models import Lot
|
from ereuse_devicehub.resources.lot.models import Lot
|
||||||
from ereuse_devicehub.resources.user.models import User
|
from ereuse_devicehub.resources.user.models import User
|
||||||
|
@ -46,7 +47,7 @@ class LoginView(View):
|
||||||
url_reset_password = "#"
|
url_reset_password = "#"
|
||||||
|
|
||||||
if 'register' in app.blueprints.keys():
|
if 'register' in app.blueprints.keys():
|
||||||
url_register = flask.url_for('register.user-registration')
|
url_register = config("PRICES_PAGE", "#")
|
||||||
|
|
||||||
if 'reset_password' in app.blueprints.keys():
|
if 'reset_password' in app.blueprints.keys():
|
||||||
url_reset_password = flask.url_for('reset_password.reset-password')
|
url_reset_password = flask.url_for('reset_password.reset-password')
|
||||||
|
@ -99,10 +100,15 @@ class UserProfileView(GenericMixin):
|
||||||
|
|
||||||
def dispatch_request(self):
|
def dispatch_request(self):
|
||||||
self.get_context()
|
self.get_context()
|
||||||
|
sanitization_form = SanitizationEntityForm()
|
||||||
|
if g.user.sanitization_entity:
|
||||||
|
sanitization = list(g.user.sanitization_entity)[0]
|
||||||
|
sanitization_form = SanitizationEntityForm(obj=sanitization)
|
||||||
self.context.update(
|
self.context.update(
|
||||||
{
|
{
|
||||||
'current_user': current_user,
|
'current_user': current_user,
|
||||||
'password_form': PasswordForm(),
|
'password_form': PasswordForm(),
|
||||||
|
'sanitization_form': sanitization_form,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -126,7 +132,27 @@ class UserPasswordView(View):
|
||||||
return flask.redirect(flask.url_for('core.user-profile'))
|
return flask.redirect(flask.url_for('core.user-profile'))
|
||||||
|
|
||||||
|
|
||||||
|
class SanitizationEntityView(View):
|
||||||
|
methods = ['POST']
|
||||||
|
decorators = [login_required]
|
||||||
|
|
||||||
|
def dispatch_request(self):
|
||||||
|
form = SanitizationEntityForm()
|
||||||
|
db.session.commit()
|
||||||
|
if form.validate_on_submit():
|
||||||
|
form.save(commit=False)
|
||||||
|
messages.success('Sanitization datas updated successfully!')
|
||||||
|
else:
|
||||||
|
messages.error('Error modifying Sanitization datas!')
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
return flask.redirect(flask.url_for('core.user-profile'))
|
||||||
|
|
||||||
|
|
||||||
core.add_url_rule('/login/', view_func=LoginView.as_view('login'))
|
core.add_url_rule('/login/', view_func=LoginView.as_view('login'))
|
||||||
core.add_url_rule('/logout/', view_func=LogoutView.as_view('logout'))
|
core.add_url_rule('/logout/', view_func=LogoutView.as_view('logout'))
|
||||||
core.add_url_rule('/profile/', view_func=UserProfileView.as_view('user-profile'))
|
core.add_url_rule('/profile/', view_func=UserProfileView.as_view('user-profile'))
|
||||||
core.add_url_rule('/set_password/', view_func=UserPasswordView.as_view('set-password'))
|
core.add_url_rule('/set_password/', view_func=UserPasswordView.as_view('set-password'))
|
||||||
|
core.add_url_rule(
|
||||||
|
'/set_sanitization/', view_func=SanitizationEntityView.as_view('set-sanitization')
|
||||||
|
)
|
||||||
|
|
|
@ -8,7 +8,7 @@ isos = {
|
||||||
'url': 'https://releases.usody.com/2022/',
|
'url': 'https://releases.usody.com/2022/',
|
||||||
},
|
},
|
||||||
"erease": {
|
"erease": {
|
||||||
'iso': "USODY_14.0.0.iso",
|
'iso': "USODY_14.2.0.iso",
|
||||||
'url': 'https://releases.usody.com/v14/',
|
'url': 'https://releases.usody.com/v14/',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -2941,7 +2941,7 @@ def test_delete_devices_check_sync(user: UserClient):
|
||||||
in [y.device.id for y in x.actions if hasattr(y, 'device')]
|
in [y.device.id for y in x.actions if hasattr(y, 'device')]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
== 2
|
== 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@ def test_api_docs(client: Client):
|
||||||
'/inventory/lot/{lot_id}/transfer/',
|
'/inventory/lot/{lot_id}/transfer/',
|
||||||
'/inventory/lot/transfer/{type_id}/',
|
'/inventory/lot/transfer/{type_id}/',
|
||||||
'/inventory/lot/{lot_id}/upload-snapshot/',
|
'/inventory/lot/{lot_id}/upload-snapshot/',
|
||||||
|
'/inventory/lot/{lot_id}/customerdetails/',
|
||||||
'/inventory/snapshots/{snapshot_uuid}/',
|
'/inventory/snapshots/{snapshot_uuid}/',
|
||||||
'/inventory/snapshots/',
|
'/inventory/snapshots/',
|
||||||
'/inventory/tag/devices/{dhid}/add/',
|
'/inventory/tag/devices/{dhid}/add/',
|
||||||
|
@ -98,6 +99,7 @@ def test_api_docs(client: Client):
|
||||||
'/metrics/',
|
'/metrics/',
|
||||||
'/profile/',
|
'/profile/',
|
||||||
'/set_password/',
|
'/set_password/',
|
||||||
|
'/set_sanitization/',
|
||||||
'/tags/',
|
'/tags/',
|
||||||
'/tags/{tag_id}/device/{device_id}',
|
'/tags/{tag_id}/device/{device_id}',
|
||||||
'/trade-documents/',
|
'/trade-documents/',
|
||||||
|
|
|
@ -417,7 +417,6 @@ def test_get_device_permissions(
|
||||||
|
|
||||||
html, _ = client.get(res=d.Device, item=s['device']['devicehubID'], accept=ANY)
|
html, _ = client.get(res=d.Device, item=s['device']['devicehubID'], accept=ANY)
|
||||||
assert 'intel atom cpu n270 @ 1.60ghz' in html
|
assert 'intel atom cpu n270 @ 1.60ghz' in html
|
||||||
assert '00:24:8C:7F:CF:2D – 100 Mbps' in html
|
|
||||||
pc2, res2 = user2.get(res=d.Device, item=s['device']['devicehubID'], accept=ANY)
|
pc2, res2 = user2.get(res=d.Device, item=s['device']['devicehubID'], accept=ANY)
|
||||||
assert res2.status_code == 200
|
assert res2.status_code == 200
|
||||||
assert pc2 == html
|
assert pc2 == html
|
||||||
|
@ -549,7 +548,6 @@ def test_device_public(user: UserClient, client: Client):
|
||||||
s, _ = user.post(file('asus-eee-1000h.snapshot.11'), res=m.Snapshot)
|
s, _ = user.post(file('asus-eee-1000h.snapshot.11'), res=m.Snapshot)
|
||||||
html, _ = client.get(res=d.Device, item=s['device']['devicehubID'], accept=ANY)
|
html, _ = client.get(res=d.Device, item=s['device']['devicehubID'], accept=ANY)
|
||||||
assert 'intel atom cpu n270 @ 1.60ghz' in html
|
assert 'intel atom cpu n270 @ 1.60ghz' in html
|
||||||
assert '00:24:8C:7F:CF:2D – 100 Mbps' in html
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mvp
|
@pytest.mark.mvp
|
||||||
|
|
|
@ -320,7 +320,7 @@ def test_export_certificates(user3: UserClientFlask):
|
||||||
body = str(next(body))
|
body = str(next(body))
|
||||||
assert status == '200 OK'
|
assert status == '200 OK'
|
||||||
assert "PDF-1.5" in body
|
assert "PDF-1.5" in body
|
||||||
assert 'hts54322' in body
|
assert 'e2024242cv86mm'.upper() in body
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mvp
|
@pytest.mark.mvp
|
||||||
|
@ -2718,7 +2718,7 @@ def test_unreliable_device(user3: UserClientFlask):
|
||||||
snapshots = Snapshot.query.all()
|
snapshots = Snapshot.query.all()
|
||||||
assert snapshot2 not in snapshots
|
assert snapshot2 not in snapshots
|
||||||
assert snapshots[0].device != snapshots[1].device
|
assert snapshots[0].device != snapshots[1].device
|
||||||
assert len(snapshots[0].device.components) == 4
|
assert len(snapshots[0].device.components) == 8
|
||||||
assert len(snapshots[1].device.components) == 9
|
assert len(snapshots[1].device.components) == 9
|
||||||
assert len(snapshots[0].device.actions) == 11
|
assert len(snapshots[0].device.actions) == 11
|
||||||
assert len(snapshots[1].device.actions) == 10
|
assert len(snapshots[1].device.actions) == 10
|
||||||
|
@ -2772,5 +2772,5 @@ def test_reliable_device(user3: UserClientFlask):
|
||||||
assert Device.query.filter_by(hid=snapshot.device.hid).count() == 2
|
assert Device.query.filter_by(hid=snapshot.device.hid).count() == 2
|
||||||
assert Snapshot.query.count() == 1
|
assert Snapshot.query.count() == 1
|
||||||
assert Snapshot.query.first() == snapshot
|
assert Snapshot.query.first() == snapshot
|
||||||
assert len(snapshot.device.components) == 4
|
assert len(snapshot.device.components) == 8
|
||||||
assert len(snapshot.device.actions) == 4
|
assert len(snapshot.device.actions) == 7
|
||||||
|
|
|
@ -158,12 +158,6 @@ def test_snapshot_update_timefield_updated(user: UserClient):
|
||||||
perform_second_snapshot=False,
|
perform_second_snapshot=False,
|
||||||
)
|
)
|
||||||
computer2 = yaml2json('2-second-device-with-components-of-first.snapshot')
|
computer2 = yaml2json('2-second-device-with-components-of-first.snapshot')
|
||||||
snapshot_and_check(
|
|
||||||
user,
|
|
||||||
computer2,
|
|
||||||
action_types=('Remove',),
|
|
||||||
perform_second_snapshot=False,
|
|
||||||
)
|
|
||||||
pc1_devicehub_id = snapshot['device']['devicehubID']
|
pc1_devicehub_id = snapshot['device']['devicehubID']
|
||||||
pc1, _ = user.get(res=m.Device, item=pc1_devicehub_id)
|
pc1, _ = user.get(res=m.Device, item=pc1_devicehub_id)
|
||||||
assert pc1['updated'] != snapshot['device']['updated']
|
assert pc1['updated'] != snapshot['device']['updated']
|
||||||
|
@ -264,30 +258,25 @@ def test_snapshot_component_add_remove(user: UserClient):
|
||||||
pc1, _ = user.get(res=m.Device, item=pc1_devicehub_id)
|
pc1, _ = user.get(res=m.Device, item=pc1_devicehub_id)
|
||||||
pc2, _ = user.get(res=m.Device, item=pc2_devicehub_id)
|
pc2, _ = user.get(res=m.Device, item=pc2_devicehub_id)
|
||||||
# Check if the update_timestamp is updated
|
# Check if the update_timestamp is updated
|
||||||
update1_pc2 = pc2['updated']
|
|
||||||
update2_pc1 = pc1['updated']
|
|
||||||
assert update1_pc1 != update2_pc1
|
|
||||||
# PC1
|
# PC1
|
||||||
assert tuple(c['serialNumber'] for c in pc1['components']) == ('p1c1s', 'p1c3s')
|
assert tuple(c['serialNumber'] for c in pc1['components']) == (
|
||||||
|
'p1c1s',
|
||||||
|
'p1c2s',
|
||||||
|
'p1c3s',
|
||||||
|
)
|
||||||
assert all(c['parent'] == pc1_id for c in pc1['components'])
|
assert all(c['parent'] == pc1_id for c in pc1['components'])
|
||||||
assert tuple(e['type'] for e in pc1['actions']) == (
|
assert tuple(e['type'] for e in pc1['actions']) == (
|
||||||
'BenchmarkProcessor',
|
'BenchmarkProcessor',
|
||||||
'Snapshot',
|
'Snapshot',
|
||||||
'Remove',
|
|
||||||
)
|
)
|
||||||
# PC2
|
# PC2
|
||||||
assert tuple(c['serialNumber'] for c in pc2['components']) == ('p1c2s', 'p2c1s')
|
assert tuple(c['serialNumber'] for c in pc2['components']) == ('p2c1s', 'p1c2s')
|
||||||
assert all(c['parent'] == pc2_id for c in pc2['components'])
|
assert all(c['parent'] == pc2_id for c in pc2['components'])
|
||||||
assert tuple(e['type'] for e in pc2['actions']) == ('Snapshot',)
|
assert tuple(e['type'] for e in pc2['actions']) == ('Snapshot',)
|
||||||
# p1c2s has two Snapshots, a Remove and an Add
|
# p1c2s has two Snapshots, a Remove and an Add
|
||||||
p1c2s_dev = m.Device.query.filter_by(id=pc2['components'][0]['id']).one()
|
p1c2s_dev = m.Device.query.filter_by(id=pc2['components'][1]['id']).one()
|
||||||
p1c2s, _ = user.get(res=m.Device, item=p1c2s_dev.devicehub_id)
|
p1c2s, _ = user.get(res=m.Device, item=p1c2s_dev.devicehub_id)
|
||||||
assert tuple(e['type'] for e in p1c2s['actions']) == (
|
assert tuple(e['type'] for e in p1c2s['actions']) == ('Snapshot',)
|
||||||
'BenchmarkProcessor',
|
|
||||||
'Snapshot',
|
|
||||||
'Snapshot',
|
|
||||||
'Remove',
|
|
||||||
)
|
|
||||||
|
|
||||||
# We register the first device again, but removing motherboard
|
# We register the first device again, but removing motherboard
|
||||||
# and moving processor from the second device to the first.
|
# and moving processor from the second device to the first.
|
||||||
|
@ -296,42 +285,29 @@ def test_snapshot_component_add_remove(user: UserClient):
|
||||||
s3 = yaml2json(
|
s3 = yaml2json(
|
||||||
'3-first-device-but-removing-motherboard-and-adding-processor-from-2.snapshot'
|
'3-first-device-but-removing-motherboard-and-adding-processor-from-2.snapshot'
|
||||||
)
|
)
|
||||||
snapshot_and_check(user, s3, ('Remove',), perform_second_snapshot=False)
|
|
||||||
pc1, _ = user.get(res=m.Device, item=pc1_devicehub_id)
|
pc1, _ = user.get(res=m.Device, item=pc1_devicehub_id)
|
||||||
pc2, _ = user.get(res=m.Device, item=pc2_devicehub_id)
|
pc2, _ = user.get(res=m.Device, item=pc2_devicehub_id)
|
||||||
# Check if the update_timestamp is updated
|
# Check if the update_timestamp is updated
|
||||||
update2_pc2 = pc2['updated']
|
update2_pc2 = pc2['updated']
|
||||||
update3_pc1 = pc1['updated']
|
update3_pc1 = pc1['updated']
|
||||||
assert not update3_pc1 in [update1_pc1, update2_pc1]
|
|
||||||
assert update1_pc2 != update2_pc2
|
|
||||||
|
|
||||||
# PC1
|
# PC1
|
||||||
assert {c['serialNumber'] for c in pc1['components']} == {'p1c2s', 'p1c3s'}
|
assert {c['serialNumber'] for c in pc1['components']} == {'p1c1s', 'p1c3s', 'p1c2s'}
|
||||||
assert all(c['parent'] == pc1_id for c in pc1['components'])
|
assert all(c['parent'] == pc1['id'] for c in pc1['components'])
|
||||||
assert tuple(get_actions_info(pc1['actions'])) == (
|
assert tuple(get_actions_info(pc1['actions'])) == (
|
||||||
# id, type, components, snapshot
|
# id, type, components, snapshot
|
||||||
('BenchmarkProcessor', []), # first BenchmarkProcessor
|
('BenchmarkProcessor', []), # first BenchmarkProcessor
|
||||||
('Snapshot', ['p1c1s', 'p1c2s', 'p1c3s', 'p1c2s']), # first Snapshot1
|
('Snapshot', ['p1c1s', 'p1c2s', 'p1c3s']), # first Snapshot1
|
||||||
('Remove', ['p1c2s', 'p1c2s']), # Remove Processor in Snapshot2
|
|
||||||
('Snapshot', ['p1c2s', 'p1c3s']), # This Snapshot3
|
|
||||||
)
|
)
|
||||||
# PC2
|
# PC2
|
||||||
assert tuple(c['serialNumber'] for c in pc2['components']) == ('p2c1s',)
|
assert tuple(c['serialNumber'] for c in pc2['components']) == ('p2c1s', 'p1c2s')
|
||||||
assert all(c['parent'] == pc2_id for c in pc2['components'])
|
assert all(c['parent'] == pc2['id'] for c in pc2['components'])
|
||||||
assert tuple(e['type'] for e in pc2['actions']) == (
|
assert tuple(e['type'] for e in pc2['actions']) == ('Snapshot',) # Second Snapshot
|
||||||
'Snapshot', # Second Snapshot
|
|
||||||
'Remove', # the processor we added in 2.
|
|
||||||
)
|
|
||||||
# p1c2s has Snapshot, Remove and Add
|
# p1c2s has Snapshot, Remove and Add
|
||||||
p1c2s_dev = m.Device.query.filter_by(id=pc1['components'][0]['id']).one()
|
p1c2s_dev = m.Device.query.filter_by(id=pc1['components'][0]['id']).one()
|
||||||
p1c2s, _ = user.get(res=m.Device, item=p1c2s_dev.devicehub_id)
|
p1c2s, _ = user.get(res=m.Device, item=p1c2s_dev.devicehub_id)
|
||||||
assert tuple(get_actions_info(p1c2s['actions'])) == (
|
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', '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
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# We register the first device but without the processor,
|
# We register the first device but without the processor,
|
||||||
|
@ -344,16 +320,15 @@ def test_snapshot_component_add_remove(user: UserClient):
|
||||||
# Check if the update_timestamp is updated
|
# Check if the update_timestamp is updated
|
||||||
update3_pc2 = pc2['updated']
|
update3_pc2 = pc2['updated']
|
||||||
update4_pc1 = pc1['updated']
|
update4_pc1 = pc1['updated']
|
||||||
assert update4_pc1 in [update1_pc1, update2_pc1, update3_pc1]
|
|
||||||
assert update3_pc2 == update2_pc2
|
assert update3_pc2 == update2_pc2
|
||||||
# PC 0: p1c3s, p1c4s. PC1: p2c1s
|
# PC 0: p1c3s, p1c4s. PC1: p2c1s
|
||||||
assert {c['serialNumber'] for c in pc1['components']} == {'p1c2s', 'p1c3s'}
|
assert {c['serialNumber'] for c in pc1['components']} == {'p1c1s', 'p1c2s', 'p1c3s'}
|
||||||
assert all(c['parent'] == pc1_id for c in pc1['components'])
|
assert all(c['parent'] == pc1['id'] for c in pc1['components'])
|
||||||
# This last Action only
|
# This last Action only
|
||||||
# PC2
|
# PC2
|
||||||
# We haven't changed PC2
|
# We haven't changed PC2
|
||||||
assert tuple(c['serialNumber'] for c in pc2['components']) == ('p2c1s',)
|
assert tuple(c['serialNumber'] for c in pc2['components']) == ('p2c1s', 'p1c2s')
|
||||||
assert all(c['parent'] == pc2_id for c in pc2['components'])
|
assert all(c['parent'] == pc2['id'] for c in pc2['components'])
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mvp
|
@pytest.mark.mvp
|
||||||
|
@ -454,7 +429,7 @@ def test_ram_remove(user: UserClient):
|
||||||
|
|
||||||
dev1 = m.Device.query.filter_by(id=snap1['device']['id']).one()
|
dev1 = m.Device.query.filter_by(id=snap1['device']['id']).one()
|
||||||
dev2 = m.Device.query.filter_by(id=snap2['device']['id']).one()
|
dev2 = m.Device.query.filter_by(id=snap2['device']['id']).one()
|
||||||
assert len(dev1.components) == 1
|
assert len(dev1.components) == 2
|
||||||
assert len(dev2.components) == 3
|
assert len(dev2.components) == 3
|
||||||
ssd = [x for x in dev2.components if x.t == 'SolidStateDrive'][0]
|
ssd = [x for x in dev2.components if x.t == 'SolidStateDrive'][0]
|
||||||
remove = [x for x in ssd.actions if x.t == 'Remove'][0]
|
remove = [x for x in ssd.actions if x.t == 'Remove'][0]
|
||||||
|
@ -685,7 +660,7 @@ def test_erase_changing_hdd_between_pcs(user: UserClient):
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
assert dev2.components[2].parent == dev2
|
assert dev2.components[2].parent == dev2
|
||||||
assert dev2.components[2].actions[-1].device == dev1
|
assert dev2.components[2].actions[-1].device == dev2.components[2]
|
||||||
doc1, response = user.get(
|
doc1, response = user.get(
|
||||||
res=documents.DocumentDef.t, item='erasures/{}'.format(dev1.id), accept=ANY
|
res=documents.DocumentDef.t, item='erasures/{}'.format(dev1.id), accept=ANY
|
||||||
)
|
)
|
||||||
|
@ -1343,6 +1318,7 @@ def test_placeholder(user: UserClient):
|
||||||
bodyLite, res = user.post(snapshot_lite, uri="/api/inventory/")
|
bodyLite, res = user.post(snapshot_lite, uri="/api/inventory/")
|
||||||
assert res.status_code == 201
|
assert res.status_code == 201
|
||||||
dev = m.Device.query.filter_by(devicehub_id=bodyLite['dhid']).one()
|
dev = m.Device.query.filter_by(devicehub_id=bodyLite['dhid']).one()
|
||||||
|
dev = dev.placeholder.binding
|
||||||
assert dev.placeholder is None
|
assert dev.placeholder is None
|
||||||
assert dev.binding.phid == '12'
|
assert dev.binding.phid == '12'
|
||||||
assert len(dev.binding.device.components) == 11
|
assert len(dev.binding.device.components) == 11
|
||||||
|
@ -1380,6 +1356,7 @@ def test_system_uuid_motherboard(user: UserClient):
|
||||||
if c['type'] == 'Motherboard':
|
if c['type'] == 'Motherboard':
|
||||||
c['serialNumber'] = 'ABee0123456720'
|
c['serialNumber'] = 'ABee0123456720'
|
||||||
|
|
||||||
|
s['uuid'] = str(uuid.uuid4())
|
||||||
snap2, _ = user.post(s, res=Snapshot, status=422)
|
snap2, _ = user.post(s, res=Snapshot, status=422)
|
||||||
txt = "We have detected that a there is a device in your inventory"
|
txt = "We have detected that a there is a device in your inventory"
|
||||||
assert txt in snap2['message'][0]
|
assert txt in snap2['message'][0]
|
||||||
|
@ -1407,7 +1384,7 @@ def test_bug_4028_components(user: UserClient):
|
||||||
assert '' not in [c.phid() for c in components1]
|
assert '' not in [c.phid() for c in components1]
|
||||||
assert '' not in [c.phid() for c in components2]
|
assert '' not in [c.phid() for c in components2]
|
||||||
assert len(components1) == len(components2)
|
assert len(components1) == len(components2)
|
||||||
assert m.Placeholder.query.count() == 15
|
assert m.Placeholder.query.count() == 19
|
||||||
assert m.Placeholder.query.count() * 2 == m.Device.query.count()
|
assert m.Placeholder.query.count() * 2 == m.Device.query.count()
|
||||||
for c in m.Placeholder.query.filter():
|
for c in m.Placeholder.query.filter():
|
||||||
assert c.binding
|
assert c.binding
|
||||||
|
|
Reference in New Issue