documents in devices
This commit is contained in:
parent
645bdf3750
commit
2f27095c84
|
@ -1392,7 +1392,7 @@ class DeviceDocumentForm(FlaskForm):
|
||||||
def validate(self, extra_validators=None):
|
def validate(self, extra_validators=None):
|
||||||
is_valid = super().validate(extra_validators)
|
is_valid = super().validate(extra_validators)
|
||||||
|
|
||||||
if g.user == self._device.owner:
|
if g.user != self._device.owner:
|
||||||
is_valid = False
|
is_valid = False
|
||||||
|
|
||||||
return is_valid
|
return is_valid
|
||||||
|
@ -1415,7 +1415,7 @@ class DeviceDocumentForm(FlaskForm):
|
||||||
|
|
||||||
if not self._obj.id:
|
if not self._obj.id:
|
||||||
db.session.add(self._obj)
|
db.session.add(self._obj)
|
||||||
self._device.documents.add(self._obj)
|
# self._device.documents.add(self._obj)
|
||||||
|
|
||||||
if commit:
|
if commit:
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from citext import CIText
|
from citext import CIText
|
||||||
|
from dateutil.tz import tzutc
|
||||||
from flask import g
|
from flask import g
|
||||||
from sortedcontainers import SortedSet
|
from sortedcontainers import SortedSet
|
||||||
from sqlalchemy import BigInteger, Column, Integer
|
from sqlalchemy import BigInteger, Column, Integer
|
||||||
|
@ -148,3 +149,13 @@ class DeviceDocument(Thing):
|
||||||
# db.Index('document_id', id, postgresql_using='hash'),
|
# db.Index('document_id', id, postgresql_using='hash'),
|
||||||
# db.Index('type_doc', type, postgresql_using='hash')
|
# db.Index('type_doc', type, postgresql_using='hash')
|
||||||
# )
|
# )
|
||||||
|
|
||||||
|
def get_url(self) -> str:
|
||||||
|
if self.url:
|
||||||
|
return self.url.to_text()
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return self.created.replace(tzinfo=tzutc()) < other.created.replace(
|
||||||
|
tzinfo=tzutc()
|
||||||
|
)
|
||||||
|
|
|
@ -569,27 +569,6 @@ class DocumentDeleteView(View):
|
||||||
return flask.redirect(next_url)
|
return flask.redirect(next_url)
|
||||||
|
|
||||||
|
|
||||||
class DeviceDocumentDeleteView(View):
|
|
||||||
methods = ['GET']
|
|
||||||
decorators = [login_required]
|
|
||||||
template_name = 'inventory/device_list.html'
|
|
||||||
form_class = TradeDocumentForm
|
|
||||||
|
|
||||||
def dispatch_request(self, lot_id, doc_id):
|
|
||||||
next_url = url_for('inventory.lotdevicelist', lot_id=lot_id)
|
|
||||||
form = self.form_class(lot=lot_id, document=doc_id)
|
|
||||||
try:
|
|
||||||
form.remove()
|
|
||||||
except Exception as err:
|
|
||||||
msg = "{}".format(err)
|
|
||||||
messages.error(msg)
|
|
||||||
return flask.redirect(next_url)
|
|
||||||
|
|
||||||
msg = "Document removed successfully."
|
|
||||||
messages.success(msg)
|
|
||||||
return flask.redirect(next_url)
|
|
||||||
|
|
||||||
|
|
||||||
class UploadSnapshotView(GenericMixin):
|
class UploadSnapshotView(GenericMixin):
|
||||||
methods = ['GET', 'POST']
|
methods = ['GET', 'POST']
|
||||||
decorators = [login_required]
|
decorators = [login_required]
|
||||||
|
@ -853,6 +832,48 @@ class NewDeviceDocumentView(GenericMixin):
|
||||||
return flask.render_template(self.template_name, **self.context)
|
return flask.render_template(self.template_name, **self.context)
|
||||||
|
|
||||||
|
|
||||||
|
class EditDeviceDocumentView(GenericMixin):
|
||||||
|
decorators = [login_required]
|
||||||
|
methods = ['POST', 'GET']
|
||||||
|
template_name = 'inventory/device_document.html'
|
||||||
|
form_class = DeviceDocumentForm
|
||||||
|
title = "Edit document"
|
||||||
|
|
||||||
|
def dispatch_request(self, dhid, doc_id):
|
||||||
|
self.form = self.form_class(dhid=dhid, document=doc_id)
|
||||||
|
self.get_context()
|
||||||
|
|
||||||
|
if self.form.validate_on_submit():
|
||||||
|
self.form.save()
|
||||||
|
messages.success('Edit document successfully!')
|
||||||
|
next_url = url_for('inventory.device_details', id=dhid)
|
||||||
|
return flask.redirect(next_url)
|
||||||
|
|
||||||
|
self.context.update({'form': self.form, 'title': self.title})
|
||||||
|
return flask.render_template(self.template_name, **self.context)
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceDocumentDeleteView(View):
|
||||||
|
methods = ['GET']
|
||||||
|
decorators = [login_required]
|
||||||
|
template_name = 'inventory/device_detail.html'
|
||||||
|
form_class = DeviceDocumentForm
|
||||||
|
|
||||||
|
def dispatch_request(self, dhid, doc_id):
|
||||||
|
self.form = self.form_class(dhid=dhid, document=doc_id)
|
||||||
|
next_url = url_for('inventory.device_details', id=dhid)
|
||||||
|
try:
|
||||||
|
self.form.remove()
|
||||||
|
except Exception as err:
|
||||||
|
msg = "{}".format(err)
|
||||||
|
messages.error(msg)
|
||||||
|
return flask.redirect(next_url)
|
||||||
|
|
||||||
|
msg = "Document removed successfully."
|
||||||
|
messages.success(msg)
|
||||||
|
return flask.redirect(next_url)
|
||||||
|
|
||||||
|
|
||||||
class NewTradeDocumentView(GenericMixin):
|
class NewTradeDocumentView(GenericMixin):
|
||||||
methods = ['POST', 'GET']
|
methods = ['POST', 'GET']
|
||||||
decorators = [login_required]
|
decorators = [login_required]
|
||||||
|
@ -875,7 +896,6 @@ class NewTradeDocumentView(GenericMixin):
|
||||||
|
|
||||||
|
|
||||||
class EditTransferDocumentView(GenericMixin):
|
class EditTransferDocumentView(GenericMixin):
|
||||||
|
|
||||||
decorators = [login_required]
|
decorators = [login_required]
|
||||||
methods = ['POST', 'GET']
|
methods = ['POST', 'GET']
|
||||||
template_name = 'inventory/trade_document.html'
|
template_name = 'inventory/trade_document.html'
|
||||||
|
@ -1601,6 +1621,14 @@ devices.add_url_rule(
|
||||||
'/device/<string:dhid>/document/add/',
|
'/device/<string:dhid>/document/add/',
|
||||||
view_func=NewDeviceDocumentView.as_view('device_document_add'),
|
view_func=NewDeviceDocumentView.as_view('device_document_add'),
|
||||||
)
|
)
|
||||||
|
devices.add_url_rule(
|
||||||
|
'/device/<string:dhid>/document/edit/<string:doc_id>',
|
||||||
|
view_func=EditDeviceDocumentView.as_view('device_document_edit'),
|
||||||
|
)
|
||||||
|
devices.add_url_rule(
|
||||||
|
'/device/<string:dhid>/document/del/<string:doc_id>',
|
||||||
|
view_func=DeviceDocumentDeleteView.as_view('device_document_del'),
|
||||||
|
)
|
||||||
devices.add_url_rule(
|
devices.add_url_rule(
|
||||||
'/lot/<string:lot_id>/transfer-document/add/',
|
'/lot/<string:lot_id>/transfer-document/add/',
|
||||||
view_func=NewTradeDocumentView.as_view('transfer_document_add'),
|
view_func=NewTradeDocumentView.as_view('transfer_document_add'),
|
||||||
|
|
|
@ -216,6 +216,7 @@
|
||||||
<th scope="col">File</th>
|
<th scope="col">File</th>
|
||||||
<th scope="col" data-type="date" data-format="YYYY-MM-DD hh:mm">Uploaded on</th>
|
<th scope="col" data-type="date" data-format="YYYY-MM-DD hh:mm">Uploaded on</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -232,7 +233,7 @@
|
||||||
{{ doc.created.strftime('%Y-%m-%d %H:%M')}}
|
{{ doc.created.strftime('%Y-%m-%d %H:%M')}}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{# url_for('inventory.transfer_document_edit', lot_id=lot.id, doc_id=doc.id)#" title="Edit document">
|
<a href="{{ url_for('inventory.device_document_edit', dhid=doc.device.dhid, doc_id=doc.id) }}" title="Edit document">
|
||||||
<i class="bi bi-pencil-square"></i>
|
<i class="bi bi-pencil-square"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
@ -259,7 +260,7 @@
|
||||||
|
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary-outline" data-bs-dismiss="modal">Cancel</button>
|
<button type="button" class="btn btn-secondary-outline" data-bs-dismiss="modal">Cancel</button>
|
||||||
<a href="{# url_for('inventory.document_del', lot_id=lot.id, doc_id=doc.id) #}" type="button" class="btn btn-danger">
|
<a href="{{ url_for('inventory.device_document_del', dhid=doc.device.dhid, doc_id=doc.id) }}" type="button" class="btn btn-danger">
|
||||||
Delete it!
|
Delete it!
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -55,6 +55,9 @@ def test_api_docs(client: Client):
|
||||||
'/inventory/device/add/',
|
'/inventory/device/add/',
|
||||||
'/inventory/device/{id}/',
|
'/inventory/device/{id}/',
|
||||||
'/inventory/device/{dhid}/binding/',
|
'/inventory/device/{dhid}/binding/',
|
||||||
|
'/inventory/device/{dhid}/document/del/{doc_id}',
|
||||||
|
'/inventory/device/{dhid}/document/edit/{doc_id}',
|
||||||
|
'/inventory/device/{dhid}/document/add/',
|
||||||
'/inventory/device/erasure/',
|
'/inventory/device/erasure/',
|
||||||
'/inventory/device/erasure/{orphans}/',
|
'/inventory/device/erasure/{orphans}/',
|
||||||
'/inventory/all/device/',
|
'/inventory/all/device/',
|
||||||
|
|
|
@ -2774,3 +2774,82 @@ def test_reliable_device(user3: UserClientFlask):
|
||||||
assert Snapshot.query.first() == snapshot
|
assert Snapshot.query.first() == snapshot
|
||||||
assert len(snapshot.device.components) == 8
|
assert len(snapshot.device.components) == 8
|
||||||
assert len(snapshot.device.actions) == 7
|
assert len(snapshot.device.actions) == 7
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.mvp
|
||||||
|
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||||
|
def test_add_device_document(user3: UserClientFlask):
|
||||||
|
snapshot = create_device(user3, 'real-eee-1001pxd.snapshot.12.json')
|
||||||
|
device = Device.query.filter_by(devicehub_id=snapshot.device.dhid).one()
|
||||||
|
uri = '/inventory/device/{}/document/add/'.format(device.dhid)
|
||||||
|
user3.get(uri)
|
||||||
|
|
||||||
|
name = "doc1.pdf"
|
||||||
|
url = "https://www.usody.com/"
|
||||||
|
file_name = (BytesIO(b'1234567890'), name)
|
||||||
|
data = {
|
||||||
|
'url': url,
|
||||||
|
'file_name': file_name,
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
}
|
||||||
|
|
||||||
|
user3.post(uri, data=data, content_type="multipart/form-data")
|
||||||
|
assert device.documents[0].file_name == name
|
||||||
|
assert device.documents[0].url.to_text() == url
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.mvp
|
||||||
|
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||||
|
def test_edit_device_document(user3: UserClientFlask):
|
||||||
|
snapshot = create_device(user3, 'real-eee-1001pxd.snapshot.12.json')
|
||||||
|
device = Device.query.filter_by(devicehub_id=snapshot.device.dhid).one()
|
||||||
|
uri = '/inventory/device/{}/document/add/'.format(device.dhid)
|
||||||
|
user3.get(uri)
|
||||||
|
|
||||||
|
name = "doc1.pdf"
|
||||||
|
url = "https://www.usody.com/"
|
||||||
|
file_name = (BytesIO(b'1234567890'), name)
|
||||||
|
data = {
|
||||||
|
'url': url,
|
||||||
|
'file_name': file_name,
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
}
|
||||||
|
|
||||||
|
user3.post(uri, data=data, content_type="multipart/form-data")
|
||||||
|
|
||||||
|
doc_id = str(device.documents[0].id)
|
||||||
|
uri = '/inventory/device/{}/document/edit/{}'.format(device.dhid, doc_id)
|
||||||
|
user3.get(uri)
|
||||||
|
|
||||||
|
data['url'] = "https://www.ereuse.org/"
|
||||||
|
data['csrf_token'] = generate_csrf()
|
||||||
|
data['file_name'] = (BytesIO(b'1234567890'), name)
|
||||||
|
|
||||||
|
user3.post(uri, data=data, content_type="multipart/form-data")
|
||||||
|
assert device.documents[0].file_name == name
|
||||||
|
assert device.documents[0].url.to_text() == data['url']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.mvp
|
||||||
|
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||||
|
def test_delete_device_document(user3: UserClientFlask):
|
||||||
|
snapshot = create_device(user3, 'real-eee-1001pxd.snapshot.12.json')
|
||||||
|
device = Device.query.filter_by(devicehub_id=snapshot.device.dhid).one()
|
||||||
|
uri = '/inventory/device/{}/document/add/'.format(device.dhid)
|
||||||
|
user3.get(uri)
|
||||||
|
|
||||||
|
name = "doc1.pdf"
|
||||||
|
url = "https://www.usody.com/"
|
||||||
|
file_name = (BytesIO(b'1234567890'), name)
|
||||||
|
data = {
|
||||||
|
'url': url,
|
||||||
|
'file_name': file_name,
|
||||||
|
'csrf_token': generate_csrf(),
|
||||||
|
}
|
||||||
|
|
||||||
|
user3.post(uri, data=data, content_type="multipart/form-data")
|
||||||
|
|
||||||
|
doc_id = str(device.documents[0].id)
|
||||||
|
uri = '/inventory/device/{}/document/del/{}'.format(device.dhid, doc_id)
|
||||||
|
user3.get(uri)
|
||||||
|
assert len(device.documents) == 0
|
||||||
|
|
Reference in a new issue