allow get device for export when is a share lot
This commit is contained in:
parent
e365c366f4
commit
0547e4cf32
|
@ -70,7 +70,7 @@ from ereuse_devicehub.resources.device.models import (
|
||||||
from ereuse_devicehub.resources.documents.models import DataWipeDocument
|
from ereuse_devicehub.resources.documents.models import DataWipeDocument
|
||||||
from ereuse_devicehub.resources.enums import Severity
|
from ereuse_devicehub.resources.enums import Severity
|
||||||
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, ShareLot
|
||||||
from ereuse_devicehub.resources.tag.model import Tag
|
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.models import User
|
from ereuse_devicehub.resources.user.models import User
|
||||||
|
@ -160,11 +160,14 @@ class FilterForm(FlaskForm):
|
||||||
'', choices=DEVICES, default="All Computers", render_kw={'class': "form-select"}
|
'', choices=DEVICES, default="All Computers", render_kw={'class': "form-select"}
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, lots, lot_id, *args, **kwargs):
|
def __init__(self, lots, lot, lot_id, *args, **kwargs):
|
||||||
self.all_devices = kwargs.pop('all_devices', False)
|
self.all_devices = kwargs.pop('all_devices', False)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.lots = lots
|
self.lots = lots
|
||||||
|
self.lot = lot
|
||||||
self.lot_id = lot_id
|
self.lot_id = lot_id
|
||||||
|
if self.lot_id and not self.lot:
|
||||||
|
self.lot = self.lots.filter(Lot.id == self.lot_id).one()
|
||||||
self._get_types()
|
self._get_types()
|
||||||
|
|
||||||
def _get_types(self):
|
def _get_types(self):
|
||||||
|
@ -175,8 +178,7 @@ class FilterForm(FlaskForm):
|
||||||
self.filter.data = self.device_type
|
self.filter.data = self.device_type
|
||||||
|
|
||||||
def filter_from_lots(self):
|
def filter_from_lots(self):
|
||||||
if self.lot_id:
|
if self.lot:
|
||||||
self.lot = self.lots.filter(Lot.id == self.lot_id).one()
|
|
||||||
device_ids = (d.id for d in self.lot.devices)
|
device_ids = (d.id for d in self.lot.devices)
|
||||||
self.devices = Device.query.filter(Device.id.in_(device_ids)).filter(
|
self.devices = Device.query.filter(Device.id.in_(device_ids)).filter(
|
||||||
Device.binding == None # noqa: E711
|
Device.binding == None # noqa: E711
|
||||||
|
@ -256,7 +258,8 @@ class LotForm(FlaskForm):
|
||||||
return self.id
|
return self.id
|
||||||
|
|
||||||
def remove(self):
|
def remove(self):
|
||||||
if self.instance and not self.instance.trade:
|
shared = ShareLot.query.filter_by(lot=self.instance).first()
|
||||||
|
if self.instance and not self.instance.trade and not shared:
|
||||||
self.instance.delete()
|
self.instance.delete()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return self.instance
|
return self.instance
|
||||||
|
|
|
@ -14,6 +14,7 @@ from flask import current_app as app
|
||||||
from flask import g, make_response, request, url_for
|
from flask import g, make_response, request, url_for
|
||||||
from flask.views import View
|
from flask.views import View
|
||||||
from flask_login import current_user, login_required
|
from flask_login import current_user, login_required
|
||||||
|
from sqlalchemy import or_
|
||||||
from werkzeug.exceptions import NotFound
|
from werkzeug.exceptions import NotFound
|
||||||
|
|
||||||
from ereuse_devicehub import messages
|
from ereuse_devicehub import messages
|
||||||
|
@ -51,7 +52,7 @@ from ereuse_devicehub.resources.device.models import (
|
||||||
from ereuse_devicehub.resources.documents.device_row import ActionRow, DeviceRow
|
from ereuse_devicehub.resources.documents.device_row import ActionRow, DeviceRow
|
||||||
from ereuse_devicehub.resources.enums import SnapshotSoftware
|
from ereuse_devicehub.resources.enums import 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, ShareLot
|
||||||
from ereuse_devicehub.resources.tag.model import Tag
|
from ereuse_devicehub.resources.tag.model import Tag
|
||||||
from ereuse_devicehub.views import GenericMixin
|
from ereuse_devicehub.views import GenericMixin
|
||||||
|
|
||||||
|
@ -73,19 +74,25 @@ class DeviceListMixin(GenericMixin):
|
||||||
per_page = int(request.args.get('per_page', PER_PAGE))
|
per_page = int(request.args.get('per_page', PER_PAGE))
|
||||||
filter = request.args.get('filter', "All+Computers")
|
filter = request.args.get('filter', "All+Computers")
|
||||||
|
|
||||||
|
lot = None
|
||||||
|
|
||||||
|
share_lots = self.context['share_lots']
|
||||||
|
share_lot = share_lots.filter_by(lot_id=lot_id).first()
|
||||||
|
if share_lot:
|
||||||
|
lot = share_lot.lot
|
||||||
|
|
||||||
lots = self.context['lots']
|
lots = self.context['lots']
|
||||||
form_filter = FilterForm(lots, lot_id, all_devices=all_devices)
|
form_filter = FilterForm(lots, lot, lot_id, all_devices=all_devices)
|
||||||
devices = form_filter.search().paginate(page=page, per_page=per_page)
|
devices = form_filter.search().paginate(page=page, per_page=per_page)
|
||||||
devices.first = per_page * devices.page - per_page + 1
|
devices.first = per_page * devices.page - per_page + 1
|
||||||
devices.last = len(devices.items) + devices.first - 1
|
devices.last = len(devices.items) + devices.first - 1
|
||||||
|
|
||||||
lot = None
|
|
||||||
form_transfer = ''
|
form_transfer = ''
|
||||||
form_delivery = ''
|
form_delivery = ''
|
||||||
form_receiver = ''
|
form_receiver = ''
|
||||||
form_customer_details = ''
|
form_customer_details = ''
|
||||||
|
|
||||||
if lot_id:
|
if lot_id and not lot:
|
||||||
lot = lots.filter(Lot.id == lot_id).one()
|
lot = lots.filter(Lot.id == lot_id).one()
|
||||||
if not lot.is_temporary and lot.transfer:
|
if not lot.is_temporary and lot.transfer:
|
||||||
form_transfer = EditTransferForm(lot_id=lot.id)
|
form_transfer = EditTransferForm(lot_id=lot.id)
|
||||||
|
@ -111,6 +118,7 @@ class DeviceListMixin(GenericMixin):
|
||||||
'list_devices': self.get_selected_devices(form_new_action),
|
'list_devices': self.get_selected_devices(form_new_action),
|
||||||
'all_devices': all_devices,
|
'all_devices': all_devices,
|
||||||
'filter': filter,
|
'filter': filter,
|
||||||
|
'share_lots': share_lots,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -537,8 +545,9 @@ class LotDeleteView(View):
|
||||||
|
|
||||||
def dispatch_request(self, id):
|
def dispatch_request(self, id):
|
||||||
form = LotForm(id=id)
|
form = LotForm(id=id)
|
||||||
if form.instance.trade:
|
shared = ShareLot.query.filter_by(lot=form.instance).first()
|
||||||
msg = "Sorry, the lot cannot be deleted because have a trade action "
|
if form.instance.trade or shared:
|
||||||
|
msg = "Sorry, the lot cannot be deleted because this lot is share"
|
||||||
messages.error(msg)
|
messages.error(msg)
|
||||||
next_url = url_for('inventory.lotdevicelist', lot_id=id)
|
next_url = url_for('inventory.lotdevicelist', lot_id=id)
|
||||||
return flask.redirect(next_url)
|
return flask.redirect(next_url)
|
||||||
|
@ -1005,9 +1014,21 @@ class ExportsView(View):
|
||||||
return export_ids[export_id]()
|
return export_ids[export_id]()
|
||||||
|
|
||||||
def find_devices(self):
|
def find_devices(self):
|
||||||
|
sql = """
|
||||||
|
select lot_device.device_id as id from
|
||||||
|
{schema}.share_lot as share
|
||||||
|
join {schema}.lot_device as lot_device on
|
||||||
|
share.lot_id=lot_device.lot_id
|
||||||
|
where share.user_to_id='{user_id}'
|
||||||
|
""".format(
|
||||||
|
schema='dbtest', user_id=g.user.id
|
||||||
|
)
|
||||||
|
|
||||||
|
shared = (x[0] for x in db.session.execute(sql))
|
||||||
|
|
||||||
args = request.args.get('ids')
|
args = request.args.get('ids')
|
||||||
ids = args.split(',') if args else []
|
ids = args.split(',') if args else []
|
||||||
query = Device.query.filter(Device.owner == g.user)
|
query = Device.query.filter(or_(Device.owner == g.user, Device.id.in_(shared)))
|
||||||
return query.filter(Device.devicehub_id.in_(ids))
|
return query.filter(Device.devicehub_id.in_(ids))
|
||||||
|
|
||||||
def response_csv(self, data, name):
|
def response_csv(self, data, name):
|
||||||
|
|
|
@ -124,7 +124,10 @@ class Lot(Thing):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_temporary(self):
|
def is_temporary(self):
|
||||||
return not bool(self.trade) and not bool(self.transfer)
|
trade = bool(self.trade)
|
||||||
|
transfer = bool(self.transfer)
|
||||||
|
owner = self.owner == g.user
|
||||||
|
return not trade and not transfer and owner
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_incoming(self):
|
def is_incoming(self):
|
||||||
|
@ -144,6 +147,19 @@ class Lot(Thing):
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_shared(self):
|
||||||
|
try:
|
||||||
|
self.shared
|
||||||
|
except Exception:
|
||||||
|
self.shared = ShareLot.query.filter_by(
|
||||||
|
lot_id=self.id, user_to=g.user
|
||||||
|
).first()
|
||||||
|
|
||||||
|
if self.shared:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def descendantsq(cls, id):
|
def descendantsq(cls, id):
|
||||||
_id = UUIDLtree.convert(id)
|
_id = UUIDLtree.convert(id)
|
||||||
|
|
|
@ -276,7 +276,28 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% if share_lots.all() %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link collapsed" data-bs-target="#share-lots-nav" data-bs-toggle="collapse" href="javascript:void()">
|
||||||
|
<i class="bi bi-share-fill"></i><span>Shared with me</span><i
|
||||||
|
class="bi bi-chevron-down ms-auto"></i>
|
||||||
|
</a>
|
||||||
|
{% if lot.is_shared %}
|
||||||
|
<ul id="share-lots-nav" class="nav-content collapse show" data-bs-parent="#sidebar-nav">
|
||||||
|
{% else %}
|
||||||
|
<ul id="share-lots-nav" class="nav-content collapse " data-bs-parent="#sidebar-nav">
|
||||||
|
{% endif %}
|
||||||
|
{% for lot in share_lots %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ url_for('inventory.lotdevicelist', lot_id=lot.lot_id) }}">
|
||||||
|
<i class="bi bi-circle"></i><span>{{ lot.lot.name }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
</li><!-- End Temporal Lots Nav -->
|
</li><!-- End Temporal Lots Nav -->
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
{% elif lot.is_outgoing %}
|
{% elif lot.is_outgoing %}
|
||||||
<li class="breadcrumb-item active">Outgoing Lot</li>
|
<li class="breadcrumb-item active">Outgoing Lot</li>
|
||||||
<li class="breadcrumb-item active">{{ lot.name }}</li>
|
<li class="breadcrumb-item active">{{ lot.name }}</li>
|
||||||
|
{% elif lot.is_shared %}
|
||||||
|
<li class="breadcrumb-item active">Shared with me</li>
|
||||||
|
<li class="breadcrumb-item active">{{ lot.name }}</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -39,7 +42,9 @@
|
||||||
<div class="d-flex align-items-center justify-content-between row">
|
<div class="d-flex align-items-center justify-content-between row">
|
||||||
<div class="col-sm-12 col-md-5">
|
<div class="col-sm-12 col-md-5">
|
||||||
<h3>
|
<h3>
|
||||||
<a href="{{ url_for('inventory.lot_edit', id=lot.id) }}">{{ lot.name }}</a>
|
<a href="{{ url_for('inventory.lot_edit', id=lot.id) }}">
|
||||||
|
{{ lot.name }} {% if lot.is_shared %}<i class="bi bi-arrow-right"></i> {{ lot.owner.email }}{% endif %}
|
||||||
|
</a>
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -54,10 +59,12 @@
|
||||||
Create Incoming Lot
|
Create Incoming Lot
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if not lot.is_shared %}
|
||||||
<a class="text-danger" href="javascript:removeLot()">
|
<a class="text-danger" href="javascript:removeLot()">
|
||||||
<i class="bi bi-trash"></i> Delete Lot
|
<i class="bi bi-trash"></i> Delete Lot
|
||||||
</a>
|
</a>
|
||||||
<span class="d-none" id="activeRemoveLotModal" data-bs-toggle="modal" data-bs-target="#btnRemoveLots"></span>
|
<span class="d-none" id="activeRemoveLotModal" data-bs-toggle="modal" data-bs-target="#btnRemoveLots"></span>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -72,7 +79,7 @@
|
||||||
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#devices-list">Devices</button>
|
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#devices-list">Devices</button>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{% if lot and not lot.is_temporary %}
|
{% if lot and not lot.is_temporary and not lot.is_shared %}
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#trade-documents-list">Documents</button>
|
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#trade-documents-list">Documents</button>
|
||||||
</li>
|
</li>
|
||||||
|
@ -106,6 +113,7 @@
|
||||||
<div class="tab-content pt-1">
|
<div class="tab-content pt-1">
|
||||||
<div id="devices-list" class="tab-pane fade devices-list active show">
|
<div id="devices-list" class="tab-pane fade devices-list active show">
|
||||||
<label class="btn btn-primary " for="SelectAllBTN"><input type="checkbox" id="SelectAllBTN" autocomplete="off"></label>
|
<label class="btn btn-primary " for="SelectAllBTN"><input type="checkbox" id="SelectAllBTN" autocomplete="off"></label>
|
||||||
|
{% if not lot or not lot.is_shared %}
|
||||||
<div class="btn-group dropdown ml-1">
|
<div class="btn-group dropdown ml-1">
|
||||||
<button id="btnLots" type="button" onclick="processSelectedDevices()" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
<button id="btnLots" type="button" onclick="processSelectedDevices()" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
<i class="bi bi-folder2"></i>
|
<i class="bi bi-folder2"></i>
|
||||||
|
@ -329,6 +337,24 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if lot and lot.is_shared %}
|
||||||
|
<div class="btn-group dropdown m-1" uib-dropdown="">
|
||||||
|
<button id="btnExport" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
<i class="bi bi-reply"></i>
|
||||||
|
Exports
|
||||||
|
</button>
|
||||||
|
<span class="d-none" id="exportAlertModal" data-bs-toggle="modal" data-bs-target="#exportErrorModal"></span>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="btnExport">
|
||||||
|
<li>
|
||||||
|
<a href="javascript:export_file('devices')" class="dropdown-item">
|
||||||
|
<i class="bi bi-file-spreadsheet"></i>
|
||||||
|
Devices Spreadsheet
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div id="select-devices-info" class="alert alert-info mb-0 mt-3 d-none" role="alert">
|
<div id="select-devices-info" class="alert alert-info mb-0 mt-3 d-none" role="alert">
|
||||||
If this text is showing is because there are an error
|
If this text is showing is because there are an error
|
||||||
|
@ -514,7 +540,7 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if lot and not lot.is_temporary %}
|
{% if lot and not lot.is_temporary and not lot.is_shared %}
|
||||||
<div id="trade-documents-list" class="tab-pane fade trade-documents-list">
|
<div id="trade-documents-list" class="tab-pane fade trade-documents-list">
|
||||||
<div class="btn-group dropdown ml-1 mt-1" uib-dropdown="">
|
<div class="btn-group dropdown ml-1 mt-1" uib-dropdown="">
|
||||||
<a href="{{ url_for('inventory.transfer_document_add', lot_id=lot.id)}}" class="btn btn-primary">
|
<a href="{{ url_for('inventory.transfer_document_add', lot_id=lot.id)}}" class="btn btn-primary">
|
||||||
|
|
|
@ -11,7 +11,7 @@ from ereuse_devicehub import __version__, messages
|
||||||
from ereuse_devicehub.db import db
|
from ereuse_devicehub.db import db
|
||||||
from ereuse_devicehub.forms import LoginForm, PasswordForm, SanitizationEntityForm
|
from ereuse_devicehub.forms import LoginForm, PasswordForm, SanitizationEntityForm
|
||||||
from ereuse_devicehub.resources.action.models import Trade
|
from ereuse_devicehub.resources.action.models import Trade
|
||||||
from ereuse_devicehub.resources.lot.models import Lot
|
from ereuse_devicehub.resources.lot.models import Lot, ShareLot
|
||||||
from ereuse_devicehub.resources.user.models import User
|
from ereuse_devicehub.resources.user.models import User
|
||||||
from ereuse_devicehub.utils import is_safe_url
|
from ereuse_devicehub.utils import is_safe_url
|
||||||
|
|
||||||
|
@ -89,6 +89,7 @@ class GenericMixin(View):
|
||||||
self.context = {
|
self.context = {
|
||||||
'lots': self.get_lots(),
|
'lots': self.get_lots(),
|
||||||
'version': __version__,
|
'version': __version__,
|
||||||
|
'share_lots': ShareLot.query.filter_by(user_to=g.user),
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.context
|
return self.context
|
||||||
|
|
Reference in New Issue