Merge branch 'testing' into feature/endpoints
This commit is contained in:
commit
3e653ee190
|
@ -9,8 +9,8 @@ import ereuse_utils.cli
|
|||
from ereuse_utils.session import DevicehubClient
|
||||
from flask.globals import _app_ctx_stack, g
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from teal.teal import Teal
|
||||
from teal.db import SchemaSQLAlchemy
|
||||
from teal.teal import Teal
|
||||
|
||||
from ereuse_devicehub.auth import Auth
|
||||
from ereuse_devicehub.client import Client, UserClient
|
||||
|
@ -19,7 +19,6 @@ from ereuse_devicehub.db import db
|
|||
from ereuse_devicehub.dummy.dummy import Dummy
|
||||
from ereuse_devicehub.resources.device.search import DeviceSearch
|
||||
from ereuse_devicehub.resources.inventory import Inventory, InventoryDef
|
||||
from ereuse_devicehub.resources.user import User
|
||||
from ereuse_devicehub.templating import Environment
|
||||
|
||||
|
||||
|
@ -117,7 +116,6 @@ class Devicehub(Teal):
|
|||
self.db.session.commit()
|
||||
print('done.')
|
||||
|
||||
|
||||
def _init_db(self, exclude_schema=None) -> bool:
|
||||
if exclude_schema:
|
||||
assert isinstance(self.db, SchemaSQLAlchemy)
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
from __future__ import with_statement
|
||||
|
||||
import os
|
||||
from logging.config import fileConfig
|
||||
|
||||
from sqlalchemy import engine_from_config
|
||||
from sqlalchemy import pool
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from alembic import context
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
from ereuse_devicehub.config import DevicehubConfig
|
||||
|
||||
|
@ -24,10 +20,11 @@ fileConfig(config.config_file_name)
|
|||
# from myapp import mymodel
|
||||
# target_metadata = mymodel.Base.metadata
|
||||
# target_metadata = None
|
||||
from ereuse_devicehub.db import db
|
||||
from ereuse_devicehub.resources.models import Thing
|
||||
|
||||
target_metadata = Thing.metadata
|
||||
|
||||
|
||||
# other values from the config, defined by the needs of env.py,
|
||||
# can be acquired:
|
||||
# my_important_option = config.get_main_option("my_important_option")
|
||||
|
|
|
@ -5,14 +5,10 @@ Revises: 151253ac5c55
|
|||
Create Date: 2020-06-30 17:41:28.611314
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
from alembic import context
|
||||
import sqlalchemy as sa
|
||||
import sqlalchemy_utils
|
||||
from alembic import context
|
||||
from alembic import op
|
||||
from sqlalchemy.dialects import postgresql
|
||||
import citext
|
||||
import teal
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'b9b0ee7d9dca'
|
||||
|
@ -27,6 +23,7 @@ def get_inv():
|
|||
raise ValueError("Inventory value is not specified")
|
||||
return INV
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column('tag', sa.Column('owner_id', postgresql.UUID(), nullable=True), schema=f'{get_inv()}')
|
||||
op.create_foreign_key("fk_tag_owner_id_user_id",
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -552,5 +552,6 @@ class MigrateTo(Migrate):
|
|||
class MigrateFrom(Migrate):
|
||||
pass
|
||||
|
||||
|
||||
class Transferred(ActionWithMultipleDevices):
|
||||
pass
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
from typing import Iterable
|
||||
|
||||
import math
|
||||
from typing import Iterable
|
||||
|
||||
from ereuse_devicehub.resources.device.models import Device
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ from itertools import groupby
|
|||
from typing import Dict, Iterable, Tuple
|
||||
|
||||
from ereuse_devicehub.resources.action.models import BenchmarkDataStorage, BenchmarkProcessor, \
|
||||
BenchmarkProcessorSysbench, RateComputer, VisualTest
|
||||
BenchmarkProcessorSysbench, RateComputer
|
||||
from ereuse_devicehub.resources.action.rate.rate import BaseRate
|
||||
from ereuse_devicehub.resources.device.models import Computer, DataStorage, Processor, \
|
||||
RamModule
|
||||
|
|
|
@ -457,5 +457,3 @@ class MigrateFrom(Migrate):
|
|||
|
||||
class Transferred(ActionWithMultipleDevices):
|
||||
__doc__ = m.Transferred.__doc__
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ from distutils.version import StrictVersion
|
|||
from typing import List
|
||||
from uuid import UUID
|
||||
|
||||
from flask import current_app as app, request
|
||||
from flask import current_app as app, request, g
|
||||
from sqlalchemy.util import OrderedSet
|
||||
from teal.marshmallow import ValidationError
|
||||
from teal.resource import View
|
||||
|
@ -13,6 +13,7 @@ from ereuse_devicehub.resources.action.models import Action, RateComputer, Snaps
|
|||
from ereuse_devicehub.resources.action.rate.v1_0 import CannotRate
|
||||
from ereuse_devicehub.resources.device.models import Component, Computer
|
||||
from ereuse_devicehub.resources.enums import SnapshotSoftware, Severity
|
||||
from ereuse_devicehub.resources.user.exceptions import InsufficientPermission
|
||||
|
||||
SUPPORTED_WORKBENCH = StrictVersion('11.0')
|
||||
|
||||
|
@ -56,6 +57,7 @@ class ActionView(View):
|
|||
# Note that if we set the device / components into the snapshot
|
||||
# model object, when we flush them to the db we will flush
|
||||
# snapshot, and we want to wait to flush snapshot at the end
|
||||
|
||||
device = snapshot_json.pop('device') # type: Computer
|
||||
components = None
|
||||
if snapshot_json['software'] == (SnapshotSoftware.Workbench or SnapshotSoftware.WorkbenchAndroid):
|
||||
|
@ -73,6 +75,7 @@ class ActionView(View):
|
|||
assert not device.actions_one
|
||||
assert all(not c.actions_one for c in components) if components else True
|
||||
db_device, remove_actions = resource_def.sync.run(device, components)
|
||||
|
||||
del device # Do not use device anymore
|
||||
snapshot.device = db_device
|
||||
snapshot.actions |= remove_actions | actions_device # Set actions to snapshot
|
||||
|
@ -87,8 +90,11 @@ class ActionView(View):
|
|||
component.actions_one |= actions
|
||||
snapshot.actions |= actions
|
||||
|
||||
# Compute ratings
|
||||
if snapshot.software == SnapshotSoftware.Workbench:
|
||||
# Check ownership of (non-component) device to from current.user
|
||||
if db_device.owner_id != g.user.id:
|
||||
raise InsufficientPermission()
|
||||
# Compute ratings
|
||||
try:
|
||||
rate_computer, price = RateComputer.compute(db_device)
|
||||
except CannotRate:
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import pathlib
|
||||
from typing import Callable, Iterable, Tuple
|
||||
|
||||
from teal.resource import Converters, Resource
|
||||
|
||||
from ereuse_devicehub.db import db
|
||||
from ereuse_devicehub.resources.deliverynote import schemas
|
||||
from ereuse_devicehub.resources.deliverynote.views import DeliverynoteView
|
||||
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Iterable
|
||||
|
||||
from boltons import urlutils
|
||||
from citext import CIText
|
||||
from flask import g
|
||||
from typing import Iterable
|
||||
from sqlalchemy.types import ARRAY
|
||||
from sqlalchemy.dialects.postgresql import UUID, JSONB
|
||||
from teal.db import CASCADE_OWN, check_range, IntEnum
|
||||
from teal.db import check_range, IntEnum
|
||||
from teal.resource import url_for_resource
|
||||
|
||||
from ereuse_devicehub.db import db, f
|
||||
from ereuse_devicehub.db import db
|
||||
from ereuse_devicehub.resources.enums import TransferState
|
||||
from ereuse_devicehub.resources.lot.models import Lot
|
||||
from ereuse_devicehub.resources.models import Thing
|
||||
from ereuse_devicehub.resources.user.models import User
|
||||
from ereuse_devicehub.resources.lot.models import Lot
|
||||
from ereuse_devicehub.resources.enums import TransferState
|
||||
|
||||
|
||||
class Deliverynote(Thing):
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
from marshmallow import fields as f
|
||||
from teal.marshmallow import SanitizedStr, URL, EnumField
|
||||
from teal.marshmallow import SanitizedStr, EnumField
|
||||
|
||||
from ereuse_devicehub.marshmallow import NestedOn
|
||||
from ereuse_devicehub.resources.deliverynote import models as m
|
||||
from ereuse_devicehub.resources.user import schemas as s_user
|
||||
from ereuse_devicehub.resources.device import schemas as s_device
|
||||
from ereuse_devicehub.resources.enums import TransferState
|
||||
from ereuse_devicehub.resources.models import STR_SIZE
|
||||
from ereuse_devicehub.resources.schemas import Thing
|
||||
from ereuse_devicehub.resources.enums import TransferState
|
||||
from ereuse_devicehub.resources.user import schemas as s_user
|
||||
|
||||
|
||||
class Deliverynote(Thing):
|
||||
|
|
|
@ -1,22 +1,12 @@
|
|||
import datetime
|
||||
import uuid
|
||||
from collections import deque
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Set, Union
|
||||
|
||||
import marshmallow as ma
|
||||
import teal.cache
|
||||
from flask import Response, jsonify, request
|
||||
from marshmallow import Schema as MarshmallowSchema, fields as f
|
||||
from teal.marshmallow import EnumField
|
||||
from flask import Response, request
|
||||
from teal.resource import View
|
||||
from sqlalchemy.orm import joinedload
|
||||
|
||||
from ereuse_devicehub.db import db
|
||||
from ereuse_devicehub.query import things_response
|
||||
from ereuse_devicehub.resources.deliverynote.models import Deliverynote
|
||||
from ereuse_devicehub.resources.lot.models import Lot
|
||||
from ereuse_devicehub.resources.device.models import Computer
|
||||
|
||||
|
||||
class DeliverynoteView(View):
|
||||
|
|
|
@ -7,17 +7,17 @@ from typing import Dict, List, Set
|
|||
|
||||
from boltons import urlutils
|
||||
from citext import CIText
|
||||
from flask import g
|
||||
from ereuse_utils.naming import HID_CONVERSION_DOC, Naming
|
||||
from flask import g
|
||||
from more_itertools import unique_everseen
|
||||
from sqlalchemy import BigInteger, Boolean, Column, Enum as DBEnum, Float, ForeignKey, Integer, \
|
||||
Sequence, SmallInteger, Unicode, inspect, text
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.ext.declarative import declared_attr
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
from sqlalchemy.orm import ColumnProperty, backref, relationship, validates
|
||||
from sqlalchemy.util import OrderedSet
|
||||
from sqlalchemy_utils import ColorType
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from stdnum import imei, meid
|
||||
from teal.db import CASCADE_DEL, POLYMORPHIC_ID, POLYMORPHIC_ON, ResourceNotFound, URL, \
|
||||
check_lower, check_range, IntEnum
|
||||
|
|
|
@ -14,7 +14,6 @@ from ereuse_devicehub.resources import enums
|
|||
from ereuse_devicehub.resources.device import models as m, states
|
||||
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE
|
||||
from ereuse_devicehub.resources.schemas import Thing, UnitCodes
|
||||
from ereuse_devicehub.resources.user import schemas as s_user
|
||||
|
||||
|
||||
class Device(Thing):
|
||||
|
|
|
@ -3,11 +3,10 @@ import uuid
|
|||
from itertools import filterfalse
|
||||
|
||||
import marshmallow
|
||||
from flask import current_app as app, render_template, request, Response
|
||||
from flask import g, current_app as app, render_template, request, Response
|
||||
from flask.json import jsonify
|
||||
from flask_sqlalchemy import Pagination
|
||||
from marshmallow import fields, fields as f, validate as v, ValidationError, \
|
||||
Schema as MarshmallowSchema
|
||||
from marshmallow import fields, fields as f, validate as v, Schema as MarshmallowSchema
|
||||
from teal import query
|
||||
from teal.cache import cache
|
||||
from teal.resource import View
|
||||
|
@ -20,9 +19,9 @@ from ereuse_devicehub.resources.action import models as actions
|
|||
from ereuse_devicehub.resources.device import states
|
||||
from ereuse_devicehub.resources.device.models import Device, Manufacturer, Computer
|
||||
from ereuse_devicehub.resources.device.search import DeviceSearch
|
||||
from ereuse_devicehub.resources.enums import SnapshotSoftware
|
||||
from ereuse_devicehub.resources.lot.models import LotDeviceDescendants
|
||||
from ereuse_devicehub.resources.tag.model import Tag
|
||||
from ereuse_devicehub.resources.enums import SnapshotSoftware
|
||||
|
||||
|
||||
class OfType(f.Str):
|
||||
|
@ -64,7 +63,8 @@ class Filters(query.Query):
|
|||
# todo This part of the query is really slow
|
||||
# And forces usage of distinct, as it returns many rows
|
||||
# due to having multiple paths to the same
|
||||
lot = query.Join(Device.id == LotDeviceDescendants.device_id, LotQ)
|
||||
lot = query.Join((Device.id == LotDeviceDescendants.device_id),
|
||||
LotQ)
|
||||
|
||||
|
||||
class Sorting(query.Sort):
|
||||
|
@ -102,7 +102,8 @@ class DeviceView(View):
|
|||
if isinstance(dev, Computer):
|
||||
resource_def = app.resources['Computer']
|
||||
# TODO check how to handle the 'actions_one'
|
||||
patch_schema = resource_def.SCHEMA(only=['ethereum_address', 'transfer_state', 'deliverynote_address', 'actions_one'], partial=True)
|
||||
patch_schema = resource_def.SCHEMA(
|
||||
only=['ethereum_address', 'transfer_state', 'deliverynote_address', 'actions_one'], partial=True)
|
||||
json = request.get_json(schema=patch_schema)
|
||||
# TODO check how to handle the 'actions_one'
|
||||
json.pop('actions_one')
|
||||
|
@ -153,14 +154,23 @@ class DeviceView(View):
|
|||
).order_by(
|
||||
search.Search.rank(properties, search_p) + search.Search.rank(tags, search_p)
|
||||
)
|
||||
query = self.visibility_filter(query)
|
||||
return query.filter(*args['filter']).order_by(*args['sort'])
|
||||
|
||||
def visibility_filter(self, query):
|
||||
filterqs = request.args.get('filter', None)
|
||||
if (filterqs and
|
||||
'lot' not in filterqs):
|
||||
query = query.filter((Computer.id == Device.id), (Computer.owner_id == g.user.id))
|
||||
pass
|
||||
return query
|
||||
|
||||
|
||||
class DeviceMergeView(View):
|
||||
|
||||
"""View for merging two devices
|
||||
Ex. ``device/<id>/merge/id=X``.
|
||||
"""
|
||||
|
||||
class FindArgs(MarshmallowSchema):
|
||||
id = fields.Integer()
|
||||
|
||||
|
@ -187,10 +197,13 @@ class DeviceMergeView(View):
|
|||
This operation is highly costly as it forces refreshing
|
||||
many models in session.
|
||||
"""
|
||||
snapshots = sorted(filterfalse(lambda x: not isinstance(x, actions.Snapshot), (base_device.actions + with_device.actions)))
|
||||
workbench_snapshots = [ s for s in snapshots if s.software == (SnapshotSoftware.Workbench or SnapshotSoftware.WorkbenchAndroid)]
|
||||
snapshots = sorted(
|
||||
filterfalse(lambda x: not isinstance(x, actions.Snapshot), (base_device.actions + with_device.actions)))
|
||||
workbench_snapshots = [s for s in snapshots if
|
||||
s.software == (SnapshotSoftware.Workbench or SnapshotSoftware.WorkbenchAndroid)]
|
||||
latest_snapshot_device = [d for d in (base_device, with_device) if d.id == snapshots[-1].device.id][0]
|
||||
latest_snapshotworkbench_device = [ d for d in (base_device, with_device) if d.id == workbench_snapshots[-1].device.id][0]
|
||||
latest_snapshotworkbench_device = \
|
||||
[d for d in (base_device, with_device) if d.id == workbench_snapshots[-1].device.id][0]
|
||||
# Adding actions of with_device
|
||||
with_actions_one = [a for a in with_device.actions if isinstance(a, actions.ActionWithOneDevice)]
|
||||
with_actions_multiple = [a for a in with_device.actions if isinstance(a, actions.ActionWithMultipleDevices)]
|
||||
|
|
|
@ -30,27 +30,23 @@ class DeviceRow(OrderedDict):
|
|||
self['Tag 1'] = self['Tag 2'] = self['Tag 3'] = ''
|
||||
for i, tag in zip(range(1, 3), device.tags):
|
||||
self['Tag {}'.format(i)] = format(tag)
|
||||
self['Serial Number'] = device.serial_number
|
||||
self['Model'] = device.model
|
||||
self['Manufacturer'] = device.manufacturer
|
||||
# self['State'] = device.last_action_of()
|
||||
self['Serial Number'] = convert_none_to_empty_str(device.serial_number)
|
||||
self['Model'] = convert_none_to_empty_str(device.model)
|
||||
self['Manufacturer'] = convert_none_to_empty_str(device.manufacturer)
|
||||
self['Registered in'] = format(device.created, '%c')
|
||||
try:
|
||||
self['Physical state'] = device.last_action_of(*states.Physical.actions()).t
|
||||
except:
|
||||
except LookupError:
|
||||
self['Physical state'] = ''
|
||||
try:
|
||||
self['Trading state'] = device.last_action_of(*states.Trading.actions()).t
|
||||
except:
|
||||
except LookupError:
|
||||
self['Trading state'] = ''
|
||||
try:
|
||||
self['Price'] = device.price
|
||||
except:
|
||||
self['Price'] = ''
|
||||
self['Price'] = convert_none_to_empty_str(device.price)
|
||||
if isinstance(device, d.Computer):
|
||||
self['Processor'] = device.processor_model
|
||||
self['RAM (MB)'] = device.ram_size
|
||||
self['Data Storage Size (MB)'] = device.data_storage_size
|
||||
self['Processor'] = convert_none_to_empty_str(device.processor_model)
|
||||
self['RAM (MB)'] = convert_none_to_empty_str(device.ram_size)
|
||||
self['Data Storage Size (MB)'] = convert_none_to_empty_str(device.data_storage_size)
|
||||
rate = device.rate
|
||||
if rate:
|
||||
self['Rate'] = rate.rating
|
||||
|
@ -137,35 +133,27 @@ class StockRow(OrderedDict):
|
|||
def __init__(self, device: d.Device) -> None:
|
||||
super().__init__()
|
||||
self.device = device
|
||||
self['Type'] = device.t
|
||||
self['Type'] = convert_none_to_empty_str(device.t)
|
||||
if isinstance(device, d.Computer):
|
||||
self['Chassis'] = device.chassis
|
||||
else:
|
||||
self['Chassis'] = ''
|
||||
self['Serial Number'] = device.serial_number
|
||||
self['Model'] = device.model
|
||||
self['Manufacturer'] = device.manufacturer
|
||||
self['Serial Number'] = convert_none_to_empty_str(device.serial_number)
|
||||
self['Model'] = convert_none_to_empty_str(device.model)
|
||||
self['Manufacturer'] = convert_none_to_empty_str(device.manufacturer)
|
||||
self['Registered in'] = format(device.created, '%c')
|
||||
try:
|
||||
self['Physical state'] = device.last_action_of(*states.Physical.actions()).t
|
||||
except:
|
||||
except LookupError:
|
||||
self['Physical state'] = ''
|
||||
try:
|
||||
self['Trading state'] = device.last_action_of(*states.Trading.actions()).t
|
||||
except:
|
||||
except LookupError:
|
||||
self['Trading state'] = ''
|
||||
try:
|
||||
self['Price'] = device.price
|
||||
except:
|
||||
self['Price'] = ''
|
||||
try:
|
||||
self['Processor'] = device.processor_model
|
||||
self['RAM (MB)'] = device.ram_size
|
||||
self['Data Storage Size (MB)'] = device.data_storage_size
|
||||
except:
|
||||
self['Processor'] = ''
|
||||
self['RAM (MB)'] = ''
|
||||
self['Data Storage Size (MB)'] = ''
|
||||
self['Price'] = convert_none_to_empty_str(device.price)
|
||||
self['Processor'] = convert_none_to_empty_str(device.processor_model)
|
||||
self['RAM (MB)'] = convert_none_to_empty_str(device.ram_size)
|
||||
self['Data Storage Size (MB)'] = convert_none_to_empty_str(device.data_storage_size)
|
||||
rate = device.rate
|
||||
if rate:
|
||||
self['Rate'] = rate.rating
|
||||
|
@ -177,3 +165,9 @@ class StockRow(OrderedDict):
|
|||
self['RAM Range'] = rate.ram_range
|
||||
self['Data Storage Rate'] = rate.data_storage
|
||||
self['Data Storage Range'] = rate.data_storage_range
|
||||
|
||||
|
||||
def convert_none_to_empty_str(s):
|
||||
if s is None:
|
||||
return ''
|
||||
return s
|
||||
|
|
|
@ -18,10 +18,10 @@ from ereuse_devicehub.db import db
|
|||
from ereuse_devicehub.resources.action import models as evs
|
||||
from ereuse_devicehub.resources.device import models as devs
|
||||
from ereuse_devicehub.resources.device.views import DeviceView
|
||||
|
||||
from ereuse_devicehub.resources.documents.device_row import DeviceRow, StockRow
|
||||
|
||||
|
||||
|
||||
class Format(enum.Enum):
|
||||
HTML = 'HTML'
|
||||
PDF = 'PDF'
|
||||
|
@ -107,7 +107,7 @@ class DocumentView(DeviceView):
|
|||
class DevicesDocumentView(DeviceView):
|
||||
@cache(datetime.timedelta(minutes=1))
|
||||
def find(self, args: dict):
|
||||
query = self.query(args)
|
||||
query = (x for x in self.query(args) if x.owner_id == g.user.id)
|
||||
return self.generate_post_csv(query)
|
||||
|
||||
def generate_post_csv(self, query):
|
||||
|
@ -172,19 +172,25 @@ class DocumentDef(Resource):
|
|||
get = {'GET'}
|
||||
|
||||
view = DocumentView.as_view('main', definition=self, auth=app.auth)
|
||||
|
||||
# TODO @cayop This two lines never pass
|
||||
if self.AUTH:
|
||||
view = app.auth.requires_auth(view)
|
||||
|
||||
self.add_url_rule('/erasures/', defaults=d, view_func=view, methods=get)
|
||||
self.add_url_rule('/erasures/<{}:{}>'.format(self.ID_CONVERTER.value, self.ID_NAME),
|
||||
view_func=view, methods=get)
|
||||
|
||||
devices_view = DevicesDocumentView.as_view('devicesDocumentView',
|
||||
definition=self,
|
||||
auth=app.auth)
|
||||
devices_view = app.auth.requires_auth(devices_view)
|
||||
|
||||
stock_view = StockDocumentView.as_view('stockDocumentView', definition=self)
|
||||
stock_view = app.auth.requires_auth(stock_view)
|
||||
|
||||
if self.AUTH:
|
||||
devices_view = app.auth.requires_auth(devices_view)
|
||||
self.add_url_rule('/devices/', defaults=d, view_func=devices_view, methods=get)
|
||||
|
||||
stock_view = StockDocumentView.as_view('stockDocumentView', definition=self, auth=app.auth)
|
||||
stock_view = app.auth.requires_auth(stock_view)
|
||||
self.add_url_rule('/stock/', defaults=d, view_func=stock_view, methods=get)
|
||||
|
|
|
@ -370,6 +370,7 @@ class ErasureStandards(Enum):
|
|||
standards.add(cls.HMG_IS5)
|
||||
return standards
|
||||
|
||||
|
||||
@unique
|
||||
class TransferState(IntEnum):
|
||||
"""State of transfer for a given Lot of devices.
|
||||
|
|
|
@ -5,7 +5,7 @@ from typing import Union
|
|||
from boltons import urlutils
|
||||
from citext import CIText
|
||||
from flask import g
|
||||
from sqlalchemy import TEXT, Enum as DBEnum
|
||||
from sqlalchemy import TEXT
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy_utils import LtreeType
|
||||
from sqlalchemy_utils.types.ltree import LQUERY
|
||||
|
@ -14,9 +14,9 @@ from teal.resource import url_for_resource
|
|||
|
||||
from ereuse_devicehub.db import create_view, db, exp, f
|
||||
from ereuse_devicehub.resources.device.models import Component, Device
|
||||
from ereuse_devicehub.resources.enums import TransferState
|
||||
from ereuse_devicehub.resources.models import Thing
|
||||
from ereuse_devicehub.resources.user.models import User
|
||||
from ereuse_devicehub.resources.enums import TransferState
|
||||
|
||||
|
||||
class Lot(Thing):
|
||||
|
|
|
@ -2,12 +2,12 @@ from marshmallow import fields as f
|
|||
from teal.marshmallow import SanitizedStr, URL, EnumField
|
||||
|
||||
from ereuse_devicehub.marshmallow import NestedOn
|
||||
from ereuse_devicehub.resources.device import schemas as s_device
|
||||
from ereuse_devicehub.resources.lot import models as m
|
||||
from ereuse_devicehub.resources.deliverynote import schemas as s_deliverynote
|
||||
from ereuse_devicehub.resources.device import schemas as s_device
|
||||
from ereuse_devicehub.resources.enums import TransferState
|
||||
from ereuse_devicehub.resources.lot import models as m
|
||||
from ereuse_devicehub.resources.models import STR_SIZE
|
||||
from ereuse_devicehub.resources.schemas import Thing
|
||||
from ereuse_devicehub.resources.enums import TransferState
|
||||
|
||||
|
||||
class Lot(Thing):
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
import datetime
|
||||
import uuid
|
||||
from collections import deque
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Set, Union
|
||||
|
||||
import marshmallow as ma
|
||||
import teal.cache
|
||||
from flask import Response, jsonify, request
|
||||
from flask import Response, jsonify, request, g
|
||||
from marshmallow import Schema as MarshmallowSchema, fields as f
|
||||
from sqlalchemy import or_
|
||||
from teal.marshmallow import EnumField
|
||||
from teal.resource import View
|
||||
from sqlalchemy.orm import joinedload
|
||||
|
||||
from ereuse_devicehub.db import db
|
||||
from ereuse_devicehub.query import things_response
|
||||
from ereuse_devicehub.resources.deliverynote.models import Deliverynote
|
||||
from ereuse_devicehub.resources.device.models import Device, Computer
|
||||
from ereuse_devicehub.resources.lot.models import Lot, Path
|
||||
|
||||
|
@ -41,7 +40,9 @@ class LotView(View):
|
|||
return ret
|
||||
|
||||
def patch(self, id):
|
||||
patch_schema = self.resource_def.SCHEMA(only=('name', 'description', 'transfer_state', 'receiver_address', 'deposit', 'deliverynote_address', 'devices', 'owner_address'), partial=True)
|
||||
patch_schema = self.resource_def.SCHEMA(only=(
|
||||
'name', 'description', 'transfer_state', 'receiver_address', 'deposit', 'deliverynote_address', 'devices',
|
||||
'owner_address'), partial=True)
|
||||
l = request.get_json(schema=patch_schema)
|
||||
lot = Lot.query.filter_by(id=id).one()
|
||||
device_fields = ['transfer_state', 'receiver_address', 'deposit', 'deliverynote_address', 'owner_address']
|
||||
|
@ -85,15 +86,23 @@ class LotView(View):
|
|||
}
|
||||
else:
|
||||
query = Lot.query
|
||||
query = self.visibility_filter(query)
|
||||
if args['search']:
|
||||
query = query.filter(Lot.name.ilike(args['search'] + '%'))
|
||||
lots = query.paginate(per_page=6 if args['search'] else 30)
|
||||
return things_response(
|
||||
self.schema.dump(lots.items, many=True, nested=0),
|
||||
self.schema.dump(lots.items, many=True, nested=2),
|
||||
lots.page, lots.per_page, lots.total, lots.prev_num, lots.next_num
|
||||
)
|
||||
return jsonify(ret)
|
||||
|
||||
def visibility_filter(self, query):
|
||||
query = query.outerjoin(Deliverynote) \
|
||||
.filter(or_(Deliverynote.receiver_address == g.user.email,
|
||||
Deliverynote.supplier_email == g.user.email,
|
||||
Lot.owner_id == g.user.id))
|
||||
return query
|
||||
|
||||
def delete(self, id):
|
||||
lot = Lot.query.filter_by(id=id).one()
|
||||
lot.delete()
|
||||
|
|
|
@ -2,30 +2,22 @@
|
|||
|
||||
"""
|
||||
|
||||
from collections import Iterable
|
||||
from datetime import datetime
|
||||
from typing import Optional, Set, Union
|
||||
from uuid import uuid4
|
||||
|
||||
from boltons import urlutils
|
||||
from citext import CIText
|
||||
from flask import current_app as app, g
|
||||
from sortedcontainers import SortedSet
|
||||
from sqlalchemy import BigInteger, Column, Enum as DBEnum, \
|
||||
ForeignKey, Integer, Unicode
|
||||
from flask import g
|
||||
from sqlalchemy import BigInteger, Column, ForeignKey, Unicode
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.ext.declarative import declared_attr
|
||||
from sqlalchemy.ext.orderinglist import ordering_list
|
||||
from sqlalchemy.orm import backref, relationship, validates
|
||||
from sqlalchemy.util import OrderedSet
|
||||
from sqlalchemy.orm import backref, relationship
|
||||
from teal.db import CASCADE_OWN, INHERIT_COND, POLYMORPHIC_ID, \
|
||||
POLYMORPHIC_ON, StrictVersionType, URL
|
||||
from teal.marshmallow import ValidationError
|
||||
POLYMORPHIC_ON
|
||||
from teal.resource import url_for_resource
|
||||
|
||||
from ereuse_devicehub.db import db
|
||||
from ereuse_devicehub.resources.action.models import Action, DisposeProduct, \
|
||||
EraseBasic, Rate, Trade
|
||||
from ereuse_devicehub.resources.action.models import EraseBasic, Rate
|
||||
from ereuse_devicehub.resources.device.models import Device
|
||||
from ereuse_devicehub.resources.models import Thing
|
||||
from ereuse_devicehub.resources.user import User
|
||||
|
@ -83,7 +75,6 @@ class Proof(Thing):
|
|||
return '<{0.t} {0.id} >'.format(self)
|
||||
|
||||
|
||||
|
||||
class ProofTransfer(JoinedTableMixin, Proof):
|
||||
supplier_id = db.Column(UUID(as_uuid=True),
|
||||
db.ForeignKey(User.id),
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
from flask import current_app as app
|
||||
from marshmallow import Schema as MarshmallowSchema, ValidationError, fields as f, validates_schema
|
||||
from marshmallow.fields import Boolean, DateTime, Integer, Nested, String, UUID
|
||||
from marshmallow import fields as f
|
||||
from marshmallow import fields as f
|
||||
from marshmallow.fields import Boolean, DateTime, Integer, String, UUID
|
||||
from marshmallow.validate import Length
|
||||
from sqlalchemy.util import OrderedSet
|
||||
from teal.marshmallow import SanitizedStr, URL
|
||||
from teal.resource import Schema
|
||||
|
||||
from ereuse_devicehub.marshmallow import NestedOn
|
||||
from ereuse_devicehub.resources.proof import models as m
|
||||
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE
|
||||
from ereuse_devicehub.resources.schemas import Thing
|
||||
from ereuse_devicehub.resources.action import schemas as s_action
|
||||
from ereuse_devicehub.resources.device import schemas as s_device
|
||||
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE
|
||||
from ereuse_devicehub.resources.proof import models as m
|
||||
from ereuse_devicehub.resources.schemas import Thing
|
||||
from ereuse_devicehub.resources.user import schemas as s_user
|
||||
|
||||
|
||||
|
|
|
@ -1,18 +1,10 @@
|
|||
from distutils.version import StrictVersion
|
||||
from typing import List
|
||||
from uuid import UUID
|
||||
|
||||
from flask import current_app as app, request, jsonify
|
||||
from sqlalchemy.util import OrderedSet
|
||||
from teal.marshmallow import ValidationError
|
||||
from teal.resource import View
|
||||
|
||||
from ereuse_devicehub.db import db
|
||||
from ereuse_devicehub.query import things_response
|
||||
from ereuse_devicehub.resources.action.models import Action, RateComputer, Snapshot, VisualTest
|
||||
from ereuse_devicehub.resources.action.rate.v1_0 import CannotRate
|
||||
from ereuse_devicehub.resources.device.models import Component, Computer
|
||||
from ereuse_devicehub.resources.enums import SnapshotSoftware
|
||||
|
||||
SUPPORTED_WORKBENCH = StrictVersion('11.0')
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
from contextlib import suppress
|
||||
from typing import Set
|
||||
|
||||
from flask import g
|
||||
from boltons import urlutils
|
||||
from flask import g
|
||||
from sqlalchemy import BigInteger, Column, ForeignKey, UniqueConstraint
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import backref, relationship, validates
|
||||
|
@ -13,8 +13,8 @@ from teal.resource import url_for_resource
|
|||
from ereuse_devicehub.db import db
|
||||
from ereuse_devicehub.resources.agent.models import Organization
|
||||
from ereuse_devicehub.resources.device.models import Device
|
||||
from ereuse_devicehub.resources.user.models import User
|
||||
from ereuse_devicehub.resources.models import Thing
|
||||
from ereuse_devicehub.resources.user.models import User
|
||||
|
||||
|
||||
class Tags(Set['Tag']):
|
||||
|
|
|
@ -3,11 +3,11 @@ from sqlalchemy.util import OrderedSet
|
|||
from teal.marshmallow import SanitizedStr, URL
|
||||
|
||||
from ereuse_devicehub.marshmallow import NestedOn
|
||||
from ereuse_devicehub.resources.user.schemas import User
|
||||
from ereuse_devicehub.resources.agent.schemas import Organization
|
||||
from ereuse_devicehub.resources.device.schemas import Device
|
||||
from ereuse_devicehub.resources.schemas import Thing
|
||||
from ereuse_devicehub.resources.tag import model as m
|
||||
from ereuse_devicehub.resources.user.schemas import User
|
||||
|
||||
|
||||
def without_slash(x: str) -> bool:
|
||||
|
|
|
@ -3,8 +3,8 @@ from flask_sqlalchemy import Pagination
|
|||
from teal.marshmallow import ValidationError
|
||||
from teal.resource import View, url_for_resource
|
||||
|
||||
from ereuse_devicehub.db import db
|
||||
from ereuse_devicehub import auth
|
||||
from ereuse_devicehub.db import db
|
||||
from ereuse_devicehub.query import things_response
|
||||
from ereuse_devicehub.resources.device.models import Device
|
||||
from ereuse_devicehub.resources.tag import Tag
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
from werkzeug.exceptions import Unauthorized
|
||||
from werkzeug.exceptions import Unauthorized, Forbidden
|
||||
|
||||
|
||||
class WrongCredentials(Unauthorized):
|
||||
description = 'There is not an user with the matching username/password'
|
||||
|
||||
|
||||
class InsufficientPermission(Forbidden):
|
||||
description = (
|
||||
"You don't have the permissions to access the requested"
|
||||
"resource. It is either read-protected or not readable by the"
|
||||
"server."
|
||||
)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from uuid import uuid4
|
||||
|
||||
from citext import CIText
|
||||
from flask import current_app as app
|
||||
from sqlalchemy import Column
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy_utils import EmailType, PasswordType
|
||||
from citext import CIText
|
||||
|
||||
from ereuse_devicehub.db import db
|
||||
from ereuse_devicehub.resources.inventory.model import Inventory
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import pytest
|
||||
import teal.marshmallow
|
||||
from ereuse_utils.test import ANY
|
||||
import csv
|
||||
from datetime import datetime
|
||||
from io import StringIO
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
import teal.marshmallow
|
||||
from ereuse_utils.test import ANY
|
||||
|
||||
from ereuse_devicehub.client import Client, UserClient
|
||||
from ereuse_devicehub.resources.action.models import Snapshot
|
||||
from ereuse_devicehub.resources.documents import documents
|
||||
|
@ -18,7 +19,7 @@ def test_erasure_certificate_public_one(user: UserClient, client: Client):
|
|||
s = file('erase-sectors.snapshot')
|
||||
snapshot, _ = user.post(s, res=Snapshot)
|
||||
|
||||
doc, response = client.get(res=documents.DocumentDef.t,
|
||||
doc, response = user.get(res=documents.DocumentDef.t,
|
||||
item='erasures/{}'.format(snapshot['device']['id']),
|
||||
accept=ANY)
|
||||
assert 'html' in response.content_type
|
||||
|
@ -145,7 +146,7 @@ def test_export_empty(user: UserClient):
|
|||
assert len(export_csv) == 0, 'Csv is not empty'
|
||||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.xfail(reason='Feature not developed (Beta)')
|
||||
def test_export_computer_monitor(user: UserClient):
|
||||
"""Test a export device type computer monitor."""
|
||||
snapshot, _ = user.post(file('computer-monitor.snapshot'), res=Snapshot)
|
||||
|
@ -170,6 +171,7 @@ def test_export_computer_monitor(user: UserClient):
|
|||
assert fixture_csv[1] == export_csv[1], 'Component information are not equal'
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason='Feature not developed (Beta)')
|
||||
def test_export_keyboard(user: UserClient):
|
||||
"""Test a export device type keyboard."""
|
||||
snapshot, _ = user.post(file('keyboard.snapshot'), res=Snapshot)
|
||||
|
@ -193,7 +195,7 @@ def test_export_keyboard(user: UserClient):
|
|||
assert fixture_csv[1] == export_csv[1], 'Component information are not equal'
|
||||
|
||||
|
||||
@pytest.mark.mvp
|
||||
@pytest.mark.xfail(reason='Feature not developed (Beta)')
|
||||
def test_export_multiple_different_devices(user: UserClient):
|
||||
"""Test function 'Export' of multiple different device types (like
|
||||
computers, keyboards, monitors, etc..)
|
||||
|
|
Reference in New Issue