Add public device view
This commit is contained in:
parent
38060d47ec
commit
77c96c5956
|
@ -1,3 +1,5 @@
|
||||||
|
from typing import Callable, Iterable, Tuple
|
||||||
|
|
||||||
from teal.resource import Converters, Resource
|
from teal.resource import Converters, Resource
|
||||||
|
|
||||||
from ereuse_devicehub.resources.device import schemas
|
from ereuse_devicehub.resources.device import schemas
|
||||||
|
@ -9,7 +11,19 @@ class DeviceDef(Resource):
|
||||||
SCHEMA = schemas.Device
|
SCHEMA = schemas.Device
|
||||||
VIEW = DeviceView
|
VIEW = DeviceView
|
||||||
ID_CONVERTER = Converters.int
|
ID_CONVERTER = Converters.int
|
||||||
AUTH = True
|
AUTH = False # We manage this at each view
|
||||||
|
|
||||||
|
def __init__(self, app,
|
||||||
|
import_name=__name__, static_folder=None,
|
||||||
|
static_url_path=None,
|
||||||
|
template_folder='templates',
|
||||||
|
url_prefix=None,
|
||||||
|
subdomain=None,
|
||||||
|
url_defaults=None,
|
||||||
|
root_path=None,
|
||||||
|
cli_commands: Iterable[Tuple[Callable, str or None]] = tuple()):
|
||||||
|
super().__init__(app, import_name, static_folder, static_url_path, template_folder,
|
||||||
|
url_prefix, subdomain, url_defaults, root_path, cli_commands)
|
||||||
|
|
||||||
|
|
||||||
class ComputerDef(DeviceDef):
|
class ComputerDef(DeviceDef):
|
||||||
|
|
|
@ -3,7 +3,7 @@ import pathlib
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
from typing import Dict, Set
|
from typing import Dict, List, Set
|
||||||
|
|
||||||
from boltons import urlutils
|
from boltons import urlutils
|
||||||
from citext import CIText
|
from citext import CIText
|
||||||
|
@ -111,8 +111,18 @@ class Device(Thing):
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
return self.id < other.id
|
return self.id < other.id
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return '<{0.t} {0.id!r} model={0.model!r} S/N={0.serial_number!r}>'.format(self)
|
return '{0.t} {0.id}: model {0.model}, S/N {0.serial_number}'.format(self)
|
||||||
|
|
||||||
|
def __format__(self, format_spec):
|
||||||
|
if not format_spec:
|
||||||
|
return super().__format__(format_spec)
|
||||||
|
v = ''
|
||||||
|
if 't' in format_spec:
|
||||||
|
v += '{0.t} {0.model}'.format(self)
|
||||||
|
if 's' in format_spec:
|
||||||
|
v += '({0.manufacturer}) S/N {0.serial_number}'.format(self)
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
class DisplayMixin:
|
class DisplayMixin:
|
||||||
|
@ -135,6 +145,14 @@ class DisplayMixin:
|
||||||
in pixels.
|
in pixels.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def __format__(self, format_spec: str) -> str:
|
||||||
|
v = ''
|
||||||
|
if 't' in format_spec:
|
||||||
|
v += '{0.t} {0.model}'.format(self)
|
||||||
|
if 's' in format_spec:
|
||||||
|
v += '({0.manufacturer}) S/N {0.serial_number} – {0.size}in {0.technology}'
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
class Computer(Device):
|
class Computer(Device):
|
||||||
id = Column(BigInteger, ForeignKey(Device.id), primary_key=True)
|
id = Column(BigInteger, ForeignKey(Device.id), primary_key=True)
|
||||||
|
@ -144,6 +162,46 @@ class Computer(Device):
|
||||||
def events(self) -> list:
|
def events(self) -> list:
|
||||||
return sorted(chain(super().events, self.events_parent), key=attrgetter('created'))
|
return sorted(chain(super().events, self.events_parent), key=attrgetter('created'))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ram_size(self) -> int:
|
||||||
|
"""The total of RAM memory the computer has."""
|
||||||
|
return sum(ram.size for ram in self.components if isinstance(ram, RamModule))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def data_storage_size(self) -> int:
|
||||||
|
"""The total of data storage the computer has."""
|
||||||
|
return sum(ds.size for ds in self.components if isinstance(ds, DataStorage))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def processor_model(self) -> str:
|
||||||
|
"""The model of one of the processors of the computer."""
|
||||||
|
return next(p.model for p in self.components if isinstance(p, Processor))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def graphic_card_model(self) -> str:
|
||||||
|
"""The model of one of the graphic cards of the computer."""
|
||||||
|
return next(p.model for p in self.components if isinstance(p, GraphicCard))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def network_speeds(self) -> List[int]:
|
||||||
|
"""Returns two speeds: the first for the eth and the
|
||||||
|
second for the wifi networks, or 0 respectively if not found.
|
||||||
|
"""
|
||||||
|
speeds = [0, 0]
|
||||||
|
for net in (c for c in self.components if isinstance(c, NetworkAdapter)):
|
||||||
|
speeds[net.wireless] = max(net.speed or 0, speeds[net.wireless])
|
||||||
|
return speeds
|
||||||
|
|
||||||
|
def __format__(self, format_spec):
|
||||||
|
if not format_spec:
|
||||||
|
return super().__format__(format_spec)
|
||||||
|
v = ''
|
||||||
|
if 't' in format_spec:
|
||||||
|
v += '{0.chassis} {0.model}'.format(self)
|
||||||
|
elif 's' in format_spec:
|
||||||
|
v += '({0.manufacturer}) S/N {0.serial_number}'.format(self)
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
class Desktop(Computer):
|
class Desktop(Computer):
|
||||||
pass
|
pass
|
||||||
|
@ -260,6 +318,12 @@ class DataStorage(JoinedComponentTableMixin, Component):
|
||||||
"""
|
"""
|
||||||
interface = Column(DBEnum(DataStorageInterface))
|
interface = Column(DBEnum(DataStorageInterface))
|
||||||
|
|
||||||
|
def __format__(self, format_spec):
|
||||||
|
v = super().__format__(format_spec)
|
||||||
|
if 's' in format_spec:
|
||||||
|
v += ' – {} GB'.format(self.size // 1000)
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
class HardDrive(DataStorage):
|
class HardDrive(DataStorage):
|
||||||
pass
|
pass
|
||||||
|
@ -290,6 +354,12 @@ class NetworkMixin:
|
||||||
Whether it is a wireless interface.
|
Whether it is a wireless interface.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def __format__(self, format_spec):
|
||||||
|
v = super().__format__(format_spec)
|
||||||
|
if 's' in format_spec:
|
||||||
|
v += ' – {} Mbps'.format(self.speed)
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
class NetworkAdapter(JoinedComponentTableMixin, NetworkMixin, Component):
|
class NetworkAdapter(JoinedComponentTableMixin, NetworkMixin, Component):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -76,6 +76,29 @@ class Computer(DisplayMixin, Device):
|
||||||
self.events_parent = ... # type: Set[Event]
|
self.events_parent = ... # type: Set[Event]
|
||||||
self.chassis = ... # type: ComputerChassis
|
self.chassis = ... # type: ComputerChassis
|
||||||
|
|
||||||
|
@property
|
||||||
|
def events(self) -> List:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ram_size(self) -> int:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def data_storage_size(self) -> int:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def processor_model(self) -> str:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def graphic_card_model(self) -> str:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def network_speeds(self) -> List[int]:
|
||||||
|
pass
|
||||||
|
|
||||||
class Desktop(Computer):
|
class Desktop(Computer):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
{% import 'devices/macros.html' as macros %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<link href="https://stackpath.bootstrapcdn.com/bootswatch/3.3.7/flatly/bootstrap.min.css"
|
||||||
|
rel="stylesheet"
|
||||||
|
integrity="sha384-+ENW/yibaokMnme+vBLnHMphUYxHs34h9lpdbSLuAwGkOKFRl4C34WkjazBtb7eT"
|
||||||
|
crossorigin="anonymous">
|
||||||
|
<title>Devicehub | {{ device.__format__('t') }}</title>
|
||||||
|
</head>
|
||||||
|
<body class="container">
|
||||||
|
|
||||||
|
<div class="page-header">
|
||||||
|
<h1>{{ device.__format__('t') }}
|
||||||
|
<small>{{ device.__format__('s') }}</small>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<article class="col-md-6">
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th>Range</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<details>
|
||||||
|
<summary>CPU – {{ device.processor_model }}</summary>
|
||||||
|
{{ macros.component_type(device.components, 'Processor') }}
|
||||||
|
</details>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<details>
|
||||||
|
<summary>RAM – {{ device.ram_size // 1000 }} GB</summary>
|
||||||
|
{{ macros.component_type(device.components, 'RamModule') }}
|
||||||
|
</details>
|
||||||
|
</td>
|
||||||
|
<td>//range//</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<details>
|
||||||
|
<summary>Data Storage – {{ device.data_storage_size // 1000 }} GB</summary>
|
||||||
|
{{ macros.component_type(device.components, 'SolidStateDrive') }}
|
||||||
|
{{ macros.component_type(device.components, 'HardDrive') }}
|
||||||
|
</details>
|
||||||
|
</td>
|
||||||
|
<td>//range//</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<details>
|
||||||
|
<summary>Graphics – {{ device.graphic_card_model }}</summary>
|
||||||
|
{{ macros.component_type(device.components, 'GraphicCard') }}
|
||||||
|
</details>
|
||||||
|
</td>
|
||||||
|
<td>//range//</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<details>
|
||||||
|
<summary>Network –
|
||||||
|
{% if device.network_speeds[0] %}
|
||||||
|
Ethernet of {{ device.network_speeds[0] }} Mbps
|
||||||
|
{% endif %}
|
||||||
|
{% if device.network_speeds[0] and device.network_speeds[1] %}
|
||||||
|
+
|
||||||
|
{% endif %}
|
||||||
|
{% if device.network_speeds[1] %}
|
||||||
|
WiFi of {{ device.network_speeds[1] }} Mbps
|
||||||
|
{% endif %}
|
||||||
|
</summary>
|
||||||
|
{{ macros.component_type(device.components, 'NetworkAdapter') }}
|
||||||
|
</details>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</article>
|
||||||
|
<aside class="col-md-6">
|
||||||
|
<h2>Check the validity of the device</h2>
|
||||||
|
<p>Use the flashlight to scan...</p>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,9 +1,13 @@
|
||||||
|
import datetime
|
||||||
|
|
||||||
import marshmallow
|
import marshmallow
|
||||||
from flask import current_app as app
|
from flask import current_app as app, render_template, request
|
||||||
from flask.json import jsonify
|
from flask.json import jsonify
|
||||||
from flask_sqlalchemy import Pagination
|
from flask_sqlalchemy import Pagination
|
||||||
|
from teal.cache import cache
|
||||||
from teal.resource import View
|
from teal.resource import View
|
||||||
|
|
||||||
|
from ereuse_devicehub import auth
|
||||||
from ereuse_devicehub.resources.device.models import Device, Manufacturer
|
from ereuse_devicehub.resources.device.models import Device, Manufacturer
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,9 +31,21 @@ class DeviceView(View):
|
||||||
|
|
||||||
def one(self, id: int):
|
def one(self, id: int):
|
||||||
"""Gets one device."""
|
"""Gets one device."""
|
||||||
|
if not request.authorization:
|
||||||
|
return self.one_public(id)
|
||||||
|
else:
|
||||||
|
return self.one_private(id)
|
||||||
|
|
||||||
|
def one_public(self, id: int):
|
||||||
|
device = Device.query.filter_by(id=id).one()
|
||||||
|
return render_template('devices/layout.html', device=device)
|
||||||
|
|
||||||
|
@auth.Auth.requires_auth
|
||||||
|
def one_private(self, id: int):
|
||||||
device = Device.query.filter_by(id=id).one()
|
device = Device.query.filter_by(id=id).one()
|
||||||
return self.schema.jsonify(device)
|
return self.schema.jsonify(device)
|
||||||
|
|
||||||
|
@auth.Auth.requires_auth
|
||||||
def find(self, args: dict):
|
def find(self, args: dict):
|
||||||
"""Gets many devices."""
|
"""Gets many devices."""
|
||||||
return self.schema.jsonify(Device.query, many=True)
|
return self.schema.jsonify(Device.query, many=True)
|
||||||
|
@ -41,6 +57,7 @@ class ManufacturerView(View):
|
||||||
# Disallow like operators
|
# Disallow like operators
|
||||||
validate=lambda x: '%' not in x and '_' not in x)
|
validate=lambda x: '%' not in x and '_' not in x)
|
||||||
|
|
||||||
|
@cache(datetime.timedelta(days=1))
|
||||||
def find(self, args: dict):
|
def find(self, args: dict):
|
||||||
name = args['name']
|
name = args['name']
|
||||||
manufacturers = Manufacturer.query \
|
manufacturers = Manufacturer.query \
|
||||||
|
|
|
@ -166,12 +166,18 @@ class RamInterface(Enum):
|
||||||
DDR5 = 'DDR5 SDRAM'
|
DDR5 = 'DDR5 SDRAM'
|
||||||
DDR6 = 'DDR6 SDRAM'
|
DDR6 = 'DDR6 SDRAM'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
@unique
|
@unique
|
||||||
class RamFormat(Enum):
|
class RamFormat(Enum):
|
||||||
DIMM = 'DIMM'
|
DIMM = 'DIMM'
|
||||||
SODIMM = 'SODIMM'
|
SODIMM = 'SODIMM'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
@unique
|
@unique
|
||||||
class DataStorageInterface(Enum):
|
class DataStorageInterface(Enum):
|
||||||
|
@ -179,6 +185,9 @@ class DataStorageInterface(Enum):
|
||||||
USB = 'USB'
|
USB = 'USB'
|
||||||
PCI = 'PCI'
|
PCI = 'PCI'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
@unique
|
@unique
|
||||||
class DisplayTech(Enum):
|
class DisplayTech(Enum):
|
||||||
|
@ -190,15 +199,18 @@ class DisplayTech(Enum):
|
||||||
OLED = 'Organic light-emitting diode (OLED)'
|
OLED = 'Organic light-emitting diode (OLED)'
|
||||||
AMOLED = 'Organic light-emitting diode (AMOLED)'
|
AMOLED = 'Organic light-emitting diode (AMOLED)'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
@unique
|
@unique
|
||||||
class ComputerChassis(Enum):
|
class ComputerChassis(Enum):
|
||||||
"""The chassis of a computer."""
|
"""The chassis of a computer."""
|
||||||
Tower = 'Tower'
|
Tower = 'Tower'
|
||||||
Docking = 'Docking'
|
Docking = 'Docking'
|
||||||
AllInOne = 'AllInOne'
|
AllInOne = 'All in one'
|
||||||
Microtower = 'Microtower'
|
Microtower = 'Microtower'
|
||||||
PizzaBox = 'PizzaBox'
|
PizzaBox = 'Pizza box'
|
||||||
Lunchbox = 'Lunchbox'
|
Lunchbox = 'Lunchbox'
|
||||||
Stick = 'Stick'
|
Stick = 'Stick'
|
||||||
Netbook = 'Netbook'
|
Netbook = 'Netbook'
|
||||||
|
@ -207,7 +219,10 @@ class ComputerChassis(Enum):
|
||||||
Convertible = 'Convertible'
|
Convertible = 'Convertible'
|
||||||
Detachable = 'Detachable'
|
Detachable = 'Detachable'
|
||||||
Tablet = 'Tablet'
|
Tablet = 'Tablet'
|
||||||
Virtual = 'Virtual: A device with no chassis, probably non-physical.'
|
Virtual = 'Non-physical device'
|
||||||
|
|
||||||
|
def __format__(self, format_spec):
|
||||||
|
return self.value.lower()
|
||||||
|
|
||||||
|
|
||||||
class ReceiverRole(Enum):
|
class ReceiverRole(Enum):
|
||||||
|
|
|
@ -26,7 +26,7 @@ requests==2.19.1
|
||||||
requests-mock==1.5.2
|
requests-mock==1.5.2
|
||||||
SQLAlchemy==1.2.11
|
SQLAlchemy==1.2.11
|
||||||
SQLAlchemy-Utils==0.33.3
|
SQLAlchemy-Utils==0.33.3
|
||||||
teal==0.2.0a20
|
teal==0.2.0a21
|
||||||
webargs==4.0.0
|
webargs==4.0.0
|
||||||
Werkzeug==0.14.1
|
Werkzeug==0.14.1
|
||||||
sqlalchemy-citext==1.3.post0
|
sqlalchemy-citext==1.3.post0
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -34,7 +34,7 @@ setup(
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
long_description_content_type='text/markdown',
|
long_description_content_type='text/markdown',
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'teal>=0.2.0a20', # teal always first
|
'teal>=0.2.0a21', # teal always first
|
||||||
'click',
|
'click',
|
||||||
'click-spinner',
|
'click-spinner',
|
||||||
'ereuse-rate==0.0.2',
|
'ereuse-rate==0.0.2',
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
|
import datetime
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from colour import Color
|
from colour import Color
|
||||||
from ereuse_utils.naming import Naming
|
from ereuse_utils.naming import Naming
|
||||||
|
from ereuse_utils.test import ANY
|
||||||
from pytest import raises
|
from pytest import raises
|
||||||
from sqlalchemy.util import OrderedSet
|
from sqlalchemy.util import OrderedSet
|
||||||
from teal.db import ResourceNotFound
|
from teal.db import ResourceNotFound
|
||||||
|
|
||||||
from ereuse_devicehub.client import UserClient
|
from ereuse_devicehub.client import Client, UserClient
|
||||||
from ereuse_devicehub.db import db
|
from ereuse_devicehub.db import db
|
||||||
from ereuse_devicehub.devicehub import Devicehub
|
from ereuse_devicehub.devicehub import Devicehub
|
||||||
from ereuse_devicehub.resources.agent.models import Person
|
from ereuse_devicehub.resources.agent.models import Person
|
||||||
from ereuse_devicehub.resources.device.exceptions import NeedsId
|
from ereuse_devicehub.resources.device.exceptions import NeedsId
|
||||||
from ereuse_devicehub.resources.device.models import Component, ComputerMonitor, Desktop, Device, \
|
from ereuse_devicehub.resources.device.models import Component, ComputerMonitor, DataStorage, \
|
||||||
GraphicCard, Laptop, Motherboard, NetworkAdapter
|
Desktop, Device, GraphicCard, Laptop, Motherboard, NetworkAdapter
|
||||||
from ereuse_devicehub.resources.device.schemas import Device as DeviceS
|
from ereuse_devicehub.resources.device.schemas import Device as DeviceS
|
||||||
from ereuse_devicehub.resources.device.search import DeviceSearch
|
from ereuse_devicehub.resources.device.search import DeviceSearch
|
||||||
from ereuse_devicehub.resources.device.sync import MismatchBetweenTags, MismatchBetweenTagsAndHid, \
|
from ereuse_devicehub.resources.device.sync import MismatchBetweenTags, MismatchBetweenTagsAndHid, \
|
||||||
|
@ -470,11 +472,42 @@ def test_device_search_all_devices_token_if_empty(app: Devicehub, user: UserClie
|
||||||
|
|
||||||
|
|
||||||
def test_manufacturer(user: UserClient):
|
def test_manufacturer(user: UserClient):
|
||||||
m, _ = user.get(res='Manufacturer', query=[('name', 'asus')])
|
m, r = user.get(res='Manufacturer', query=[('name', 'asus')])
|
||||||
assert m == {'items': [{'name': 'Asus', 'url': 'https://en.wikipedia.org/wiki/Asus'}]}
|
assert m == {'items': [{'name': 'Asus', 'url': 'https://en.wikipedia.org/wiki/Asus'}]}
|
||||||
|
assert r.cache_control.public
|
||||||
|
assert r.expires > datetime.datetime.now()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.xfail(reason='Develop functionality')
|
@pytest.mark.xfail(reason='Develop functionality')
|
||||||
def test_manufacturer_enforced():
|
def test_manufacturer_enforced():
|
||||||
"""Ensures that non-computer devices can submit only
|
"""Ensures that non-computer devices can submit only
|
||||||
manufacturers from the Manufacturer table."""
|
manufacturers from the Manufacturer table."""
|
||||||
|
|
||||||
|
|
||||||
|
def test_device_properties_format(app: Devicehub, user: UserClient):
|
||||||
|
user.post(file('asus-eee-1000h.snapshot.11'), res=m.Snapshot)
|
||||||
|
with app.app_context():
|
||||||
|
pc = Laptop.query.one() # type: Laptop
|
||||||
|
assert format(pc) == 'Laptop 1: model 1000h, S/N 94oaaq021116'
|
||||||
|
assert format(pc, 't') == 'netbook 1000h'
|
||||||
|
assert format(pc, 's') == '(asustek computer inc.) S/N 94oaaq021116'
|
||||||
|
assert pc.ram_size == 1024
|
||||||
|
assert pc.data_storage_size == 152627
|
||||||
|
assert pc.graphic_card_model == 'mobile 945gse express integrated graphics controller'
|
||||||
|
assert pc.processor_model == 'intel atom cpu n270 @ 1.60ghz'
|
||||||
|
net = next(c for c in pc.components if isinstance(c, NetworkAdapter))
|
||||||
|
assert format(net) == 'NetworkAdapter 2: model ar8121/ar8113/ar8114 ' \
|
||||||
|
'gigabit or fast ethernet, S/N 00:24:8c:7f:cf:2d'
|
||||||
|
assert format(net, 't') == 'NetworkAdapter ar8121/ar8113/ar8114 gigabit or fast ethernet'
|
||||||
|
assert format(net, 's') == '(qualcomm atheros) S/N 00:24:8c:7f:cf:2d – 100 Mbps'
|
||||||
|
hdd = next(c for c in pc.components if isinstance(c, DataStorage))
|
||||||
|
assert format(hdd) == 'HardDrive 7: model st9160310as, S/N 5sv4tqa6'
|
||||||
|
assert format(hdd, 't') == 'HardDrive st9160310as'
|
||||||
|
assert format(hdd, 's') == '(seagate) S/N 5sv4tqa6 – 152 GB'
|
||||||
|
|
||||||
|
|
||||||
|
def test_device_public(user: UserClient, client: Client):
|
||||||
|
s, _ = user.post(file('asus-eee-1000h.snapshot.11'), res=m.Snapshot)
|
||||||
|
html, _ = client.get(res=Device, item=s['device']['id'], accept=ANY)
|
||||||
|
assert 'intel atom cpu n270 @ 1.60ghz' in html
|
||||||
|
assert 'S/N 00:24:8c:7f:cf:2d – 100 Mbps' in html
|
||||||
|
|
Reference in New Issue