Add inventories

This commit is contained in:
Xavier Bustamante Talavera 2019-01-21 16:08:55 +01:00
parent f0f1376b7d
commit 9272674760
11 changed files with 50 additions and 13 deletions

View file

@ -64,10 +64,15 @@ class DevicehubConfig(Config):
TAG_TOKEN = None
"""Access to the tag provider."""
def __init__(self, db: str = None) -> None:
def __init__(self, schema: str = None, token=None) -> None:
if not self.ORGANIZATION_NAME or not self.ORGANIZATION_TAX_ID:
raise ValueError('You need to set the main organization parameters.')
if not self.TAG_BASE_URL or not self.TAG_TOKEN:
if not self.TAG_BASE_URL:
raise ValueError('You need a tag service.')
self.TAG_TOKEN = token or self.TAG_TOKEN
if not self.TAG_TOKEN:
raise ValueError('You need a tag token')
self.TAG_BASE_URL = boltons.urlutils.URL(self.TAG_BASE_URL)
super().__init__(db)
if schema:
self.SCHEMA = schema
super().__init__()

View file

@ -1,3 +1,4 @@
import citext
from sqlalchemy import event
from sqlalchemy.dialects import postgresql
from sqlalchemy.sql import expression
@ -11,7 +12,10 @@ class SQLAlchemy(SchemaSQLAlchemy):
schema of the database, as it is in the `search_path`
defined in teal.
"""
# todo add here all types of columns used so we don't have to
# manually import them all the time
UUID = postgresql.UUID
CIText = citext.CIText
def drop_all(self, bind='__all__', app=None):
"""A faster nuke-like option to drop everything."""
@ -37,6 +41,6 @@ def create_view(name, selectable):
return table
db = SQLAlchemy(session_options={"autoflush": False})
db = SQLAlchemy(session_options={'autoflush': False})
f = db.func
exp = expression

View file

@ -44,9 +44,11 @@ class Devicehub(Teal):
# todo can I make it with a global Session only?
event.listen(db.session, 'before_commit', DeviceSearch.update_modified_devices)
def _init_db(self):
super()._init_db()
def _init_db(self, exclude_schema=None, check=False):
created = super()._init_db(exclude_schema, check)
if created:
DeviceSearch.set_all_devices_tokens_if_empty(self.db.session)
return created
def regenerate_search(self):
"""Re-creates from 0 all the search tables."""

View file

@ -46,7 +46,7 @@ class OrganizationDef(AgentDef):
print(json.dumps(o, indent=2))
return o
def init_db(self, db: SQLAlchemy):
def init_db(self, db: SQLAlchemy, exclude_schema=None):
"""Creates the default organization."""
org = models.Organization(**app.config.get_namespace('ORGANIZATION_'))
db.session.add(org)

View file

@ -297,6 +297,7 @@ class ManufacturerDef(Resource):
SCHEMA = schemas.Manufacturer
AUTH = True
def init_db(self, db: 'db.SQLAlchemy'):
def init_db(self, db: 'db.SQLAlchemy', exclude_schema=None):
"""Loads the manufacturers to the database."""
if exclude_schema != 'common':
Manufacturer.add_all_to_session(db.session)

View file

@ -0,0 +1,12 @@
from ereuse_devicehub.db import db
from ereuse_devicehub.resources.models import Thing
class Inventory(Thing):
__table_args__ = {'schema': 'common'}
id = db.Column(db.Unicode(), primary_key=True)
id.comment = """The name of the inventory as in the URL and schema."""
name = db.Column(db.CIText(), nullable=False, unique=True)
name.comment = """The human name of the inventory."""
tag_token = db.Column(db.UUID(as_uuid=True), unique=True)
tag_token.comment = """The token to access a Tag service."""

View file

@ -34,7 +34,7 @@ class LotDef(Resource):
view_func=lot_device,
methods={'POST', 'DELETE'})
def init_db(self, db: 'db.SQLAlchemy'):
def init_db(self, db: 'db.SQLAlchemy', exclude_schema=None):
# Create functions
with pathlib.Path(__file__).parent.joinpath('dag.sql').open() as f:
sql = f.read()

View file

@ -5,6 +5,8 @@ from sqlalchemy import Column
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy_utils import EmailType, PasswordType
from ereuse_devicehub.db import db
from ereuse_devicehub.resources.inventory.model import Inventory
from ereuse_devicehub.resources.models import STR_SIZE, Thing
@ -23,6 +25,10 @@ class User(Thing):
data_types.html#module-sqlalchemy_utils.types.password>`_
"""
token = Column(UUID(as_uuid=True), default=uuid4, unique=True)
inventories = db.relationship(Inventory,
backref=db.backref('users', lazy=True, collection_class=set),
secondary=lambda: UserInventory.__table__,
collection_class=set)
def __repr__(self) -> str:
return '<User {0.email}>'.format(self)
@ -31,3 +37,10 @@ class User(Thing):
def individual(self):
"""The individual associated for this database, or None."""
return next(iter(self.individuals), None)
class UserInventory(db.Model):
"""Relationship between users and their inventories."""
__table_args__ = {'schema': 'common'}
user_id = db.Column(db.UUID(as_uuid=True), db.ForeignKey(User.id), primary_key=True)
inventory_id = db.Column(db.Unicode(), db.ForeignKey(Inventory.id), primary_key=True)

View file

@ -25,7 +25,7 @@ requests==2.19.1
requests-mock==1.5.2
SQLAlchemy==1.2.14
SQLAlchemy-Utils==0.33.6
teal==0.2.0a32
teal==0.2.0a33
webargs==4.0.0
Werkzeug==0.14.1
sqlalchemy-citext==1.3.post0

View file

@ -29,7 +29,7 @@ setup(
long_description=long_description,
long_description_content_type='text/markdown',
install_requires=[
'teal>=0.2.0a32', # teal always first
'teal>=0.2.0a33', # teal always first
'click',
'click-spinner',
'ereuse-utils[Naming]>=0.4b14',