summaryrefslogtreecommitdiff
path: root/app/lib/django_comments/forms.py
diff options
context:
space:
mode:
authorluxagraf <sng@luxagraf.net>2015-09-07 17:22:24 +0000
committerluxagraf <sng@luxagraf.net>2015-09-07 17:22:24 +0000
commit6cf2f5b09f3753351abc291cc70c6ae7e1126078 (patch)
treeebd14d3fd9b425eb8d8a88a0cae4034dddf28061 /app/lib/django_comments/forms.py
parent6ff5d738b9442c92fa6cc36477a3e099eb516f7d (diff)
added comments to my apps, fixed uwsgi config, fixed bug in photo template jquery url, added piwik stats code
Diffstat (limited to 'app/lib/django_comments/forms.py')
-rw-r--r--app/lib/django_comments/forms.py197
1 files changed, 197 insertions, 0 deletions
diff --git a/app/lib/django_comments/forms.py b/app/lib/django_comments/forms.py
new file mode 100644
index 0000000..6a3082f
--- /dev/null
+++ b/app/lib/django_comments/forms.py
@@ -0,0 +1,197 @@
+import time
+from django import forms
+from django.forms.util import ErrorDict
+from django.conf import settings
+from django.contrib.contenttypes.models import ContentType
+from django.utils.crypto import salted_hmac, constant_time_compare
+from django.utils.encoding import force_text
+from django.utils.text import get_text_list
+from django.utils import timezone
+from django.utils.translation import ungettext, ugettext, ugettext_lazy as _
+
+from django_comments.models import Comment
+
+COMMENT_MAX_LENGTH = getattr(settings,'COMMENT_MAX_LENGTH', 3000)
+
+class CommentSecurityForm(forms.Form):
+ """
+ Handles the security aspects (anti-spoofing) for comment forms.
+ """
+ content_type = forms.CharField(widget=forms.HiddenInput)
+ object_pk = forms.CharField(widget=forms.HiddenInput)
+ timestamp = forms.IntegerField(widget=forms.HiddenInput)
+ security_hash = forms.CharField(min_length=40, max_length=40, widget=forms.HiddenInput)
+
+ def __init__(self, target_object, data=None, initial=None):
+ self.target_object = target_object
+ if initial is None:
+ initial = {}
+ initial.update(self.generate_security_data())
+ super(CommentSecurityForm, self).__init__(data=data, initial=initial)
+
+ def security_errors(self):
+ """Return just those errors associated with security"""
+ errors = ErrorDict()
+ for f in ["honeypot", "timestamp", "security_hash"]:
+ if f in self.errors:
+ errors[f] = self.errors[f]
+ return errors
+
+ def clean_security_hash(self):
+ """Check the security hash."""
+ security_hash_dict = {
+ 'content_type' : self.data.get("content_type", ""),
+ 'object_pk' : self.data.get("object_pk", ""),
+ 'timestamp' : self.data.get("timestamp", ""),
+ }
+ expected_hash = self.generate_security_hash(**security_hash_dict)
+ actual_hash = self.cleaned_data["security_hash"]
+ if not constant_time_compare(expected_hash, actual_hash):
+ raise forms.ValidationError("Security hash check failed.")
+ return actual_hash
+
+ def clean_timestamp(self):
+ """Make sure the timestamp isn't too far (> 2 hours) in the past."""
+ ts = self.cleaned_data["timestamp"]
+ """
+ if time.time() - ts > (2 * 60 * 60):
+ raise forms.ValidationError("Timestamp check failed")
+ """
+ return ts
+
+ def generate_security_data(self):
+ """Generate a dict of security data for "initial" data."""
+ timestamp = int(time.time())
+ security_dict = {
+ 'content_type' : str(self.target_object._meta),
+ 'object_pk' : str(self.target_object._get_pk_val()),
+ 'timestamp' : str(timestamp),
+ 'security_hash' : self.initial_security_hash(timestamp),
+ }
+ return security_dict
+
+ def initial_security_hash(self, timestamp):
+ """
+ Generate the initial security hash from self.content_object
+ and a (unix) timestamp.
+ """
+
+ initial_security_dict = {
+ 'content_type' : str(self.target_object._meta),
+ 'object_pk' : str(self.target_object._get_pk_val()),
+ 'timestamp' : str(timestamp),
+ }
+ return self.generate_security_hash(**initial_security_dict)
+
+ def generate_security_hash(self, content_type, object_pk, timestamp):
+ """
+ Generate a HMAC security hash from the provided info.
+ """
+ info = (content_type, object_pk, timestamp)
+ key_salt = "django.contrib.forms.CommentSecurityForm"
+ value = "-".join(info)
+ return salted_hmac(key_salt, value).hexdigest()
+
+class CommentDetailsForm(CommentSecurityForm):
+ """
+ Handles the specific details of the comment (name, comment, etc.).
+ """
+ name = forms.CharField(label=_("Name"), max_length=50)
+ email = forms.EmailField(label=_("Email address"))
+ url = forms.URLField(label=_("URL"), required=False)
+ comment = forms.CharField(label=_('Comment'), widget=forms.Textarea,
+ max_length=COMMENT_MAX_LENGTH)
+
+ def get_comment_object(self):
+ """
+ Return a new (unsaved) comment object based on the information in this
+ form. Assumes that the form is already validated and will throw a
+ ValueError if not.
+
+ Does not set any of the fields that would come from a Request object
+ (i.e. ``user`` or ``ip_address``).
+ """
+ if not self.is_valid():
+ raise ValueError("get_comment_object may only be called on valid forms")
+
+ CommentModel = self.get_comment_model()
+ new = CommentModel(**self.get_comment_create_data())
+ new = self.check_for_duplicate_comment(new)
+
+ return new
+
+ def get_comment_model(self):
+ """
+ Get the comment model to create with this form. Subclasses in custom
+ comment apps should override this, get_comment_create_data, and perhaps
+ check_for_duplicate_comment to provide custom comment models.
+ """
+ return Comment
+
+ def get_comment_create_data(self):
+ """
+ Returns the dict of data to be used to create a comment. Subclasses in
+ custom comment apps that override get_comment_model can override this
+ method to add extra fields onto a custom comment model.
+ """
+ return dict(
+ content_type = ContentType.objects.get_for_model(self.target_object),
+ object_pk = force_text(self.target_object._get_pk_val()),
+ user_name = self.cleaned_data["name"],
+ user_email = self.cleaned_data["email"],
+ user_url = self.cleaned_data["url"],
+ comment = self.cleaned_data["comment"],
+ submit_date = timezone.now(),
+ site_id = settings.SITE_ID,
+ is_public = True,
+ is_removed = False,
+ )
+
+ def check_for_duplicate_comment(self, new):
+ """
+ Check that a submitted comment isn't a duplicate. This might be caused
+ by someone posting a comment twice. If it is a dup, silently return the *previous* comment.
+ """
+ possible_duplicates = self.get_comment_model()._default_manager.using(
+ self.target_object._state.db
+ ).filter(
+ content_type = new.content_type,
+ object_pk = new.object_pk,
+ user_name = new.user_name,
+ user_email = new.user_email,
+ user_url = new.user_url,
+ )
+ for old in possible_duplicates:
+ if old.submit_date.date() == new.submit_date.date() and old.comment == new.comment:
+ return old
+
+ return new
+
+ def clean_comment(self):
+ """
+ If COMMENTS_ALLOW_PROFANITIES is False, check that the comment doesn't
+ contain anything in PROFANITIES_LIST.
+ """
+ comment = self.cleaned_data["comment"]
+ if settings.COMMENTS_ALLOW_PROFANITIES == False:
+ bad_words = [w for w in settings.PROFANITIES_LIST if w in comment.lower()]
+ if bad_words:
+ raise forms.ValidationError(ungettext(
+ "Watch your mouth! The word %s is not allowed here.",
+ "Watch your mouth! The words %s are not allowed here.",
+ len(bad_words)) % get_text_list(
+ ['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1])
+ for i in bad_words], ugettext('and')))
+ return comment
+
+class CommentForm(CommentDetailsForm):
+ honeypot = forms.CharField(required=False,
+ label=_('If you enter anything in this field '\
+ 'your comment will be treated as spam'))
+
+ def clean_honeypot(self):
+ """Check that nothing's been entered into the honeypot."""
+ value = self.cleaned_data["honeypot"]
+ if value:
+ raise forms.ValidationError(self.fields["honeypot"].label)
+ return value