summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-10-28 05:37:03 -0300
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-10-28 05:37:03 -0300
commit980989b786c77ef2a7a23e23545c402e1b072591 (patch)
treee97799696a9770904f406cfdbd6fcbdb76aab262
parentd35142f03ff8631d81d9d1307666994ea2da6270 (diff)
downloadaskbot-980989b786c77ef2a7a23e23545c402e1b072591.tar.gz
askbot-980989b786c77ef2a7a23e23545c402e1b072591.tar.bz2
askbot-980989b786c77ef2a7a23e23545c402e1b072591.zip
added reputation limit to insert links into questions and answers
-rw-r--r--askbot/conf/minimum_reputation.py9
-rw-r--r--askbot/forms.py54
-rw-r--r--askbot/mail/__init__.py4
-rw-r--r--askbot/models/post.py11
-rw-r--r--askbot/models/question.py5
-rw-r--r--askbot/tests/form_tests.py56
-rw-r--r--askbot/views/commands.py2
-rw-r--r--askbot/views/readers.py2
-rw-r--r--askbot/views/widgets.py12
-rw-r--r--askbot/views/writers.py45
10 files changed, 137 insertions, 63 deletions
diff --git a/askbot/conf/minimum_reputation.py b/askbot/conf/minimum_reputation.py
index 152a2079..359855c9 100644
--- a/askbot/conf/minimum_reputation.py
+++ b/askbot/conf/minimum_reputation.py
@@ -107,6 +107,15 @@ settings.register(
settings.register(
livesettings.IntegerValue(
MIN_REP,
+ 'MIN_REP_TO_INSERT_LINK',
+ default=10,
+ description=_('Insert links')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
'MIN_REP_TO_CLOSE_OWN_QUESTIONS',
default=25,
description=_('Close own questions'),
diff --git a/askbot/forms.py b/askbot/forms.py
index 1c5bc3d6..0a0f4f33 100644
--- a/askbot/forms.py
+++ b/askbot/forms.py
@@ -11,6 +11,7 @@ from django.utils.text import get_text_list
from django.contrib.auth.models import User
from django_countries import countries
from askbot.utils.forms import NextUrlField, UserNameField
+from askbot.utils.markup import URL_RE
from askbot.mail import extract_first_email_address
from recaptcha_works.fields import RecaptchaField
from askbot.conf import settings as askbot_settings
@@ -273,6 +274,11 @@ class EditorField(forms.CharField):
min_length = 10 # sentinel default value
def __init__(self, *args, **kwargs):
+ user = kwargs.pop('user', None)
+ if user is None:
+ raise ValueError('user parameter is required')
+ self.user = user
+
editor_attrs = kwargs.pop('editor_attrs', {})
super(EditorField, self).__init__(*args, **kwargs)
self.required = True
@@ -295,6 +301,21 @@ class EditorField(forms.CharField):
self.min_length
) % self.min_length
raise forms.ValidationError(msg)
+
+ if re.search(URL_RE, value):
+ min_rep = askbot_settings.MIN_REP_TO_INSERT_LINK
+ if self.user.is_anonymous():
+ raise forms.ValidationError(
+ _('Links or images cannot be inserted anonymously')
+ )
+ elif self.user.reputation < min_rep:
+ raise forms.ValidationError(
+ ungettext_lazy(
+ 'At at least %d karma point is required to insert links',
+ 'At at least %d karma points are required to insert links',
+ min_rep
+ ) % min_rep
+ )
return value
@@ -302,7 +323,10 @@ class QuestionEditorField(EditorField):
"""Editor field for the questions"""
def __init__(self, *args, **kwargs):
- super(QuestionEditorField, self).__init__(*args, **kwargs)
+ user = kwargs.pop('user', None)
+ super(QuestionEditorField, self).__init__(
+ user=user, *args, **kwargs
+ )
self.length_error_template_singular = \
'question body must be > %d character'
self.length_error_template_plural = \
@@ -477,10 +501,12 @@ class EditorForm(forms.Form):
the field must be created dynamically, so it's added
in the __init__() function"""
- def __init__(self, editor_attrs=None):
+ def __init__(self, user=None, editor_attrs=None):
super(EditorForm, self).__init__()
editor_attrs = editor_attrs or {}
- self.fields['editor'] = EditorField(editor_attrs=editor_attrs)
+ self.fields['editor'] = EditorField(
+ user=user, editor_attrs=editor_attrs
+ )
class DumpUploadForm(forms.Form):
@@ -897,9 +923,10 @@ class AskForm(PostAsSomeoneForm, PostPrivatelyForm):
)
def __init__(self, *args, **kwargs):
+ user = kwargs.pop('user', None)
super(AskForm, self).__init__(*args, **kwargs)
#it's important that this field is set up dynamically
- self.fields['text'] = QuestionEditorField()
+ self.fields['text'] = QuestionEditorField(user=user)
#hide ask_anonymously field
if askbot_settings.ALLOW_ASK_ANONYMOUSLY is False:
self.hide_field('ask_anonymously')
@@ -932,11 +959,12 @@ class AskWidgetForm(forms.Form, FormWithHideableFields):
)
def __init__(self, include_text=True, *args, **kwargs):
+ user = kwargs.pop('user', None)
super(AskWidgetForm, self).__init__(*args, **kwargs)
#hide ask_anonymously field
if not askbot_settings.ALLOW_ASK_ANONYMOUSLY:
self.hide_field('ask_anonymously')
- self.fields['text'] = QuestionEditorField()
+ self.fields['text'] = QuestionEditorField(user=user)
if not include_text:
self.hide_field('text')
#hack to make it validate
@@ -1020,7 +1048,11 @@ class AskByEmailForm(forms.Form):
'required': ASK_BY_EMAIL_SUBJECT_HELP
}
)
- body_text = QuestionEditorField()
+
+ def __init__(self, *args, **kwargs):
+ user = kwargs.pop('user', None)
+ super(AskByEmailForm, self).__init__(*args, **kwargs)
+ self.fields['body_text'] = QuestionEditorField(user=user)
def clean_sender(self):
"""Cleans the :attr:`~askbot.forms.AskByEmail.sender` attribute
@@ -1074,7 +1106,6 @@ class AskByEmailForm(forms.Form):
class AnswerForm(PostAsSomeoneForm, PostPrivatelyForm):
- text = AnswerEditorField()
wiki = WikiField()
openid = forms.CharField(
required=False, max_length=255,
@@ -1084,7 +1115,7 @@ class AnswerForm(PostAsSomeoneForm, PostPrivatelyForm):
def __init__(self, *args, **kwargs):
super(AnswerForm, self).__init__(*args, **kwargs)
- self.fields['text'] = AnswerEditorField()
+ self.fields['text'] = AnswerEditorField(user=kwargs['user'])
self.fields['email_notify'].widget.attrs['id'] = \
'question-subscribe-updates'
@@ -1169,11 +1200,11 @@ class EditQuestionForm(PostAsSomeoneForm, PostPrivatelyForm):
def __init__(self, *args, **kwargs):
"""populate EditQuestionForm with initial data"""
self.question = kwargs.pop('question')
- self.user = kwargs['user']#preserve for superclass
+ self.user = kwargs.pop('user')#preserve for superclass
revision = kwargs.pop('revision')
super(EditQuestionForm, self).__init__(*args, **kwargs)
#it is important to add this field dynamically
- self.fields['text'] = QuestionEditorField()
+ self.fields['text'] = QuestionEditorField(user=self.user)
self.fields['title'].initial = revision.title
self.fields['text'].initial = revision.text
self.fields['tags'].initial = revision.tagnames
@@ -1275,9 +1306,10 @@ class EditAnswerForm(PostAsSomeoneForm, PostPrivatelyForm):
def __init__(self, answer, revision, *args, **kwargs):
self.answer = answer
+ user = kwargs.pop('user', None)
super(EditAnswerForm, self).__init__(*args, **kwargs)
#it is important to add this field dynamically
- self.fields['text'] = AnswerEditorField()
+ self.fields['text'] = AnswerEditorField(user=user)
self.fields['text'].initial = revision.text
self.fields['wiki'].initial = answer.wiki
diff --git a/askbot/mail/__init__.py b/askbot/mail/__init__.py
index 74aa27e9..c8ec130e 100644
--- a/askbot/mail/__init__.py
+++ b/askbot/mail/__init__.py
@@ -362,10 +362,10 @@ def process_emailed_question(
'subject': subject,
'body_text': body_text
}
- form = AskByEmailForm(data)
+ user = User.objects.get(email__iexact = email_address)
+ form = AskByEmailForm(data, user=user)
if form.is_valid():
email_address = form.cleaned_data['email']
- user = User.objects.get(email__iexact = email_address)
if user.can_post_by_email() is False:
raise PermissionDenied(messages.insufficient_reputation(user))
diff --git a/askbot/models/post.py b/askbot/models/post.py
index daf9c93f..62fdcc46 100644
--- a/askbot/models/post.py
+++ b/askbot/models/post.py
@@ -884,17 +884,6 @@ class Post(models.Model):
if parent_post is None:
break
quote_level += 1
- """
- output += '<p>'
- output += _(
- 'In reply to %(user)s %(post)s of %(date)s'
- ) % {
- 'user': parent_post.author.username,
- 'post': _(parent_post.post_type),
- 'date': parent_post.added_at.strftime(const.DATETIME_FORMAT)
- }
- output += '</p>'
- """
output += parent_post.format_for_email(
quote_level = quote_level,
format = 'parent_subthread'
diff --git a/askbot/models/question.py b/askbot/models/question.py
index 7faf589b..43844c82 100644
--- a/askbot/models/question.py
+++ b/askbot/models/question.py
@@ -702,7 +702,10 @@ class Thread(models.Model):
def format_for_email(self, user=None):
"""experimental function: output entire thread for email"""
- question, answers, junk, published_ans_ids = self.get_cached_post_data(user=user)
+
+ question, answers, junk, published_ans_ids = \
+ self.get_cached_post_data(user=user)
+
output = question.format_for_email_as_subthread()
if answers:
answer_heading = ungettext(
diff --git a/askbot/tests/form_tests.py b/askbot/tests/form_tests.py
index 90f4f4f2..21286b9b 100644
--- a/askbot/tests/form_tests.py
+++ b/askbot/tests/form_tests.py
@@ -1,5 +1,7 @@
from django import forms as django_forms
+from django.contrib.auth.models import AnonymousUser
from askbot.tests.utils import AskbotTestCase
+from askbot.tests.utils import with_settings
from askbot.conf import settings as askbot_settings
from askbot import forms
from askbot.utils import forms as util_forms
@@ -53,9 +55,10 @@ class AskByEmailFormTests(AskbotTestCase):
and makes sure that tags and title are parsed out"""
setting_backup = askbot_settings.TAGS_ARE_REQUIRED
askbot_settings.update('TAGS_ARE_REQUIRED', True)
+ user = AnonymousUser()
for test_case in SUBJECT_LINE_CASES:
self.data['subject'] = test_case[0]
- form = forms.AskByEmailForm(self.data)
+ form = forms.AskByEmailForm(self.data, user=user)
output = test_case[1]
if output is None:
self.assertFalse(form.is_valid())
@@ -75,10 +78,11 @@ class AskByEmailFormTests(AskbotTestCase):
"""loops through variants of the from field
in the emails and tests the email address
extractor"""
+ user = AnonymousUser()
for test_case in EMAIL_CASES:
self.data['sender'] = test_case[0]
expected_result = test_case[1]
- form = forms.AskByEmailForm(self.data)
+ form = forms.AskByEmailForm(self.data, user=user)
if expected_result is None:
self.assertFalse(form.is_valid())
else:
@@ -196,9 +200,9 @@ class EditQuestionAnonymouslyFormTests(AskbotTestCase):
data['reveal_identity'] = 'on'
self.form = forms.EditQuestionForm(
data,
- question = question,
- user = editor,
- revision = question.get_latest_revision(),
+ question=question,
+ user=editor,
+ revision=question.get_latest_revision(),
)
def test_reveal_identity_field(self):
@@ -230,7 +234,7 @@ class AskFormTests(AskbotTestCase):
}
if ask_anonymously == True:
data['ask_anonymously'] = 'on'
- self.form = forms.AskForm(data)
+ self.form = forms.AskForm(data, user=AnonymousUser())
self.form.full_clean()
def assert_anon_is(self, value):
@@ -317,7 +321,7 @@ class AnswerEditorFieldTests(AskbotTestCase):
def setUp(self):
self.old_min_length = askbot_settings.MIN_ANSWER_BODY_LENGTH
askbot_settings.update('MIN_ANSWER_BODY_LENGTH', 10)
- self.field = forms.AnswerEditorField()
+ self.field = forms.AnswerEditorField(user=AnonymousUser())
def tearDown(self):
askbot_settings.update('MIN_ANSWER_BODY_LENGTH', self.old_min_length)
@@ -364,8 +368,6 @@ class PostAsSomeoneFormTests(AskbotTestCase):
class AskWidgetFormTests(AskbotTestCase):
- form = forms.AskWidgetForm
-
def setUp(self):
self.good_data = {'title': "What's the price of a house in london?"}
self.good_data_anon = {'title': "What's the price of a house in london?",
@@ -374,12 +376,40 @@ class AskWidgetFormTests(AskbotTestCase):
self.bad_data = {'title': ''}
def test_valid_input(self):
- form_object = self.form(include_text=False, data=self.good_data)
- print form_object.errors
+ form_object = forms.AskWidgetForm(
+ include_text=False, data=self.good_data, user=AnonymousUser()
+ )
self.assertTrue(form_object.is_valid())
- form_object = self.form(include_text=False, data=self.good_data_anon)
+ form_object = forms.AskWidgetForm(
+ include_text=False, data=self.good_data_anon, user=AnonymousUser()
+ )
self.assertTrue(form_object.is_valid())
def test_invalid_input(self):
- form_object = self.form(False, data=self.bad_data)
+ form_object = forms.AskWidgetForm(
+ include_text=False, data=self.bad_data, user=AnonymousUser()
+ )
self.assertFalse(form_object.is_valid())
+
+
+TEXT_WITH_LINK = 'blah blah http://example.com/url/image.png'
+class EditorFieldTests(AskbotTestCase):
+
+ def setUp(self):
+ self.user = self.create_user('user')
+ self.user.reputation = 5
+ self.user.save()
+
+ @with_settings(EDITOR_TYPE='markdown', MIN_REP_TO_INSERT_LINK=10)
+ def test_low_rep_user_cannot_post_links_markdown(self):
+ field = forms.EditorField(user=self.user)
+ self.assertRaises(
+ django_forms.ValidationError, field.clean, TEXT_WITH_LINK
+ )
+
+ @with_settings(EDITOR_TYPE='tinymce', MIN_REP_TO_INSERT_LINK=10)
+ def test_low_rep_user_cannot_post_links_tinymce(self):
+ field = forms.EditorField(user=self.user)
+ self.assertRaises(
+ django_forms.ValidationError, field.clean, TEXT_WITH_LINK
+ )
diff --git a/askbot/views/commands.py b/askbot/views/commands.py
index 698bf2db..c072f7b8 100644
--- a/askbot/views/commands.py
+++ b/askbot/views/commands.py
@@ -1348,7 +1348,7 @@ def get_editor(request):
if 'config' not in request.GET:
return HttpResponseForbidden()
config = simplejson.loads(request.GET['config'])
- form = forms.EditorForm(editor_attrs=config)
+ form = forms.EditorForm(editor_attrs=config, user=request.user)
editor_html = render_text_into_skin(
'{{ form.media }} {{ form.editor }}',
{'form': form},
diff --git a/askbot/views/readers.py b/askbot/views/readers.py
index 5a3e378b..9801d5bc 100644
--- a/askbot/views/readers.py
+++ b/askbot/views/readers.py
@@ -549,7 +549,7 @@ def question(request, id):#refactor - long subroutine. display question body, an
if drafts.count() > 0:
initial['text'] = drafts[0].text
- answer_form = AnswerForm(initial)
+ answer_form = AnswerForm(initial, user=request.user)
user_can_post_comment = (
request.user.is_authenticated() and request.user.can_post_comment()
diff --git a/askbot/views/widgets.py b/askbot/views/widgets.py
index 8699cdf1..4401bbdc 100644
--- a/askbot/views/widgets.py
+++ b/askbot/views/widgets.py
@@ -61,8 +61,11 @@ def ask_widget(request, widget_id):
widget = get_object_or_404(models.AskWidget, id=widget_id)
if request.method == "POST":
- form = forms.AskWidgetForm(include_text=widget.include_text_field,
- data=request.POST)
+ form = forms.AskWidgetForm(
+ include_text=widget.include_text_field,
+ data=request.POST,
+ user=request.user
+ )
if form.is_valid():
ask_anonymously = form.cleaned_data['ask_anonymously']
title = form.cleaned_data['title']
@@ -116,7 +119,10 @@ def ask_widget(request, widget_id):
next_url = '%s?next=%s' % (reverse('widget_signin'), reverse('ask_by_widget'))
return redirect(next_url)
- form = forms.AskWidgetForm(include_text=widget.include_text_field)
+ form = forms.AskWidgetForm(
+ include_text=widget.include_text_field,
+ user=request.user
+ )
data = {
'form': form,
diff --git a/askbot/views/writers.py b/askbot/views/writers.py
index db7a24d2..d1504d23 100644
--- a/askbot/views/writers.py
+++ b/askbot/views/writers.py
@@ -211,7 +211,7 @@ def ask(request):#view used to ask a new question
user can start posting a question anonymously but then
must login/register in order for the question go be shown
"""
- form = forms.AskForm(request.REQUEST)
+ form = forms.AskForm(request.REQUEST, user=request.user)
if request.method == 'POST':
if form.is_valid():
timestamp = datetime.datetime.now()
@@ -264,7 +264,7 @@ def ask(request):#view used to ask a new question
return HttpResponseRedirect(url_utils.get_login_url())
if request.method == 'GET':
- form = forms.AskForm()
+ form = forms.AskForm(user=request.user)
draft_title = ''
draft_text = ''
@@ -386,24 +386,24 @@ def edit_question(request, id):
rev_id = revision_form.cleaned_data['revision']
revision = question.revisions.get(revision = rev_id)
form = forms.EditQuestionForm(
- question = question,
- user = request.user,
- revision = revision
+ question=question,
+ user=request.user,
+ revision=revision
)
else:
form = forms.EditQuestionForm(
request.POST,
- question = question,
- user = request.user,
- revision = revision
+ question=question,
+ user=quest.user,
+ revision=revision
)
else:#new content edit
# Always check modifications against the latest revision
form = forms.EditQuestionForm(
request.POST,
- question = question,
- revision = revision,
- user = request.user,
+ question=question,
+ revision=revision,
+ user=request.user,
)
revision_form = forms.RevisionForm(question, revision)
if form.is_valid():
@@ -437,10 +437,10 @@ def edit_question(request, id):
'wiki': question.wiki
}
form = forms.EditQuestionForm(
- question = question,
- revision = revision,
- user = request.user,
- initial = initial
+ question=question,
+ revision=revision,
+ user=request.user,
+ initial=initial
)
data = {
@@ -481,15 +481,20 @@ def edit_answer(request, id):
# Replace with those from the selected revision
rev = revision_form.cleaned_data['revision']
revision = answer.revisions.get(revision = rev)
- form = forms.EditAnswerForm(answer, revision)
+ form = forms.EditAnswerForm(
+ answer, revision, user=request.user
+ )
else:
form = forms.EditAnswerForm(
answer,
revision,
- request.POST
+ request.POST,
+ user=request.user
)
else:
- form = forms.EditAnswerForm(answer, revision, request.POST)
+ form = forms.EditAnswerForm(
+ answer, revision, request.POST, user=request.user
+ )
revision_form = forms.RevisionForm(answer, revision)
if form.is_valid():
@@ -506,7 +511,7 @@ def edit_answer(request, id):
return HttpResponseRedirect(answer.get_absolute_url())
else:
revision_form = forms.RevisionForm(answer, revision)
- form = forms.EditAnswerForm(answer, revision)
+ form = forms.EditAnswerForm(answer, revision, user=request.user)
if request.user.can_make_group_private_posts():
form.initial['post_privately'] = answer.is_private()
data = {
@@ -536,7 +541,7 @@ def answer(request, id):#process a new answer
"""
question = get_object_or_404(models.Post, post_type='question', id=id)
if request.method == "POST":
- form = forms.AnswerForm(request.POST)
+ form = forms.AnswerForm(request.POST, user=request.user)
if form.is_valid():
wiki = form.cleaned_data['wiki']
text = form.cleaned_data['text']