1 from __future__ import unicode_literals
2 from future.builtins import bytes, open
5 from mimetypes import guess_type
6 from os.path import join
7 from datetime import datetime
8 from io import BytesIO, StringIO
10 from django.conf.urls import patterns, 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 _
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
29 XLWT_DATETIME_STYLE = xlwt.easyxf(num_format_str='MM/DD/YYYY HH:MM:SS')
31 XLWT_INSTALLED = False
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")}),]
44 form_admin_fieldsets.append(
45 (_("Slug"), {"fields": ("slug",), "classes": ("collapse",)}))
48 form_admin_fieldsets.append((_("Sites"), {"fields": ("sites",),
49 "classes": ("collapse",)}))
50 form_admin_filter_horizontal = ("sites",)
53 class FieldAdmin(admin.TabularInline):
58 class FormAdmin(admin.ModelAdmin):
59 formentry_model = FormEntry
60 fieldentry_model = FieldEntry
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",
71 radio_fields = {"status": admin.HORIZONTAL}
72 fieldsets = form_admin_fieldsets
74 def get_queryset(self, request):
76 Annotate the queryset with the entries count for use in the
79 qs = super(FormAdmin, self).get_queryset(request)
80 return qs.annotate(total_entries=Count("entries"))
84 Add the entries view to urls.
86 urls = super(FormAdmin, self).get_urls()
87 extra_urls = patterns("",
88 url("^(?P<form_id>\d+)/entries/$",
89 self.admin_site.admin_view(self.entries_view),
91 url("^(?P<form_id>\d+)/entries/show/$",
92 self.admin_site.admin_view(self.entries_view),
93 {"show": True}, name="form_entries_show"),
94 url("^(?P<form_id>\d+)/entries/export/$",
95 self.admin_site.admin_view(self.entries_view),
96 {"export": True}, name="form_entries_export"),
97 url("^file/(?P<field_entry_id>\d+)/$",
98 self.admin_site.admin_view(self.file_view),
101 return extra_urls + urls
103 def entries_view(self, request, form_id, show=False, export=False,
106 Displays the form entries in a HTML table with option to
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")
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
130 csv = writer(queue, delimiter=CSV_DELIMITER)
131 writerow = csv.writerow
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):
141 data = queue.getvalue()
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
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)
160 sheet.write(r + 2, c, item)
162 data = queue.getvalue()
165 elif request.POST.get("delete") and can_delete_entries:
166 selected = request.POST.getlist("selected")
169 from django.contrib.messages import info
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()
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))
188 def file_view(self, request, field_entry_id):
190 Output the file for the requested field entry.
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())
203 admin.site.register(Form, FormAdmin)