permit PDF as well as images for invoice uploads for expenses

This commit is contained in:
Thomas Steen Rasmussen 2018-08-30 12:18:56 +02:00
parent ed736938cc
commit 93b0bff50b
4 changed files with 46 additions and 3 deletions

38
src/economy/forms.py Normal file
View file

@ -0,0 +1,38 @@
import os, magic, copy
from django import forms
from .models import Expense
class ExpenseCreateForm(forms.ModelForm):
"""
We have to define this form explicitly because we want our ImageField to accept PDF files as well as images,
and we cannot change the clean_* methods with an autogenerated form from inside views.py
"""
class Meta:
model = Expense
fields = ['description', 'amount', 'invoice', 'paid_by_bornhack', 'responsible_team']
invoice = forms.FileField()
def clean_invoice(self):
# get the uploaded file from cleaned_data
uploaded_file = self.cleaned_data['invoice']
# is this a valid image?
try:
# create an ImageField instance
im = forms.ImageField()
# now check if the file is a valid image
im.to_python(uploaded_file)
except forms.ValidationError:
# file is not a valid image, so check if it's a pdf
# do a deep copy so we dont mess with the file object we might be passing on
testfile = copy.deepcopy(uploaded_file)
# read the uploaded file into memory (the webserver limits uploads to a reasonable max size so this should be safe)
mimetype = magic.from_buffer(testfile.open().read(), mime=True)
if mimetype != "application/pdf":
raise forms.ValidationError("Only images and PDF files allowed")
# this is either a valid image, or has mimetype application/pdf, all good
return uploaded_file

View file

@ -31,7 +31,7 @@
<tr> <tr>
<th>Invoice</th> <th>Invoice</th>
<td> <td>
<a href="{% url 'economy:expense_invoice' camp_slug=camp.slug pk=expense.pk %}"><img src="{% url 'economy:expense_invoice' camp_slug=camp.slug pk=expense.pk %}" height=200></a><br> <a href="{% url 'economy:expense_invoice' camp_slug=camp.slug pk=expense.pk %}"><img src="{% url 'economy:expense_invoice' camp_slug=camp.slug pk=expense.pk %}?preview" height=200></a><br>
Filename: {{ expense.invoice_filename }} Filename: {{ expense.invoice_filename }}
</td> </td>
</tr> </tr>

View file

@ -1,4 +1,4 @@
import magic import os, magic
from django.shortcuts import render from django.shortcuts import render
from django.conf import settings from django.conf import settings
@ -15,6 +15,7 @@ from utils.mixins import RaisePermissionRequiredMixin
from teams.models import Team from teams.models import Team
from .models import Expense, Reimbursement from .models import Expense, Reimbursement
from .mixins import ExpensePermissionMixin, ReimbursementPermissionMixin from .mixins import ExpensePermissionMixin, ReimbursementPermissionMixin
from .forms import ExpenseCreateForm
class ExpenseListView(LoginRequiredMixin, CampViewMixin, ListView): class ExpenseListView(LoginRequiredMixin, CampViewMixin, ListView):
@ -41,9 +42,9 @@ class ExpenseDetailView(CampViewMixin, ExpensePermissionMixin, DetailView):
class ExpenseCreateView(CampViewMixin, RaisePermissionRequiredMixin, CreateView): class ExpenseCreateView(CampViewMixin, RaisePermissionRequiredMixin, CreateView):
model = Expense model = Expense
fields = ['description', 'amount', 'invoice', 'paid_by_bornhack', 'responsible_team']
template_name = 'expense_form.html' template_name = 'expense_form.html'
permission_required = ("camps.expense_create_permission") permission_required = ("camps.expense_create_permission")
form_class = ExpenseCreateForm
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
""" """
@ -92,6 +93,10 @@ class ExpenseInvoiceView(CampViewMixin, ExpensePermissionMixin, DetailView):
invoicedata = expense.invoice.read() invoicedata = expense.invoice.read()
# find mimetype # find mimetype
mimetype = magic.from_buffer(invoicedata, mime=True) mimetype = magic.from_buffer(invoicedata, mime=True)
# check if we have a PDF, no preview if so, load a pdf icon instead
if mimetype=="application/pdf" and 'preview' in request.GET:
invoicedata = open(os.path.join(settings.DJANGO_BASE_PATH, "static_src/img/pdf.png"), "rb").read()
mimetype = magic.from_buffer(invoicedata, mime=True)
# put the response together and return it # put the response together and return it
response = HttpResponse(content_type=mimetype) response = HttpResponse(content_type=mimetype)
response.write(invoicedata) response.write(invoicedata)

BIN
src/static_src/img/pdf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB