oauth2: do not use the document hash as primary key for temp files (#22717)

It prevents a client from pushing the same file multiple times, which
makes temporary errors harder to handle (client would have to handle a
failure from the web-service). We allow any number of push of the same
document, orphans will be cleaned up by a background task, and storage
is not duplicated as document are deduplicated through their hash.
This commit is contained in:
Benjamin Dauvergne 2018-03-22 11:17:07 +01:00
parent d813e2b167
commit 59ec2bea1a
3 changed files with 45 additions and 14 deletions

View File

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.11 on 2018-03-22 10:16
from __future__ import unicode_literals
from django.db import migrations, models
import fargo.oauth2.models
class Migration(migrations.Migration):
dependencies = [
('oauth2', '0002_auto_20180321_2343'),
]
operations = [
migrations.RemoveField(
model_name='oauth2tempfile',
name='hash_key',
),
migrations.AddField(
model_name='oauth2tempfile',
name='creation_date',
field=models.DateTimeField(auto_now=True),
),
migrations.AddField(
model_name='oauth2tempfile',
name='uuid',
field=models.CharField(default=fargo.oauth2.models.generate_uuid, max_length=16, primary_key=True, serialize=False),
),
]

View File

@ -75,11 +75,8 @@ class OAuth2Authorize(models.Model):
class OAuth2TempFile(models.Model):
uuid = models.CharField(max_length=16, default=generate_uuid, primary_key=True)
client = models.ForeignKey(OAuth2Client)
hash_key = models.CharField(max_length=128, primary_key=True)
document = models.ForeignKey(Document)
filename = models.CharField(max_length=512)
def save(self, *args, **kwargs):
self.hash_key = self.document.content_hash
return super(OAuth2TempFile, self).save(*args, **kwargs)
creation_date = models.DateTimeField(auto_now=True)

View File

@ -131,10 +131,14 @@ def test_put_document(app, john_doe, oauth2_client):
}
assert len(OAuth2TempFile.objects.all()) == 0
resp = app.post(url, params=data, headers=headers, status=200)
# test that we can still push the same document
resp = app.post(url, params=data, headers=headers, status=200)
assert len(OAuth2TempFile.objects.all()) == 1
doc = OAuth2TempFile.objects.all()[0]
assert len(OAuth2TempFile.objects.all()) == 2
doc = OAuth2TempFile.objects.latest('creation_date')
location = reverse('oauth2-put-document-authorize', kwargs={'pk': doc.pk})
assert location in resp.location
@ -142,17 +146,17 @@ def test_put_document(app, john_doe, oauth2_client):
url = location + '?%s' % urlencode({'redirect_uri': 'https://example.com'})
resp = app.get(url, status=200)
assert len(UserDocument.objects.all()) == 0
resp = resp.forms[0].submit()
assert OAuth2TempFile.objects.count() == 2
assert UserDocument.objects.count() == 0
resp = resp.forms[0].submit()
assert resp.status_code == 302
assert resp.location == 'https://example.com'
try:
user_document = UserDocument.objects.get(user=john_doe, document=doc.document)
except UserDocument.DoesNotExist:
assert False
assert user_document.filename == 'Baudelaire.txt'
assert OAuth2TempFile.objects.count() == 1
assert UserDocument.objects.count() == 1
assert OAuth2TempFile.objects.get().document == UserDocument.objects.get().document
assert UserDocument.objects.filter(user=john_doe, document=doc.document, filename='Baudelaire.txt').exists()
def test_confirm_put_document_file_exception(app, oauth2_client, john_doe, user_doc):