From 2db8756f48b817ca97ff9598ec9cb559556cb2ed Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Tue, 27 Mar 2018 13:08:06 +0200 Subject: [PATCH] fargo: prevent pushing the same file many times (#22682) Bug was discovered because we added the creation_date non-null field as content_hash is the primary key. When saving a Document with the same content_hash, Django try to update the existing document by setting creation_date to NULL which fails. --- fargo/fargo/api_errors.py | 1 + fargo/fargo/api_views.py | 8 ++++++-- tests/test_api.py | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/fargo/fargo/api_errors.py b/fargo/fargo/api_errors.py index 8ad3a6b..7b2af1c 100644 --- a/fargo/fargo/api_errors.py +++ b/fargo/fargo/api_errors.py @@ -10,6 +10,7 @@ class APIError(ValidationError): NOT_STRING = {'code': 'not-string', 'msg': _('data is not a string')} TOO_BIG = {'code': 'too-big', 'msg': _('file is too big (limit is {limit})')} BOX_IS_FULL = {'code': 'box-is-full', 'msg': _('box is full (limit is {limit})')} + DOCUMENT_EXISTS = {'code': 'document-exists', 'msg': _('user already have this document')} def __init__(self, kind, **kwargs): assert hasattr(self, kind), 'error %s is not defined' % kind diff --git a/fargo/fargo/api_views.py b/fargo/fargo/api_views.py index 4c39445..0e27530 100644 --- a/fargo/fargo/api_views.py +++ b/fargo/fargo/api_views.py @@ -121,8 +121,12 @@ class PushDocument(CommonAPIMixin, GenericAPIView): document_file = data['file_b64_content'] if data.get('file_name'): document_file.name = data.get('file_name') - document = Document(content=document_file) - document.save() + content_hash = utils.sha256_of_file(document_file) + document, created = Document.objects.get_or_create( + content_hash=content_hash, + defaults={'content': document_file}) + if not created: + raise api_errors.APIError('DOCUMENT_EXISTS') user_document = UserDocument( user=data.get('user'), diff --git a/tests/test_api.py b/tests/test_api.py index b10168a..1753d30 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -83,6 +83,7 @@ def test_push_document(app, admin_user, john_doe): assert (models.UserDocument.objects.get().origin == models.Origin.objects.get()) + data['file_b64_content'] = base64.b64encode('coin2') data['deletable_by_user'] = False response = app.post_json(url, params=data, status=200) assert response.json['result'] == 1 @@ -90,6 +91,7 @@ def test_push_document(app, admin_user, john_doe): assert models.UserDocument.objects.count() == 2 # new document assert models.UserDocument.objects.filter(deletable_by_user=False).count() == 1 + data['file_b64_content'] = base64.b64encode('coin3') data['deletable_by_user'] = True response = app.post_json(url, params=data, status=200) assert response.json['result'] == 1