Parcourir la source

Make use of django-sendfile to have the possibility to make use of web serveur to send a private file to a client.
Ex for apache we could use mod_xsendfile.
Now invoices must be stored in a private folder which is not directly accessible by the web server.
in settings.py a PRIVATE_FILES_ROOT should indicate where to store the private files (so not the same location as static or media)
This allow us to protect users invoices and to control who can / or can't download an invoice as pdf file and in the same time to make use of the web server to send the file to the client.

Fabs il y a 10 ans
Parent
commit
5a71dd3438
5 fichiers modifiés avec 24 ajouts et 24 suppressions
  1. 1 0
      .gitignore
  2. 7 1
      coin/billing/models.py
  3. 5 23
      coin/billing/views.py
  4. 10 0
      coin/settings.py
  5. 1 0
      requirements.txt

+ 1 - 0
.gitignore

@@ -9,5 +9,6 @@ coin/settings_local.py
 .settings/*
 /static
 /media
+/smedia
 .idea
 venv

+ 7 - 1
coin/billing/models.py

@@ -2,17 +2,23 @@
 import datetime
 import random
 import uuid
+import os
 from decimal import Decimal
 
 from django.db import models
 from django.db.models.signals import post_save
 from django.dispatch import receiver
+from django.core.files.storage import FileSystemStorage
+from django.conf import settings
 
 from coin.offers.models import OfferSubscription
 from coin.members.models import Member
 from coin.html2pdf import render_as_pdf
 
 
+# Stockage des factures
+invoices_storage = FileSystemStorage(location=os.path.join(settings.PRIVATE_FILES_ROOT, 'invoices/'))
+
 def next_invoice_number():
     "Détermine un numéro de facture aléatoire"
     return u'%s%02i-%i-%i' % (datetime.date.today().year,
@@ -47,7 +53,7 @@ class Invoice(models.Model):
                                related_name='invoices',
                                verbose_name='Membre',
                                on_delete=models.SET_NULL)
-    pdf = models.FileField(upload_to='invoices',
+    pdf = models.FileField(storage=invoices_storage,
                            null=True, blank=True,
                            verbose_name=u'Facture en PDF')
 

+ 5 - 23
coin/billing/views.py

@@ -5,6 +5,8 @@ from django.shortcuts import render, render_to_response
 from django.core.exceptions import PermissionDenied
 from django.contrib import messages
 
+from sendfile import sendfile
+
 from coin.billing.models import Invoice
 from coin.members.models import Member
 from coin.html2pdf import render_as_pdf
@@ -26,30 +28,10 @@ def invoice_pdf(request, id):
        and not request.user.is_superuser:
         raise PermissionDenied
 
-    return HttpResponseRedirect(invoice.pdf.url)
-
-    # pdf = render_as_pdf('billing/invoice_pdf.html', {"invoice": invoice})
-
-    # response = HttpResponse(content_type='application/pdf')
-    # response['Content-Disposition'] = 'attachment; filename="facture.pdf"'
-
-    # response.write(invoice.pdf)
-
-    # return response
-
-# def invoice_validate(request, id):
-#     """
-#     Valide la facture
-#     """
-#     #TODO change this by perm : has_validate_invoice_permission
-#     if request.user.is_superuser:
-#         invoice = get_invoice_from_id_or_number(id)
-#         invoice.validate()
-#         messages.success(request, 'La facture a été validée.')
-#     else:
-#         messages.error(request, 'Vous n\'avez pas l\'autorisation de valider une facture.')
+    pdf_filename = 'Facture_%s.pdf' % invoice.number
 
-#     return HttpResponseRedirect(request.META["HTTP_REFERER"])
+    return sendfile(request, invoice.pdf.path,
+                    attachment=True, attachment_filename=pdf_filename)
 
 def invoice(request, id):
     """

+ 10 - 0
coin/settings.py

@@ -111,6 +111,16 @@ STATICFILES_FINDERS = (
     #'django.contrib.staticfiles.finders.DefaultStorageFinder',
 )
 
+# Location of private files. (Like invoices)
+# In production, this location should not be publicly accessible through
+# the web server
+PRIVATE_FILES_ROOT = os.path.join(BASE_DIR, 'smedia/')
+
+# Backend to use when sending private files to client
+# In production, must be sendfile.backends.xsendfile with Apache xsend file mod
+# https://github.com/johnsensible/django-sendfile
+SENDFILE_BACKEND = 'sendfile.backends.development'
+
 # Make this unique, and don't share it with anybody.
 SECRET_KEY = '!qy_)gao6q)57#mz1s-d$5^+dp1nt=lk1d19&9bb3co37vn)!3'
 

+ 1 - 0
requirements.txt

@@ -8,6 +8,7 @@ reportlab==2.5
 django-activelink==0.4
 html2text
 django-polymorphic==0.5.6
+django-sendfile==0.3.6
 -e git+https://github.com/jmacul2/django-postgresql-netfields@2d6e597c3d65ba8b0e1f6e3183869216e990e915#egg=django-netfields
 -e git+https://github.com/chrisglass/xhtml2pdf@a5d37ffd0ccb0603bdf668198de0f21766816104#egg=xhtml2pdf-master
 -e git+https://github.com/jlaine/django-ldapdb@1c4f9f29e52176f4367a1dffec2ecd2e123e2e7a#egg=django-ldapdb