diff --git a/ereuse_devicehub/api/views.py b/ereuse_devicehub/api/views.py index 5aa7ccc5..dff860aa 100644 --- a/ereuse_devicehub/api/views.py +++ b/ereuse_devicehub/api/views.py @@ -1,10 +1,24 @@ +import json from binascii import Error as asciiError -from flask import Blueprint, jsonify, request +from flask import Blueprint +from flask import current_app as app +from flask import g, jsonify, request from flask.views import View +from marshmallow import ValidationError +from sqlalchemy.util import OrderedSet from werkzeug.exceptions import Unauthorized from ereuse_devicehub.auth import Auth +from ereuse_devicehub.db import db +from ereuse_devicehub.parser.models import SnapshotErrors +from ereuse_devicehub.parser.parser import ParseSnapshotLsHw +from ereuse_devicehub.parser.schemas import Snapshot_lite +from ereuse_devicehub.resources.action.models import Snapshot +from ereuse_devicehub.resources.action.views.snapshot import move_json, save_json +from ereuse_devicehub.resources.device.models import Computer +from ereuse_devicehub.resources.enums import Severity, SnapshotSoftware +from ereuse_devicehub.resources.user.exceptions import InsufficientPermission api = Blueprint('api', __name__, url_prefix='/api') @@ -26,13 +40,91 @@ class LoginMix(View): except asciiError: raise unauthorized self.user = Auth().authenticate(token) + g.user = self.user class InventoryView(LoginMix): methods = ['POST'] def dispatch_request(self): + import pdb + + pdb.set_trace() + snapshot_json = json.loads(request.data) + self.tmp_snapshots = app.config['TMP_SNAPSHOTS'] + self.path_snapshot = save_json(snapshot_json, self.tmp_snapshots, g.user.email) + schema = Snapshot_lite() + try: + snapshot_json = schema.load(snapshot_json) + except ValidationError as err: + txt = "{}".format(err) + uuid = snapshot_json.get('uuid') + error = SnapshotErrors( + description=txt, snapshot_uuid=uuid, severity=Severity.Error + ) + error.save(commit=True) + raise err + self.snapshot_json = ParseSnapshotLsHw(snapshot_json) + snapshot = self.build() + ret = schema.jsonify(snapshot) # transform it back + ret.status_code = 201 + db.session.commit() + return ret + move_json(self.tmp_snapshots, self.path_snapshot, g.user.email) return jsonify("Ok") + def build(self): + device = self.snapshot_json.pop('device') # type: Computer + components = None + if self.snapshot_json['software'] == ( + SnapshotSoftware.Workbench or SnapshotSoftware.WorkbenchAndroid + ): + components = self.snapshot_json.pop('components', None) + if isinstance(device, Computer) and device.hid: + device.add_mac_to_hid(components_snap=components) + snapshot = Snapshot(**self.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.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 + # 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() + 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() + return snapshot + api.add_url_rule('/inventory/', view_func=InventoryView.as_view('inventory'))