Merge pull request #209 from eReuse/feature/server-side-render-create-device-#2895
Add a new device to a lot if it is created from a lot
This commit is contained in:
commit
fb3a895b19
|
@ -1,26 +1,46 @@
|
||||||
import copy
|
import copy
|
||||||
import json
|
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 import g, request
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
|
from sqlalchemy import or_
|
||||||
from sqlalchemy.util import OrderedSet
|
from sqlalchemy.util import OrderedSet
|
||||||
from wtforms import (
|
from wtforms import (
|
||||||
BooleanField, DateField, FileField, FloatField, Form, HiddenField,
|
BooleanField,
|
||||||
IntegerField, MultipleFileField, SelectField, StringField, TextAreaField,
|
DateField,
|
||||||
URLField, validators)
|
FileField,
|
||||||
|
FloatField,
|
||||||
|
Form,
|
||||||
|
HiddenField,
|
||||||
|
IntegerField,
|
||||||
|
MultipleFileField,
|
||||||
|
SelectField,
|
||||||
|
StringField,
|
||||||
|
TextAreaField,
|
||||||
|
URLField,
|
||||||
|
validators,
|
||||||
|
)
|
||||||
from wtforms.fields import FormField
|
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, Trade
|
||||||
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 (
|
|
||||||
move_json, save_json)
|
|
||||||
from ereuse_devicehub.resources.device.models import (
|
from ereuse_devicehub.resources.device.models import (
|
||||||
SAI, Cellphone, Computer, Device, Keyboard, MemoryCardReader, Monitor,
|
SAI,
|
||||||
Mouse, Smartphone, Tablet)
|
Cellphone,
|
||||||
|
Computer,
|
||||||
|
Device,
|
||||||
|
Keyboard,
|
||||||
|
MemoryCardReader,
|
||||||
|
Monitor,
|
||||||
|
Mouse,
|
||||||
|
Smartphone,
|
||||||
|
Tablet,
|
||||||
|
)
|
||||||
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
|
||||||
|
@ -30,8 +50,6 @@ from ereuse_devicehub.resources.tag.model import Tag
|
||||||
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
|
from ereuse_devicehub.resources.user.models import User
|
||||||
from ereuse_devicehub.resources.action.models import Trade
|
|
||||||
from sqlalchemy import or_
|
|
||||||
|
|
||||||
|
|
||||||
class LotDeviceForm(FlaskForm):
|
class LotDeviceForm(FlaskForm):
|
||||||
|
@ -47,9 +65,14 @@ class LotDeviceForm(FlaskForm):
|
||||||
self._lot = (
|
self._lot = (
|
||||||
Lot.query.outerjoin(Trade)
|
Lot.query.outerjoin(Trade)
|
||||||
.filter(Lot.id == self.lot.data)
|
.filter(Lot.id == self.lot.data)
|
||||||
.filter(or_(Trade.user_from == g.user,
|
.filter(
|
||||||
Trade.user_to == g.user,
|
or_(
|
||||||
Lot.owner_id == g.user.id)).one()
|
Trade.user_from == g.user,
|
||||||
|
Trade.user_to == g.user,
|
||||||
|
Lot.owner_id == g.user.id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.one()
|
||||||
)
|
)
|
||||||
|
|
||||||
devices = set(self.devices.data.split(","))
|
devices = set(self.devices.data.split(","))
|
||||||
|
@ -163,7 +186,7 @@ class UploadSnapshotForm(FlaskForm):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def save(self):
|
def save(self, commit=True):
|
||||||
if any([x == 'Error' for x in self.result.values()]):
|
if any([x == 'Error' for x in self.result.values()]):
|
||||||
return
|
return
|
||||||
# result = []
|
# result = []
|
||||||
|
@ -185,7 +208,8 @@ class UploadSnapshotForm(FlaskForm):
|
||||||
|
|
||||||
move_json(self.tmp_snapshots, path_snapshot, g.user.email)
|
move_json(self.tmp_snapshots, path_snapshot, g.user.email)
|
||||||
|
|
||||||
db.session.commit()
|
if commit:
|
||||||
|
db.session.commit()
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def build(self, snapshot_json): # noqa: C901
|
def build(self, snapshot_json): # noqa: C901
|
||||||
|
@ -355,7 +379,7 @@ class NewDeviceForm(FlaskForm):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def save(self):
|
def save(self, commit=True):
|
||||||
|
|
||||||
json_snapshot = {
|
json_snapshot = {
|
||||||
'type': 'Snapshot',
|
'type': 'Snapshot',
|
||||||
|
@ -411,7 +435,8 @@ class NewDeviceForm(FlaskForm):
|
||||||
snapshot.device.resolution = self.resolution.data
|
snapshot.device.resolution = self.resolution.data
|
||||||
snapshot.device.screen = self.screen.data
|
snapshot.device.screen = self.screen.data
|
||||||
|
|
||||||
db.session.commit()
|
if commit:
|
||||||
|
db.session.commit()
|
||||||
return snapshot
|
return snapshot
|
||||||
|
|
||||||
|
|
||||||
|
@ -466,11 +491,17 @@ 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_by(
|
tags = (
|
||||||
device_id=self.device_id
|
Tag.query.filter(Tag.owner_id == g.user.id)
|
||||||
).order_by(Tag.id)
|
.filter_by(device_id=self.device_id)
|
||||||
|
.order_by(Tag.id)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
tags = Tag.query.filter(Tag.owner_id == g.user.id).filter_by(device_id=None).order_by(Tag.id)
|
tags = (
|
||||||
|
Tag.query.filter(Tag.owner_id == g.user.id)
|
||||||
|
.filter_by(device_id=None)
|
||||||
|
.order_by(Tag.id)
|
||||||
|
)
|
||||||
|
|
||||||
self.tag.choices = [(tag.id, tag.id) for tag in tags]
|
self.tag.choices = [(tag.id, tag.id) for tag in tags]
|
||||||
|
|
||||||
|
@ -729,9 +760,14 @@ class TradeForm(NewActionForm):
|
||||||
self._lot = (
|
self._lot = (
|
||||||
Lot.query.outerjoin(Trade)
|
Lot.query.outerjoin(Trade)
|
||||||
.filter(Lot.id == self.lot.data)
|
.filter(Lot.id == self.lot.data)
|
||||||
.filter(or_(Trade.user_from == g.user,
|
.filter(
|
||||||
Trade.user_to == g.user,
|
or_(
|
||||||
Lot.owner_id == g.user.id)).one()
|
Trade.user_from == g.user,
|
||||||
|
Trade.user_to == g.user,
|
||||||
|
Lot.owner_id == g.user.id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.one()
|
||||||
)
|
)
|
||||||
|
|
||||||
def validate(self, extra_validators=None):
|
def validate(self, extra_validators=None):
|
||||||
|
|
|
@ -40,15 +40,9 @@ devices = Blueprint('inventory.devices', __name__, url_prefix='/inventory')
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DeviceListMix(View):
|
class GenericMixView(View):
|
||||||
decorators = [login_required]
|
def get_lots(self):
|
||||||
template_name = 'inventory/device_list.html'
|
return (
|
||||||
|
|
||||||
def get_context(self, lot_id):
|
|
||||||
# TODO @cayop adding filter
|
|
||||||
# https://github.com/eReuse/devicehub-teal/blob/testing/ereuse_devicehub/resources/device/views.py#L56
|
|
||||||
filter_types = ['Desktop', 'Laptop', 'Server']
|
|
||||||
lots = (
|
|
||||||
Lot.query.outerjoin(Trade)
|
Lot.query.outerjoin(Trade)
|
||||||
.filter(
|
.filter(
|
||||||
or_(
|
or_(
|
||||||
|
@ -59,6 +53,17 @@ class DeviceListMix(View):
|
||||||
)
|
)
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceListMix(GenericMixView):
|
||||||
|
decorators = [login_required]
|
||||||
|
template_name = 'inventory/device_list.html'
|
||||||
|
|
||||||
|
def get_context(self, lot_id):
|
||||||
|
# TODO @cayop adding filter
|
||||||
|
# https://github.com/eReuse/devicehub-teal/blob/testing/ereuse_devicehub/resources/device/views.py#L56
|
||||||
|
filter_types = ['Desktop', 'Laptop', 'Server']
|
||||||
|
lots = self.get_lots()
|
||||||
lot = None
|
lot = None
|
||||||
tags = (
|
tags = (
|
||||||
Tag.query.filter(Tag.owner_id == current_user.id)
|
Tag.query.filter(Tag.owner_id == current_user.id)
|
||||||
|
@ -118,12 +123,12 @@ class DeviceListView(DeviceListMix):
|
||||||
return flask.render_template(self.template_name, **self.context)
|
return flask.render_template(self.template_name, **self.context)
|
||||||
|
|
||||||
|
|
||||||
class DeviceDetailView(View):
|
class DeviceDetailView(GenericMixView):
|
||||||
decorators = [login_required]
|
decorators = [login_required]
|
||||||
template_name = 'inventory/device_detail.html'
|
template_name = 'inventory/device_detail.html'
|
||||||
|
|
||||||
def dispatch_request(self, id):
|
def dispatch_request(self, id):
|
||||||
lots = Lot.query.filter(Lot.owner_id == current_user.id)
|
lots = self.get_lots()
|
||||||
device = (
|
device = (
|
||||||
Device.query.filter(Device.owner_id == current_user.id)
|
Device.query.filter(Device.owner_id == current_user.id)
|
||||||
.filter(Device.devicehub_id == id)
|
.filter(Device.devicehub_id == id)
|
||||||
|
@ -178,7 +183,7 @@ class LotDeviceDeleteView(View):
|
||||||
return flask.redirect(next_url)
|
return flask.redirect(next_url)
|
||||||
|
|
||||||
|
|
||||||
class LotCreateView(View):
|
class LotCreateView(GenericMixView):
|
||||||
methods = ['GET', 'POST']
|
methods = ['GET', 'POST']
|
||||||
decorators = [login_required]
|
decorators = [login_required]
|
||||||
template_name = 'inventory/lot.html'
|
template_name = 'inventory/lot.html'
|
||||||
|
@ -191,7 +196,7 @@ class LotCreateView(View):
|
||||||
next_url = url_for('inventory.devices.lotdevicelist', lot_id=form.id)
|
next_url = url_for('inventory.devices.lotdevicelist', lot_id=form.id)
|
||||||
return flask.redirect(next_url)
|
return flask.redirect(next_url)
|
||||||
|
|
||||||
lots = Lot.query.filter(Lot.owner_id == current_user.id)
|
lots = self.get_lots()
|
||||||
context = {'form': form, 'title': self.title, 'lots': lots}
|
context = {'form': form, 'title': self.title, 'lots': lots}
|
||||||
return flask.render_template(self.template_name, **context)
|
return flask.render_template(self.template_name, **context)
|
||||||
|
|
||||||
|
@ -232,33 +237,56 @@ class LotDeleteView(View):
|
||||||
return flask.redirect(next_url)
|
return flask.redirect(next_url)
|
||||||
|
|
||||||
|
|
||||||
class UploadSnapshotView(View):
|
class UploadSnapshotView(GenericMixView):
|
||||||
methods = ['GET', 'POST']
|
methods = ['GET', 'POST']
|
||||||
decorators = [login_required]
|
decorators = [login_required]
|
||||||
template_name = 'inventory/upload_snapshot.html'
|
template_name = 'inventory/upload_snapshot.html'
|
||||||
|
|
||||||
def dispatch_request(self):
|
def dispatch_request(self, lot_id=None):
|
||||||
lots = Lot.query.filter(Lot.owner_id == current_user.id).all()
|
lots = self.get_lots()
|
||||||
form = UploadSnapshotForm()
|
form = UploadSnapshotForm()
|
||||||
context = {'page_title': 'Upload Snapshot', 'lots': lots, 'form': form}
|
context = {
|
||||||
|
'page_title': 'Upload Snapshot',
|
||||||
|
'lots': lots,
|
||||||
|
'form': form,
|
||||||
|
'lot_id': lot_id,
|
||||||
|
}
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
form.save()
|
snapshot = form.save(commit=False)
|
||||||
|
if lot_id:
|
||||||
|
lot = lots.filter(Lot.id == lot_id).one()
|
||||||
|
lot.devices.add(snapshot.device)
|
||||||
|
db.session.add(lot)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
return flask.render_template(self.template_name, **context)
|
return flask.render_template(self.template_name, **context)
|
||||||
|
|
||||||
|
|
||||||
class DeviceCreateView(View):
|
class DeviceCreateView(GenericMixView):
|
||||||
methods = ['GET', 'POST']
|
methods = ['GET', 'POST']
|
||||||
decorators = [login_required]
|
decorators = [login_required]
|
||||||
template_name = 'inventory/device_create.html'
|
template_name = 'inventory/device_create.html'
|
||||||
|
|
||||||
def dispatch_request(self):
|
def dispatch_request(self, lot_id=None):
|
||||||
lots = Lot.query.filter(Lot.owner_id == current_user.id).all()
|
lots = self.get_lots()
|
||||||
form = NewDeviceForm()
|
form = NewDeviceForm()
|
||||||
context = {'page_title': 'New Device', 'lots': lots, 'form': form}
|
context = {
|
||||||
|
'page_title': 'New Device',
|
||||||
|
'lots': lots,
|
||||||
|
'form': form,
|
||||||
|
'lot_id': lot_id,
|
||||||
|
}
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
form.save()
|
snapshot = form.save(commit=False)
|
||||||
next_url = url_for('inventory.devices.devicelist')
|
next_url = url_for('inventory.devices.devicelist')
|
||||||
|
if lot_id:
|
||||||
|
next_url = url_for('inventory.devices.lotdevicelist', lot_id=lot_id)
|
||||||
|
lot = lots.filter(Lot.id == lot_id).one()
|
||||||
|
lot.devices.add(snapshot.device)
|
||||||
|
db.session.add(lot)
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
messages.success('Device "{}" created successfully!'.format(form.type.data))
|
||||||
return flask.redirect(next_url)
|
return flask.redirect(next_url)
|
||||||
|
|
||||||
return flask.render_template(self.template_name, **context)
|
return flask.render_template(self.template_name, **context)
|
||||||
|
@ -646,7 +674,15 @@ devices.add_url_rule('/lot/<string:id>/', view_func=LotUpdateView.as_view('lot_e
|
||||||
devices.add_url_rule(
|
devices.add_url_rule(
|
||||||
'/upload-snapshot/', view_func=UploadSnapshotView.as_view('upload_snapshot')
|
'/upload-snapshot/', view_func=UploadSnapshotView.as_view('upload_snapshot')
|
||||||
)
|
)
|
||||||
|
devices.add_url_rule(
|
||||||
|
'/lot/<string:lot_id>/upload-snapshot/',
|
||||||
|
view_func=UploadSnapshotView.as_view('lot_upload_snapshot'),
|
||||||
|
)
|
||||||
devices.add_url_rule('/device/add/', view_func=DeviceCreateView.as_view('device_add'))
|
devices.add_url_rule('/device/add/', view_func=DeviceCreateView.as_view('device_add'))
|
||||||
|
devices.add_url_rule(
|
||||||
|
'/lot/<string:lot_id>/device/add/',
|
||||||
|
view_func=DeviceCreateView.as_view('lot_device_add'),
|
||||||
|
)
|
||||||
devices.add_url_rule('/tag/', view_func=TagListView.as_view('taglist'))
|
devices.add_url_rule('/tag/', view_func=TagListView.as_view('taglist'))
|
||||||
devices.add_url_rule('/tag/add/', view_func=TagAddView.as_view('tag_add'))
|
devices.add_url_rule('/tag/add/', view_func=TagAddView.as_view('tag_add'))
|
||||||
devices.add_url_rule(
|
devices.add_url_rule(
|
||||||
|
|
|
@ -370,7 +370,11 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
{% if lot_id %}
|
||||||
|
<a href="{{ url_for('inventory.devices.lotdevicelist', lot_id=lot_id) }}" class="btn btn-danger">Cancel</a>
|
||||||
|
{% else %}
|
||||||
<a href="{{ url_for('inventory.devices.devicelist') }}" class="btn btn-danger">Cancel</a>
|
<a href="{{ url_for('inventory.devices.devicelist') }}" class="btn btn-danger">Cancel</a>
|
||||||
|
{% endif %}
|
||||||
<button class="btn btn-primary" type="submit">Save</button>
|
<button class="btn btn-primary" type="submit">Save</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -245,13 +245,21 @@
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" aria-labelledby="btnSnapshot">
|
<ul class="dropdown-menu" aria-labelledby="btnSnapshot">
|
||||||
<li>
|
<li>
|
||||||
|
{% if lot %}
|
||||||
|
<a href="{{ url_for('inventory.devices.lot_upload_snapshot', lot_id=lot.id) }}" class="dropdown-item">
|
||||||
|
{% else %}
|
||||||
<a href="{{ url_for('inventory.devices.upload_snapshot') }}" class="dropdown-item">
|
<a href="{{ url_for('inventory.devices.upload_snapshot') }}" class="dropdown-item">
|
||||||
|
{% endif %}
|
||||||
<i class="bi bi-plus"></i>
|
<i class="bi bi-plus"></i>
|
||||||
Upload a new Snapshot
|
Upload a new Snapshot
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
{% if lot %}
|
||||||
|
<a href="{{ url_for('inventory.devices.lot_device_add', lot_id=lot.id) }}" class="dropdown-item">
|
||||||
|
{% else %}
|
||||||
<a href="{{ url_for('inventory.devices.device_add') }}" class="dropdown-item">
|
<a href="{{ url_for('inventory.devices.device_add') }}" class="dropdown-item">
|
||||||
|
{% endif %}
|
||||||
<i class="bi bi-plus"></i>
|
<i class="bi bi-plus"></i>
|
||||||
Create a new Device
|
Create a new Device
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -55,7 +55,11 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
{% if lot_id %}
|
||||||
|
<a href="{{ url_for('inventory.devices.lotdevicelist', lot_id=lot_id) }}" class="btn btn-danger">Cancel</a>
|
||||||
|
{% else %}
|
||||||
<a href="{{ url_for('inventory.devices.devicelist') }}" class="btn btn-danger">Cancel</a>
|
<a href="{{ url_for('inventory.devices.devicelist') }}" class="btn btn-danger">Cancel</a>
|
||||||
|
{% endif %}
|
||||||
<button class="btn btn-primary" type="submit">Send</button>
|
<button class="btn btn-primary" type="submit">Send</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
Reference in New Issue