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:
Santiago L 2022-03-08 22:09:52 +01:00 committed by GitHub
commit fb3a895b19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 137 additions and 49 deletions

View File

@ -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(
or_(
Trade.user_from == g.user,
Trade.user_to == g.user, Trade.user_to == g.user,
Lot.owner_id == g.user.id)).one() 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,6 +208,7 @@ class UploadSnapshotForm(FlaskForm):
move_json(self.tmp_snapshots, path_snapshot, g.user.email) move_json(self.tmp_snapshots, path_snapshot, g.user.email)
if commit:
db.session.commit() db.session.commit()
return response return response
@ -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,6 +435,7 @@ 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
if commit:
db.session.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(
or_(
Trade.user_from == g.user,
Trade.user_to == g.user, Trade.user_to == g.user,
Lot.owner_id == g.user.id)).one() Lot.owner_id == g.user.id,
)
)
.one()
) )
def validate(self, extra_validators=None): def validate(self, extra_validators=None):

View File

@ -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(

View File

@ -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>

View File

@ -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>

View File

@ -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>