diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index ea9a8bc8..bf05376e 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -1,10 +1,19 @@ +import json from flask_wtf import FlaskForm -from wtforms import StringField, validators -from flask import g +from wtforms import StringField, validators, MultipleFileField +from flask import g, request, app +from sqlalchemy.util import OrderedSet from ereuse_devicehub.db import db -from ereuse_devicehub.resources.device.models import Device +from ereuse_devicehub.resources.device.models import Device, Computer +from ereuse_devicehub.resources.action.models import RateComputer, Snapshot +from ereuse_devicehub.resources.action.schemas import Snapshot as SnapshotSchema from ereuse_devicehub.resources.lot.models import Lot +from ereuse_devicehub.resources.enums import SnapshotSoftware, Severity +from ereuse_devicehub.resources.user.exceptions import InsufficientPermission +from ereuse_devicehub.resources.action.rate.v1_0 import CannotRate +from ereuse_devicehub.resources.device.sync import Sync +from ereuse_devicehub.resources.action.views.snapshot import save_json, move_json class LotDeviceForm(FlaskForm): @@ -75,6 +84,109 @@ class LotForm(FlaskForm): return self.instance +class UploadSnapshotForm(FlaskForm): + snapshot = MultipleFileField(u'Select a Snapshot File', [validators.DataRequired()]) + + def validate(self, extra_validators=None): + is_valid = super().validate(extra_validators) + + if not is_valid: + return False + + data = request.files.getlist(self.snapshot.name) + if not data: + return False + self.snapshots = [] + self.result = {} + for d in data: + filename = d.filename + self.result[filename] = 'Ok' + d = d.stream.read() + if not d: + self.result[filename] = 'Error' + continue + self.snapshots.append((filename, json.loads(d))) + + if not self.snapshots: + return False + + return True + + def save(self): + if any([x == 'Error' for x in self.result.values()]): + return + # result = [] + self.sync = Sync() + schema = SnapshotSchema() + # self.tmp_snapshots = app.config['TMP_SNAPSHOTS'] + # TODO @cayop get correct var config + self.tmp_snapshots = '/tmp/' + for k, snapshot_json in self.snapshots: + path_snapshot = save_json(snapshot_json, self.tmp_snapshots, g.user.email) + snapshot_json.pop('debug', None) + snapshot_json = schema.load(snapshot_json) + response = self.build(snapshot_json) + move_json(self.tmp_snapshots, path_snapshot, g.user.email) + + def build(self, snapshot_json): + # this is a copy adaptated from ereuse_devicehub.resources.action.views.snapshot + device = snapshot_json.pop('device') # type: Computer + components = None + if snapshot_json['software'] == (SnapshotSoftware.Workbench or SnapshotSoftware.WorkbenchAndroid): + components = snapshot_json.pop('components', None) # type: List[Component] + if isinstance(device, Computer) and device.hid: + device.add_mac_to_hid(components_snap=components) + snapshot = Snapshot(**snapshot_json) + + # Remove new actions from devices so they don't interfere with sync + actions_device = set(e for e in device.actions_one) + device.actions_one.clear() + if components: + actions_components = tuple(set(e for e in c.actions_one) for c in components) + for component in components: + component.actions_one.clear() + + assert not device.actions_one + assert all(not c.actions_one for c in components) if components else True + db_device, remove_actions = self.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 + # commit will change the order of the components by what + # the DB wants. Let's get a copy of the list so we preserve order + ordered_components = OrderedSet(x for x in snapshot.components) + + # Add the new actions to the db-existing devices and components + db_device.actions_one |= actions_device + if components: + for component, actions in zip(ordered_components, actions_components): + component.actions_one |= actions + snapshot.actions |= actions + + 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: + pass + else: + snapshot.actions.add(rate_computer) + if price: + snapshot.actions.add(price) + elif snapshot.software == SnapshotSoftware.WorkbenchAndroid: + pass # TODO try except to compute RateMobile + # Check if HID is null and add Severity:Warning to Snapshot + if snapshot.device.hid is None: + snapshot.severity = Severity.Warning + + db.session.add(snapshot) + db.session().final_flush() + + class NewActionForm(FlaskForm): name = StringField(u'Name') date = StringField(u'Date')