django 1.10
[redakcja.git] / apps / forms_builder / forms / admin.py
1 from __future__ import unicode_literals
2 from future.builtins import bytes, open
3
4 from csv import writer
5 from mimetypes import guess_type
6 from os.path import join
7 from datetime import datetime
8 from io import BytesIO, StringIO
9
10 from django.conf.urls import url
11 from django.contrib import admin
12 from django.core.files.storage import FileSystemStorage
13 from django.core.urlresolvers import reverse
14 from django.db.models import Count
15 from django.http import HttpResponse, HttpResponseRedirect
16 from django.shortcuts import render_to_response, get_object_or_404
17 from django.template import RequestContext
18 from django.utils.translation import ungettext, ugettext_lazy as _
19
20 from forms_builder.forms.forms import EntriesForm
21 from forms_builder.forms.models import Form, Field, FormEntry, FieldEntry
22 from forms_builder.forms.settings import CSV_DELIMITER, UPLOAD_ROOT
23 from forms_builder.forms.settings import USE_SITES, EDITABLE_SLUGS
24 from forms_builder.forms.utils import now, slugify
25
26 try:
27     import xlwt
28     XLWT_INSTALLED = True
29     XLWT_DATETIME_STYLE = xlwt.easyxf(num_format_str='MM/DD/YYYY HH:MM:SS')
30 except ImportError:
31     XLWT_INSTALLED = False
32
33
34 fs = FileSystemStorage(location=UPLOAD_ROOT)
35 form_admin_filter_horizontal = ()
36 form_admin_fieldsets = [
37     (None, {"fields": ("title", ("status", "login_required",),
38         ("publish_date", "expiry_date",),
39         "intro", "button_text", "response", "redirect_url")}),
40     (_("Email"), {"fields": ("send_email", "email_from", "email_copies",
41         "email_subject", "email_message")}),]
42
43 if EDITABLE_SLUGS:
44     form_admin_fieldsets.append(
45             (_("Slug"), {"fields": ("slug",), "classes": ("collapse",)}))
46
47 if USE_SITES:
48     form_admin_fieldsets.append((_("Sites"), {"fields": ("sites",),
49         "classes": ("collapse",)}))
50     form_admin_filter_horizontal = ("sites",)
51
52
53 class FieldAdmin(admin.TabularInline):
54     model = Field
55     exclude = ('slug', )
56
57
58 class FormAdmin(admin.ModelAdmin):
59     formentry_model = FormEntry
60     fieldentry_model = FieldEntry
61
62     inlines = (FieldAdmin,)
63     list_display = ("title", "status", "email_copies", "publish_date",
64                     "expiry_date", "total_entries", "admin_links")
65     list_display_links = ("title",)
66     list_editable = ("status", "email_copies", "publish_date", "expiry_date")
67     list_filter = ("status",)
68     filter_horizontal = form_admin_filter_horizontal
69     search_fields = ("title", "intro", "response", "email_from",
70                      "email_copies")
71     radio_fields = {"status": admin.HORIZONTAL}
72     fieldsets = form_admin_fieldsets
73
74     def get_queryset(self, request):
75         """
76         Annotate the queryset with the entries count for use in the
77         admin list view.
78         """
79         qs = super(FormAdmin, self).get_queryset(request)
80         return qs.annotate(total_entries=Count("entries"))
81
82     def get_urls(self):
83         """
84         Add the entries view to urls.
85         """
86         urls = super(FormAdmin, self).get_urls()
87         extra_urls = [
88             url(r"^(?P<form_id>\d+)/entries/$",
89                 self.admin_site.admin_view(self.entries_view),
90                 name="form_entries"),
91             url(r"^(?P<form_id>\d+)/entries/show/$",
92                 self.admin_site.admin_view(self.entries_view),
93                 {"show": True}, name="form_entries_show"),
94             url(r"^(?P<form_id>\d+)/entries/export/$",
95                 self.admin_site.admin_view(self.entries_view),
96                 {"export": True}, name="form_entries_export"),
97             url(r"^file/(?P<field_entry_id>\d+)/$",
98                 self.admin_site.admin_view(self.file_view),
99                 name="form_file"),
100         ]
101         return extra_urls + urls
102
103     def entries_view(self, request, form_id, show=False, export=False,
104                      export_xls=False):
105         """
106         Displays the form entries in a HTML table with option to
107         export as CSV file.
108         """
109         if request.POST.get("back"):
110             bits = (self.model._meta.app_label, self.model.__name__.lower())
111             change_url = reverse("admin:%s_%s_change" % bits, args=(form_id,))
112             return HttpResponseRedirect(change_url)
113         form = get_object_or_404(self.model, id=form_id)
114         post = request.POST or None
115         args = form, request, self.formentry_model, self.fieldentry_model, post
116         entries_form = EntriesForm(*args)
117         delete = "%s.delete_formentry" % self.formentry_model._meta.app_label
118         can_delete_entries = request.user.has_perm(delete)
119         submitted = entries_form.is_valid() or show or export or export_xls
120         export = export or request.POST.get("export")
121         export_xls = export_xls or request.POST.get("export_xls")
122         if submitted:
123             if export:
124                 response = HttpResponse(content_type="text/csv")
125                 fname = "%s-%s.csv" % (form.slug, slugify(now().ctime()))
126                 attachment = "attachment; filename=%s" % fname
127                 response["Content-Disposition"] = attachment
128                 queue = StringIO()
129                 try:
130                     csv = writer(queue, delimiter=CSV_DELIMITER)
131                     writerow = csv.writerow
132                 except TypeError:
133                     queue = BytesIO()
134                     delimiter = bytes(CSV_DELIMITER, encoding="utf-8")
135                     csv = writer(queue, delimiter=delimiter)
136                     writerow = lambda row: csv.writerow([c.encode("utf-8")
137                         if hasattr(c, "encode") else c for c in row])
138                 writerow(entries_form.columns())
139                 for row in entries_form.rows(csv=True):
140                     writerow(row)
141                 data = queue.getvalue()
142                 response.write(data)
143                 return response
144             elif XLWT_INSTALLED and export_xls:
145                 response = HttpResponse(content_type="application/vnd.ms-excel")
146                 fname = "%s-%s.xls" % (form.slug, slugify(now().ctime()))
147                 attachment = "attachment; filename=%s" % fname
148                 response["Content-Disposition"] = attachment
149                 queue = BytesIO()
150                 workbook = xlwt.Workbook(encoding='utf8')
151                 sheet = workbook.add_sheet(form.title[:31])
152                 for c, col in enumerate(entries_form.columns()):
153                     sheet.write(0, c, col)
154                 for r, row in enumerate(entries_form.rows(csv=True)):
155                     for c, item in enumerate(row):
156                         if isinstance(item, datetime):
157                             item = item.replace(tzinfo=None)
158                             sheet.write(r + 2, c, item, XLWT_DATETIME_STYLE)
159                         else:
160                             sheet.write(r + 2, c, item)
161                 workbook.save(queue)
162                 data = queue.getvalue()
163                 response.write(data)
164                 return response
165             elif request.POST.get("delete") and can_delete_entries:
166                 selected = request.POST.getlist("selected")
167                 if selected:
168                     try:
169                         from django.contrib.messages import info
170                     except ImportError:
171                         def info(request, message, fail_silently=True):
172                             request.user.message_set.create(message=message)
173                     entries = self.formentry_model.objects.filter(id__in=selected)
174                     count = entries.count()
175                     if count > 0:
176                         entries.delete()
177                         message = ungettext("1 entry deleted",
178                                             "%(count)s entries deleted", count)
179                         info(request, message % {"count": count})
180         template = "admin/forms/entries.html"
181         context = {"title": _("View Entries"), "entries_form": entries_form,
182                    "opts": self.model._meta, "original": form,
183                    "can_delete_entries": can_delete_entries,
184                    "submitted": submitted,
185                    "xlwt_installed": XLWT_INSTALLED}
186         return render_to_response(template, context, RequestContext(request))
187
188     def file_view(self, request, field_entry_id):
189         """
190         Output the file for the requested field entry.
191         """
192         model = self.fieldentry_model
193         field_entry = get_object_or_404(model, id=field_entry_id)
194         path = join(fs.location, field_entry.value)
195         response = HttpResponse(content_type=guess_type(path)[0])
196         f = open(path, "r+b")
197         response["Content-Disposition"] = "attachment; filename=%s" % f.name
198         response.write(f.read())
199         f.close()
200         return response
201
202
203 admin.site.register(Form, FormAdmin)