admin.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. from __future__ import unicode_literals
  2. from future.builtins import open, bytes
  3. from copy import deepcopy
  4. from io import BytesIO, StringIO
  5. from csv import writer
  6. from datetime import datetime
  7. from mimetypes import guess_type
  8. from os.path import join
  9. from django.conf.urls import url
  10. from django.contrib import admin
  11. from django.contrib.messages import info
  12. from django.core.files.storage import FileSystemStorage
  13. from django.http import HttpResponse, HttpResponseRedirect
  14. from django.shortcuts import render, get_object_or_404
  15. from django.utils.translation import ungettext, ugettext_lazy as _
  16. from mezzanine.conf import settings
  17. from mezzanine.core.admin import TabularDynamicInlineAdmin
  18. from mezzanine.forms.forms import EntriesForm
  19. from mezzanine.forms.models import Form, Field, FormEntry, FieldEntry
  20. from mezzanine.pages.admin import PageAdmin
  21. from mezzanine.utils.static import static_lazy as static
  22. from mezzanine.utils.urls import admin_url, slugify
  23. fs = FileSystemStorage(location=settings.FORMS_UPLOAD_ROOT)
  24. # Copy the fieldsets for PageAdmin and add the extra fields for FormAdmin.
  25. form_fieldsets = deepcopy(PageAdmin.fieldsets)
  26. form_fieldsets[0][1]["fields"][3:0] = ["content", "button_text", "response"]
  27. form_fieldsets = list(form_fieldsets)
  28. form_fieldsets.insert(1, (_("Email"), {"fields": ("send_email", "email_from",
  29. "email_copies", "email_subject", "email_message")}))
  30. inline_field_excludes = []
  31. if not settings.FORMS_USE_HTML5:
  32. inline_field_excludes += ["placeholder_text"]
  33. class FieldAdmin(TabularDynamicInlineAdmin):
  34. """
  35. Admin class for the form field. Inherits from TabularDynamicInlineAdmin to
  36. add dynamic "Add another" link and drag/drop ordering.
  37. """
  38. model = Field
  39. exclude = inline_field_excludes
  40. class FormAdmin(PageAdmin):
  41. """
  42. Admin class for the Form model. Includes the urls & views for exporting
  43. form entries as CSV and downloading files uploaded via the forms app.
  44. """
  45. class Media:
  46. css = {"all": (static("mezzanine/css/admin/form.css"),)}
  47. inlines = (FieldAdmin,)
  48. list_display = ("title", "status", "email_copies",)
  49. list_display_links = ("title",)
  50. list_editable = ("status", "email_copies")
  51. list_filter = ("status",)
  52. search_fields = ("title", "content", "response", "email_from",
  53. "email_copies")
  54. fieldsets = form_fieldsets
  55. def get_urls(self):
  56. """
  57. Add the entries view to urls.
  58. """
  59. urls = super(FormAdmin, self).get_urls()
  60. extra_urls = [
  61. url("^(?P<form_id>\d+)/entries/$",
  62. self.admin_site.admin_view(self.entries_view),
  63. name="form_entries"),
  64. url("^file/(?P<field_entry_id>\d+)/$",
  65. self.admin_site.admin_view(self.file_view),
  66. name="form_file"),
  67. ]
  68. return extra_urls + urls
  69. def entries_view(self, request, form_id):
  70. """
  71. Displays the form entries in a HTML table with option to
  72. export as CSV file.
  73. """
  74. if request.POST.get("back"):
  75. change_url = admin_url(Form, "change", form_id)
  76. return HttpResponseRedirect(change_url)
  77. form = get_object_or_404(Form, id=form_id)
  78. entries_form = EntriesForm(form, request, request.POST or None)
  79. delete_entries_perm = "%s.delete_formentry" % FormEntry._meta.app_label
  80. can_delete_entries = request.user.has_perm(delete_entries_perm)
  81. submitted = entries_form.is_valid()
  82. if submitted:
  83. if request.POST.get("export"):
  84. response = HttpResponse(content_type="text/csv")
  85. timestamp = slugify(datetime.now().ctime())
  86. fname = "%s-%s.csv" % (form.slug, timestamp)
  87. header = "attachment; filename=%s" % fname
  88. response["Content-Disposition"] = header
  89. queue = StringIO()
  90. delimiter = settings.FORMS_CSV_DELIMITER
  91. try:
  92. csv = writer(queue, delimiter=delimiter)
  93. writerow = csv.writerow
  94. except TypeError:
  95. queue = BytesIO()
  96. delimiter = bytes(delimiter, encoding="utf-8")
  97. csv = writer(queue, delimiter=delimiter)
  98. writerow = lambda row: csv.writerow([c.encode("utf-8")
  99. if hasattr(c, "encode") else c for c in row])
  100. writerow(entries_form.columns())
  101. for row in entries_form.rows(csv=True):
  102. writerow(row)
  103. data = queue.getvalue()
  104. response.write(data)
  105. return response
  106. elif request.POST.get("delete") and can_delete_entries:
  107. selected = request.POST.getlist("selected")
  108. if selected:
  109. entries = FormEntry.objects.filter(id__in=selected)
  110. count = entries.count()
  111. if count > 0:
  112. entries.delete()
  113. message = ungettext("1 entry deleted",
  114. "%(count)s entries deleted", count)
  115. info(request, message % {"count": count})
  116. template = "admin/forms/entries.html"
  117. context = {"title": _("View Entries"), "entries_form": entries_form,
  118. "opts": self.model._meta, "original": form,
  119. "can_delete_entries": can_delete_entries,
  120. "submitted": submitted}
  121. return render(request, template, context)
  122. def file_view(self, request, field_entry_id):
  123. """
  124. Output the file for the requested field entry.
  125. """
  126. field_entry = get_object_or_404(FieldEntry, id=field_entry_id)
  127. path = join(fs.location, field_entry.value)
  128. response = HttpResponse(content_type=guess_type(path)[0])
  129. f = open(path, "r+b")
  130. response["Content-Disposition"] = "attachment; filename=%s" % f.name
  131. response.write(f.read())
  132. f.close()
  133. return response
  134. admin.site.register(Form, FormAdmin)