Revert "Add a send-to view (fixes #7080)"
This reverts commit 651681aa6e
.
This commit is contained in:
parent
d6b774ee47
commit
36437f440b
11
COPYING
11
COPYING
|
@ -1,11 +1,2 @@
|
||||||
Fargo is mainly under the copyright of Entr'ouvert and distributed
|
Fargo is entirely under the copyright of Entr'ouvert and distributed
|
||||||
under the license AGPLv3 or later.
|
under the license AGPLv3 or later.
|
||||||
|
|
||||||
A file was copied from the project django-multiupload
|
|
||||||
(https://github.com/Chive/django-multiupload) and licensed under the MIT
|
|
||||||
license.
|
|
||||||
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2014 Chive - Kim Thoenen (kim@smuzey.ch)
|
|
||||||
|
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copied from https://github.com/Chive/django-multiupload/blob/master/multiupload/fields.py
|
|
||||||
from django import forms
|
|
||||||
from django.core.exceptions import ValidationError
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
|
|
||||||
class MultiFileInput(forms.FileInput):
|
|
||||||
def render(self, name, value, attrs=None):
|
|
||||||
attrs['multiple'] = 'multiple'
|
|
||||||
return super(MultiFileInput, self).render(name, value, attrs)
|
|
||||||
|
|
||||||
def value_from_datadict(self, data, files, name):
|
|
||||||
if hasattr(files, 'getlist'):
|
|
||||||
return files.getlist(name)
|
|
||||||
else:
|
|
||||||
return [files.get(name)]
|
|
||||||
|
|
||||||
|
|
||||||
class MultiFileField(forms.FileField):
|
|
||||||
widget = MultiFileInput
|
|
||||||
default_error_messages = {
|
|
||||||
'min_num': _(u'Ensure at least %(min_num)s files are uploaded (received %(num_files)s).'),
|
|
||||||
'max_num': _(u'Ensure at most %(max_num)s files are uploaded (received %(num_files)s).'),
|
|
||||||
'file_size': _(u'File %(uploaded_file_name)s exceeded maximum upload size.'),
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
self.min_num = kwargs.pop('min_num', 0)
|
|
||||||
self.max_num = kwargs.pop('max_num', None)
|
|
||||||
self.maximum_file_size = kwargs.pop('max_file_size', None)
|
|
||||||
super(MultiFileField, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def to_python(self, data):
|
|
||||||
ret = []
|
|
||||||
for item in data:
|
|
||||||
i = super(MultiFileField, self).to_python(item)
|
|
||||||
if i:
|
|
||||||
ret.append(i)
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def validate(self, data):
|
|
||||||
super(MultiFileField, self).validate(data)
|
|
||||||
num_files = len(data)
|
|
||||||
if len(data) and not data[0]:
|
|
||||||
num_files = 0
|
|
||||||
if num_files < self.min_num:
|
|
||||||
raise ValidationError(self.error_messages['min_num'] % {'min_num': self.min_num, 'num_files': num_files})
|
|
||||||
elif self.max_num and num_files > self.max_num:
|
|
||||||
raise ValidationError(self.error_messages['max_num'] % {'max_num': self.max_num, 'num_files': num_files})
|
|
||||||
for uploaded_file in data:
|
|
||||||
if self.maximum_file_size and uploaded_file.size > self.maximum_file_size:
|
|
||||||
raise ValidationError(self.error_messages['file_size'] % {'uploaded_file_name': uploaded_file.name})
|
|
|
@ -1,14 +1,8 @@
|
||||||
import base64
|
from django.forms import ModelForm
|
||||||
|
|
||||||
from django.utils.text import slugify
|
from . import models
|
||||||
from django.core.exceptions import ValidationError
|
|
||||||
from django import forms
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from django.core.files.base import ContentFile
|
|
||||||
|
|
||||||
from . import models, fields
|
class UploadForm(ModelForm):
|
||||||
|
|
||||||
class UploadForm(forms.ModelForm):
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.user = kwargs.pop('user')
|
self.user = kwargs.pop('user')
|
||||||
super(UploadForm, self).__init__(*args, **kwargs)
|
super(UploadForm, self).__init__(*args, **kwargs)
|
||||||
|
@ -21,31 +15,3 @@ class UploadForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Document
|
model = models.Document
|
||||||
fields = ['document_file']
|
fields = ['document_file']
|
||||||
|
|
||||||
class SendToForm(forms.Form):
|
|
||||||
email = forms.EmailField()
|
|
||||||
documents = fields.MultiFileField()
|
|
||||||
|
|
||||||
def clean_email(self):
|
|
||||||
User = get_user_model()
|
|
||||||
try:
|
|
||||||
self.cached_user = User.objects.get(
|
|
||||||
email=self.cleaned_data['email'])
|
|
||||||
except User.DoesNotExist:
|
|
||||||
raise ValidationError('no such user')
|
|
||||||
return self.cleaned_data['email']
|
|
||||||
|
|
||||||
|
|
||||||
def clean_documents(self):
|
|
||||||
for i, document in enumerate(self.cleaned_data['documents']):
|
|
||||||
if not document.name or document.name == 'documents':
|
|
||||||
raise ValidationError('%d-th document is missing a name' % i)
|
|
||||||
return self.cleaned_data['documents']
|
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
|
||||||
for document in self.cleaned_data['documents']:
|
|
||||||
document = models.Document(
|
|
||||||
user=self.cached_user,
|
|
||||||
document_filename=document.name,
|
|
||||||
document_file=document)
|
|
||||||
document.save()
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import urlparse
|
import urlparse
|
||||||
import urllib
|
import urllib
|
||||||
import logging
|
import logging
|
||||||
import json
|
from json import dumps
|
||||||
|
|
||||||
from django.views.generic import CreateView, DeleteView, View, TemplateView
|
from django.views.generic import CreateView, DeleteView, View, TemplateView
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.shortcuts import get_object_or_404, resolve_url
|
from django.shortcuts import get_object_or_404, resolve_url
|
||||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, HttpResponseBadRequest
|
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden
|
||||||
from django.core import signing
|
from django.core import signing
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth import get_user_model, REDIRECT_FIELD_NAME
|
from django.contrib.auth import get_user_model, REDIRECT_FIELD_NAME
|
||||||
|
@ -181,7 +181,7 @@ class JSONP(Documents, View):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
callback = request.GET.get('callback', 'callback')
|
callback = request.GET.get('callback', 'callback')
|
||||||
s = '%s(%s)' % (callback.encode('ascii'),
|
s = '%s(%s)' % (callback.encode('ascii'),
|
||||||
json.dumps(self.get_data(request)))
|
dumps(self.get_data(request)))
|
||||||
return HttpResponse(s, content_type='application/javascript')
|
return HttpResponse(s, content_type='application/javascript')
|
||||||
|
|
||||||
class JSON(JSONP):
|
class JSON(JSONP):
|
||||||
|
@ -192,22 +192,11 @@ class JSON(JSONP):
|
||||||
request.user = get_object_or_404(User, username=username)
|
request.user = get_object_or_404(User, username=username)
|
||||||
elif not request.user.is_authenticated():
|
elif not request.user.is_authenticated():
|
||||||
return method_decorator(login_required)(JSON.get)(self, request)
|
return method_decorator(login_required)(JSON.get)(self, request)
|
||||||
response = HttpResponse(json.dumps(self.get_data(request)),
|
response = HttpResponse(dumps(self.get_data(request)),
|
||||||
content_type='application/json')
|
content_type='application/json')
|
||||||
response['Access-Control-Allow-Origin'] = '*'
|
response['Access-Control-Allow-Origin'] = '*'
|
||||||
return response
|
return response
|
||||||
|
|
||||||
class SendTo(View):
|
|
||||||
http_method_allowed = ['post']
|
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
|
||||||
form = forms.SendToForm(request.GET, request.FILES)
|
|
||||||
if form.is_valid():
|
|
||||||
form.save()
|
|
||||||
return HttpResponse('ok', content_type='text/plain')
|
|
||||||
else:
|
|
||||||
result = {'errors': form.errors}
|
|
||||||
return HttpResponseBadRequest(json.dumps(result))
|
|
||||||
|
|
||||||
def login(request, *args, **kwargs):
|
def login(request, *args, **kwargs):
|
||||||
if any(get_idps()):
|
if any(get_idps()):
|
||||||
|
@ -234,8 +223,7 @@ document = login_required(Document.as_view())
|
||||||
download = login_required(Download.as_view())
|
download = login_required(Download.as_view())
|
||||||
upload = login_required(Upload.as_view())
|
upload = login_required(Upload.as_view())
|
||||||
remote_download = RemoteDownload.as_view()
|
remote_download = RemoteDownload.as_view()
|
||||||
send_to = SendTo.as_view()
|
|
||||||
delete = login_required(Delete.as_view())
|
delete = login_required(Delete.as_view())
|
||||||
pick = login_required(Pick.as_view())
|
pick = login_required(Pick.as_view())
|
||||||
jsonp_view = login_required(JSONP.as_view())
|
jsonp = login_required(JSONP.as_view())
|
||||||
json_view = login_required(JSON.as_view())
|
json = login_required(JSON.as_view())
|
||||||
|
|
|
@ -1,80 +1,3 @@
|
||||||
from django.test import TestCase, Client
|
from django.test import TestCase
|
||||||
import django
|
|
||||||
|
|
||||||
import unittest
|
# Create your tests here.
|
||||||
|
|
||||||
django18_only = unittest.skipUnless(django.VERSION >= (1,8), 'required Django 1.8')
|
|
||||||
|
|
||||||
class FargoTestCase(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
import StringIO
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
self.email = 'john.doe@example.com'
|
|
||||||
self.username = 'john.doe'
|
|
||||||
self.user = User.objects.create(
|
|
||||||
username=self.username,
|
|
||||||
email=self.email)
|
|
||||||
self.filename = 'attachment.pdf'
|
|
||||||
self.content = 'coucou'
|
|
||||||
self.contentfile = StringIO.StringIO(self.content)
|
|
||||||
self.contentfile.content_type = 'application/pdf'
|
|
||||||
self.contentfile.name = self.filename
|
|
||||||
|
|
||||||
@django18_only
|
|
||||||
def test_send_to(self):
|
|
||||||
from fargo.models import Document
|
|
||||||
|
|
||||||
client = Client()
|
|
||||||
response = client.post('/send-to/?email=%s' % self.email,
|
|
||||||
data={'documents': [self.contentfile]})
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertEqual(response.content, 'ok')
|
|
||||||
self.assertEqual(Document.objects.count(), 1, 'no document found')
|
|
||||||
document = Document.objects.get()
|
|
||||||
self.assertEqual(document.user, self.user)
|
|
||||||
self.assertEqual(document.document_filename, self.filename)
|
|
||||||
self.assertEqual(document.document_file.read(), self.content)
|
|
||||||
|
|
||||||
@django18_only
|
|
||||||
def test_remote_send_to_unknown_user(self):
|
|
||||||
client = Client()
|
|
||||||
response = client.post('/send-to/?email=%s' % 'unknown@example.com',
|
|
||||||
data={'documents': [self.contentfile]})
|
|
||||||
self.assertEqual(response.status_code, 400)
|
|
||||||
self.assertJSONEqual(response.content, {
|
|
||||||
'errors': {
|
|
||||||
'email': ['no such user'],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_remote_upload_missing_fields(self):
|
|
||||||
client = Client()
|
|
||||||
response = client.post('/send-to/')
|
|
||||||
self.assertEqual(response.status_code, 400)
|
|
||||||
self.assertJSONEqual(response.content, {
|
|
||||||
'errors': {
|
|
||||||
'email': ['This field is required.'],
|
|
||||||
'documents': ['This field is required.'],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
@django18_only
|
|
||||||
def test_remote_upload_missing_name(self):
|
|
||||||
import StringIO
|
|
||||||
|
|
||||||
client = Client()
|
|
||||||
contentfile = StringIO.StringIO(self.content)
|
|
||||||
contentfile.content_type = 'application/pdf'
|
|
||||||
response = client.post('/send-to/?email=%s' % self.email,
|
|
||||||
data={'documents': [contentfile]})
|
|
||||||
self.assertEqual(response.status_code, 400)
|
|
||||||
self.assertJSONEqual(response.content, {
|
|
||||||
'errors': {
|
|
||||||
'documents': ['0-th document is missing a name'],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
|
@ -2,25 +2,24 @@ from django.conf import settings
|
||||||
from django.conf.urls import patterns, include, url
|
from django.conf.urls import patterns, include, url
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .fargo.views import (home, jsonp_view, json_view, document, download,
|
from .fargo.views import (home, jsonp, json, document, download, pick, delete, upload,
|
||||||
pick, delete, upload, remote_download, send_to, login,
|
remote_download, login, logout)
|
||||||
logout)
|
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
url(r'^$', home, name='home'),
|
url(r'^$', home, name='home'),
|
||||||
url(r'^jsonp/$', jsonp_view, name='jsonp'),
|
url(r'^jsonp/$', jsonp, name='jsonp'),
|
||||||
url(r'^json/$', json_view, name='json'),
|
url(r'^json/$', json, name='json'),
|
||||||
url(r'^(?P<pk>\d+)/$', document, name='document'),
|
url(r'^(?P<pk>\d+)/$', document, name='document'),
|
||||||
url(r'^(?P<pk>\d+)/delete/$', delete, name='delete'),
|
url(r'^(?P<pk>\d+)/delete/$', delete, name='delete'),
|
||||||
url(r'^(?P<pk>\d+)/pick/$', pick, name='pick'),
|
url(r'^(?P<pk>\d+)/pick/$', pick, name='pick'),
|
||||||
url(r'^(?P<pk>\d+)/download/(?P<filename>[^/]*)$', download, name='download'),
|
url(r'^(?P<pk>\d+)/download/(?P<filename>[^/]*)$', download, name='download'),
|
||||||
url(r'^upload/$', upload, name='upload'),
|
url(r'^upload/$', upload, name='upload'),
|
||||||
url(r'^remote-download/(?P<filename>[^/]*)$', remote_download, name='remote_download'),
|
url(r'^remote-download/(?P<filename>[^/]*)$', remote_download, name='remote_download'),
|
||||||
url(r'^send-to/$', send_to, name='send_to'),
|
|
||||||
url(r'^admin/', include(admin.site.urls)),
|
url(r'^admin/', include(admin.site.urls)),
|
||||||
url(r'^login/$', login, name='auth_login'),
|
url(r'^login/$', login, name='auth_login'),
|
||||||
url(r'^logout/$', logout, name='auth_logout'),
|
url(r'^logout/$', logout, name='auth_logout'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if 'mellon' in settings.INSTALLED_APPS:
|
if 'mellon' in settings.INSTALLED_APPS:
|
||||||
urlpatterns += patterns('', url(r'^accounts/mellon/', include('mellon.urls')))
|
urlpatterns += patterns('', url(r'^accounts/mellon/', include('mellon.urls')))
|
||||||
|
|
Loading…
Reference in New Issue