summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--askbot/conf/forum_data_rules.py27
-rw-r--r--askbot/doc/source/changelog.rst2
-rw-r--r--askbot/forms.py45
-rw-r--r--askbot/models/__init__.py8
-rw-r--r--askbot/models/content.py2
-rw-r--r--askbot/skins/common/media/js/post.js42
-rw-r--r--askbot/skins/default/media/style/style.less4
-rw-r--r--askbot/skins/default/templates/answer_edit.html6
-rw-r--r--askbot/skins/default/templates/meta/editor_data.html3
-rw-r--r--askbot/skins/default/templates/question/javascript.html6
-rw-r--r--askbot/tests/db_api_tests.py9
-rw-r--r--askbot/tests/form_tests.py24
-rw-r--r--askbot/views/commands.py2
13 files changed, 155 insertions, 25 deletions
diff --git a/askbot/conf/forum_data_rules.py b/askbot/conf/forum_data_rules.py
index a875092e..d6d2efd3 100644
--- a/askbot/conf/forum_data_rules.py
+++ b/askbot/conf/forum_data_rules.py
@@ -100,9 +100,22 @@ settings.register(
settings.register(
livesettings.IntegerValue(
FORUM_DATA_RULES,
- 'MIN_EDITOR_LENGTH',
+ 'MIN_QUESTION_BODY_LENGTH',
default=10,
- description=_('Minimum length of question content (number of characters)')
+ description=_(
+ 'Minimum length of question body (number of characters)'
+ )
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ FORUM_DATA_RULES,
+ 'MIN_ANSWER_BODY_LENGTH',
+ default=10,
+ description=_(
+ 'Minimum length of answer body (number of characters)'
+ )
)
)
@@ -127,11 +140,11 @@ settings.register(
default = False,
description = _('Force lowercase the tags'),
help_text = _(
- 'Attention: after checking this, please back up the database, '
- 'and run a management command: '
- '<code>python manage.py fix_question_tags</code> to globally '
- 'rename the tags'
- )
+ 'Attention: after checking this, please back up the database, '
+ 'and run a management command: '
+ '<code>python manage.py fix_question_tags</code> to globally '
+ 'rename the tags'
+ )
)
)
diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst
index 0977a156..7ef46ffe 100644
--- a/askbot/doc/source/changelog.rst
+++ b/askbot/doc/source/changelog.rst
@@ -11,6 +11,8 @@ Development version (not released yet)
that may be used for other projects (Evgeny)
* added more rigorous test for the user name to make it slug safe (Evgeny)
* made setting `ASKBOT_FILE_UPLOAD_DIR` work (Radim Řehůřek)
+* added minimal length of question title ond body
+ text to live settings and allowed body-less questions (Radim Řehůřek, Evgeny)
0.7.36 (Dec 20, 2011)
---------------------
diff --git a/askbot/forms.py b/askbot/forms.py
index e880d4a7..00735b72 100644
--- a/askbot/forms.py
+++ b/askbot/forms.py
@@ -107,12 +107,23 @@ class TitleField(forms.CharField):
def clean(self, value):
if len(value) < askbot_settings.MIN_TITLE_LENGTH:
- msg = _('title must be > %d characters') % askbot_settings.MIN_TITLE_LENGTH
+ msg = ungettext_lazy(
+ 'title must be > %d character',
+ 'title must be > %d characters',
+ askbot_settings.MIN_TITLE_LENGTH
+ ) % askbot_settings.MIN_TITLE_LENGTH
raise forms.ValidationError(msg)
return value
class EditorField(forms.CharField):
+ """EditorField is subclassed by the
+ :class:`QuestionEditorField` and :class:`AnswerEditorField`
+ """
+ length_error_template_singular = 'post content must be > %d character',
+ length_error_template_plural = 'post content must be > %d characters',
+ min_length = 10#sentinel default value
+
def __init__(self, *args, **kwargs):
super(EditorField, self).__init__(*args, **kwargs)
self.required = True
@@ -122,11 +133,29 @@ class EditorField(forms.CharField):
self.initial = ''
def clean(self, value):
- if len(value) < askbot_settings.MIN_EDITOR_LENGTH:
- msg = _('question content must be > %d characters') % askbot_settings.MIN_EDITOR_LENGTH
+ if len(value) < self.min_length:
+ msg = ungettext_lazy(
+ self.length_error_template_singular,
+ self.length_error_template_plural,
+ self.min_length
+ ) % self.min_length
raise forms.ValidationError(msg)
return value
+class QuestionEditorField(EditorField):
+ def __init__(self, *args, **kwargs):
+ super(QuestionEditorField, self).__init__(*args, **kwargs)
+ self.length_error_template_singular = 'question body must be > %d character'
+ self.length_error_template_plural = 'question body must be > %d characters'
+ self.min_length = askbot_settings.MIN_QUESTION_BODY_LENGTH
+
+class AnswerEditorField(EditorField):
+ def __init__(self, *args, **kwargs):
+ super(AnswerEditorField, self).__init__(*args, **kwargs)
+ self.length_error_template_singular = 'answer must be > %d character'
+ self.length_error_template_plural = 'answer must be > %d characters'
+ self.min_length = askbot_settings.MIN_ANSWER_BODY_LENGTH
+
class TagNamesField(forms.CharField):
def __init__(self, *args, **kwargs):
super(TagNamesField, self).__init__(*args, **kwargs)
@@ -612,7 +641,7 @@ class AskForm(forms.Form, FormWithHideableFields):
settings forbids anonymous asking
"""
title = TitleField()
- text = EditorField()
+ text = QuestionEditorField()
tags = TagNamesField()
wiki = WikiField()
ask_anonymously = forms.BooleanField(
@@ -663,7 +692,7 @@ class AskByEmailForm(forms.Form):
"""
sender = forms.CharField(max_length = 255)
subject = forms.CharField(max_length = 255)
- body_text = EditorField()
+ body_text = QuestionEditorField()
def clean_sender(self):
"""Cleans the :attr:`~askbot.forms.AskByEmail.sender` attribute
@@ -708,7 +737,7 @@ class AskByEmailForm(forms.Form):
return self.cleaned_data['subject']
class AnswerForm(forms.Form):
- text = EditorField()
+ text = AnswerEditorField()
wiki = WikiField()
openid = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 40, 'class':'openid-input'}))
user = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35}))
@@ -772,7 +801,7 @@ class RevisionForm(forms.Form):
class EditQuestionForm(forms.Form, FormWithHideableFields):
title = TitleField()
- text = EditorField()
+ text = QuestionEditorField()
tags = TagNamesField()
summary = SummaryField()
wiki = WikiField()
@@ -879,7 +908,7 @@ class EditQuestionForm(forms.Form, FormWithHideableFields):
return self.cleaned_data
class EditAnswerForm(forms.Form):
- text = EditorField()
+ text = AnswerEditorField()
summary = SummaryField()
wiki = WikiField()
diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py
index d43b0e53..0ba2e4c7 100644
--- a/askbot/models/__init__.py
+++ b/askbot/models/__init__.py
@@ -1264,7 +1264,7 @@ def user_restore_post(
def user_post_question(
self,
title = None,
- body_text = None,
+ body_text = '',
tags = None,
wiki = False,
is_anonymous = False,
@@ -1275,10 +1275,11 @@ def user_post_question(
self.assert_can_post_question()
+ if body_text == '':#a hack to allow bodyless question
+ body_text = ' '
+
if title is None:
raise ValueError('Title is required to post question')
- if body_text is None:
- raise ValueError('Text body is required to post question')
if tags is None:
raise ValueError('Tags are required to post question')
if timestamp is None:
@@ -1371,6 +1372,7 @@ def user_post_answer(
timestamp = None
):
+ #todo: move this to assertion - user_assert_can_post_answer
if self == question.author and not self.is_administrator():
# check date and rep required to post answer to own question
diff --git a/askbot/models/content.py b/askbot/models/content.py
index f2645cc2..ca747cc8 100644
--- a/askbot/models/content.py
+++ b/askbot/models/content.py
@@ -691,6 +691,8 @@ class Content(models.Model):
self.parse_and_save(author = edited_by)
def apply_edit(self, *kargs, **kwargs):
+ if kwargs['text'] == '':
+ kwargs['text'] = ' '#a hack allowing empty body text in posts
if self.is_answer():
return self._answer__apply_edit(*kargs, **kwargs)
elif self.is_question():
diff --git a/askbot/skins/common/media/js/post.js b/askbot/skins/common/media/js/post.js
index 9939537b..2f2fbd75 100644
--- a/askbot/skins/common/media/js/post.js
+++ b/askbot/skins/common/media/js/post.js
@@ -112,7 +112,7 @@ var CPValidator = function(){
limit_tag_length: true
},
text: {
- minlength: askbot['settings']['minEditorLength']
+ minlength: askbot['settings']['minQuestionBodyLength']
},
title: {
minlength: askbot['settings']['minTitleLength']
@@ -129,13 +129,49 @@ var CPValidator = function(){
},
text: {
required: " " + gettext('content cannot be empty'),
- minlength: interpolate(gettext('%s content minchars'), [askbot['settings']['minEditorLength']])
+ minlength: interpolate(
+ ngettext(
+ 'question body must be > %s character',
+ 'question body must be > %s characters',
+ askbot['settings']['minQuestionBodyLength']
+ ),
+ [askbot['settings']['minQuestionBodyLength'], ]
+ )
},
title: {
required: " " + gettext('please enter title'),
- minlength: interpolate(gettext('%s title minchars'), [askbot['settings']['minTitleLength']])
+ minlength: interpolate(
+ ngettext(
+ 'title must be > %s character',
+ 'title must be > %s characters',
+ askbot['settings']['minTitleLength']
+ ),
+ [askbot['settings']['minTitleLength'], ]
+ )
}
};
+ },
+ getAnswerFormRules : function(){
+ return {
+ text: {
+ minlength: askbot['settings']['minAnswerBodyLength']
+ },
+ };
+ },
+ getAnswerFormMessages: function(){
+ return {
+ text: {
+ required: " " + gettext('content cannot be empty'),
+ minlength: interpolate(
+ ngettext(
+ 'answer must be > %s character',
+ 'answer must be > %s characters',
+ askbot['settings']['minAnswerBodyLength']
+ ),
+ [askbot['settings']['minAnswerBodyLength'], ]
+ )
+ },
+ }
}
};
}();
diff --git a/askbot/skins/default/media/style/style.less b/askbot/skins/default/media/style/style.less
index e92b6888..389a0acc 100644
--- a/askbot/skins/default/media/style/style.less
+++ b/askbot/skins/default/media/style/style.less
@@ -2667,6 +2667,10 @@ span.form-error {
margin-left: 5px;
}
+ul.errorlist {
+ margin-bottom: 0;
+}
+
p.form-item {
margin: 0px;
}
diff --git a/askbot/skins/default/templates/answer_edit.html b/askbot/skins/default/templates/answer_edit.html
index bbf3edef..28824968 100644
--- a/askbot/skins/default/templates/answer_edit.html
+++ b/askbot/skins/default/templates/answer_edit.html
@@ -67,7 +67,11 @@
$('#pre-collapse').text(txt);
});
- setupFormValidation($("#fmedit"), CPValidator.getQuestionFormRules(), CPValidator.getQuestionFormMessages());
+ setupFormValidation(
+ $("#fmedit"),
+ CPValidator.getAnswerFormRules(),
+ CPValidator.getAnswerFormMessages()
+ );
$('#id_revision').unbind().change(function(){
$("#select_revision").click();
diff --git a/askbot/skins/default/templates/meta/editor_data.html b/askbot/skins/default/templates/meta/editor_data.html
index 7902fe8e..025be8a0 100644
--- a/askbot/skins/default/templates/meta/editor_data.html
+++ b/askbot/skins/default/templates/meta/editor_data.html
@@ -8,5 +8,6 @@
askbot['messages']['tagLimits'] = '{% trans tag_count=settings.MAX_TAGS_PER_POST, max_chars=settings.MAX_TAG_LENGTH %}please use up to {{tag_count}} tags, less than {{max_chars}} characters each{% endtrans %}';
askbot['urls']['upload'] = '{% url "upload" %}';
askbot['settings']['minTitleLength'] = {{settings.MIN_TITLE_LENGTH}}
- askbot['settings']['minEditorLength'] = {{settings.MIN_EDITOR_LENGTH}}
+ askbot['settings']['minQuestionBodyLength'] = {{settings.MIN_QUESTION_BODY_LENGTH}}
+ askbot['settings']['minAnswerBodyLength'] = {{settings.MIN_ANSWER_BODY_LENGTH}}
</script>
diff --git a/askbot/skins/default/templates/question/javascript.html b/askbot/skins/default/templates/question/javascript.html
index af1c7056..7f90627b 100644
--- a/askbot/skins/default/templates/question/javascript.html
+++ b/askbot/skins/default/templates/question/javascript.html
@@ -94,7 +94,11 @@
$('#previewer').toggle();
$('#pre-collapse').text(txt);
});
- setupFormValidation($("#fmanswer"), CPValidator.getQuestionFormRules(), CPValidator.getQuestionFormMessages());
+ setupFormValidation(
+ $("#fmanswer"),
+ CPValidator.getAnswerFormRules(),
+ CPValidator.getAnswerFormMessages()
+ );
}
</script>
{% include "meta/editor_data.html" %}
diff --git a/askbot/tests/db_api_tests.py b/askbot/tests/db_api_tests.py
index b54bb2e9..585784aa 100644
--- a/askbot/tests/db_api_tests.py
+++ b/askbot/tests/db_api_tests.py
@@ -7,6 +7,7 @@ from django.core import exceptions
from django.core.urlresolvers import reverse
from django.test.client import Client
from django.conf import settings
+from django import forms
from askbot.tests.utils import AskbotTestCase
from askbot import models
from askbot import const
@@ -74,6 +75,14 @@ class DBApiTests(AskbotTestCase):
rev = q.revisions.all()[0]
self.assertTrue(rev.is_anonymous)
+ def test_post_bodyless_question(self):
+ q = self.user.post_question(
+ body_text = '',
+ title = 'aeuaouaousaotuhao',
+ tags = 'test'
+ )
+ self.assertEquals(q.text.strip(), '')
+
def test_reveal_asker_identity(self):
q = self.ask_anonymous_question()
self.other_user.set_status('m')
diff --git a/askbot/tests/form_tests.py b/askbot/tests/form_tests.py
index 5235b13a..22f2a77c 100644
--- a/askbot/tests/form_tests.py
+++ b/askbot/tests/form_tests.py
@@ -306,3 +306,27 @@ class UserNameFieldTest(AskbotTestCase):
self.assertRaises(django_forms.ValidationError, self.username_field.clean, '......')
#TODO: test more things
+
+class AnswerEditorFieldTests(AskbotTestCase):
+ """don't need to test the QuestionEditorFieldTests, b/c the
+ class is identical"""
+ 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()
+
+ def tearDown(self):
+ askbot_settings.update('MIN_ANSWER_BODY_LENGTH', self.old_min_length)
+
+ def test_fail_short_body(self):
+ self.assertRaises(
+ django_forms.ValidationError,
+ self.field.clean,
+ 'a'
+ )
+
+ def test_pass_long_body(self):
+ self.assertEquals(
+ self.field.clean(10*'a'),
+ 10*'a'
+ )
diff --git a/askbot/views/commands.py b/askbot/views/commands.py
index 3aeba161..7e219572 100644
--- a/askbot/views/commands.py
+++ b/askbot/views/commands.py
@@ -458,7 +458,7 @@ def api_get_questions(request):
questions = models.Question.objects.get_by_text_query(query)
if should_show_sort_by_relevance():
questions = questions.extra(order_by = ['-relevance'])
- questions = questions.distinct()
+ questions = questions.filter(deleted = False).distinct()
page_size = form.cleaned_data.get('page_size', 30)
questions = questions[:page_size]