From db15cf5836155cc4ad3e6dce812400ded9f614d5 Mon Sep 17 00:00:00 2001 From: Maxim Gurets Date: Thu, 29 Mar 2012 14:00:31 +0400 Subject: [PATCH 1/2] Added fields headers, ip_address, email to model. Localize app. Fix tests. Send emails without threading. --- README.rst | 20 ++++- feedback/admin.py | 20 ++++- feedback/context_processors.py | 6 +- feedback/forms.py | 2 +- feedback/locale/ru/LC_MESSAGES/django.po | 49 +++++++++++ ...h__add_field_feedback_email__add_field_.py | 84 +++++++++++++++++++ ...004_auto__add_field_feedback_ip_address.py | 73 ++++++++++++++++ feedback/models.py | 20 +++-- feedback/templates/feedback/email/body.txt | 6 +- feedback/templates/feedback/email/subject.txt | 2 +- feedback/templates/feedback/form.html | 2 + feedback/tests.py | 13 ++- feedback/utils.py | 6 -- feedback/views.py | 80 ++++++++++++++---- 14 files changed, 341 insertions(+), 42 deletions(-) create mode 100644 feedback/locale/ru/LC_MESSAGES/django.po create mode 100644 feedback/migrations/0003_auto__del_field_feedback_publish__add_field_feedback_email__add_field_.py create mode 100644 feedback/migrations/0004_auto__add_field_feedback_ip_address.py delete mode 100644 feedback/utils.py diff --git a/README.rst b/README.rst index e89c356..b83f75d 100644 --- a/README.rst +++ b/README.rst @@ -51,11 +51,27 @@ There are a few optional settings available: Default: False. If set to True, an email will be sent each time a user provides feedback. -``FEEDBACK_EMAIL_TO`` +``FEEDBACK_TO_EMAIL`` - Default: ``settings.DEFAULT_FROM_EMAIL``. The email address to which + Default: None. The email addresses to which feedback emails should be sent. +``FEEDBACK_HEADER_FILTER`` + + Default: see feedback.views for details. The http headers that will be + stored in the headers field. + +``FEEDBACK_FLASH_MESSAGE`` + + Default: False. If True and django.messages installed it adds a + flash message to the user. + +``FEEDBACK_SUCCESS_URL`` + + Default: /. The default URL to which to send the user for successful + feedback. + + There are also two additional templates ``feedback/email/body.txt`` and ``feedback/email/subject.txt`` which control the output formatting for the email messages. diff --git a/feedback/admin.py b/feedback/admin.py index 0879aac..6ae4ef8 100644 --- a/feedback/admin.py +++ b/feedback/admin.py @@ -4,9 +4,21 @@ class FeedbackAdmin(admin.ModelAdmin): date_hierarchy = 'timestamp' - list_display = ('user', 'feedback', 'timestamp', 'resolved', 'publish') - list_editable = ('resolved', 'publish') - list_filter = ('user', 'resolved', 'publish') - search_fields = ['feedback', 'user'] + readonly_fields = ('url', 'email', 'user', 'timestamp', 'headers', \ + 'ip_address') + + list_display = ('get_user', 'get_feedback', 'timestamp', 'type', \ + 'resolved') + + list_editable = ('resolved',) + list_filter = ('resolved', 'type', 'timestamp') + search_fields = ['feedback', 'email'] + + + def get_user(self, object): + return object.user if object.user else 'Anonymous' + + def get_feedback(self, object): + return object.feedback[:100] admin.site.register(Feedback, FeedbackAdmin) \ No newline at end of file diff --git a/feedback/context_processors.py b/feedback/context_processors.py index 82ee9df..e5e3dcf 100644 --- a/feedback/context_processors.py +++ b/feedback/context_processors.py @@ -1,4 +1,8 @@ from feedback.forms import FeedbackForm def feedback_form(request): - return {'feedback_form': FeedbackForm()} + return {'feedback_form': FeedbackForm( + initial={'email':request.user.email \ + if hasattr(request, 'user') and request.user.is_authenticated() and \ + request.user.email else None} + )} diff --git a/feedback/forms.py b/feedback/forms.py index cd49bfc..db576e6 100644 --- a/feedback/forms.py +++ b/feedback/forms.py @@ -5,4 +5,4 @@ class FeedbackForm(forms.ModelForm): class Meta: model = Feedback - exclude = ("user", "url", "resolved", "publish",) \ No newline at end of file + exclude = ('user', 'resolved', 'url', 'headers', 'ip_address') \ No newline at end of file diff --git a/feedback/locale/ru/LC_MESSAGES/django.po b/feedback/locale/ru/LC_MESSAGES/django.po new file mode 100644 index 0000000..5d72eb3 --- /dev/null +++ b/feedback/locale/ru/LC_MESSAGES/django.po @@ -0,0 +1,49 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-03-29 11:47+0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" + +#: models.py:8 +msgid "Bug" +msgstr "" + +#: models.py:9 +msgid "Feature" +msgstr "" + +#: models.py:10 +msgid "Support request" +msgstr "" + +#: models.py:23 +msgid "IP address" +msgstr "" + +#: models.py:27 +msgid "Feedback" +msgstr "" + +#: models.py:30 +#, python-format +msgid "Feedback from %(user)s sent %(date)s" +msgstr "" + +#: views.py:73 +msgid "Your feedback has been sent. Thank you!" +msgstr "" diff --git a/feedback/migrations/0003_auto__del_field_feedback_publish__add_field_feedback_email__add_field_.py b/feedback/migrations/0003_auto__del_field_feedback_publish__add_field_feedback_email__add_field_.py new file mode 100644 index 0000000..8033397 --- /dev/null +++ b/feedback/migrations/0003_auto__del_field_feedback_publish__add_field_feedback_email__add_field_.py @@ -0,0 +1,84 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Deleting field 'Feedback.publish' + db.delete_column('feedback_feedback', 'publish') + + # Adding field 'Feedback.email' + db.add_column('feedback_feedback', 'email', self.gf('django.db.models.fields.EmailField')(max_length=75, null=True, blank=True), keep_default=False) + + # Adding field 'Feedback.headers' + db.add_column('feedback_feedback', 'headers', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False) + + + def backwards(self, orm): + + # Adding field 'Feedback.publish' + db.add_column('feedback_feedback', 'publish', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False) + + # Deleting field 'Feedback.email' + db.delete_column('feedback_feedback', 'email') + + # Deleting field 'Feedback.headers' + db.delete_column('feedback_feedback', 'headers') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'feedback.feedback': { + 'Meta': {'ordering': "['-timestamp']", 'object_name': 'Feedback'}, + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), + 'feedback': ('django.db.models.fields.TextField', [], {}), + 'headers': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'resolved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['feedback'] diff --git a/feedback/migrations/0004_auto__add_field_feedback_ip_address.py b/feedback/migrations/0004_auto__add_field_feedback_ip_address.py new file mode 100644 index 0000000..75d5e69 --- /dev/null +++ b/feedback/migrations/0004_auto__add_field_feedback_ip_address.py @@ -0,0 +1,73 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding field 'Feedback.ip_address' + db.add_column('feedback_feedback', 'ip_address', self.gf('django.db.models.fields.IPAddressField')(max_length=15, null=True, blank=True), keep_default=False) + + + def backwards(self, orm): + + # Deleting field 'Feedback.ip_address' + db.delete_column('feedback_feedback', 'ip_address') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'feedback.feedback': { + 'Meta': {'ordering': "['-timestamp']", 'object_name': 'Feedback'}, + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), + 'feedback': ('django.db.models.fields.TextField', [], {}), + 'headers': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'resolved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['feedback'] diff --git a/feedback/models.py b/feedback/models.py index 4e99ea5..b7550bb 100644 --- a/feedback/models.py +++ b/feedback/models.py @@ -1,25 +1,31 @@ from django.conf import settings from django.db import models from django.contrib.auth.models import User +from django.utils.translation import ugettext_lazy as _ + FEEDBACK_TYPES = ( - ('bug', 'Bug'), - ('feature', 'Feature'), - ('support', 'Support request'), + ('bug', _('Bug')), + ('feature', _('Feature')), + ('support', _('Support request')), ) class Feedback(models.Model): feedback = models.TextField() user = models.ForeignKey(User, null=True, blank=True) + email = models.EmailField(blank=True, null=True) url = models.URLField(blank=True, verify_exists=False) timestamp = models.DateTimeField(auto_now_add=True, editable=False) resolved = models.BooleanField(default=False) - publish = models.BooleanField(default=False) - type = models.CharField(max_length=128, blank=True, choices=getattr(settings, 'FEEDBACK_TYPES', FEEDBACK_TYPES)) + type = models.CharField(max_length=128, blank=True, \ + choices=getattr(settings, 'FEEDBACK_TYPES', FEEDBACK_TYPES)) + headers = models.TextField(blank=True, null=True) + ip_address = models.IPAddressField(_('IP address'), blank=True, null=True) class Meta: ordering = ['-timestamp',] - verbose_name_plural = "Feedback" + verbose_name_plural = _('Feedback') def __unicode__(self): - return "Feedback from %s sent %s" % (self.user, self.timestamp,) + return _('Feedback from %(user)s sent %(date)s') % \ + {'user':self.user if self.user else 'Anonymous', 'date': self.timestamp} diff --git a/feedback/templates/feedback/email/body.txt b/feedback/templates/feedback/email/body.txt index 1dd3263..7735ea2 100644 --- a/feedback/templates/feedback/email/body.txt +++ b/feedback/templates/feedback/email/body.txt @@ -3,4 +3,8 @@ Page URL: {{ feedback.url|default:"URL not available" }} User: {% if feedback.user %}{{ feedback.user.get_full_name }} ({{ feedback.user.username }}){% else %}Anonymous{% endif %} Feedback: -{{ feedback.feedback }} \ No newline at end of file +{{ feedback.feedback }} + +Headers: +{{ feedback.headers }} + diff --git a/feedback/templates/feedback/email/subject.txt b/feedback/templates/feedback/email/subject.txt index f78432c..ceab0c8 100644 --- a/feedback/templates/feedback/email/subject.txt +++ b/feedback/templates/feedback/email/subject.txt @@ -1 +1 @@ -Feedback from {{ feedback.user }} \ No newline at end of file +Feedback from {% if feedback.user %}{{ feedback.user }}{% else %}anonymous user{% endif %} \ No newline at end of file diff --git a/feedback/templates/feedback/form.html b/feedback/templates/feedback/form.html index d3a43f2..7b76e1e 100644 --- a/feedback/templates/feedback/form.html +++ b/feedback/templates/feedback/form.html @@ -1,4 +1,6 @@
{% csrf_token %} + {{ feedback_form.as_p }} +
\ No newline at end of file diff --git a/feedback/tests.py b/feedback/tests.py index 10a8135..c5bd6eb 100644 --- a/feedback/tests.py +++ b/feedback/tests.py @@ -6,6 +6,7 @@ from django.template import Template, RequestContext from django.test import TestCase from django.test.client import Client, RequestFactory +from django.test.utils import override_settings from feedback.models import Feedback @@ -19,6 +20,7 @@ def setUp(self): ) self.data = { "feedback": "Your site is great.", + "email": "user@example.com", } self.c = Client() self.feedback_url = reverse('django-user-feedback') @@ -33,12 +35,17 @@ def test_feedback_submission(self): self.assertNotEqual(feedback1.id, feedback2.id) self.assertEqual(self.user.id, feedback2.user.id) + @override_settings(TEMPLATE_CONTEXT_PROCESSORS=tuple(settings.TEMPLATE_CONTEXT_PROCESSORS) + ('feedback.context_processors.feedback_form',)) def test_context_processor(self): - OLD_TEMPLATE_CONTEXT_PROCESSORS = settings.TEMPLATE_CONTEXT_PROCESSORS - settings.TEMPLATE_CONTEXT_PROCESSORS = tuple(settings.TEMPLATE_CONTEXT_PROCESSORS) + ('feedback.context_processors.feedback_form',) + + from django.template import loader, context + context._standard_context_processors = None + request = self.factory.get(self.feedback_url) c = RequestContext(request) self.assertTrue(c.has_key('feedback_form')) response = self.c.post(self.feedback_url, {}) self.assertEqual(1, len(response.context['feedback_form'].errors)) - settings.TEMPLATE_CONTEXT_PROCESSORS = OLD_TEMPLATE_CONTEXT_PROCESSORS \ No newline at end of file + + context._standard_context_processors = None + diff --git a/feedback/utils.py b/feedback/utils.py deleted file mode 100644 index 61500d9..0000000 --- a/feedback/utils.py +++ /dev/null @@ -1,6 +0,0 @@ -import threading - -def send_threaded(msg, fail_silently=True, *args): - t = threading.Thread(target=msg.send, args=args, kwargs={'fail_silently': fail_silently}) - t.setDaemon(True) - t.start() diff --git a/feedback/views.py b/feedback/views.py index 158b71e..496e005 100644 --- a/feedback/views.py +++ b/feedback/views.py @@ -1,43 +1,88 @@ from django.conf import settings -from django.core.urlresolvers import reverse from django.contrib import messages from django.core.mail import EmailMultiAlternatives +from django.utils.translation import ugettext_lazy as _ from django.template import RequestContext from django.template.loader import render_to_string from django.views.generic import CreateView -from feedback.utils import send_threaded from feedback.forms import FeedbackForm from feedback.models import Feedback + class FeedbackView(CreateView): form_class = FeedbackForm template_name = 'feedback/feedback.html' + header_filter = getattr(settings, 'FEEDBACK_HEADER_FILTER', + ( + 'CONTENT_TYPE', + 'HTTP_ACCEPT', + 'HTTP_ACCEPT_CHARSET', + 'HTTP_ACCEPT_ENCODING', + 'HTTP_ACCEPT_LANGUAGE', + 'HTTP_CACHE_CONTROL', + 'HTTP_CONNECTION', + 'HTTP_HOST', + 'HTTP_KEEP_ALIVE', + 'HTTP_REFERER', + 'HTTP_USER_AGENT', + 'QUERY_STRING', + 'REMOTE_ADDR', + 'REMOTE_HOST', + 'REQUEST_METHOD', + 'SCRIPT_NAME', + 'SERVER_NAME', + 'SERVER_PORT', + 'SERVER_PROTOCOL', + 'SERVER_SOFTWARE', + 'HTTP_COOKIE', + ) + ) + + def get_initial(self): + if self.request.user.is_authenticated() and \ + self.request.user.email: + return {'email': self.request.user.email} + return {} def get_form_kwargs(self): kwargs = super(FeedbackView, self).get_form_kwargs() + headers = "\n".join( + ['='.join([k, self.request.META[k]]) for k in self.header_filter if k in self.request.META] + ) instance = Feedback( - url = self.request.META.get("HTTP_REFERER", ''), - user = self.request.user if self.request.user.is_authenticated() else None + url = self.request.POST.get('url', self.request.META.get('HTTP_REFERER', '')), + user = self.request.user if self.request.user.is_authenticated() else None, + headers = unicode(headers), + ip_address = self.request.META.get('REMOTE_ADDR', '') ) kwargs.update({ - "instance": instance, + 'instance': instance, }) return kwargs + def get_context_data(self, **kwargs): + if kwargs.get('form'): + kwargs['feedback_form'] = kwargs['form'] + return kwargs + def form_valid(self, *args, **kwargs): - if getattr(settings, 'FEEDBACK_SEND_EMAIL', False): + response = super(FeedbackView, self).form_valid(*args, **kwargs) + + if getattr(settings, 'FEEDBACK_SEND_EMAIL', False) and \ + getattr(settings, 'FEEDBACK_TO_EMAIL', False): context = {"feedback":self.object} - send_threaded(EmailMultiAlternatives( - render_to_string('feedback/emails/feedback_subject.txt', context), - render_to_string('feedback/emails/feedback_body.txt', context), + EmailMultiAlternatives( + render_to_string('feedback/email/subject.txt', context), + render_to_string('feedback/email/body.txt', context), settings.DEFAULT_FROM_EMAIL, - [getattr(settings, 'FEEDBACK_TO_EMAIL', settings.DEFAULT_FROM_EMAIL),] - ) - ) - if 'django.contrib.messages' in settings.INSTALLED_APPS: - messages.success(self.request, "Your feedback has been sent. Thank you!") - return super(FeedbackView, self).form_valid(*args, **kwargs) + getattr(settings, 'FEEDBACK_TO_EMAIL'), + ).send(fail_silently=False) + + if getattr(settings, 'FEEDBACK_FLASH_MESSAGE', False) and \ + 'django.contrib.messages' in settings.INSTALLED_APPS: + messages.success(self.request, _('Your feedback has been sent. Thank you!')) + return response def form_invalid(self, form): # Update our context to avoid being overwritten by context processors @@ -46,4 +91,7 @@ def form_invalid(self, form): return self.render_to_response(context) def get_success_url(self): - return self.request.META.get("HTTP_REFERER", reverse('django-user-feedback')) + return self.request.META.get( + 'HTTP_REFERER', + getattr(settings, 'FEEDBACK_SUCCESS_URL', '/') + ) From 6456efcd24e7817d4d04d98153d58a89dcb0c12d Mon Sep 17 00:00:00 2001 From: Kirill Zaitsev Date: Tue, 25 Sep 2012 19:50:40 +0400 Subject: [PATCH 2/2] ajax, translation, form-widget params --- feedback/forms.py | 19 +++++++++++++++++-- feedback/locale/ru/LC_MESSAGES/django.po | 8 ++++---- feedback/views.py | 17 ++++++++++++++++- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/feedback/forms.py b/feedback/forms.py index db576e6..c88751f 100644 --- a/feedback/forms.py +++ b/feedback/forms.py @@ -1,8 +1,23 @@ from django import forms -from feedback.models import Feedback +from feedback.models import Feedback, FEEDBACK_TYPES class FeedbackForm(forms.ModelForm): class Meta: model = Feedback - exclude = ('user', 'resolved', 'url', 'headers', 'ip_address') \ No newline at end of file + fields = ('type', 'email', 'feedback',) + + type = forms.ChoiceField(choices=FEEDBACK_TYPES, + initial=FEEDBACK_TYPES[0][0], widget=forms.RadioSelect(attrs={ + 'id':'feedback_type_id', + #'class': 'pseudo-popup_input', + })) + email = forms.EmailField(widget=forms.TextInput(attrs={ + 'id':'feedback_email_id', + 'class':'pseudo-popup_input', + })) + feedback = forms.CharField(widget=forms.Textarea(attrs={ + 'id':'feedback_feedback_id', + 'class':'pseudo-popup_input', + 'rows': '4', + })) diff --git a/feedback/locale/ru/LC_MESSAGES/django.po b/feedback/locale/ru/LC_MESSAGES/django.po index 5d72eb3..9d467f4 100644 --- a/feedback/locale/ru/LC_MESSAGES/django.po +++ b/feedback/locale/ru/LC_MESSAGES/django.po @@ -21,15 +21,15 @@ msgstr "" #: models.py:8 msgid "Bug" -msgstr "" +msgstr "Ошибка" #: models.py:9 msgid "Feature" -msgstr "" +msgstr "Предложение" #: models.py:10 msgid "Support request" -msgstr "" +msgstr "Нужна помощь" #: models.py:23 msgid "IP address" @@ -46,4 +46,4 @@ msgstr "" #: views.py:73 msgid "Your feedback has been sent. Thank you!" -msgstr "" +msgstr "Мы получили ваше послание, спасибо!" diff --git a/feedback/views.py b/feedback/views.py index 496e005..f7fcf2c 100644 --- a/feedback/views.py +++ b/feedback/views.py @@ -1,14 +1,17 @@ from django.conf import settings from django.contrib import messages from django.core.mail import EmailMultiAlternatives -from django.utils.translation import ugettext_lazy as _ +from django.http import HttpResponse from django.template import RequestContext from django.template.loader import render_to_string +from django.utils.translation import ugettext_lazy as _ from django.views.generic import CreateView from feedback.forms import FeedbackForm from feedback.models import Feedback +import json + class FeedbackView(CreateView): form_class = FeedbackForm @@ -82,12 +85,24 @@ def form_valid(self, *args, **kwargs): if getattr(settings, 'FEEDBACK_FLASH_MESSAGE', False) and \ 'django.contrib.messages' in settings.INSTALLED_APPS: messages.success(self.request, _('Your feedback has been sent. Thank you!')) + if self.request.is_ajax(): + return HttpResponse( + json.dumps({'redirect': self.get_success_url()}), + mimetype="application/json", + ) + return response def form_invalid(self, form): # Update our context to avoid being overwritten by context processors context = RequestContext(self.request, self.get_context_data()) context['feedback_form'] = form + if self.request.is_ajax(): + return HttpResponse( + json.dumps({'errors': form.errors}), + mimetype="application/json", + status=400 + ) return self.render_to_response(context) def get_success_url(self):