diff --git a/ereuse_devicehub/migrations/versions/3ac2bc1897ce_adding_weight_to_tradedocuments.py b/ereuse_devicehub/migrations/versions/3ac2bc1897ce_adding_weight_to_tradedocuments.py index bb5d4b6f..38fa9b69 100644 --- a/ereuse_devicehub/migrations/versions/3ac2bc1897ce_adding_weight_to_tradedocuments.py +++ b/ereuse_devicehub/migrations/versions/3ac2bc1897ce_adding_weight_to_tradedocuments.py @@ -12,7 +12,7 @@ from alembic import context # revision identifiers, used by Alembic. revision = '3ac2bc1897ce' -down_revision = '0103a9c96b2d' +down_revision = '7ecb8ff7abad' branch_labels = None depends_on = None diff --git a/ereuse_devicehub/resources/action/views/documents.py b/ereuse_devicehub/resources/action/views/documents.py index 3f3aaa84..4224f69f 100644 --- a/ereuse_devicehub/resources/action/views/documents.py +++ b/ereuse_devicehub/resources/action/views/documents.py @@ -3,7 +3,7 @@ import copy from ereuse_devicehub.db import db from ereuse_devicehub.resources.action.models import DataWipe from ereuse_devicehub.resources.documents.models import DataWipeDocument -from ereuse_devicehub.resources.device.models import DataStorage +from ereuse_devicehub.resources.device.models import DataStorage from ereuse_devicehub.resources.documents.schemas import DataWipeDocument as sh_document from ereuse_devicehub.resources.hash_reports import ReportHash @@ -29,17 +29,17 @@ class ErasedView(): schema = sh_document() [data.pop(x, None) for x in ['severity', 'devices', 'name', 'description']] doc_data = schema.load(data) - doc_data['type'] = 'DataWipe' + # doc_data['type'] = 'DataWipe' self.document = DataWipeDocument(**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', 'software', 'success']] self.data = self.schema.load(data) - + for dev in self.data['devices']: if not hasattr(dev, 'components'): continue diff --git a/ereuse_devicehub/resources/documents/documents.py b/ereuse_devicehub/resources/documents/documents.py index f45cf808..079d763d 100644 --- a/ereuse_devicehub/resources/documents/documents.py +++ b/ereuse_devicehub/resources/documents/documents.py @@ -283,6 +283,28 @@ class StampsView(View): result=result) +class RecycleDocumentView(View): + """ + This view allow save one document as a proof of one container with some weight was send to recycling. + """ + + def post(self): + from flask import jsonify + from ereuse_devicehub.resources.documents.models import RecycleDocument + from ereuse_devicehub.resources.documents.schemas import RecycleDocument as sh_document + data = request.get_data() + schema = sh_document() + doc = schema.loads(data) + document = RecycleDocument(**doc) + db.session.add(document) + + db.session().final_flush() + ret = jsonify(document) + ret.status_code = 201 + db.session.commit() + return ret + + class InternalStatsView(DeviceView): @cache(datetime.timedelta(minutes=1)) def find(self, args: dict): @@ -428,3 +450,7 @@ class DocumentDef(Resource): auth=app.auth) wbconf_view = app.auth.requires_auth(wbconf_view) self.add_url_rule('/wbconf/', view_func=wbconf_view, methods=get) + + recycle_doc_view = RecycleDocumentView.as_view('RecycleDocumentView', definition=self, auth=app.auth) + self.add_url_rule('/recycle/', defaults={}, view_func=recycle_doc_view, methods={'POST'}) + diff --git a/ereuse_devicehub/resources/documents/models.py b/ereuse_devicehub/resources/documents/models.py index ee2ac071..bf2ae1a5 100644 --- a/ereuse_devicehub/resources/documents/models.py +++ b/ereuse_devicehub/resources/documents/models.py @@ -1,14 +1,23 @@ -from citext import CIText from flask import g +from citext import CIText +from sortedcontainers import SortedSet from sqlalchemy import BigInteger, Column, Sequence, Unicode, Boolean, ForeignKey from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.dialects.postgresql import UUID -from teal.db import URL +from sqlalchemy.orm import backref +from teal.db import CASCADE_OWN, URL + from ereuse_devicehub.db import db from ereuse_devicehub.resources.user.models import User from ereuse_devicehub.resources.models import Thing, STR_SM_SIZE +_sorted_documents = { + 'order_by': lambda: Document.created, + 'collection_class': SortedSet +} + + class Document(Thing): """This represent a generic document.""" @@ -16,7 +25,7 @@ class Document(Thing): id.comment = """The identifier of the device for this database. Used only internally for software; users should not use this. """ - type = Column(Unicode(STR_SM_SIZE), nullable=False) + document_type = Column(Unicode(STR_SM_SIZE), nullable=False) date = Column(db.DateTime, nullable=True) date.comment = """The date of document, some documents need to have one date """ @@ -55,3 +64,26 @@ class DataWipeDocument(JoinedTableMixin, Document): def __str__(self) -> str: return '{0.file_name}'.format(self) + + +from ereuse_devicehub.resources.tradedocument.models import TradeDocument +class RecycleDocument(JoinedTableMixin, Document): + """Document than proof how any of weight go to recycling.""" + + weight = db.Column(db.Float(nullable=True)) + weight.comment = """Weight than go to recycling""" + trade_document_id = db.Column(db.BigInteger, db.ForeignKey(TradeDocument.id)) + trade_document_id.comment = """This is the trade document used for send material to recyle""" + lot_id = db.Column(UUID(as_uuid=True), + db.ForeignKey('lot.id'), + nullable=False) + lot_id.comment = """This lot is the input lot if the material that will then go definitively to recycling""" + lot = db.relationship('Lot', + backref=backref('recycling_documents', + lazy=True, + cascade=CASCADE_OWN, + **_sorted_documents), + primaryjoin='RecycleDocument.lot_id == Lot.id') + + def __str__(self) -> str: + return '{0.file_name}'.format(self) diff --git a/ereuse_devicehub/resources/documents/schemas.py b/ereuse_devicehub/resources/documents/schemas.py index c9df245f..4ead41f0 100644 --- a/ereuse_devicehub/resources/documents/schemas.py +++ b/ereuse_devicehub/resources/documents/schemas.py @@ -1,13 +1,16 @@ -from marshmallow.fields import DateTime, Integer, validate, Boolean +from marshmallow.fields import DateTime, Integer, validate, Boolean, Float +from marshmallow import post_load +from marshmallow.validate import Range from teal.marshmallow import SanitizedStr, URL +from ereuse_devicehub.marshmallow import NestedOn from ereuse_devicehub.resources.schemas import Thing +from ereuse_devicehub.resources.tradedocument.models import TradeDocument from ereuse_devicehub.resources.documents import models as m class DataWipeDocument(Thing): __doc__ = m.DataWipeDocument.__doc__ id = Integer(description=m.DataWipeDocument.id.comment, dump_only=True) - type = SanitizedStr(default='DataWipeDocument') url = URL(required= False, description=m.DataWipeDocument.url.comment) success = Boolean(required=False, default=False, description=m.DataWipeDocument.success.comment) software = SanitizedStr(description=m.DataWipeDocument.software.comment) @@ -26,3 +29,27 @@ class DataWipeDocument(Thing): default='', description=m.DataWipeDocument.file_hash.comment, validate=validate.Length(max=64)) + + @post_load + def get_trade_document(self, data): + data['document_type'] = 'DataWipeDocument' + + +class RecycleDocument(Thing): + __doc__ = m.DataWipeDocument.__doc__ + file_hash = SanitizedStr(data_key='hash', + default='', + description=m.RecycleDocument.file_hash.comment, + validate=validate.Length(max=64)) + weight = Float(required=False, validate=Range(0.1), description=m.RecycleDocument.weight.comment) + lot = NestedOn('Lot', only_query='id', description=m.RecycleDocument.lot.__doc__) + + @post_load + def get_trade_document(self, data): + tradedocument = TradeDocument.query.filter_by(file_hash=data['file_hash']).one() + data['trade_document_id'] = tradedocument.id + data['file_name'] = tradedocument.file_name + data['date'] = tradedocument.date + data['id_document'] = tradedocument.id_document + data['url'] = tradedocument.url + data['document_type'] = 'RecycleDocument' diff --git a/ereuse_devicehub/resources/tradedocument/models.py b/ereuse_devicehub/resources/tradedocument/models.py index e1326613..354fbb4d 100644 --- a/ereuse_devicehub/resources/tradedocument/models.py +++ b/ereuse_devicehub/resources/tradedocument/models.py @@ -1,4 +1,3 @@ -import copy from citext import CIText from flask import g diff --git a/tests/test_documents.py b/tests/test_documents.py index 9f80b5ea..9ed874b2 100644 --- a/tests/test_documents.py +++ b/tests/test_documents.py @@ -705,12 +705,40 @@ def test_trade_documents_with_weight(user: UserClient): """Tests upload one document""" lot, _ = user.post({'name': 'MyLot'}, res=Lot) + # long url + url = 'http://www.ereuse.org/apapaapaapaapaapaapaapaapaapaapapaapaapaapaapaapaapaapaapaapapaapaapaapaapaapaapaapaapaapaaaa', request_post = { 'filename': 'test.pdf', 'hash': 'bbbbbbbb', - 'url': 'http://www.ereuse.org/', + 'url': url, 'weight': 15, 'lot': lot['id'] } doc, _ = user.post(res=TradeDocument, data=request_post) assert doc['weight'] == request_post['weight'] + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_recycle_document(user: UserClient): + """Tests upload one document""" + + lotIn, _ = user.post({'name': 'MyLotIn'}, res=Lot) + lotOut, _ = user.post({'name': 'MyLotOut'}, res=Lot) + url = 'http://www.ereuse.org/apapaapaapaapaapaapaapaapaapaapapaapaapaapaapaapaapaapaapaapapaapaapaapaapaapaapaapaapaapaaaa', + request_post = { + 'filename': 'test.pdf', + 'hash': 'bbbbbbbb', + 'url': url, + 'weight': 15, + 'lot': lotOut['id'] + } + tradedocument, _ = user.post(res=TradeDocument, data=request_post) + # import pdb; pdb.set_trace() + request_post2 = { + 'weight': 15, + 'hash': tradedocument['hash'], + 'lot': lotIn['id'] + } + doc, _ = user.post(res=documents.DocumentDef.t, item='recycle/', data=request_post2) + assert doc == request_post['filename']