resolve conflict

This commit is contained in:
Cayo Puigdefabregas 2022-02-25 10:07:44 +01:00
commit 04cc244f2d
1 changed files with 210 additions and 123 deletions

View File

@ -3,33 +3,34 @@ import json
from json.decoder import JSONDecodeError from json.decoder import JSONDecodeError
from boltons.urlutils import URL from boltons.urlutils import URL
from flask import g, request
from flask_wtf import FlaskForm
from sqlalchemy.util import OrderedSet
from wtforms import (
BooleanField, DateField, FileField, FloatField, Form, HiddenField,
IntegerField, MultipleFileField, SelectField, StringField, TextAreaField,
URLField, validators)
from wtforms.fields import FormField
from ereuse_devicehub.db import db from ereuse_devicehub.db import db
from ereuse_devicehub.resources.action.models import RateComputer, Snapshot from ereuse_devicehub.resources.action.models import RateComputer, Snapshot
from ereuse_devicehub.resources.action.rate.v1_0 import CannotRate from ereuse_devicehub.resources.action.rate.v1_0 import CannotRate
from ereuse_devicehub.resources.action.schemas import \ from ereuse_devicehub.resources.action.schemas import \
Snapshot as SnapshotSchema Snapshot as SnapshotSchema
from ereuse_devicehub.resources.action.views.snapshot import move_json, save_json from ereuse_devicehub.resources.action.views.snapshot import (
from ereuse_devicehub.resources.device.models import (SAI, Cellphone, Computer, move_json, save_json)
Device, Keyboard, MemoryCardReader, from ereuse_devicehub.resources.device.models import (
Monitor, Mouse, Smartphone, Tablet) SAI, Cellphone, Computer, Device, Keyboard, MemoryCardReader, Monitor,
from flask import g, request Mouse, Smartphone, Tablet)
from flask_wtf import FlaskForm
from sqlalchemy.util import OrderedSet
from wtforms import (BooleanField, DateField, FileField, FloatField, Form,
HiddenField, IntegerField, MultipleFileField, SelectField,
StringField, TextAreaField, URLField, validators)
from wtforms.fields import FormField
from wtforms.validators import ValidationError
from ereuse_devicehub.resources.device.sync import Sync from ereuse_devicehub.resources.device.sync import Sync
from ereuse_devicehub.resources.documents.models import DataWipeDocument from ereuse_devicehub.resources.documents.models import DataWipeDocument
from ereuse_devicehub.resources.enums import Severity, SnapshotSoftware from ereuse_devicehub.resources.enums import Severity, SnapshotSoftware
from ereuse_devicehub.resources.hash_reports import insert_hash from ereuse_devicehub.resources.hash_reports import insert_hash
from ereuse_devicehub.resources.lot.models import Lot from ereuse_devicehub.resources.lot.models import Lot
from ereuse_devicehub.resources.tag.model import Tag from ereuse_devicehub.resources.tag.model import Tag
from ereuse_devicehub.resources.user.models import User
from ereuse_devicehub.resources.tradedocument.models import TradeDocument from ereuse_devicehub.resources.tradedocument.models import TradeDocument
from ereuse_devicehub.resources.user.exceptions import InsufficientPermission from ereuse_devicehub.resources.user.exceptions import InsufficientPermission
from ereuse_devicehub.resources.user.models import User
class LotDeviceForm(FlaskForm): class LotDeviceForm(FlaskForm):
@ -42,12 +43,19 @@ class LotDeviceForm(FlaskForm):
if not is_valid: if not is_valid:
return False return False
self._lot = Lot.query.filter(Lot.id == self.lot.data).filter( self._lot = (
Lot.owner_id == g.user.id).one() Lot.query.filter(Lot.id == self.lot.data)
.filter(Lot.owner_id == g.user.id)
.one()
)
devices = set(self.devices.data.split(",")) devices = set(self.devices.data.split(","))
self._devices = Device.query.filter(Device.id.in_(devices)).filter( self._devices = (
Device.owner_id == g.user.id).distinct().all() Device.query.filter(Device.id.in_(devices))
.filter(Device.owner_id == g.user.id)
.distinct()
.all()
)
return bool(self._devices) return bool(self._devices)
@ -55,7 +63,7 @@ class LotDeviceForm(FlaskForm):
trade = self._lot.trade trade = self._lot.trade
if trade: if trade:
for dev in self._devices: for dev in self._devices:
if not trade in dev.actions: if trade not in dev.actions:
trade.devices.add(dev) trade.devices.add(dev)
self._lot.devices.update(self._devices) self._lot.devices.update(self._devices)
@ -75,8 +83,11 @@ class LotForm(FlaskForm):
self.id = kwargs.pop('id', None) self.id = kwargs.pop('id', None)
self.instance = None self.instance = None
if self.id: if self.id:
self.instance = Lot.query.filter(Lot.id == self.id).filter( self.instance = (
Lot.owner_id == g.user.id).one() Lot.query.filter(Lot.id == self.id)
.filter(Lot.owner_id == g.user.id)
.one()
)
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
if self.instance and not self.name.data: if self.instance and not self.name.data:
self.name.data = self.instance.name self.name.data = self.instance.name
@ -172,8 +183,10 @@ class UploadSnapshotForm(FlaskForm):
# this is a copy adaptated from ereuse_devicehub.resources.action.views.snapshot # this is a copy adaptated from ereuse_devicehub.resources.action.views.snapshot
device = snapshot_json.pop('device') # type: Computer device = snapshot_json.pop('device') # type: Computer
components = None components = None
if snapshot_json['software'] == (SnapshotSoftware.Workbench or SnapshotSoftware.WorkbenchAndroid): if snapshot_json['software'] == (
components = snapshot_json.pop('components', None) # type: List[Component] SnapshotSoftware.Workbench or SnapshotSoftware.WorkbenchAndroid
):
components = snapshot_json.pop('components', None)
if isinstance(device, Computer) and device.hid: if isinstance(device, Computer) and device.hid:
device.add_mac_to_hid(components_snap=components) device.add_mac_to_hid(components_snap=components)
snapshot = Snapshot(**snapshot_json) snapshot = Snapshot(**snapshot_json)
@ -182,7 +195,9 @@ class UploadSnapshotForm(FlaskForm):
actions_device = set(e for e in device.actions_one) actions_device = set(e for e in device.actions_one)
device.actions_one.clear() device.actions_one.clear()
if components: if components:
actions_components = tuple(set(e for e in c.actions_one) for c in components) actions_components = tuple(
set(e for e in c.actions_one) for c in components
)
for component in components: for component in components:
component.actions_one.clear() component.actions_one.clear()
@ -252,14 +267,16 @@ class NewDeviceForm(FlaskForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.devices = {"Smartphone": Smartphone, self.devices = {
"Smartphone": Smartphone,
"Tablet": Tablet, "Tablet": Tablet,
"Cellphone": Cellphone, "Cellphone": Cellphone,
"Monitor": Monitor, "Monitor": Monitor,
"Mouse": Mouse, "Mouse": Mouse,
"Keyboard": Keyboard, "Keyboard": Keyboard,
"SAI": SAI, "SAI": SAI,
"MemoryCardReader": MemoryCardReader} "MemoryCardReader": MemoryCardReader,
}
if not self.generation.data: if not self.generation.data:
self.generation.data = 1 self.generation.data = 1
@ -349,16 +366,18 @@ class NewDeviceForm(FlaskForm):
'height': self.height.data, 'height': self.height.data,
'depth': self.depth.data, 'depth': self.depth.data,
'variant': self.variant.data, 'variant': self.variant.data,
'image': self.image.data 'image': self.image.data,
} },
} }
if self.appearance.data or self.functionality.data: if self.appearance.data or self.functionality.data:
json_snapshot['device']['actions'] = [{ json_snapshot['device']['actions'] = [
{
'type': 'VisualTest', 'type': 'VisualTest',
'appearanceRange': self.appearance.data, 'appearanceRange': self.appearance.data,
'functionalityRange': self.functionality.data 'functionalityRange': self.functionality.data,
}] }
]
upload_form = UploadSnapshotForm() upload_form = UploadSnapshotForm()
upload_form.sync = Sync() upload_form.sync = Sync()
@ -438,9 +457,11 @@ class TagDeviceForm(FlaskForm):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
if self.delete: if self.delete:
tags = Tag.query.filter(Tag.owner_id==g.user.id).filter(Tag.device_id==self.device_id) tags = Tag.query.filter(Tag.owner_id == g.user.id).filter_by(
device_id=self.device_id
)
else: else:
tags = Tag.query.filter(Tag.owner_id==g.user.id).filter(Tag.device_id==None) tags = Tag.query.filter(Tag.owner_id == g.user.id).filter_by(device_id=None)
self.tag.choices = [(tag.id, tag.id) for tag in tags] self.tag.choices = [(tag.id, tag.id) for tag in tags]
@ -450,8 +471,11 @@ class TagDeviceForm(FlaskForm):
if not is_valid: if not is_valid:
return False return False
self._tag = Tag.query.filter(Tag.id == self.tag.data).filter( self._tag = (
Tag.owner_id == g.user.id).one() Tag.query.filter(Tag.id == self.tag.data)
.filter(Tag.owner_id == g.user.id)
.one()
)
if not self.delete and self._tag.device_id: if not self.delete and self._tag.device_id:
self.tag.errors = [("This tag is actualy in use.")] self.tag.errors = [("This tag is actualy in use.")]
@ -465,8 +489,11 @@ class TagDeviceForm(FlaskForm):
if self.device_id or self.device.data: if self.device_id or self.device.data:
self.device_id = self.device_id or self.device.data self.device_id = self.device_id or self.device.data
self._device = Device.query.filter(Device.id == self.device_id).filter( self._device = (
Device.owner_id == g.user.id).one() Device.query.filter(Device.id == self.device_id)
.filter(Device.owner_id == g.user.id)
.one()
)
return True return True
@ -482,18 +509,27 @@ class TagDeviceForm(FlaskForm):
class NewActionForm(FlaskForm): class NewActionForm(FlaskForm):
name = StringField('Name', [validators.length(max=50)], name = StringField(
description="A name or title of the event. Something to look for.") 'Name',
[validators.length(max=50)],
description="A name or title of the event. Something to look for.",
)
devices = HiddenField() devices = HiddenField()
date = DateField('Date', [validators.Optional()], date = DateField(
'Date',
[validators.Optional()],
description="""When the action ends. For some actions like booking description="""When the action ends. For some actions like booking
the time when it expires, for others like renting the the time when it expires, for others like renting the
time that the end rents. For specific actions, it is the time that the end rents. For specific actions, it is the
time in which they are carried out; differs from created time in which they are carried out; differs from created
in that created is where the system receives the action.""") in that created is where the system receives the action.""",
severity = SelectField('Severity', choices=[(v.name, v.name) for v in Severity], )
severity = SelectField(
'Severity',
choices=[(v.name, v.name) for v in Severity],
description="""An indicator that evaluates the execution of the event. description="""An indicator that evaluates the execution of the event.
For example, failed events are set to Error""") For example, failed events are set to Error""",
)
description = TextAreaField('Description') description = TextAreaField('Description')
lot = HiddenField() lot = HiddenField()
type = HiddenField() type = HiddenField()
@ -507,8 +543,11 @@ class NewActionForm(FlaskForm):
self._devices = OrderedSet() self._devices = OrderedSet()
if self.devices.data: if self.devices.data:
devices = set(self.devices.data.split(",")) devices = set(self.devices.data.split(","))
self._devices = OrderedSet(Device.query.filter(Device.id.in_(devices)).filter( self._devices = OrderedSet(
Device.owner_id == g.user.id).all()) Device.query.filter(Device.id.in_(devices))
.filter(Device.owner_id == g.user.id)
.all()
)
if not self._devices: if not self._devices:
return False return False
@ -570,19 +609,31 @@ class AllocateForm(NewActionForm):
class DataWipeDocumentForm(Form): class DataWipeDocumentForm(Form):
date = DateField('Date', [validators.Optional()], date = DateField(
description="Date when was data wipe") 'Date', [validators.Optional()], description="Date when was data wipe"
url = URLField('Url', [validators.Optional()], )
description="Url where the document resides") url = URLField(
success = BooleanField('Success', [validators.Optional()], 'Url', [validators.Optional()], description="Url where the document resides"
description="The erase was success or not?") )
software = StringField('Software', [validators.Optional()], success = BooleanField(
description="Which software has you use for erase the disks") 'Success', [validators.Optional()], description="The erase was success or not?"
id_document = StringField('Document Id', [validators.Optional()], )
description="Identification number of document") software = StringField(
file_name = FileField('File', [validators.DataRequired()], 'Software',
[validators.Optional()],
description="Which software has you use for erase the disks",
)
id_document = StringField(
'Document Id',
[validators.Optional()],
description="Identification number of document",
)
file_name = FileField(
'File',
[validators.DataRequired()],
description="""This file is not stored on our servers, it is only used to description="""This file is not stored on our servers, it is only used to
generate a digital signature and obtain the name of the file.""") generate a digital signature and obtain the name of the file.""",
)
def validate(self, extra_validators=None): def validate(self, extra_validators=None):
is_valid = super().validate(extra_validators) is_valid = super().validate(extra_validators)
@ -638,23 +689,39 @@ class DataWipeForm(NewActionForm):
class TradeForm(NewActionForm): class TradeForm(NewActionForm):
user_from = StringField('Supplier', [validators.Optional()], user_from = StringField(
'Supplier',
[validators.Optional()],
description="Please enter the supplier's email address", description="Please enter the supplier's email address",
render_kw={'data-email': ""}) render_kw={'data-email': ""},
user_to = StringField('Receiver', [validators.Optional()], )
user_to = StringField(
'Receiver',
[validators.Optional()],
description="Please enter the receiver's email address", description="Please enter the receiver's email address",
render_kw={'data-email': ""}) render_kw={'data-email': ""},
confirm = BooleanField('Confirm', [validators.Optional()], )
confirm = BooleanField(
'Confirm',
[validators.Optional()],
default=True, default=True,
description="I need confirmation from the other user for every device and document.") description="I need confirmation from the other user for every device and document.",
code = StringField('Code', [validators.Optional()], )
description="If you don't need confirm, you need put a code for trace the user in the statistics.") code = StringField(
'Code',
[validators.Optional()],
description="If you don't need confirm, you need put a code for trace the user in the statistics.",
)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.user_from.render_kw['data-email'] = g.user.email self.user_from.render_kw['data-email'] = g.user.email
self.user_to.render_kw['data-email'] = g.user.email self.user_to.render_kw['data-email'] = g.user.email
self._lot = Lot.query.filter(Lot.id==self.lot.data).filter(Lot.owner_id==g.user.id).one() self._lot = (
Lot.query.filter(Lot.id == self.lot.data)
.filter(Lot.owner_id == g.user.id)
.one()
)
def validate(self, extra_validators=None): def validate(self, extra_validators=None):
is_valid = self.generic_validation(extra_validators=extra_validators) is_valid = self.generic_validation(extra_validators=extra_validators)
@ -662,11 +729,15 @@ class TradeForm(NewActionForm):
email_to = self.user_to.data email_to = self.user_to.data
if not self.confirm.data and not self.code.data: if not self.confirm.data and not self.code.data:
self.code.errors = ["If you don't want confirm, you need a code"] self.code.errors = ["If you don't want to confirm, you need a code"]
is_valid = False is_valid = False
if self.confirm.data and not (email_from and email_to) or email_to == email_from or \ if (
g.user.email not in [email_from, email_to]: self.confirm.data
and not (email_from and email_to)
or email_to == email_from
or g.user.email not in [email_from, email_to]
):
errors = ["If you want confirm, you need a correct email"] errors = ["If you want confirm, you need a correct email"]
self.user_to.errors = errors self.user_to.errors = errors
@ -683,9 +754,15 @@ class TradeForm(NewActionForm):
self.db_user_to = user_to self.db_user_to = user_to
self.db_user_from = user_from self.db_user_from = user_from
self.has_errors = not is_valid
return is_valid return is_valid
def save(self, commit=True): def save(self, commit=True):
if self.has_errors:
raise ValueError(
"The %s could not be saved because the data didn't validate."
% (self.instance._meta.object_name)
)
if not self.confirm.data: if not self.confirm.data:
self.create_phantom_account() self.create_phantom_account()
self.prepare_instance() self.prepare_instance()
@ -720,11 +797,6 @@ class TradeForm(NewActionForm):
The same if exist to but not from The same if exist to but not from
""" """
# Checks
if self.code.data:
msg = "If you don't want confirm, you need a code"
return ValidationError(msg)
user_from = self.user_from.data user_from = self.user_from.data
user_to = self.user_to.data user_to = self.user_to.data
code = self.code.data code = self.code.data
@ -736,16 +808,16 @@ class TradeForm(NewActionForm):
# Create receiver (to) phantom account # Create receiver (to) phantom account
if user_from and not user_to: if user_from and not user_to:
assert g.user.email == user_from assert g.user.email == user_from
user = self.get_or_create_user(code)
self.user_from = g.user self.user_from = g.user
self.user_to = user self.user_to = self.get_or_create_user(code)
return return
# Create supplier (from) phantom account # Create supplier (from) phantom account
if not user_from and user_to: if not user_from and user_to:
assert g.user.email == user_to assert g.user.email == user_to
user = self.get_or_create_user(code)
self.user_from = user self.user_from = self.get_or_create_user(code)
self.user_to = g.user self.user_to = g.user
def get_or_create_user(self, code): def get_or_create_user(self, code):
@ -778,22 +850,37 @@ class TradeForm(NewActionForm):
class TradeDocumentForm(FlaskForm): class TradeDocumentForm(FlaskForm):
url = URLField('Url', [validators.Optional()], url = URLField(
'Url',
[validators.Optional()],
render_kw={'class': "form-control"}, render_kw={'class': "form-control"},
description="Url where the document resides") description="Url where the document resides",
description = StringField('Description', [validators.Optional()], )
description = StringField(
'Description',
[validators.Optional()],
render_kw={'class': "form-control"}, render_kw={'class': "form-control"},
description="") description="",
id_document = StringField('Document Id', [validators.Optional()], )
id_document = StringField(
'Document Id',
[validators.Optional()],
render_kw={'class': "form-control"}, render_kw={'class': "form-control"},
description="Identification number of document") description="Identification number of document",
date = DateField('Date', [validators.Optional()], )
date = DateField(
'Date',
[validators.Optional()],
render_kw={'class': "form-control"}, render_kw={'class': "form-control"},
description="") description="",
file_name = FileField('File', [validators.DataRequired()], )
file_name = FileField(
'File',
[validators.DataRequired()],
render_kw={'class': "form-control"}, render_kw={'class': "form-control"},
description="""This file is not stored on our servers, it is only used to description="""This file is not stored on our servers, it is only used to
generate a digital signature and obtain the name of the file.""") generate a digital signature and obtain the name of the file.""",
)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
lot_id = kwargs.pop('lot') lot_id = kwargs.pop('lot')