diff --git a/ereuse_devicehub/resources/action/views/documents.py b/ereuse_devicehub/resources/action/views/documents.py index 65c20857..c21f9d42 100644 --- a/ereuse_devicehub/resources/action/views/documents.py +++ b/ereuse_devicehub/resources/action/views/documents.py @@ -13,6 +13,7 @@ from ereuse_devicehub.resources.action.models import ToErased from ereuse_devicehub.resources.documents.models import Document from ereuse_devicehub.resources.device.models import DataStorage from ereuse_devicehub.resources.documents.schemas import Document as sh_document +from ereuse_devicehub.resources.hash_reports import ReportHash class ErasedView(): @@ -39,6 +40,9 @@ class ErasedView(): doc_data['type'] = 'ToErased' self.document = Document(**doc_data) db.session.add(self.document) + + db_hash = ReportHash(hash3=self.document.file_hash) + db.session.add(db_hash) def insert_action(self, data): [data.pop(x, None) for x in ['url', 'documentId', 'filename', 'hash']] diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index ea585785..35937101 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -696,6 +696,25 @@ class Computer(Device): if privacy ) + @property + def external_document_erasure(self): + """Returns the external ``DataStorage`` proof of erasure. + """ + from ereuse_devicehub.resources.action.models import ToErased + urls = set() + try: + ev = self.last_action_of(ToErased) + urls.add(ev.document.url.to_text()) + except LookupError: + pass + + for comp in self.components: + if isinstance(comp, DataStorage): + doc = comp.external_document_erasure + if doc: + urls.add(doc) + return urls + def add_mac_to_hid(self, components_snap=None): """Returns the Naming.hid with the first mac of network adapter, following an alphabetical order. @@ -879,6 +898,17 @@ class DataStorage(JoinedComponentTableMixin, Component): v += ' – {} GB'.format(self.size // 1000 if self.size else '?') return v + @property + def external_document_erasure(self): + """Returns the external ``DataStorage`` proof of erasure. + """ + from ereuse_devicehub.resources.action.models import ToErased + try: + ev = self.last_action_of(ToErased) + return ev.document.url.to_text() + except LookupError: + return None + class HardDrive(DataStorage): pass diff --git a/ereuse_devicehub/resources/documents/documents.py b/ereuse_devicehub/resources/documents/documents.py index 26e94292..8e8db6ff 100644 --- a/ereuse_devicehub/resources/documents/documents.py +++ b/ereuse_devicehub/resources/documents/documents.py @@ -90,6 +90,7 @@ class DocumentView(DeviceView): res = flask.make_response(template) return res + @staticmethod def erasure(query: db.Query): def erasures(): @@ -114,6 +115,34 @@ class DocumentView(DeviceView): } return flask.render_template('documents/erasure.html', **params) +class ExternalErasureDocumentView(DeviceView): + @cache(datetime.timedelta(minutes=1)) + def find(self, args: dict): + query = (x for x in self.query(args) if x.owner_id == g.user.id) + return self.generate_post_csv(query) + + def generate_post_csv(self, query): + """Get device query and put information in csv format.""" + data = StringIO() + cw = csv.writer(data, delimiter=';', lineterminator="\n", quotechar='"') + cw.writerow(['Urls']) + for device in query: + if isinstance(device, devs.Computer): + urls = device.external_document_erasure + if urls: + cw.writerow(urls) + elif isinstance(device, devs.DataStorage): + url = device.external_document_erasure + if url: + cw.writerow(set(url)) + + bfile = data.getvalue().encode('utf-8') + output = make_response(bfile) + insert_hash(bfile) + output.headers['Content-Disposition'] = 'attachment; filename=export_urls_external_proof.csv' + output.headers['Content-type'] = 'text/csv' + return output + class DevicesDocumentView(DeviceView): @cache(datetime.timedelta(minutes=1)) @@ -291,7 +320,6 @@ class InternalStatsView(DeviceView): evs.Action.type.in_(('Snapshot', 'Live', 'Allocate', 'Deallocate'))) return self.generate_post_csv(query) - def generate_post_csv(self, query): d = {} for ac in query: @@ -417,6 +445,12 @@ class DocumentDef(Resource): self.add_url_rule('/internalstats/', defaults=d, view_func=internalstats_view, methods=get) + externalErasureDocument_view = ExternalErasureDocumentView.as_view( + 'ExternalErasureDocumentView', definition=self, auth=app.auth) + externalErasureDocument_view = app.auth.requires_auth(externalErasureDocument_view) + self.add_url_rule('/externalErasureDocuments/', defaults=d, + view_func=externalErasureDocument_view, methods=get) + actions_view = ActionsDocumentView.as_view('ActionsDocumentView', definition=self, auth=app.auth) diff --git a/tests/test_action.py b/tests/test_action.py index 951e91ab..bfdcebd2 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -6,6 +6,7 @@ import copy import pytest from datetime import datetime, timedelta +from io import BytesIO from dateutil.tz import tzutc from decimal import Decimal from typing import Tuple, Type @@ -2412,10 +2413,13 @@ def test_trade_case14(user: UserClient, user2: UserClient): @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) -def test_action_web_erase(user: UserClient): - # import pdb; pdb.set_trace() +def test_action_web_erase(user: UserClient, client: Client): + import hashlib + from ereuse_devicehub.resources.documents import documents + bfile = BytesIO(b'abc') + hash3 = hashlib.sha3_256(bfile.read()).hexdigest() snap, _ = user.post(file('acer.happy.battery.snapshot'), res=models.Snapshot) - request = {'type': 'ToErased', 'devices': [snap['device']['id']], 'name': 'borrado universal', 'severity': 'Info', 'description': 'nada que describir', 'url': 'http://www.google.com/', 'documentId': '33', 'endTime': '2021-07-07T22:00:00.000Z', 'filename': 'Certificado de borrado1.pdf', 'hash': 'fedbcbd057d25df9915ca9758b7537794148b896b66b3bbc972fe966dcced34b'} + request = {'type': 'ToErased', 'devices': [snap['device']['id']], 'name': 'borrado universal', 'severity': 'Info', 'description': 'nada que describir', 'url': 'http://www.google.com/', 'documentId': '33', 'endTime': '2021-07-07T22:00:00.000Z', 'filename': 'Certificado de borrado1.pdf', 'hash': hash3} user.post(res=models.Action, data=request) action = models.ToErased.query.one() @@ -2423,3 +2427,14 @@ def test_action_web_erase(user: UserClient): assert action in dev.actions assert action.document.file_hash == request['hash'] + + bfile = BytesIO(b'abc') + response, _ = client.post(res=documents.DocumentDef.t, + item='stamps/', + content_type='multipart/form-data', + accept='text/html', + data={'docUpload': [(bfile, 'example.csv')]}, + status=200) + assert "alert alert-info" in response + assert "100% coincidence." in response + assert not "alert alert-danger" in response diff --git a/tests/test_basic.py b/tests/test_basic.py index c04e8fb6..18973f6a 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -40,6 +40,7 @@ def test_api_docs(client: Client): '/documents/erasures/', '/documents/devices/', '/documents/stamps/', + '/documents/externalErasureDocuments/', '/documents/wbconf/{wbtype}', '/documents/internalstats/', '/documents/stock/',