diff --git a/ereuse_devicehub/resources/device/views.py b/ereuse_devicehub/resources/device/views.py index 8bab2a3c..6412518c 100644 --- a/ereuse_devicehub/resources/device/views.py +++ b/ereuse_devicehub/resources/device/views.py @@ -3,28 +3,33 @@ import uuid from itertools import filterfalse import marshmallow -from flask import g, current_app as app, render_template, request, Response +from flask import Response +from flask import current_app as app +from flask import g, render_template, request from flask.json import jsonify from flask_sqlalchemy import Pagination +from marshmallow import Schema as MarshmallowSchema +from marshmallow import fields +from marshmallow import fields as f +from marshmallow import validate as v from sqlalchemy.util import OrderedSet -from marshmallow import fields, fields as f, validate as v, Schema as MarshmallowSchema from teal import query -from teal.db import ResourceNotFound from teal.cache import cache -from teal.resource import View +from teal.db import ResourceNotFound from teal.marshmallow import ValidationError +from teal.resource import View from ereuse_devicehub import auth from ereuse_devicehub.db import db from ereuse_devicehub.query import SearchQueryParser, things_response from ereuse_devicehub.resources import search from ereuse_devicehub.resources.action import models as actions +from ereuse_devicehub.resources.action.models import Trade from ereuse_devicehub.resources.device import states -from ereuse_devicehub.resources.device.models import Device, Manufacturer, Computer +from ereuse_devicehub.resources.device.models import Computer, Device, Manufacturer 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.action.models import Trade from ereuse_devicehub.resources.tag.model import Tag @@ -61,15 +66,16 @@ class Filters(query.Query): manufacturer = query.ILike(Device.manufacturer) serialNumber = query.ILike(Device.serial_number) # todo test query for rating (and possibly other filters) - rating = query.Join((Device.id == actions.ActionWithOneDevice.device_id) - & (actions.ActionWithOneDevice.id == actions.Rate.id), - RateQ) + rating = query.Join( + (Device.id == actions.ActionWithOneDevice.device_id) + & (actions.ActionWithOneDevice.id == actions.Rate.id), + RateQ, + ) tag = query.Join(Device.id == Tag.device_id, TagQ) # 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): @@ -104,12 +110,15 @@ class DeviceView(View): return super().get(id) def patch(self, id): - dev = Device.query.filter_by(id=id, owner_id=g.user.id, active=True).one() + dev = Device.query.filter_by( + id=id, owner_id=g.user.id, active=True, placeholder=None + ).one() if isinstance(dev, Computer): resource_def = app.resources['Computer'] # TODO check how to handle the 'actions_one' patch_schema = resource_def.SCHEMA( - only=['transfer_state', 'actions_one'], partial=True) + only=['transfer_state', 'actions_one'], partial=True + ) json = request.get_json(schema=patch_schema) # TODO check how to handle the 'actions_one' json.pop('actions_one') @@ -129,12 +138,16 @@ class DeviceView(View): return self.one_private(id) def one_public(self, id: int): - device = Device.query.filter_by(devicehub_id=id, active=True).one() + device = Device.query.filter_by( + devicehub_id=id, active=True, placeholder=None + ).one() return render_template('devices/layout.html', device=device, states=states) @auth.Auth.requires_auth def one_private(self, id: str): - device = Device.query.filter_by(devicehub_id=id, owner_id=g.user.id, active=True).first() + device = Device.query.filter_by( + devicehub_id=id, owner_id=g.user.id, active=True, placeholder=None + ).first() if not device: return self.one_public(id) return self.schema.jsonify(device) @@ -148,7 +161,11 @@ class DeviceView(View): devices = query.paginate(page=args['page'], per_page=30) # type: Pagination return things_response( self.schema.dump(devices.items, many=True, nested=1), - devices.page, devices.per_page, devices.total, devices.prev_num, devices.next_num + devices.page, + devices.per_page, + devices.total, + devices.prev_num, + devices.next_num, ) def query(self, args): @@ -158,9 +175,11 @@ class DeviceView(View): trades_dev_ids = {d.id for t in trades for d in t.devices} - query = Device.query.filter(Device.active == True).filter( - (Device.owner_id == g.user.id) | (Device.id.in_(trades_dev_ids)) - ).distinct() + query = ( + Device.query.filter(Device.active == True, Device.placeholder == None) + .filter((Device.owner_id == g.user.id) | (Device.id.in_(trades_dev_ids))) + .distinct() + ) unassign = args.get('unassign', None) search_p = args.get('search', None) @@ -168,18 +187,22 @@ class DeviceView(View): properties = DeviceSearch.properties tags = DeviceSearch.tags devicehub_ids = DeviceSearch.devicehub_ids - query = query.join(DeviceSearch).filter( - search.Search.match(properties, search_p) | - search.Search.match(tags, search_p) | - search.Search.match(devicehub_ids, search_p) - ).order_by( - search.Search.rank(properties, search_p) + - search.Search.rank(tags, search_p) + - search.Search.rank(devicehub_ids, search_p) + query = ( + query.join(DeviceSearch) + .filter( + search.Search.match(properties, search_p) + | search.Search.match(tags, search_p) + | search.Search.match(devicehub_ids, search_p) + ) + .order_by( + search.Search.rank(properties, search_p) + + search.Search.rank(tags, search_p) + + search.Search.rank(devicehub_ids, search_p) + ) ) if unassign: subquery = LotDeviceDescendants.query.with_entities( - LotDeviceDescendants.device_id + LotDeviceDescendants.device_id ) query = query.filter(Device.id.notin_(subquery)) return query.filter(*args['filter']).order_by(*args['sort']) @@ -221,10 +244,16 @@ class DeviceMergeView(View): raise ValidationError('The devices is not the same type.') # Adding actions of self.with_device - with_actions_one = [a for a in self.with_device.actions - if isinstance(a, actions.ActionWithOneDevice)] - with_actions_multiple = [a for a in self.with_device.actions - if isinstance(a, actions.ActionWithMultipleDevices)] + with_actions_one = [ + a + for a in self.with_device.actions + if isinstance(a, actions.ActionWithOneDevice) + ] + with_actions_multiple = [ + a + for a in self.with_device.actions + if isinstance(a, actions.ActionWithMultipleDevices) + ] # Moving the tags from `with_device` to `base_device` # Union of tags the device had plus the (potentially) new ones @@ -269,20 +298,22 @@ class DeviceMergeView(View): class ManufacturerView(View): class FindArgs(marshmallow.Schema): - search = marshmallow.fields.Str(required=True, - # Disallow like operators - validate=lambda x: '%' not in x and '_' not in x) + search = marshmallow.fields.Str( + required=True, + # Disallow like operators + validate=lambda x: '%' not in x and '_' not in x, + ) @cache(datetime.timedelta(days=1)) def find(self, args: dict): search = args['search'] - manufacturers = Manufacturer.query \ - .filter(Manufacturer.name.ilike(search + '%')) \ - .paginate(page=1, per_page=6) # type: Pagination + manufacturers = Manufacturer.query.filter( + Manufacturer.name.ilike(search + '%') + ).paginate( + page=1, per_page=6 + ) # type: Pagination return jsonify( items=app.resources[Manufacturer.t].schema.dump( - manufacturers.items, - many=True, - nested=1 + manufacturers.items, many=True, nested=1 ) )