Django

Code

root/django/trunk/django/contrib/comments/forms.py

Revision 9116, 6.6 kB (checked in by mtredinnick, 2 months ago)

Fixed #8879 -- Used ungettext instead of ngettext in the comments framework.
Patch from zgoda.

Line 
1 import re
2 import time
3 import datetime
4
5 from django import forms
6 from django.forms.util import ErrorDict
7 from django.conf import settings
8 from django.http import Http404
9 from django.contrib.contenttypes.models import ContentType
10 from models import Comment
11 from django.utils.encoding import force_unicode
12 from django.utils.hashcompat import sha_constructor
13 from django.utils.text import get_text_list
14 from django.utils.translation import ungettext, ugettext_lazy as _
15
16 COMMENT_MAX_LENGTH = getattr(settings,'COMMENT_MAX_LENGTH', 3000)
17
18 class CommentForm(forms.Form):
19     name          = forms.CharField(label=_("Name"), max_length=50)
20     email         = forms.EmailField(label=_("Email address"))
21     url           = forms.URLField(label=_("URL"), required=False)
22     comment       = forms.CharField(label=_('Comment'), widget=forms.Textarea,
23                                     max_length=COMMENT_MAX_LENGTH)
24     honeypot      = forms.CharField(required=False,
25                                     label=_('If you enter anything in this field '\
26                                             'your comment will be treated as spam'))
27     content_type  = forms.CharField(widget=forms.HiddenInput)
28     object_pk     = forms.CharField(widget=forms.HiddenInput)
29     timestamp     = forms.IntegerField(widget=forms.HiddenInput)
30     security_hash = forms.CharField(min_length=40, max_length=40, widget=forms.HiddenInput)
31
32     def __init__(self, target_object, data=None, initial=None):
33         self.target_object = target_object
34         if initial is None:
35             initial = {}
36         initial.update(self.generate_security_data())
37         super(CommentForm, self).__init__(data=data, initial=initial)
38
39     def get_comment_object(self):
40         """
41         Return a new (unsaved) comment object based on the information in this
42         form. Assumes that the form is already validated and will throw a
43         ValueError if not.
44
45         Does not set any of the fields that would come from a Request object
46         (i.e. ``user`` or ``ip_address``).
47         """
48         if not self.is_valid():
49             raise ValueError("get_comment_object may only be called on valid forms")
50
51         new = Comment(
52             content_type = ContentType.objects.get_for_model(self.target_object),
53             object_pk    = force_unicode(self.target_object._get_pk_val()),
54             user_name    = self.cleaned_data["name"],
55             user_email   = self.cleaned_data["email"],
56             user_url     = self.cleaned_data["url"],
57             comment      = self.cleaned_data["comment"],
58             submit_date  = datetime.datetime.now(),
59             site_id      = settings.SITE_ID,
60             is_public    = True,
61             is_removed   = False,
62         )
63
64         # Check that this comment isn't duplicate. (Sometimes people post comments
65         # twice by mistake.) If it is, fail silently by returning the old comment.
66         possible_duplicates = Comment.objects.filter(
67             content_type = new.content_type,
68             object_pk = new.object_pk,
69             user_name = new.user_name,
70             user_email = new.user_email,
71             user_url = new.user_url,
72         )
73         for old in possible_duplicates:
74             if old.submit_date.date() == new.submit_date.date() and old.comment == new.comment:
75                 return old
76
77         return new
78
79     def security_errors(self):
80         """Return just those errors associated with security"""
81         errors = ErrorDict()
82         for f in ["honeypot", "timestamp", "security_hash"]:
83             if f in self.errors:
84                 errors[f] = self.errors[f]
85         return errors
86
87     def clean_honeypot(self):
88         """Check that nothing's been entered into the honeypot."""
89         value = self.cleaned_data["honeypot"]
90         if value:
91             raise forms.ValidationError(self.fields["honeypot"].label)
92         return value
93
94     def clean_security_hash(self):
95         """Check the security hash."""
96         security_hash_dict = {
97             'content_type' : self.data.get("content_type", ""),
98             'object_pk' : self.data.get("object_pk", ""),
99             'timestamp' : self.data.get("timestamp", ""),
100         }
101         expected_hash = self.generate_security_hash(**security_hash_dict)
102         actual_hash = self.cleaned_data["security_hash"]
103         if expected_hash != actual_hash:
104             raise forms.ValidationError("Security hash check failed.")
105         return actual_hash
106
107     def clean_timestamp(self):
108         """Make sure the timestamp isn't too far (> 2 hours) in the past."""
109         ts = self.cleaned_data["timestamp"]
110         if time.time() - ts > (2 * 60 * 60):
111             raise forms.ValidationError("Timestamp check failed")
112         return ts
113
114     def clean_comment(self):
115         """
116         If COMMENTS_ALLOW_PROFANITIES is False, check that the comment doesn't
117         contain anything in PROFANITIES_LIST.
118         """
119         comment = self.cleaned_data["comment"]
120         if settings.COMMENTS_ALLOW_PROFANITIES == False:
121             bad_words = [w for w in settings.PROFANITIES_LIST if w in comment.lower()]
122             if bad_words:
123                 plural = len(bad_words) > 1
124                 raise forms.ValidationError(ungettext(
125                     "Watch your mouth! The word %s is not allowed here.",
126                     "Watch your mouth! The words %s are not allowed here.", plural) % \
127                     get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in bad_words], 'and'))
128         return comment
129
130     def generate_security_data(self):
131         """Generate a dict of security data for "initial" data."""
132         timestamp = int(time.time())
133         security_dict =   {
134             'content_type'  : str(self.target_object._meta),
135             'object_pk'     : str(self.target_object._get_pk_val()),
136             'timestamp'     : str(timestamp),
137             'security_hash' : self.initial_security_hash(timestamp),
138         }
139         return security_dict
140
141     def initial_security_hash(self, timestamp):
142         """
143         Generate the initial security hash from self.content_object
144         and a (unix) timestamp.
145         """
146
147         initial_security_dict = {
148             'content_type' : str(self.target_object._meta),
149             'object_pk' : str(self.target_object._get_pk_val()),
150             'timestamp' : str(timestamp),
151           }
152         return self.generate_security_hash(**initial_security_dict)
153
154     def generate_security_hash(self, content_type, object_pk, timestamp):
155         """Generate a (SHA1) security hash from the provided info."""
156         info = (content_type, object_pk, timestamp, settings.SECRET_KEY)
157         return sha_constructor("".join(info)).hexdigest()
Note: See TracBrowser for help on using the browser.