summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2011-02-14 04:51:57 -0500
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2011-02-14 04:51:57 -0500
commit8c1f61bcd212363720f11a65e4e43bc96a9987f7 (patch)
tree5cea30c153f657fcca408413976f57843a25a3d3
parentd5fc91612df57fdef04f1cb3d107bdbaab3f6d23 (diff)
downloadaskbot-8c1f61bcd212363720f11a65e4e43bc96a9987f7.tar.gz
askbot-8c1f61bcd212363720f11a65e4e43bc96a9987f7.tar.bz2
askbot-8c1f61bcd212363720f11a65e4e43bc96a9987f7.zip
almost finished anonymous posting feature still need to fix presentational parts and make sure that rep cannot accumulate when posts are made anonymously
-rw-r--r--askbot/conf/forum_data_rules.py14
-rw-r--r--askbot/forms.py151
-rw-r--r--askbot/migrations/0036_auto__add_field_anonymousquestion_is_anonymous__add_field_questionrevi.py319
-rw-r--r--askbot/models/__init__.py18
-rw-r--r--askbot/models/question.py68
-rwxr-xr-xaskbot/skins/default/media/style/style.css6
-rw-r--r--askbot/skins/default/templates/answer_edit.html5
-rw-r--r--askbot/skins/default/templates/blocks/ask_form.html10
-rw-r--r--askbot/skins/default/templates/macros.html22
-rw-r--r--askbot/skins/default/templates/question.html7
-rw-r--r--askbot/skins/default/templates/question_edit.html15
-rw-r--r--askbot/tests/db_api_tests.py32
-rw-r--r--askbot/tests/form_tests.py114
-rw-r--r--askbot/tests/utils.py7
-rw-r--r--askbot/views/writers.py82
15 files changed, 807 insertions, 63 deletions
diff --git a/askbot/conf/forum_data_rules.py b/askbot/conf/forum_data_rules.py
index 02e5b0a3..7dfee665 100644
--- a/askbot/conf/forum_data_rules.py
+++ b/askbot/conf/forum_data_rules.py
@@ -21,6 +21,20 @@ settings.register(
)
settings.register(
+ livesettings.BooleanValue(
+ FORUM_DATA_RULES,
+ 'ALLOW_ASK_ANONYMOUSLY',
+ default=True,
+ description=_('Allow asking questions anonymously'),
+ help_text=_(
+ 'Users do not accrue reputation for anonymous questions '
+ 'and their identity is not revealed until they change their '
+ 'mind'
+ )
+ )
+)
+
+settings.register(
livesettings.IntegerValue(
FORUM_DATA_RULES,
'MAX_TAG_LENGTH',
diff --git a/askbot/forms.py b/askbot/forms.py
index 115a7485..0f6edef4 100644
--- a/askbot/forms.py
+++ b/askbot/forms.py
@@ -44,7 +44,6 @@ def filter_choices(remove_choices = None, from_choices = None):
return filtered_choices
-
COUNTRY_CHOICES = (('unknown',_('select country')),) + countries.COUNTRIES
class CountryField(forms.ChoiceField):
@@ -461,16 +460,64 @@ class FeedbackForm(forms.Form):
message = forms.CharField(label=_('Your message:'), max_length=800,widget=forms.Textarea(attrs={'cols':60}))
next = NextUrlField()
-class AskForm(forms.Form):
+class FormWithHideableFields(object):
+ """allows to swap a field widget to HiddenInput() and back"""
+
+ def hide_field(self, name):
+ """replace widget with HiddenInput()
+ and save the original in the __hidden_fields dictionary
+ """
+ if not hasattr(self, '__hidden_fields'):
+ self.__hidden_fields = dict()
+ if name in self.__hidden_fields:
+ return
+ self.__hidden_fields[name] = self.fields[name].widget
+ self.fields[name].widget = forms.HiddenInput()
+
+ def show_field(self, name):
+ """restore the original widget on the field
+ if it was previously hidden
+ """
+ if name in self.__hidden_fields:
+ self.fields[name] = self.__hidden_fields.pop(name)
+
+class AskForm(forms.Form, FormWithHideableFields):
+ """the form used to askbot questions
+ field ask_anonymously is shown to the user if the
+ if ALLOW_ASK_ANONYMOUSLY live setting is True
+ however, for simplicity, the value will always be present
+ in the cleaned data, and will evaluate to False if the
+ settings forbids anonymous asking
+ """
title = TitleField()
text = EditorField()
tags = TagNamesField()
wiki = WikiField()
-
+ ask_anonymously = forms.BooleanField(
+ label = _('Ask anonymously'),
+ help_text = _(
+ 'Check if you do not want to reveal your name '
+ 'when asking this question'
+ ),
+ required = False,
+ )
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}))
email = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35}))
+ def __init__(self, *args, **kwargs):
+ super(AskForm, self).__init__(*args, **kwargs)
+ #hide ask_anonymously field
+ if askbot_settings.ALLOW_ASK_ANONYMOUSLY == False:
+ self.hide_field('ask_anonymously')
+
+ def clean_ask_anonymously(self):
+ """returns false if anonymous asking is not allowed
+ """
+ if askbot_settings.ALLOW_ASK_ANONYMOUSLY == False:
+ self.cleaned_data['ask_anonymously'] = False
+ return self.cleaned_data['ask_anonymously']
+
class AnswerForm(forms.Form):
text = EditorField()
wiki = WikiField()
@@ -516,21 +563,113 @@ class RevisionForm(forms.Form):
for r in revisions]
self.fields['revision'].initial = latest_revision.revision
-class EditQuestionForm(forms.Form):
+class EditQuestionForm(forms.Form, FormWithHideableFields):
title = TitleField()
text = EditorField()
tags = TagNamesField()
summary = SummaryField()
wiki = WikiField()
+ reveal_identity = forms.BooleanField(
+ help_text = _(
+ 'You have asked this question anonymously, '
+ 'if you decide to reveal your identity, please check '
+ 'this box.'
+ ),
+ label = _('Reveal identity'),
+ required = False,
+ )
#todo: this is odd that this form takes question as an argument
- def __init__(self, question, revision, *args, **kwargs):
+ def __init__(self, *args, **kwargs):
"""populate EditQuestionForm with initial data"""
+ self.question = kwargs.pop('question')
+ self.user = kwargs.pop('user')
+ revision = kwargs.pop('revision')
super(EditQuestionForm, self).__init__(*args, **kwargs)
self.fields['title'].initial = revision.title
self.fields['text'].initial = revision.text
self.fields['tags'].initial = revision.tagnames
- self.fields['wiki'].initial = question.wiki
+ self.fields['wiki'].initial = self.question.wiki
+ #hide the reveal identity field
+ if not self.can_stay_anonymous():
+ self.hide_field('reveal_identity')
+
+ def can_stay_anonymous(self):
+ """determines if the user cat keep editing the question
+ anonymously"""
+ return (askbot_settings.ALLOW_ASK_ANONYMOUSLY \
+ and self.question.is_anonymous \
+ and self.user.is_owner_of(self.question)
+ )
+
+ def clean_reveal_identity(self):
+ """cleans the reveal_identity field
+ which determines whether previous anonymous
+ edits must be rewritten as not anonymous
+ this does not necessarily mean that the edit will be anonymous
+
+ only does real work when question is anonymous
+ based on the following truth table:
+
+ is_anon can owner checked cleaned data
+ - * * * False (ignore choice in checkbox)
+ + + + + True
+ + + + - False
+ + + - + Raise(Not owner)
+ + + - - False
+ + - + + True (setting "can" changed, say yes)
+ + - + - False, warn (but prev edits stay anon)
+ + - - + Raise(Not owner)
+ + - - - False
+ """
+ value = self.cleaned_data['reveal_identity']
+ if self.question.is_anonymous:
+ if value == True:
+ if self.user.is_owner_of(self.question):
+ #regardless of the ALLOW_ASK_ANONYMOUSLY
+ return True
+ else:
+ self.show_field('reveal_identity')
+ del self.cleaned_data['reveal_identity']
+ raise forms.ValidationError(
+ _(
+ 'Sorry, only owner of the anonymous '
+ 'question can reveal his or her '
+ 'identity, please uncheck the '
+ 'box'
+ )
+ )
+ else:
+ can_ask_anon = askbot_settings.ALLOW_ASK_ANONYMOUSLY
+ is_owner = self.user.is_owner_of(self.question)
+ if can_ask_anon == False and is_owner:
+ self.show_field('reveal_identity')
+ raise forms.ValidationError(
+ _(
+ 'Sorry, apparently rules have just changed - '
+ 'it is no longer possible to ask anonymously. '
+ 'Please either check the "reveal identity" box '
+ 'or reload this page and try editing the question '
+ 'again.'
+ )
+ )
+ return False
+ else:
+ #takes care of 8 possibilities - first row of the table
+ return False
+
+ def clean(self):
+ """Purpose of this function is to determine whether
+ it is ok to apply edit anonymously in the synthetic
+ field edit_anonymously. It relies on correct cleaning
+ if the "reveal_identity" field
+ """
+ reveal_identity = self.cleaned_data.get('reveal_identity', False)
+ stay_anonymous = False
+ if reveal_identity == False and self.can_stay_anonymous():
+ stay_anonymous = True
+ self.cleaned_data['stay_anonymous'] = stay_anonymous
+ return self.cleaned_data
class EditAnswerForm(forms.Form):
text = EditorField()
diff --git a/askbot/migrations/0036_auto__add_field_anonymousquestion_is_anonymous__add_field_questionrevi.py b/askbot/migrations/0036_auto__add_field_anonymousquestion_is_anonymous__add_field_questionrevi.py
new file mode 100644
index 00000000..e515b402
--- /dev/null
+++ b/askbot/migrations/0036_auto__add_field_anonymousquestion_is_anonymous__add_field_questionrevi.py
@@ -0,0 +1,319 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding field 'AnonymousQuestion.is_anonymous'
+ db.add_column('askbot_anonymousquestion', 'is_anonymous', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)
+
+ # Adding field 'QuestionRevision.is_anonymous'
+ db.add_column(u'question_revision', 'is_anonymous', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)
+
+ # Adding field 'Question.is_anonymous'
+ db.add_column(u'question', 'is_anonymous', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)
+
+
+ def backwards(self, orm):
+
+ # Deleting field 'AnonymousQuestion.is_anonymous'
+ db.delete_column('askbot_anonymousquestion', 'is_anonymous')
+
+ # Deleting field 'QuestionRevision.is_anonymous'
+ db.delete_column(u'question_revision', 'is_anonymous')
+
+ # Deleting field 'Question.is_anonymous'
+ db.delete_column(u'question', 'is_anonymous')
+
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'through': "'ActivityAuditStatus'", 'to': "orm['auth.User']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Question']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'askbot.answer': {
+ 'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},
+ 'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_answers'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_answers'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_answers'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['askbot.Question']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.Answer']"}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answerrevisions'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'})
+ },
+ 'askbot.comment': {
+ 'Meta': {'object_name': 'Comment', 'db_table': "u'comment'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '2048'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'html': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.question': {
+ 'Meta': {'object_name': 'Question', 'db_table': "u'question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questions'", 'to': "orm['auth.User']"}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_questions'", 'to': "orm['auth.User']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'to': "orm['auth.User']"}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'questions'", 'to': "orm['askbot.Tag']"}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.questionrevision': {
+ 'Meta': {'object_name': 'QuestionRevision', 'db_table': "u'question_revision'"},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questionrevisions'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.Question']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('content_type', 'object_id', 'user'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'has_custom_avatar': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'tag_filter_setting': ('django.db.models.fields.CharField', [], {'default': "'ignored'", 'max_length': '16'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py
index b4d9f4d4..260ad0c5 100644
--- a/askbot/models/__init__.py
+++ b/askbot/models/__init__.py
@@ -998,6 +998,7 @@ def user_post_question(
body_text = None,
tags = None,
wiki = False,
+ is_anonymous = False,
timestamp = None
):
@@ -1018,7 +1019,8 @@ def user_post_question(
text = body_text,
tagnames = tags,
added_at = timestamp,
- wiki = wiki
+ wiki = wiki,
+ is_anonymous = is_anonymous,
)
return question
@@ -1039,7 +1041,8 @@ def user_edit_question(
revision_comment = None,
tags = None,
wiki = False,
- timestamp = None
+ edit_anonymously = False,
+ timestamp = None,
):
self.assert_can_edit_question(question)
question.apply_edit(
@@ -1051,6 +1054,7 @@ def user_edit_question(
comment = revision_comment,
tags = tags,
wiki = wiki,
+ edit_anonymously = edit_anonymously,
)
award_badges_signal.send(None,
event = 'edit_question',
@@ -1224,6 +1228,15 @@ def user_is_watched(self):
def user_is_approved(self):
return (self.status == 'a')
+def user_is_owner_of(self, obj):
+ """True if user owns object
+ False otherwise
+ """
+ if isinstance(obj, Question):
+ return self == obj.author
+ else:
+ raise NotImplementedError()
+
def user_set_status(self, new_status):
"""sets new status to user
@@ -1664,6 +1677,7 @@ User.add_to_class('is_approved', user_is_approved)
User.add_to_class('is_watched', user_is_watched)
User.add_to_class('is_suspended', user_is_suspended)
User.add_to_class('is_blocked', user_is_blocked)
+User.add_to_class('is_owner_of', user_is_owner_of)
User.add_to_class('can_moderate_user', user_can_moderate_user)
User.add_to_class('moderate_user_reputation', user_moderate_user_reputation)
User.add_to_class('set_status', user_set_status)
diff --git a/askbot/models/question.py b/askbot/models/question.py
index 04147c92..f1612e88 100644
--- a/askbot/models/question.py
+++ b/askbot/models/question.py
@@ -37,7 +37,16 @@ QUESTION_ORDER_BY_MAP = {
}
class QuestionManager(models.Manager):
- def create_new(self, title=None,author=None,added_at=None, wiki=False,tagnames=None, text=None):
+ def create_new(
+ self,
+ title = None,
+ author = None,
+ added_at = None,
+ wiki = False,
+ is_anonymous = False,
+ tagnames = None,
+ text = None
+ ):
question = Question(
title = title,
@@ -46,6 +55,7 @@ class QuestionManager(models.Manager):
last_activity_at = added_at,
last_activity_by = author,
wiki = wiki,
+ is_anonymous = is_anonymous,
tagnames = tagnames,
#html field is denormalized in .save() call
text = text,
@@ -64,10 +74,11 @@ class QuestionManager(models.Manager):
question.update_tags(tagnames = tagnames, user = author, timestamp = added_at)
question.add_revision(
- author=author,
- text=text,
- comment=const.POST_STATUS['default_version'],
- revised_at=added_at,
+ author = author,
+ is_anonymous = is_anonymous,
+ text = text,
+ comment = const.POST_STATUS['default_version'],
+ revised_at = added_at,
)
return question
@@ -312,6 +323,7 @@ class Question(content.Content, DeletableContent):
summary = models.CharField(max_length=180)
favorited_by = models.ManyToManyField(User, through='FavoriteQuestion', related_name='favorite_questions')
+ is_anonymous = models.BooleanField(default=False)
objects = QuestionManager()
@@ -335,6 +347,17 @@ class Question(content.Content, DeletableContent):
except django_exceptions.PermissionDenied:
raise exceptions.QuestionHidden(message)
+ def remove_author_anonymity(self):
+ """removes anonymous flag from the question
+ and all its revisions
+ the function calls update method to make sure that
+ signals are not called
+ """
+ #it is important that update method is called - not save,
+ #because we do not want the signals to fire here
+ Question.objects.filter(id = self.id).update(is_anonymous = False)
+ self.revisions.all().update(is_anonymous = False)
+
def update_answer_count(self, save = True):
"""updates the denormalized field 'answer_count'
on the question
@@ -565,7 +588,8 @@ class Question(content.Content, DeletableContent):
return self
def apply_edit(self, edited_at=None, edited_by=None, title=None,\
- text=None, comment=None, tags=None, wiki=False):
+ text=None, comment=None, tags=None, wiki=False, \
+ edit_anonymously = False):
latest_revision = self.get_latest_revision()
#a hack to allow partial edits - important for SE loader
@@ -590,6 +614,7 @@ class Question(content.Content, DeletableContent):
self.last_activity_by = edited_by
self.tagnames = tags
self.text = text
+ self.is_anonymous = edit_anonymously
#wiki is an eternal trap whence there is no exit
if self.wiki == False and wiki == True:
@@ -604,12 +629,20 @@ class Question(content.Content, DeletableContent):
author = edited_by,
text = text,
revised_at = edited_at,
+ is_anonymous = edit_anonymously,
comment = comment,
)
self.parse_and_save(author = edited_by)
- def add_revision(self,author=None, text=None, comment=None, revised_at=None):
+ def add_revision(
+ self,
+ author = None,
+ is_anonymous = False,
+ text = None,
+ comment = None,
+ revised_at = None
+ ):
if None in (author, text, comment):
raise Exception('author, text and comment are required arguments')
rev_no = self.revisions.all().count() + 1
@@ -624,6 +657,7 @@ class Question(content.Content, DeletableContent):
revision = rev_no,
title = self.title,
author = author,
+ is_anonymous = is_anonymous,
revised_at = revised_at,
tagnames = self.tagnames,
summary = comment,
@@ -779,6 +813,7 @@ class QuestionRevision(ContentRevision):
question = models.ForeignKey(Question, related_name='revisions')
title = models.CharField(max_length=300)
tagnames = models.CharField(max_length=125)
+ is_anonymous = models.BooleanField(default=False)
class Meta(ContentRevision.Meta):
db_table = u'question_revision'
@@ -812,17 +847,24 @@ class QuestionRevision(ContentRevision):
return u'revision %s of %s' % (self.revision, self.title)
class AnonymousQuestion(AnonymousContent):
+ """question that was asked before logging in
+ maybe the name is a little misleading, the user still
+ may or may not want to stay anonymous after the question
+ is published
+ """
title = models.CharField(max_length=300)
tagnames = models.CharField(max_length=125)
+ is_anonymous = models.BooleanField(default=False)
def publish(self,user):
added_at = datetime.datetime.now()
Question.objects.create_new(
- title=self.title,
- author=user,
- added_at=added_at,
- wiki=self.wiki,
- tagnames=self.tagnames,
- text=self.text,
+ title = self.title,
+ added_at = added_at,
+ author = user,
+ wiki = self.wiki,
+ is_anonymous = self.is_anonymous,
+ tagnames = self.tagnames,
+ text = self.text,
)
self.delete()
diff --git a/askbot/skins/default/media/style/style.css b/askbot/skins/default/media/style/style.css
index 97adc3e0..7a3ab944 100755
--- a/askbot/skins/default/media/style/style.css
+++ b/askbot/skins/default/media/style/style.css
@@ -1153,6 +1153,12 @@ span.form-error {
margin-top: 10px;
}
+.checkbox {
+ margin-left:5px;
+ font-weight:normal;
+ cursor:help
+}
+
.edit-content-html {
border-top: 1px dotted #D8D2A9;
border-bottom: 1px dotted #D8D2A9;
diff --git a/askbot/skins/default/templates/answer_edit.html b/askbot/skins/default/templates/answer_edit.html
index e67973b1..0dc137ae 100644
--- a/askbot/skins/default/templates/answer_edit.html
+++ b/askbot/skins/default/templates/answer_edit.html
@@ -17,11 +17,14 @@
<div style="vertical-align:middle">
{{ revision_form.revision }} <input type="submit" style="display:none" id="select_revision" name="select_revision" value="{% trans %}select revision{% endtrans %}">
</div>
- {{macros.edit_post(form, settings.WIKI_ON and answer.wiki == False)}}
+ {{ macros.edit_post(form) }}
<div class="after-editor">
<input type="submit" value="{% trans %}Save edit{% endtrans %}" class="submit" />&nbsp;
<input type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" onclick="history.back(-1);" />
</div>
+ {% if settings.WIKI_ON and answer.wiki == False %}
+ {{ macros.checkbox_in_div(form.wiki) }}
+ {% endif %}
</form>
</div>
</div>
diff --git a/askbot/skins/default/templates/blocks/ask_form.html b/askbot/skins/default/templates/blocks/ask_form.html
index ff7fea0d..e1a93711 100644
--- a/askbot/skins/default/templates/blocks/ask_form.html
+++ b/askbot/skins/default/templates/blocks/ask_form.html
@@ -22,11 +22,19 @@
{{ form.title.help_text }}
</div>
</div>
- {{macros.edit_post(form, settings.WIKI_ON, post_type='question', edit_title=False)}}
+ {{macros.edit_post(form, post_type='question', edit_title=False)}}
{% if not request.user.is_authenticated() %}
<input type="submit" name="post_anon" value="{% trans %}Login/signup to post your question{% endtrans %}" class="submit" />
{% else %}
<input type="submit" name="post" value="{% trans %}Ask your question{% endtrans %}" class="submit" />
{% endif %}
+ <div class="question-options">
+ {% if settings.WIKI_ON %}
+ {{ macros.checkbox_in_div(form.wiki) }}
+ {% endif %}
+ {% if settings.ALLOW_ASK_ANONYMOUSLY %}
+ {{ macros.checkbox_in_div(form.ask_anonymously) }}
+ {% endif %}
+ </div>
</form>
</div>
diff --git a/askbot/skins/default/templates/macros.html b/askbot/skins/default/templates/macros.html
index 32d4c5bb..84716dcf 100644
--- a/askbot/skins/default/templates/macros.html
+++ b/askbot/skins/default/templates/macros.html
@@ -431,7 +431,20 @@ poor design of the data or methods on data objects #}
</script>
{%- endmacro %}
-{%- macro edit_post(post_form, wiki_on, post_type=None, edit_title=False) -%}
+{%- macro checkbox_in_div(checkbox_field, class = 'checkbox') -%}
+ <div{% if class %} class="{{class}}"{% endif %}
+ title="{{checkbox_field.help_text}}">
+ {{ checkbox_field }}
+ {{ checkbox_field.label_tag() }}
+ {{ checkbox_field.errors }}
+ </div>
+{%- endmacro -%}
+
+{%- macro edit_post(
+ post_form,
+ post_type=None,
+ edit_title=False)
+-%}
{% if edit_title %}
<div class="form-item">
<label for="id_title" ><strong>{{ post_form.title.label_tag() }}:</strong></label> <span class="form-error"></span><br/>
@@ -444,13 +457,6 @@ poor design of the data or methods on data objects #}
<div id="wmd-button-bar" class="wmd-panel"></div>
<div class="form-item">
{{ post_form.text }}{# this element is resizable and will be wrapped by js #}
- {% if wiki_on %}
- <div style="margin-right:5px;float:right;font-weight:normal;cursor:help"
- title="{{post_form.wiki.help_text}}">
- {{ post_form.wiki }}
- {{ post_form.wiki.label_tag() }}
- </div>
- {% endif %}
<label for="editor" class="form-error">{{ post_form.text.errors }}</label>
</div>
{# need label element for resizable input, b/c form validation won't find span #}
diff --git a/askbot/skins/default/templates/question.html b/askbot/skins/default/templates/question.html
index 927e2888..7eb21d21 100644
--- a/askbot/skins/default/templates/question.html
+++ b/askbot/skins/default/templates/question.html
@@ -349,7 +349,7 @@
{% endif %}
</p>
{% endif %}
- {{macros.edit_post(answer, settings.WIKI_ON)}}
+ {{ macros.edit_post(answer) }}
<input type="submit"
{% if user.is_anonymous() %}
value="{% trans %}Login/Signup to Post Your Answer{% endtrans %}"
@@ -361,7 +361,10 @@
{% endif %}
{% endif %}
class="submit after-editor" style="float:left"/>
- {% endif %}
+ {% if settings.WIKI_ON %}
+ {{ macros.checkbox_in_div(answer.wiki) }}
+ {% endif %}
+ {% endif %}
</form>
</div>
{% endblock %}
diff --git a/askbot/skins/default/templates/question_edit.html b/askbot/skins/default/templates/question_edit.html
index 04c6c28c..6a3aae0c 100644
--- a/askbot/skins/default/templates/question_edit.html
+++ b/askbot/skins/default/templates/question_edit.html
@@ -15,16 +15,19 @@
id="select_revision" name="select_revision"
value="{% trans %}select revision{% endtrans %}">
</div>
- {{macros.edit_post(
- form,
- settings.WIKI_ON and question.wiki == False,
- post_type='question',
- edit_title=True,
- )}}
+ {{ macros.edit_post(form, post_type='question', edit_title=True,) }}
<div class="after-editor">
<input type="submit" value="{% trans %}Save edit{% endtrans %}" class="submit" />&nbsp;
<input type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" onclick="history.back(-1);" />
</div>
+ <div class="question-options">
+ {% if settings.WIKI_ON and question.wiki == False %}
+ {{ macros.checkbox_in_div(form.wiki) }}
+ {% endif %}
+ {% if form.can_stay_anonymous() %}
+ {{ macros.checkbox_in_div(form.reveal_identity) }}
+ {% endif %}
+ </div>
</form>
{% endblock %}
diff --git a/askbot/tests/db_api_tests.py b/askbot/tests/db_api_tests.py
index c4c31fc4..fe09b283 100644
--- a/askbot/tests/db_api_tests.py
+++ b/askbot/tests/db_api_tests.py
@@ -53,6 +53,38 @@ class DBApiTests(AskbotTestCase):
1
)
+ def ask_anonymous_question(self):
+ q = self.user.post_question(
+ is_anonymous = True,
+ body_text = 'hahahah',
+ title = 'aouaouaosuoa',
+ tags = 'test'
+ )
+ return self.reload_object(q)
+
+ def test_post_anonymous_question(self):
+ q = self.ask_anonymous_question()
+ self.assertTrue(q.is_anonymous)
+ rev = q.revisions.all()[0]
+ self.assertTrue(rev.is_anonymous)
+
+ def test_reveal_asker_identity(self):
+ q = self.ask_anonymous_question()
+ self.other_user.set_status('m')
+ self.other_user.save()
+ self.other_user.edit_question(
+ question = q,
+ title = 'hahah',
+ body_text = 'hoeuaoea',
+ tags = 'aoeuaoeu',
+ revision_comment = 'hahahah'
+ )
+ q.remove_author_anonymity()
+ q = self.reload_object(q)
+ self.assertFalse(q.is_anonymous)
+ for rev in q.revisions.all():
+ self.assertFalse(rev.is_anonymous)
+
def test_accept_best_answer(self):
self.post_answer(user = self.other_user)
self.user.accept_best_answer(self.answer)
diff --git a/askbot/tests/form_tests.py b/askbot/tests/form_tests.py
index dfa2d628..1a18678c 100644
--- a/askbot/tests/form_tests.py
+++ b/askbot/tests/form_tests.py
@@ -31,5 +31,119 @@ class TagNamesFieldTests(AskbotTestCase):
cleaned_tags = self.clean('tag1 taG2 TAG1 tag3 tag3')
self.assert_tags_equal(cleaned_tags, ['TAG1', 'Tag2', 'tag3'])
+class EditQuestionAnonymouslyFormTests(AskbotTestCase):
+ """setup the following truth table
+ on reveal_identity field:
+ is_anon can owner checked result
+ """
+ truth_table = (
+ (0, 0, 0, 0, False),
+ (0, 0, 0, 1, False),
+ (0, 0, 1, 0, False),
+ (0, 0, 1, 1, False),
+ (0, 1, 0, 0, False),
+ (0, 1, 0, 1, False),
+ (0, 1, 1, 0, False),
+ (0, 1, 1, 1, False),#all up to this point are False
+ (1, 0, 0, 0, False),
+ (1, 0, 0, 1, 'error'),#not owner
+ (1, 0, 1, 0, 'error'),#rules changed either reload page or check box
+ (1, 0, 1, 1, True),#rules changed - say yes here
+ (1, 1, 0, 0, False),
+ (1, 1, 0, 1, 'error'),
+ (1, 1, 1, 0, False),
+ (1, 1, 1, 1, True),
+ )
+ #legend: is_anon - question is anonymous
+ # can - askbot_settings.ALLOW_ASK_ANONYMOUSLY
+ # owner - editor is question owner
+ # checked - the checkbox "reveal_identity" is marked
+ def setUp(self):
+ self.create_user()
+ self.create_user(
+ username = 'other_user',
+ status = 'm'#must be able to edit
+ )
+ super(EditQuestionAnonymouslyFormTests, self).setUp()
+
+ def setup_data(self, is_anon, can_be_anon, is_owner, box_checked):
+ """sets up data in the same order as shown in the
+ truth table above
+
+ the four positional arguments are in the same order
+ """
+ askbot_settings.update('ALLOW_ASK_ANONYMOUSLY', can_be_anon)
+ question = self.post_question(is_anonymous = is_anon)
+ if is_owner:
+ editor = self.user
+ else:
+ editor = self.other_user
+ data = {
+ 'tags': 'tag1 tag2',
+ 'text': 'ostaousohuosuh',
+ 'title': 'stahosetuhaoeudhuh'
+ }
+ if box_checked:
+ data['reveal_identity'] = 'on'
+ self.form = forms.EditQuestionForm(
+ data,
+ question = question,
+ user = editor,
+ revision = question.get_latest_revision(),
+ )
+
+ def test_reveal_identity_field(self):
+ """runs through the truth table and tests them items by one
+ """
+ current_item = 0
+ for entry in self.truth_table:
+ self.setup_data(*(entry[:4]))
+
+ if self.form.is_valid():
+ result = self.form.cleaned_data['reveal_identity']
+ else:
+ result = 'error'
+
+ error_message = 'failed truth table item %d' % current_item
+ current_item += 1
+ expected_result = entry[4]
+ self.assertEquals(result, expected_result, error_message)
+
+class AskFormTests(AskbotTestCase):
+
+ def setup_data(self, allow_anonymous = True, ask_anonymously = None):
+ askbot_settings.update('ALLOW_ASK_ANONYMOUSLY', allow_anonymous)
+ data = {
+ 'title': 'test title',
+ 'text': 'test content',
+ 'tags': 'test',
+ }
+ if ask_anonymously == True:
+ data['ask_anonymously'] = 'on'
+ self.form = forms.AskForm(data)
+ self.form.full_clean()
+
+ def assert_anon_is(self, value):
+ self.assertEquals(
+ self.form.cleaned_data['ask_anonymously'],
+ value
+ )
+
+ def test_ask_anonymously_disabled(self):
+ """test that disabled anon postings yields False"""
+ self.setup_data(ask_anonymously = True, allow_anonymous = False)
+ self.assert_anon_is(False)
+
+ def test_ask_anonymously_field_positive(self):
+ """check that the 'yes' selection goes through
+ """
+ self.setup_data(ask_anonymously = True)
+ self.assert_anon_is(True)
+
+ def test_ask_anonymously_field_negative(self):
+ """check that the 'no' selection goes through
+ """
+ self.setup_data(ask_anonymously = False)
+ self.assert_anon_is(False)
diff --git a/askbot/tests/utils.py b/askbot/tests/utils.py
index 6942ce29..76eda149 100644
--- a/askbot/tests/utils.py
+++ b/askbot/tests/utils.py
@@ -77,6 +77,7 @@ class AskbotTestCase(TestCase):
body_text = 'test question body text',
tags = 'test',
wiki = False,
+ is_anonymous = False,
follow = False,
timestamp = None
):
@@ -94,6 +95,7 @@ class AskbotTestCase(TestCase):
body_text = body_text,
tags = tags,
wiki = wiki,
+ is_anonymous = is_anonymous,
timestamp = timestamp
)
@@ -102,6 +104,11 @@ class AskbotTestCase(TestCase):
return question
+ def reload_object(self, obj):
+ """reloads model object from the database
+ """
+ return obj.__class__.objects.get(id = obj.id)
+
def post_answer(
self,
user = None,
diff --git a/askbot/views/writers.py b/askbot/views/writers.py
index 2bc4d3a3..aa062d87 100644
--- a/askbot/views/writers.py
+++ b/askbot/views/writers.py
@@ -197,7 +197,6 @@ def ask(request):#view used to ask a new question
if request.method == "POST":
form = forms.AskForm(request.POST)
if form.is_valid():
-
timestamp = datetime.datetime.now()
#todo: move this to clean_title
title = form.cleaned_data['title'].strip()
@@ -205,17 +204,18 @@ def ask(request):#view used to ask a new question
#todo: move this to clean_tagnames
tagnames = form.cleaned_data['tags'].strip()
text = form.cleaned_data['text']
+ ask_anonymously = form.cleaned_data['ask_anonymously']
if request.user.is_authenticated():
-
try:
question = request.user.post_question(
- title = title,
- body_text = text,
- tags = tagnames,
- wiki = wiki,
- timestamp = timestamp
- )
+ title = title,
+ body_text = text,
+ tags = tagnames,
+ wiki = wiki,
+ is_anonymous = ask_anonymously,
+ timestamp = timestamp
+ )
return HttpResponseRedirect(question.get_absolute_url())
except exceptions.PermissionDenied, e:
request.user.message_set.create(message = unicode(e))
@@ -230,6 +230,7 @@ def ask(request):#view used to ask a new question
title = title,
tagnames = tagnames,
wiki = wiki,
+ is_anonymous = ask_anonymously,
text = text,
summary = summary,
added_at = timestamp,
@@ -324,33 +325,66 @@ def edit_question(request, id):
try:
request.user.assert_can_edit_question(question)
if request.method == 'POST':
- if 'select_revision' in request.POST:#revert-type edit
- # user has changed revistion number
- revision_form = forms.RevisionForm(question, latest_revision, request.POST)
+ if 'select_revision' in request.POST:
+ #revert-type edit - user selected previous revision
+ revision_form = forms.RevisionForm(
+ question,
+ latest_revision,
+ request.POST
+ )
if revision_form.is_valid():
# Replace with those from the selected revision
- form = forms.EditQuestionForm(question,
- models.QuestionRevision.objects.get(question=question,
- revision=revision_form.cleaned_data['revision']))
+ rev_id = revision_form.cleaned_data['revision']
+ selected_revision = models.QuestionRevision.objects.get(
+ question = question,
+ revision = rev_id
+ )
+ form = forms.EditQuestionForm(
+ question = question,
+ user = request.user,
+ revision = selected_revision
+ )
else:
- form = forms.EditQuestionForm(question, latest_revision, request.POST)
+ form = forms.EditQuestionForm(
+ request.POST,
+ question = question,
+ user = request.user,
+ revision = latest_revision
+ )
else:#new content edit
# Always check modifications against the latest revision
- form = forms.EditQuestionForm(question, latest_revision, request.POST)
+ form = forms.EditQuestionForm(
+ request.POST,
+ question = question,
+ revision = latest_revision,
+ user = request.user,
+ )
if form.is_valid():
if form.has_changed():
+
+ if form.cleaned_data['reveal_identity']:
+ question.remove_author_anonymity()
+
+ is_anon_edit = form.cleaned_data['edit_anonymously']
+ is_wiki = form.cleaned_data.get('wiki', question.wiki)
request.user.edit_question(
- question = question,
- title = form.cleaned_data['title'],
- body_text = form.cleaned_data['text'],
- revision_comment = form.cleaned_data['summary'],
- tags = form.cleaned_data['tags'],
- wiki = form.cleaned_data.get('wiki', question.wiki)
- )
+ question = question,
+ title = form.cleaned_data['title'],
+ body_text = form.cleaned_data['text'],
+ revision_comment = form.cleaned_data['summary'],
+ tags = form.cleaned_data['tags'],
+ wiki = is_wiki,
+ edit_anonymously = is_anon_edit,
+ )
return HttpResponseRedirect(question.get_absolute_url())
else:
+ #request type was "GET"
revision_form = forms.RevisionForm(question, latest_revision)
- form = forms.EditQuestionForm(question, latest_revision)
+ form = forms.EditQuestionForm(
+ question = question,
+ revision = latest_revision,
+ user = request.user
+ )
data = {
'active_tab': 'questions',