diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 63a0458c..e26265b1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,6 +7,7 @@ repos: rev: 5.9.3 hooks: - id: isort + # args: ["--profile", "black", "--filter-files"] - repo: https://github.com/PyCQA/flake8 rev: 4.0.1 hooks: diff --git a/ereuse_devicehub/cli.py b/ereuse_devicehub/cli.py index 47cece32..67054095 100644 --- a/ereuse_devicehub/cli.py +++ b/ereuse_devicehub/cli.py @@ -1,8 +1,8 @@ import os import click.testing -import ereuse_utils import flask.cli +import ereuse_utils from ereuse_devicehub.config import DevicehubConfig from ereuse_devicehub.devicehub import Devicehub diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index 6b3955de..91b80305 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -1,7 +1,6 @@ import copy import json from json.decoder import JSONDecodeError - from boltons.urlutils import URL from flask import g, request from flask_wtf import FlaskForm @@ -139,7 +138,7 @@ class LotDeviceForm(FlaskForm): return bool(self._devices) - def save(self): + def save(self, commit=True): trade = self._lot.trade if trade: for dev in self._devices: @@ -149,12 +148,16 @@ class LotDeviceForm(FlaskForm): if self._devices: self._lot.devices.update(self._devices) db.session.add(self._lot) + + if commit: db.session.commit() - def remove(self): + def remove(self, commit=True): if self._devices: self._lot.devices.difference_update(self._devices) db.session.add(self._lot) + + if commit: db.session.commit() @@ -190,7 +193,7 @@ class LotForm(FlaskForm): return self.id def remove(self): - if self.instance and not self.instance.devices: + if self.instance and not self.instance.trade: self.instance.delete() db.session.commit() return self.instance @@ -541,9 +544,9 @@ class TagDeviceForm(FlaskForm): if self.delete: tags = Tag.query.filter(Tag.owner_id == g.user.id).filter_by( device_id=self.device_id - ) + ).order_by(Tag.id) else: - tags = Tag.query.filter(Tag.owner_id == g.user.id).filter_by(device_id=None) + 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] diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index f9629e59..0d3f2864 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -1,4 +1,5 @@ import csv +import logging from io import StringIO import flask @@ -6,10 +7,12 @@ import flask_weasyprint from flask import Blueprint, g, make_response, request, url_for from flask.views import View from flask_login import current_user, login_required -from werkzeug.exceptions import NotFound +from requests.exceptions import ConnectionError from sqlalchemy import or_ +from werkzeug.exceptions import NotFound from ereuse_devicehub import messages +from ereuse_devicehub.db import db from ereuse_devicehub.inventory.forms import ( AllocateForm, DataWipeForm, @@ -35,6 +38,8 @@ from ereuse_devicehub.resources.tag.model import Tag # TODO(@slamora): rename base 'inventory.devices' --> 'inventory' devices = Blueprint('inventory.devices', __name__, url_prefix='/inventory') +logger = logging.getLogger(__name__) + class DeviceListMix(View): decorators = [login_required] @@ -43,22 +48,28 @@ class DeviceListMix(View): def get_context(self, lot_id): form_filter = FilterForm() filter_types = form_filter.search() - - lots = Lot.query.outerjoin(Trade) \ - .filter(or_(Trade.user_from == g.user, - Trade.user_to == g.user, - Lot.owner_id == g.user.id)).distinct() + lots = ( + Lot.query.outerjoin(Trade) + .filter( + or_( + Trade.user_from == g.user, + Trade.user_to == g.user, + Lot.owner_id == g.user.id, + ) + ) + .distinct() + ) lot = None tags = ( Tag.query.filter(Tag.owner_id == current_user.id) .filter(Tag.device_id.is_(None)) - .order_by(Tag.created.desc()) + .order_by(Tag.id.asc()) ) if lot_id: lot = lots.filter(Lot.id == lot_id).one() devices = lot.devices - if filter_types: + if "All" not in filter_types: devices = [dev for dev in lot.devices if dev.type in filter_types] devices = sorted(devices, key=lambda x: x.updated, reverse=True) form_new_action = NewActionForm(lot=lot.id) @@ -145,10 +156,11 @@ class LotDeviceAddView(View): def dispatch_request(self): form = LotDeviceForm() if form.validate_on_submit(): - form.save() + form.save(commit=False) messages.success( 'Add devices to lot "{}" successfully!'.format(form._lot.name) ) + db.session.commit() else: messages.error('Error adding devices to lot!') @@ -164,10 +176,11 @@ class LotDeviceDeleteView(View): def dispatch_request(self): form = LotDeviceForm() if form.validate_on_submit(): - form.remove() + form.remove(commit=False) messages.success( 'Remove devices from lot "{}" successfully!'.format(form._lot.name) ) + db.session.commit() else: messages.error('Error removing devices from lot!') @@ -218,6 +231,12 @@ class LotDeleteView(View): def dispatch_request(self, id): form = LotForm(id=id) + if form.instance.trade: + msg = "Sorry, the lot cannot be deleted because have a trade action " + messages.error(msg) + next_url = url_for('inventory.devices.lotdevicelist', lot_id=id) + return flask.redirect(next_url) + form.remove() next_url = url_for('inventory.devices.devicelist') return flask.redirect(next_url) @@ -262,7 +281,7 @@ class TagListView(View): def dispatch_request(self): lots = Lot.query.filter(Lot.owner_id == current_user.id) - tags = Tag.query.filter(Tag.owner_id == current_user.id) + tags = Tag.query.filter(Tag.owner_id == current_user.id).order_by(Tag.id) context = { 'lots': lots, 'tags': tags, @@ -298,7 +317,18 @@ class TagAddUnnamedView(View): context = {'page_title': 'New Unnamed Tag', 'lots': lots} form = TagUnnamedForm() if form.validate_on_submit(): - form.save() + try: + form.save() + except ConnectionError as e: + logger.error( + "Error while trying to connect to tag server: {}".format(e) + ) + msg = ( + "Sorry, we cannot create the unnamed tags requested because " + "some error happens while connecting to the tag server!" + ) + messages.error(msg) + next_url = url_for('inventory.devices.taglist') return flask.redirect(next_url) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 16b9df5b..89ddc846 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -474,6 +474,13 @@ class Device(Thing): key=attrgetter('type')) # last test of each type return self._warning_actions(current_tests) + @property + def verbose_name(self): + type = self.type or '' + manufacturer = self.manufacturer or '' + model = self.model or '' + return f'{type} {manufacturer} {model}' + @declared_attr def __mapper_args__(cls): """Defines inheritance. diff --git a/ereuse_devicehub/static/js/main_inventory.js b/ereuse_devicehub/static/js/main_inventory.js index d790af81..86c25a82 100644 --- a/ereuse_devicehub/static/js/main_inventory.js +++ b/ereuse_devicehub/static/js/main_inventory.js @@ -59,18 +59,39 @@ function deviceSelect() { } } +function removeLot() { + var devices = $(".deviceSelect"); + if (devices.length > 0) { + $("#btnRemoveLots .text-danger").show(); + } else { + $("#btnRemoveLots .text-danger").hide(); + } + $("#activeRemoveLotModal").click(); +} + function removeTag() { var devices = $(".deviceSelect").filter(':checked'); var devices_id = $.map(devices, function(x) { return $(x).attr('data')}); - if (devices_id.length > 0) { + if (devices_id.length == 1) { var url = "/inventory/tag/devices/"+devices_id[0]+"/del/"; window.location.href = url; + } else { + $("#unlinkTagAlertModal").click(); } } function addTag() { - deviceSelect(); - $("#addingTagModal").click(); + var devices = $(".deviceSelect").filter(':checked'); + var devices_id = $.map(devices, function(x) { return $(x).attr('data')}); + if (devices_id.length == 1) { + $("#addingTagModal .pol").hide(); + $("#addingTagModal .btn-primary").show(); + } else { + $("#addingTagModal .pol").show(); + $("#addingTagModal .btn-primary").hide(); + } + + $("#addTagAlertModal").click(); } function newTrade(action) { diff --git a/ereuse_devicehub/static/js/print.pdf.js b/ereuse_devicehub/static/js/print.pdf.js index d7d9833a..5316e1ef 100644 --- a/ereuse_devicehub/static/js/print.pdf.js +++ b/ereuse_devicehub/static/js/print.pdf.js @@ -65,5 +65,5 @@ function printpdf() { min_tag_side = (Math.min(height, width)/2) + border; pdf.addImage(imgData, 'PNG', border, border, img_side, img_side); pdf.text(tag, max_tag_side, min_tag_side); - pdf.save('Tags.pdf'); + pdf.save('Tag_'+tag+'.pdf'); } diff --git a/ereuse_devicehub/templates/ereuse_devicehub/base.html b/ereuse_devicehub/templates/ereuse_devicehub/base.html index 5ca885f7..7b56a1ec 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/base.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/base.html @@ -17,9 +17,14 @@ + + + + + diff --git a/ereuse_devicehub/templates/inventory/addDevicestag.html b/ereuse_devicehub/templates/inventory/addDevicestag.html index cb929d37..5170b454 100644 --- a/ereuse_devicehub/templates/inventory/addDevicestag.html +++ b/ereuse_devicehub/templates/inventory/addDevicestag.html @@ -18,7 +18,7 @@
- You need select first some device for adding this in a tag + You need select first one device and only one for add this in a tag
diff --git a/ereuse_devicehub/templates/inventory/alert_unlink_tag_error.html b/ereuse_devicehub/templates/inventory/alert_unlink_tag_error.html new file mode 100644 index 00000000..b05fb40f --- /dev/null +++ b/ereuse_devicehub/templates/inventory/alert_unlink_tag_error.html @@ -0,0 +1,21 @@ + diff --git a/ereuse_devicehub/templates/inventory/device_create.html b/ereuse_devicehub/templates/inventory/device_create.html index 1296531f..8bcb5fae 100644 --- a/ereuse_devicehub/templates/inventory/device_create.html +++ b/ereuse_devicehub/templates/inventory/device_create.html @@ -31,7 +31,7 @@