2006-05-02 09:31:56 +08:00
from django . core import validators
2006-12-16 02:00:50 +08:00
from django import oldforms
2005-07-13 09:25:57 +08:00
from django . core . mail import mail_admins , mail_managers
2006-05-02 09:31:56 +08:00
from django . http import Http404
from django . core . exceptions import ObjectDoesNotExist
from django . shortcuts import render_to_response
from django . template import RequestContext
2006-07-22 01:11:13 +08:00
from django . contrib . comments . models import Comment , FreeComment , RATINGS_REQUIRED , RATINGS_OPTIONAL , IS_PUBLIC
2006-05-02 09:31:56 +08:00
from django . contrib . contenttypes . models import ContentType
from django . contrib . auth . forms import AuthenticationForm
from django . http import HttpResponseRedirect
2005-07-13 09:25:57 +08:00
from django . utils . text import normalize_newlines
2006-05-02 09:31:56 +08:00
from django . conf import settings
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
from django . utils . translation import ungettext , ugettext as _
from django . utils . encoding import smart_unicode
2005-07-13 09:25:57 +08:00
import base64 , datetime
COMMENTS_PER_PAGE = 20
class PublicCommentManipulator ( AuthenticationForm ) :
" Manipulator that handles public registered comments "
def __init__ ( self , user , ratings_required , ratings_range , num_rating_choices ) :
AuthenticationForm . __init__ ( self )
self . ratings_range , self . num_rating_choices = ratings_range , num_rating_choices
choices = [ ( c , c ) for c in ratings_range ]
def get_validator_list ( rating_num ) :
if rating_num < = num_rating_choices :
2005-11-23 23:42:09 +08:00
return [ validators . RequiredIfOtherFieldsGiven ( [ ' rating %d ' % i for i in range ( 1 , 9 ) if i != rating_num ] , _ ( " This rating is required because you ' ve entered at least one other rating. " ) ) ]
2005-07-13 09:25:57 +08:00
else :
return [ ]
self . fields . extend ( [
2007-08-05 13:14:46 +08:00
oldforms . LargeTextField ( field_name = " comment " , max_length = 3000 , is_required = True ,
2005-07-13 09:25:57 +08:00
validator_list = [ self . hasNoProfanities ] ) ,
2006-12-16 02:00:50 +08:00
oldforms . RadioSelectField ( field_name = " rating1 " , choices = choices ,
2005-07-13 09:25:57 +08:00
is_required = ratings_required and num_rating_choices > 0 ,
validator_list = get_validator_list ( 1 ) ,
) ,
2006-12-16 02:00:50 +08:00
oldforms . RadioSelectField ( field_name = " rating2 " , choices = choices ,
2005-07-13 09:25:57 +08:00
is_required = ratings_required and num_rating_choices > 1 ,
validator_list = get_validator_list ( 2 ) ,
) ,
2006-12-16 02:00:50 +08:00
oldforms . RadioSelectField ( field_name = " rating3 " , choices = choices ,
2005-07-13 09:25:57 +08:00
is_required = ratings_required and num_rating_choices > 2 ,
validator_list = get_validator_list ( 3 ) ,
) ,
2006-12-16 02:00:50 +08:00
oldforms . RadioSelectField ( field_name = " rating4 " , choices = choices ,
2005-07-13 09:25:57 +08:00
is_required = ratings_required and num_rating_choices > 3 ,
validator_list = get_validator_list ( 4 ) ,
) ,
2006-12-16 02:00:50 +08:00
oldforms . RadioSelectField ( field_name = " rating5 " , choices = choices ,
2005-07-13 09:25:57 +08:00
is_required = ratings_required and num_rating_choices > 4 ,
validator_list = get_validator_list ( 5 ) ,
) ,
2006-12-16 02:00:50 +08:00
oldforms . RadioSelectField ( field_name = " rating6 " , choices = choices ,
2005-07-13 09:25:57 +08:00
is_required = ratings_required and num_rating_choices > 5 ,
validator_list = get_validator_list ( 6 ) ,
) ,
2006-12-16 02:00:50 +08:00
oldforms . RadioSelectField ( field_name = " rating7 " , choices = choices ,
2005-07-13 09:25:57 +08:00
is_required = ratings_required and num_rating_choices > 6 ,
validator_list = get_validator_list ( 7 ) ,
) ,
2006-12-16 02:00:50 +08:00
oldforms . RadioSelectField ( field_name = " rating8 " , choices = choices ,
2005-07-13 09:25:57 +08:00
is_required = ratings_required and num_rating_choices > 7 ,
validator_list = get_validator_list ( 8 ) ,
) ,
] )
2006-07-19 10:09:26 +08:00
if user . is_authenticated ( ) :
2005-07-13 09:25:57 +08:00
self [ " username " ] . is_required = False
self [ " username " ] . validator_list = [ ]
self [ " password " ] . is_required = False
self [ " password " ] . validator_list = [ ]
self . user_cache = user
def hasNoProfanities ( self , field_data , all_data ) :
2006-05-02 09:31:56 +08:00
if settings . COMMENTS_ALLOW_PROFANITIES :
2005-07-13 09:25:57 +08:00
return
return validators . hasNoProfanities ( field_data , all_data )
def get_comment ( self , new_data ) :
" Helper function "
2006-05-02 09:31:56 +08:00
return Comment ( None , self . get_user_id ( ) , new_data [ " content_type_id " ] ,
2005-07-13 09:25:57 +08:00
new_data [ " object_id " ] , new_data . get ( " headline " , " " ) . strip ( ) ,
new_data [ " comment " ] . strip ( ) , new_data . get ( " rating1 " , None ) ,
new_data . get ( " rating2 " , None ) , new_data . get ( " rating3 " , None ) ,
new_data . get ( " rating4 " , None ) , new_data . get ( " rating5 " , None ) ,
new_data . get ( " rating6 " , None ) , new_data . get ( " rating7 " , None ) ,
new_data . get ( " rating8 " , None ) , new_data . get ( " rating1 " , None ) is not None ,
2006-05-02 09:31:56 +08:00
datetime . datetime . now ( ) , new_data [ " is_public " ] , new_data [ " ip_address " ] , False , settings . SITE_ID )
2005-07-13 09:25:57 +08:00
def save ( self , new_data ) :
today = datetime . date . today ( )
c = self . get_comment ( new_data )
2006-05-02 09:31:56 +08:00
for old in Comment . objects . filter ( content_type__id__exact = new_data [ " content_type_id " ] ,
2005-08-26 06:51:30 +08:00
object_id__exact = new_data [ " object_id " ] , user__id__exact = self . get_user_id ( ) ) :
2005-07-13 09:25:57 +08:00
# Check that this comment isn't duplicate. (Sometimes people post
# comments twice by mistake.) If it is, fail silently by pretending
# the comment was posted successfully.
if old . submit_date . date ( ) == today and old . comment == c . comment \
and old . rating1 == c . rating1 and old . rating2 == c . rating2 \
and old . rating3 == c . rating3 and old . rating4 == c . rating4 \
and old . rating5 == c . rating5 and old . rating6 == c . rating6 \
and old . rating7 == c . rating7 and old . rating8 == c . rating8 :
return old
# If the user is leaving a rating, invalidate all old ratings.
if c . rating1 is not None :
old . valid_rating = False
old . save ( )
c . save ( )
# If the commentor has posted fewer than COMMENTS_FIRST_FEW comments,
# send the comment to the managers.
2006-05-02 09:31:56 +08:00
if self . user_cache . comment_set . count ( ) < = settings . COMMENTS_FIRST_FEW :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
message = ungettext ( ' This comment was posted by a user who has posted fewer than %(count)s comment: \n \n %(text)s ' ,
2006-10-26 05:56:17 +08:00
' This comment was posted by a user who has posted fewer than %(count)s comments: \n \n %(text)s ' , settings . COMMENTS_FIRST_FEW ) % \
2006-05-02 09:31:56 +08:00
{ ' count ' : settings . COMMENTS_FIRST_FEW , ' text ' : c . get_as_text ( ) }
2005-07-13 09:25:57 +08:00
mail_managers ( " Comment posted by rookie user " , message )
2007-08-11 18:50:39 +08:00
if settings . COMMENTS_SKETCHY_USERS_GROUP and settings . COMMENTS_SKETCHY_USERS_GROUP in [ g . id for g in self . user_cache . groups . all ( ) ] :
2005-11-23 23:42:09 +08:00
message = _ ( ' This comment was posted by a sketchy user: \n \n %(text)s ' ) % { ' text ' : c . get_as_text ( ) }
2005-07-13 09:25:57 +08:00
mail_managers ( " Comment posted by sketchy user ( %s ) " % self . user_cache . username , c . get_as_text ( ) )
return c
2006-12-16 02:00:50 +08:00
class PublicFreeCommentManipulator ( oldforms . Manipulator ) :
2005-07-13 09:25:57 +08:00
" Manipulator that handles public free (unregistered) comments "
def __init__ ( self ) :
self . fields = (
2007-08-05 13:14:46 +08:00
oldforms . TextField ( field_name = " person_name " , max_length = 50 , is_required = True ,
2005-07-13 09:25:57 +08:00
validator_list = [ self . hasNoProfanities ] ) ,
2007-08-05 13:14:46 +08:00
oldforms . LargeTextField ( field_name = " comment " , max_length = 3000 , is_required = True ,
2005-07-13 09:25:57 +08:00
validator_list = [ self . hasNoProfanities ] ) ,
)
def hasNoProfanities ( self , field_data , all_data ) :
2006-05-02 09:31:56 +08:00
if settings . COMMENTS_ALLOW_PROFANITIES :
2005-07-13 09:25:57 +08:00
return
return validators . hasNoProfanities ( field_data , all_data )
def get_comment ( self , new_data ) :
" Helper function "
2006-05-02 09:31:56 +08:00
return FreeComment ( None , new_data [ " content_type_id " ] ,
2005-07-13 09:25:57 +08:00
new_data [ " object_id " ] , new_data [ " comment " ] . strip ( ) ,
new_data [ " person_name " ] . strip ( ) , datetime . datetime . now ( ) , new_data [ " is_public " ] ,
2006-05-02 09:31:56 +08:00
new_data [ " ip_address " ] , False , settings . SITE_ID )
2005-07-13 09:25:57 +08:00
def save ( self , new_data ) :
today = datetime . date . today ( )
c = self . get_comment ( new_data )
# Check that this comment isn't duplicate. (Sometimes people post
# comments twice by mistake.) If it is, fail silently by pretending
# the comment was posted successfully.
2006-05-02 09:31:56 +08:00
for old_comment in FreeComment . objects . filter ( content_type__id__exact = new_data [ " content_type_id " ] ,
2005-07-13 09:25:57 +08:00
object_id__exact = new_data [ " object_id " ] , person_name__exact = new_data [ " person_name " ] ,
submit_date__year = today . year , submit_date__month = today . month ,
submit_date__day = today . day ) :
if old_comment . comment == c . comment :
return old_comment
c . save ( )
return c
def post_comment ( request ) :
"""
Post a comment
Redirects to the ` comments . comments . comment_was_posted ` view upon success .
Templates : ` comment_preview `
Context :
comment
the comment being posted
comment_form
the comment form
options
comment options
target
comment target
hash
security hash ( must be included in a posted form to succesfully
post a comment ) .
rating_options
comment ratings options
ratings_optional
are ratings optional ?
ratings_required
are ratings required ?
rating_range
range of ratings
rating_choices
choice of ratings
"""
if not request . POST :
2005-11-23 23:42:09 +08:00
raise Http404 , _ ( " Only POSTs are allowed " )
2005-07-13 09:25:57 +08:00
try :
options , target , security_hash = request . POST [ ' options ' ] , request . POST [ ' target ' ] , request . POST [ ' gonzo ' ]
except KeyError :
2005-11-23 23:42:09 +08:00
raise Http404 , _ ( " One or more of the required fields wasn ' t submitted " )
2005-07-13 09:25:57 +08:00
photo_options = request . POST . get ( ' photo_options ' , ' ' )
rating_options = normalize_newlines ( request . POST . get ( ' rating_options ' , ' ' ) )
2006-05-02 09:31:56 +08:00
if Comment . objects . get_security_hash ( options , photo_options , rating_options , target ) != security_hash :
2005-11-23 23:42:09 +08:00
raise Http404 , _ ( " Somebody tampered with the comment form (security violation) " )
2005-07-13 09:25:57 +08:00
# Now we can be assured the data is valid.
if rating_options :
2006-05-02 09:31:56 +08:00
rating_range , rating_choices = Comment . objects . get_rating_options ( base64 . decodestring ( rating_options ) )
2005-07-13 09:25:57 +08:00
else :
rating_range , rating_choices = [ ] , [ ]
content_type_id , object_id = target . split ( ' : ' ) # target is something like '52:5157'
try :
2006-05-02 09:31:56 +08:00
obj = ContentType . objects . get ( pk = content_type_id ) . get_object_for_this_type ( pk = object_id )
2005-07-13 09:25:57 +08:00
except ObjectDoesNotExist :
2005-11-23 23:42:09 +08:00
raise Http404 , _ ( " The comment form had an invalid ' target ' parameter -- the object ID was invalid " )
2005-07-13 09:25:57 +08:00
option_list = options . split ( ' , ' ) # options is something like 'pa,ra'
new_data = request . POST . copy ( )
new_data [ ' content_type_id ' ] = content_type_id
new_data [ ' object_id ' ] = object_id
2005-09-01 00:27:59 +08:00
new_data [ ' ip_address ' ] = request . META . get ( ' REMOTE_ADDR ' )
2006-05-02 09:31:56 +08:00
new_data [ ' is_public ' ] = IS_PUBLIC in option_list
2005-07-13 09:25:57 +08:00
manipulator = PublicCommentManipulator ( request . user ,
2006-05-02 09:31:56 +08:00
ratings_required = RATINGS_REQUIRED in option_list ,
2005-07-13 09:25:57 +08:00
ratings_range = rating_range ,
num_rating_choices = len ( rating_choices ) )
errors = manipulator . get_validation_errors ( new_data )
# If user gave correct username/password and wasn't already logged in, log them in
# so they don't have to enter a username/password again.
2007-04-26 21:30:48 +08:00
if manipulator . get_user ( ) and not manipulator . get_user ( ) . is_authenticated ( ) and ' password ' in new_data and manipulator . get_user ( ) . check_password ( new_data [ ' password ' ] ) :
2006-06-29 00:37:02 +08:00
from django . contrib . auth import login
login ( request , manipulator . get_user ( ) )
2007-04-26 21:30:48 +08:00
if errors or ' preview ' in request . POST :
2006-12-16 02:00:50 +08:00
class CommentFormWrapper ( oldforms . FormWrapper ) :
2005-07-13 09:25:57 +08:00
def __init__ ( self , manipulator , new_data , errors , rating_choices ) :
2006-12-16 02:00:50 +08:00
oldforms . FormWrapper . __init__ ( self , manipulator , new_data , errors )
2005-07-13 09:25:57 +08:00
self . rating_choices = rating_choices
def ratings ( self ) :
field_list = [ self [ ' rating %d ' % ( i + 1 ) ] for i in range ( len ( rating_choices ) ) ]
for i , f in enumerate ( field_list ) :
f . choice = rating_choices [ i ]
return field_list
comment = errors and ' ' or manipulator . get_comment ( new_data )
comment_form = CommentFormWrapper ( manipulator , new_data , errors , rating_choices )
2006-05-02 09:31:56 +08:00
return render_to_response ( ' comments/preview.html ' , {
2005-07-13 09:25:57 +08:00
' comment ' : comment ,
' comment_form ' : comment_form ,
' options ' : options ,
' target ' : target ,
' hash ' : security_hash ,
' rating_options ' : rating_options ,
2006-05-02 09:31:56 +08:00
' ratings_optional ' : RATINGS_OPTIONAL in option_list ,
' ratings_required ' : RATINGS_REQUIRED in option_list ,
2005-07-13 09:25:57 +08:00
' rating_range ' : rating_range ,
' rating_choices ' : rating_choices ,
2006-05-02 09:31:56 +08:00
} , context_instance = RequestContext ( request ) )
2007-04-26 21:30:48 +08:00
elif ' post ' in request . POST :
2005-07-13 09:25:57 +08:00
# If the IP is banned, mail the admins, do NOT save the comment, and
# serve up the "Thanks for posting" page as if the comment WAS posted.
2006-05-02 09:31:56 +08:00
if request . META [ ' REMOTE_ADDR ' ] in settings . BANNED_IPS :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
mail_admins ( " Banned IP attempted to post comment " , smart_unicode ( request . POST ) + " \n \n " + str ( request . META ) )
2005-07-13 09:25:57 +08:00
else :
manipulator . do_html2python ( new_data )
comment = manipulator . save ( new_data )
2006-05-26 12:06:46 +08:00
return HttpResponseRedirect ( " ../posted/?c= %s : %s " % ( content_type_id , object_id ) )
2005-07-13 09:25:57 +08:00
else :
2005-11-23 23:42:09 +08:00
raise Http404 , _ ( " The comment form didn ' t provide either ' preview ' or ' post ' " )
2005-07-13 09:25:57 +08:00
def post_free_comment ( request ) :
"""
Post a free comment ( not requiring a log in )
Redirects to ` comments . comments . comment_was_posted ` view on success .
Templates : ` comment_free_preview `
Context :
comment
comment being posted
comment_form
comment form object
options
comment options
target
comment target
hash
security hash ( must be included in a posted form to succesfully
post a comment ) .
"""
if not request . POST :
2005-11-23 23:42:09 +08:00
raise Http404 , _ ( " Only POSTs are allowed " )
2005-07-13 09:25:57 +08:00
try :
options , target , security_hash = request . POST [ ' options ' ] , request . POST [ ' target ' ] , request . POST [ ' gonzo ' ]
except KeyError :
2005-11-23 23:42:09 +08:00
raise Http404 , _ ( " One or more of the required fields wasn ' t submitted " )
2006-05-02 09:31:56 +08:00
if Comment . objects . get_security_hash ( options , ' ' , ' ' , target ) != security_hash :
2005-11-23 23:42:09 +08:00
raise Http404 , _ ( " Somebody tampered with the comment form (security violation) " )
2005-07-13 09:25:57 +08:00
content_type_id , object_id = target . split ( ' : ' ) # target is something like '52:5157'
2006-05-02 09:31:56 +08:00
content_type = ContentType . objects . get ( pk = content_type_id )
2005-07-13 09:25:57 +08:00
try :
2005-07-27 00:11:43 +08:00
obj = content_type . get_object_for_this_type ( pk = object_id )
2005-07-13 09:25:57 +08:00
except ObjectDoesNotExist :
2005-11-23 23:42:09 +08:00
raise Http404 , _ ( " The comment form had an invalid ' target ' parameter -- the object ID was invalid " )
2005-07-13 09:25:57 +08:00
option_list = options . split ( ' , ' )
new_data = request . POST . copy ( )
new_data [ ' content_type_id ' ] = content_type_id
new_data [ ' object_id ' ] = object_id
new_data [ ' ip_address ' ] = request . META [ ' REMOTE_ADDR ' ]
2006-05-02 09:31:56 +08:00
new_data [ ' is_public ' ] = IS_PUBLIC in option_list
2005-07-13 09:25:57 +08:00
manipulator = PublicFreeCommentManipulator ( )
errors = manipulator . get_validation_errors ( new_data )
2007-04-26 21:30:48 +08:00
if errors or ' preview ' in request . POST :
2005-07-13 09:25:57 +08:00
comment = errors and ' ' or manipulator . get_comment ( new_data )
2006-05-02 09:31:56 +08:00
return render_to_response ( ' comments/free_preview.html ' , {
2005-07-13 09:25:57 +08:00
' comment ' : comment ,
2006-12-16 02:00:50 +08:00
' comment_form ' : oldforms . FormWrapper ( manipulator , new_data , errors ) ,
2005-07-13 09:25:57 +08:00
' options ' : options ,
' target ' : target ,
' hash ' : security_hash ,
2006-05-02 09:31:56 +08:00
} , context_instance = RequestContext ( request ) )
2007-04-26 21:30:48 +08:00
elif ' post ' in request . POST :
2005-07-13 09:25:57 +08:00
# If the IP is banned, mail the admins, do NOT save the comment, and
# serve up the "Thanks for posting" page as if the comment WAS posted.
2006-05-02 09:31:56 +08:00
if request . META [ ' REMOTE_ADDR ' ] in settings . BANNED_IPS :
2005-07-13 09:25:57 +08:00
from django . core . mail import mail_admins
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
mail_admins ( " Practical joker " , smart_unicode ( request . POST ) + " \n \n " + str ( request . META ) )
2005-07-13 09:25:57 +08:00
else :
manipulator . do_html2python ( new_data )
comment = manipulator . save ( new_data )
2006-05-26 12:06:46 +08:00
return HttpResponseRedirect ( " ../posted/?c= %s : %s " % ( content_type_id , object_id ) )
2005-07-13 09:25:57 +08:00
else :
2005-11-23 23:42:09 +08:00
raise Http404 , _ ( " The comment form didn ' t provide either ' preview ' or ' post ' " )
2005-07-13 09:25:57 +08:00
def comment_was_posted ( request ) :
"""
Display " comment was posted " success page
Templates : ` comment_posted `
Context :
object
The object the comment was posted on
"""
obj = None
2007-04-26 21:30:48 +08:00
if ' c ' in request . GET :
2005-07-13 09:25:57 +08:00
content_type_id , object_id = request . GET [ ' c ' ] . split ( ' : ' )
try :
2006-05-02 09:31:56 +08:00
content_type = ContentType . objects . get ( pk = content_type_id )
2005-07-27 00:11:43 +08:00
obj = content_type . get_object_for_this_type ( pk = object_id )
2005-07-13 09:25:57 +08:00
except ObjectDoesNotExist :
pass
2006-05-02 09:31:56 +08:00
return render_to_response ( ' comments/posted.html ' , { ' object ' : obj } , context_instance = RequestContext ( request ) )