Add Manufacturer
This commit is contained in:
parent
042b7718ec
commit
38060d47ec
|
@ -23,6 +23,9 @@ an ID and a tag provider. Note though that these virtual tags don't have
|
||||||
to forcefully be printed or have a physical representation
|
to forcefully be printed or have a physical representation
|
||||||
(this is not imposed at system level).
|
(this is not imposed at system level).
|
||||||
|
|
||||||
|
Tags are case insensitive and are converted to lower-case in
|
||||||
|
Devicehub.
|
||||||
|
|
||||||
eTags
|
eTags
|
||||||
*****
|
*****
|
||||||
We recognize a special type of tag, the **eReuse.org tags (eTag)**.
|
We recognize a special type of tag, the **eReuse.org tags (eTag)**.
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
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
|
||||||
from ereuse_devicehub.resources.device.views import DeviceView
|
from ereuse_devicehub.resources.device.models import Manufacturer
|
||||||
|
from ereuse_devicehub.resources.device.views import DeviceView, ManufacturerView
|
||||||
|
|
||||||
|
|
||||||
class DeviceDef(Resource):
|
class DeviceDef(Resource):
|
||||||
|
@ -119,3 +120,13 @@ class SoundCardDef(ComponentDef):
|
||||||
class DisplayDef(ComponentDef):
|
class DisplayDef(ComponentDef):
|
||||||
VIEW = None
|
VIEW = None
|
||||||
SCHEMA = schemas.Display
|
SCHEMA = schemas.Display
|
||||||
|
|
||||||
|
|
||||||
|
class ManufacturerDef(Resource):
|
||||||
|
VIEW = ManufacturerView
|
||||||
|
SCHEMA = schemas.Manufacturer
|
||||||
|
AUTH = True
|
||||||
|
|
||||||
|
def init_db(self, db: 'db.SQLAlchemy'):
|
||||||
|
"""Loads the manufacturers to the database."""
|
||||||
|
Manufacturer.add_all_to_session(db.session)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +1,12 @@
|
||||||
|
import json
|
||||||
|
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, Set
|
||||||
|
|
||||||
|
from boltons import urlutils
|
||||||
|
from citext import CIText
|
||||||
from ereuse_utils.naming import Naming
|
from ereuse_utils.naming import Naming
|
||||||
from sqlalchemy import BigInteger, Boolean, Column, Enum as DBEnum, Float, ForeignKey, Integer, \
|
from sqlalchemy import BigInteger, Boolean, Column, Enum as DBEnum, Float, ForeignKey, Integer, \
|
||||||
Sequence, SmallInteger, Unicode, inspect
|
Sequence, SmallInteger, Unicode, inspect
|
||||||
|
@ -11,10 +15,11 @@ from sqlalchemy.orm import ColumnProperty, backref, relationship, validates
|
||||||
from sqlalchemy.util import OrderedSet
|
from sqlalchemy.util import OrderedSet
|
||||||
from sqlalchemy_utils import ColorType
|
from sqlalchemy_utils import ColorType
|
||||||
from stdnum import imei, meid
|
from stdnum import imei, meid
|
||||||
from teal.db import CASCADE, POLYMORPHIC_ID, POLYMORPHIC_ON, ResourceNotFound, check_lower, \
|
from teal.db import CASCADE, POLYMORPHIC_ID, POLYMORPHIC_ON, ResourceNotFound, URL, check_lower, \
|
||||||
check_range
|
check_range
|
||||||
from teal.marshmallow import ValidationError
|
from teal.marshmallow import ValidationError
|
||||||
|
|
||||||
|
from ereuse_devicehub.db import db
|
||||||
from ereuse_devicehub.resources.enums import ComputerChassis, DataStorageInterface, DisplayTech, \
|
from ereuse_devicehub.resources.enums import ComputerChassis, DataStorageInterface, DisplayTech, \
|
||||||
RamFormat, RamInterface
|
RamFormat, RamInterface
|
||||||
from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing
|
from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing
|
||||||
|
@ -316,3 +321,25 @@ class Display(JoinedComponentTableMixin, DisplayMixin, Component):
|
||||||
and Television Set.
|
and Television Set.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Manufacturer(db.Model):
|
||||||
|
__table_args__ = {'schema': 'common'}
|
||||||
|
CUSTOM_MANUFACTURERS = {'Belinea', 'OKI Data Corporation', 'Vivitek', 'Yuraku'}
|
||||||
|
"""A list of manufacturer names that are not from Wikipedia's JSON."""
|
||||||
|
|
||||||
|
name = db.Column(CIText(), primary_key=True)
|
||||||
|
url = db.Column(URL(), unique=True)
|
||||||
|
logo = db.Column(URL())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def add_all_to_session(cls, session):
|
||||||
|
"""Adds all manufacturers to session."""
|
||||||
|
with pathlib.Path(__file__).parent.joinpath('manufacturers.json').open() as f:
|
||||||
|
for m in json.load(f):
|
||||||
|
man = cls(name=m['name'],
|
||||||
|
url=urlutils.URL(m['url']),
|
||||||
|
logo=urlutils.URL(m['logo']) if m.get('logo', None) else None)
|
||||||
|
session.add(man)
|
||||||
|
for name in cls.CUSTOM_MANUFACTURERS:
|
||||||
|
session.add(cls(name=name))
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
from typing import Dict, List, Set
|
from typing import Dict, List, Set
|
||||||
|
|
||||||
|
from boltons.urlutils import URL
|
||||||
from colour import Color
|
from colour import Color
|
||||||
from sqlalchemy import Column, Integer
|
from sqlalchemy import Column, Integer
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
from teal.db import Model
|
||||||
|
|
||||||
from ereuse_devicehub.resources.enums import ComputerChassis, DataStorageInterface, DisplayTech, \
|
from ereuse_devicehub.resources.enums import ComputerChassis, DataStorageInterface, DisplayTech, \
|
||||||
RamFormat, RamInterface
|
RamFormat, RamInterface
|
||||||
|
@ -210,3 +212,20 @@ class RamModule(Component):
|
||||||
|
|
||||||
class Display(DisplayMixin, Component):
|
class Display(DisplayMixin, Component):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Manufacturer(Model):
|
||||||
|
CUSTOM_MANUFACTURERS = ... # type: set
|
||||||
|
name = ... # type: Column
|
||||||
|
url = ... # type: Column
|
||||||
|
logo = ... # type: Column
|
||||||
|
|
||||||
|
def __init__(self, **kwargs) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.name = ... # type: str
|
||||||
|
self.url = ... # type: URL
|
||||||
|
self.logo = ... # type: URL
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def add_all_to_session(cls, session):
|
||||||
|
pass
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
from marshmallow import post_load, pre_load
|
from marshmallow import post_load, pre_load
|
||||||
from marshmallow.fields import Boolean, Float, Integer, Str
|
from marshmallow.fields import Boolean, Float, Integer, Str, String
|
||||||
from marshmallow.validate import Length, OneOf, Range
|
from marshmallow.validate import Length, OneOf, Range
|
||||||
from sqlalchemy.util import OrderedSet
|
from sqlalchemy.util import OrderedSet
|
||||||
from stdnum import imei, meid
|
from stdnum import imei, meid
|
||||||
from teal.marshmallow import EnumField, SanitizedStr, ValidationError
|
from teal.marshmallow import EnumField, SanitizedStr, URL, ValidationError
|
||||||
|
from teal.resource import Schema
|
||||||
|
|
||||||
from ereuse_devicehub.marshmallow import NestedOn
|
from ereuse_devicehub.marshmallow import NestedOn
|
||||||
from ereuse_devicehub.resources.device import models as m
|
from ereuse_devicehub.resources.device import models as m
|
||||||
|
@ -183,3 +184,9 @@ class SoundCard(Component):
|
||||||
|
|
||||||
class Display(DisplayMixin, Component):
|
class Display(DisplayMixin, Component):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Manufacturer(Schema):
|
||||||
|
name = String(dump_only=True)
|
||||||
|
url = URL(dump_only=True)
|
||||||
|
logo = URL(dump_only=True)
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
|
import marshmallow
|
||||||
|
from flask import current_app as app
|
||||||
|
from flask.json import jsonify
|
||||||
|
from flask_sqlalchemy import Pagination
|
||||||
from teal.resource import View
|
from teal.resource import View
|
||||||
|
|
||||||
from ereuse_devicehub.resources.device.models import Device
|
from ereuse_devicehub.resources.device.models import Device, Manufacturer
|
||||||
|
|
||||||
|
|
||||||
class DeviceView(View):
|
class DeviceView(View):
|
||||||
|
@ -29,3 +33,23 @@ class DeviceView(View):
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
|
class ManufacturerView(View):
|
||||||
|
class FindArgs(marshmallow.Schema):
|
||||||
|
name = marshmallow.fields.Str(required=True,
|
||||||
|
# Disallow like operators
|
||||||
|
validate=lambda x: '%' not in x and '_' not in x)
|
||||||
|
|
||||||
|
def find(self, args: dict):
|
||||||
|
name = args['name']
|
||||||
|
manufacturers = Manufacturer.query \
|
||||||
|
.filter(Manufacturer.name.ilike(name + '%')) \
|
||||||
|
.paginate(page=1, per_page=6) # type: Pagination
|
||||||
|
return jsonify(
|
||||||
|
items=app.resources[Manufacturer.t].schema.dump(
|
||||||
|
manufacturers.items,
|
||||||
|
many=True,
|
||||||
|
nested=1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
|
@ -26,6 +26,7 @@ def test_api_docs(client: Client):
|
||||||
'/users/login',
|
'/users/login',
|
||||||
'/events/',
|
'/events/',
|
||||||
'/lots/',
|
'/lots/',
|
||||||
|
'/manufacturers/',
|
||||||
'/lots/{id}/children',
|
'/lots/{id}/children',
|
||||||
'/lots/{id}/devices',
|
'/lots/{id}/devices',
|
||||||
'/tags/{tag_id}/device/{device_id}'
|
'/tags/{tag_id}/device/{device_id}'
|
||||||
|
@ -39,4 +40,4 @@ def test_api_docs(client: Client):
|
||||||
'scheme': 'basic',
|
'scheme': 'basic',
|
||||||
'name': 'Authorization'
|
'name': 'Authorization'
|
||||||
}
|
}
|
||||||
assert 77 == len(docs['definitions'])
|
assert 78 == len(docs['definitions'])
|
||||||
|
|
|
@ -467,3 +467,14 @@ def test_device_search_all_devices_token_if_empty(app: Devicehub, user: UserClie
|
||||||
DeviceSearch.set_all_devices_tokens_if_empty(app.db.session)
|
DeviceSearch.set_all_devices_tokens_if_empty(app.db.session)
|
||||||
i, _ = user.get(res=Inventory, query=[('search', 'Desktop')])
|
i, _ = user.get(res=Inventory, query=[('search', 'Desktop')])
|
||||||
assert not len(i['devices'])
|
assert not len(i['devices'])
|
||||||
|
|
||||||
|
|
||||||
|
def test_manufacturer(user: UserClient):
|
||||||
|
m, _ = user.get(res='Manufacturer', query=[('name', 'asus')])
|
||||||
|
assert m == {'items': [{'name': 'Asus', 'url': 'https://en.wikipedia.org/wiki/Asus'}]}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xfail(reason='Develop functionality')
|
||||||
|
def test_manufacturer_enforced():
|
||||||
|
"""Ensures that non-computer devices can submit only
|
||||||
|
manufacturers from the Manufacturer table."""
|
||||||
|
|
Reference in New Issue