summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--askbot/conf/forum_data_rules.py41
-rw-r--r--askbot/doc/source/changelog.rst3
-rw-r--r--askbot/forms.py49
-rw-r--r--askbot/models/__init__.py8
-rw-r--r--askbot/models/content.py2
-rw-r--r--askbot/skins/common/media/js/post.js51
-rw-r--r--askbot/skins/default/media/style/style.less6
-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/urls.py9
-rw-r--r--askbot/views/commands.py2
14 files changed, 182 insertions, 37 deletions
diff --git a/askbot/conf/forum_data_rules.py b/askbot/conf/forum_data_rules.py
index 80af2f5b..d6d2efd3 100644
--- a/askbot/conf/forum_data_rules.py
+++ b/askbot/conf/forum_data_rules.py
@@ -89,6 +89,37 @@ settings.register(
)
settings.register(
+ livesettings.IntegerValue(
+ FORUM_DATA_RULES,
+ 'MIN_TITLE_LENGTH',
+ default=10,
+ description=_('Minimum length of title (number of characters)')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ FORUM_DATA_RULES,
+ 'MIN_QUESTION_BODY_LENGTH',
+ default=10,
+ 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)'
+ )
+ )
+)
+
+settings.register(
livesettings.StringValue(
FORUM_DATA_RULES,
'MANDATORY_TAGS',
@@ -109,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 a3e4ef05..7ef46ffe 100644
--- a/askbot/doc/source/changelog.rst
+++ b/askbot/doc/source/changelog.rst
@@ -10,6 +10,9 @@ Development version (not released yet)
* made askbot compatible with django's `CSRFViewMiddleware`
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 d2215189..00735b72 100644
--- a/askbot/forms.py
+++ b/askbot/forms.py
@@ -106,12 +106,24 @@ class TitleField(forms.CharField):
self.initial = ''
def clean(self, value):
- if len(value) < 10:
- raise forms.ValidationError(_('title must be > 10 characters'))
+ if len(value) < 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
@@ -121,10 +133,29 @@ class EditorField(forms.CharField):
self.initial = ''
def clean(self, value):
- if len(value) < 10:
- raise forms.ValidationError(_('question content must be > 10 characters'))
+ 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)
@@ -610,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(
@@ -661,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
@@ -706,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}))
@@ -770,7 +801,7 @@ class RevisionForm(forms.Form):
class EditQuestionForm(forms.Form, FormWithHideableFields):
title = TitleField()
- text = EditorField()
+ text = QuestionEditorField()
tags = TagNamesField()
summary = SummaryField()
wiki = WikiField()
@@ -877,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 22e2b6c4..2f2fbd75 100644
--- a/askbot/skins/common/media/js/post.js
+++ b/askbot/skins/common/media/js/post.js
@@ -112,17 +112,14 @@ var CPValidator = function(){
limit_tag_length: true
},
text: {
- required: true,
- minlength: 10
+ minlength: askbot['settings']['minQuestionBodyLength']
+ },
+ title: {
+ minlength: askbot['settings']['minTitleLength']
}
- /*title: {
- required: true,
- minlength: 10
- }*/
};
},
getQuestionFormMessages: function(){
- var chars = 10
return {
tags: {
required: " " + gettext('tags cannot be empty'),
@@ -132,13 +129,49 @@ var CPValidator = function(){
},
text: {
required: " " + gettext('content cannot be empty'),
- minlength: interpolate(gettext('%s content minchars'), [chars])
+ 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'), [chars])
+ 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 d1ca6283..389a0acc 100644
--- a/askbot/skins/default/media/style/style.less
+++ b/askbot/skins/default/media/style/style.less
@@ -1383,7 +1383,7 @@ ul#related-tags li {
border-top:0;
padding:10px;
margin-bottom:10px;
- width:710px;
+ width:717px;
}
#id_title {
@@ -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 79ed96fb..025be8a0 100644
--- a/askbot/skins/default/templates/meta/editor_data.html
+++ b/askbot/skins/default/templates/meta/editor_data.html
@@ -7,4 +7,7 @@
askbot['messages']['maxTagsPerPost'] = '{% trans tag_count = settings.MAX_TAGS_PER_POST %}please use {{tag_count}} tag{% pluralize %}please use {{tag_count}} tags or less{% endtrans %}';
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']['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/urls.py b/askbot/urls.py
index 2c3d143d..4bfab225 100644
--- a/askbot/urls.py
+++ b/askbot/urls.py
@@ -41,15 +41,10 @@ urlpatterns = patterns('',
views.meta.media,
name='askbot_media',
),
- url(
+ url( # TODO: replace with django.conf.urls.static ?
r'^%s(?P<path>.*)$' % settings.ASKBOT_UPLOADED_FILES_URL,
'django.views.static.serve',
- {'document_root': os.path.join(
- settings.PROJECT_ROOT,
- 'askbot',
- 'upfiles'
- ).replace('\\','/')
- },
+ {'document_root': settings.ASKBOT_FILE_UPLOAD_DIR.replace('\\','/')},
name='uploaded_file',
),
#no translation for this url!!
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]