diff options
-rw-r--r-- | askbot/conf/forum_data_rules.py | 2 | ||||
-rw-r--r-- | askbot/models/answer.py | 46 | ||||
-rw-r--r-- | askbot/models/question.py | 36 | ||||
-rw-r--r-- | askbot/skins/default/media/js/post.js | 51 | ||||
-rw-r--r-- | askbot/skins/default/templates/question.html | 6 | ||||
-rw-r--r-- | askbot/urls.py | 5 | ||||
-rw-r--r-- | askbot/views/commands.py | 20 |
7 files changed, 160 insertions, 6 deletions
diff --git a/askbot/conf/forum_data_rules.py b/askbot/conf/forum_data_rules.py index 6ce169fa..dc801d41 100644 --- a/askbot/conf/forum_data_rules.py +++ b/askbot/conf/forum_data_rules.py @@ -66,7 +66,7 @@ settings.register( settings.register( livesettings.BooleanValue( FORUM_DATA_RULES, - 'ALLOW_SWAPPING_ANSWER_WITH_QUESTION', + 'ALLOW_SWAPPING_QUESTION_WITH_ANSWER', default = False, description = _('Allow swapping answer with question'), help_text = _( diff --git a/askbot/models/answer.py b/askbot/models/answer.py index c268551d..09b5a444 100644 --- a/askbot/models/answer.py +++ b/askbot/models/answer.py @@ -161,6 +161,52 @@ class Answer(content.Content, DeletableContent): self.question.last_activity_by = edited_by self.question.save() + def repost_as_question(self, new_title = None): + """posts answer as question, together with all the comments + while preserving time stamps and authors + does not delete the answer itself though + """ + revisions = self.revisions.all().order_by('revised_at') + rev0 = revisions[0] + new_question = rev0.author.post_question( + title = new_title, + body_text = rev0.text, + tags = self.question.tagnames, + wiki = self.question.wiki, + is_anonymous = self.question.is_anonymous, + timestamp = rev0.revised_at + ) + if len(revisions) > 1: + for rev in revisions[1:]: + rev.author.edit_question( + question = new_question, + body_text = rev.text, + revision_comment = rev.summary, + timestamp = rev.revised_at + ) + for comment in self.comments.all(): + comment.content_object = new_question + comment.save() + return new_question + + def swap_with_question(self, new_title = None): + """swaps answer with the question it belongs to and + sets the title of question to ``new_title`` + """ + #1) make new question by using new title, tags of old question + # and the answer body, as well as the authors of all revisions + # and repost all the comments + new_question = self.repost_as_question(new_title = new_title) + + #2) post question (all revisions and comments) as answer + new_answer = self.question.repost_as_answer(question = new_question) + + #3) assign all remaining answers to the new question + self.question.answers.update(question = new_question) + self.question.delete() + self.delete() + return new_question + def add_revision(self, author=None, revised_at=None, text=None, comment=None): #todo: this may be identical to Question.add_revision if None in (author, revised_at, text): diff --git a/askbot/models/question.py b/askbot/models/question.py index 41579c11..7a2be48c 100644 --- a/askbot/models/question.py +++ b/askbot/models/question.py @@ -457,15 +457,13 @@ class Question(content.Content, DeletableContent): self.save() def update_favorite_count(self): - """ - update favourite_count for given question + """update favourite_count for given question """ self.favourite_count = FavoriteQuestion.objects.filter( question=self ).count() self.save() - def get_similar_questions(self): """ Get 10 similar questions for given one. @@ -602,6 +600,31 @@ class Question(content.Content, DeletableContent): return False + def repost_as_answer(self, question = None): + """posts question as answer to another question, + but does not delete the question, + but moves all the comments to the new answer""" + revisions = self.revisions.all().order_by('revised_at') + rev0 = revisions[0] + new_answer = rev0.author.post_answer( + question = question, + body_text = rev0.text, + wiki = self.wiki, + timestamp = rev0.revised_at + ) + if len(revisions) > 1: + for rev in revisions: + rev.author.edit_answer( + answer = new_answer, + body_text = rev.text, + revision_comment = rev.summary, + timestamp = rev.revised_at + ) + for comment in self.comments.all(): + comment.content_object = new_answer + comment.save() + return new_answer + def delete(self): super(Question, self).delete() try: @@ -782,7 +805,12 @@ class Question(content.Content, DeletableContent): if no_slug == True: return url else: - return url + django_urlquote(slugify(self.title)) + return url + django_urlquote(self.slug) + + def _get_slug(self): + return slugify(self.title) + + slug = property(_get_slug) def has_favorite_by_user(self, user): if not user.is_authenticated(): diff --git a/askbot/skins/default/media/js/post.js b/askbot/skins/default/media/js/post.js index 0d84508e..a228e9ce 100644 --- a/askbot/skins/default/media/js/post.js +++ b/askbot/skins/default/media/js/post.js @@ -1394,11 +1394,62 @@ var socialSharing = function(){ } }(); +/** + * @constructor + * @extends {SimpleControl} + */ +var QASwapper = function(){ + SimpleControl.call(this); + this._ans_id = null; +}; +inherits(QASwapper, SimpleControl); + +QASwapper.prototype.decorate = function(element){ + this._element = element; + this._ans_id = parseInt(element.attr('id').split('-').pop()); + var me = this; + this.setHandler(function(){ + me.startSwapping(); + }); +}; + +QASwapper.prototype.startSwapping = function(){ + while (true){ + var title = prompt(gettext('Please enter question title (>10 characters)')); + if (title.length >= 10){ + var data = {new_title: title, answer_id: this._ans_id}; + $.ajax({ + type: "POST", + cache: false, + dataType: "json", + url: askbot['urls']['swap_question_with_answer'], + data: data, + success: function(data){ + var url_template = askbot['urls']['question_url_template']; + new_question_url = url_template.replace( + '{{QuestionID}}', + data['id'] + ).replace( + '{{questionSlug}}', + data['slug'] + ); + window.location.href = new_question_url; + } + }); + break; + } + } +}; + $(document).ready(function() { $('[id^="comments-for-"]').each(function(index, element){ var comments = new PostCommentsWidget(); comments.decorate(element); }); + $('[id^="swap-question-with-answer-"]').each(function(idx, element){ + var swapper = new QASwapper(); + swapper.decorate($(element)); + }); questionRetagger.init(); socialSharing.init(); }); diff --git a/askbot/skins/default/templates/question.html b/askbot/skins/default/templates/question.html index 6b51c756..b9f3edc5 100644 --- a/askbot/skins/default/templates/question.html +++ b/askbot/skins/default/templates/question.html @@ -264,6 +264,11 @@ </span> {% endspaceless %} {% endif %} + {% if settings.ALLOW_SWAPPING_QUESTION_WITH_ANSWER %}{{ pipe() }} + <span class="action-link"> + <a id="swap-question-with-answer-{{answer.id}}">{% trans %}swap with question{% endtrans %}</a> + </span> + {% endif %} </div> <div class="post-update-info-container"> {{ @@ -441,6 +446,7 @@ askbot['urls']['question_url_template'] = scriptUrl + '{% trans %}question/{% endtrans %}{{ "{{QuestionID}}/{{questionSlug}}" }}';{# yes it needs to be that whacky #} askbot['urls']['user_signin'] = '{{ settings.LOGIN_URL }}'; askbot['urls']['vote_url_template'] = scriptUrl + '{% trans %}questions/{% endtrans %}{{ "{{QuestionID}}/" }}{% trans %}vote/{% endtrans %}'; + askbot['urls']['swap_question_with_answer'] = '{% url swap_question_with_answer %}'; askbot['messages']['addComment'] = '{% trans %}add comment{% endtrans %}'; {% if settings.SAVE_COMMENT_ON_ENTER %} askbot['settings']['saveCommentOnEnter'] = true; diff --git a/askbot/urls.py b/askbot/urls.py index 99ff6300..714ce4ca 100644 --- a/askbot/urls.py +++ b/askbot/urls.py @@ -171,6 +171,11 @@ urlpatterns = patterns('', name = 'get_tag_list' ), url( + r'^swap-question-with-answer/', + views.commands.swap_question_with_answer, + name = 'swap_question_with_answer' + ), + url( r'^%s$' % _('subscribe-for-tags/'), views.commands.subscribe_for_tags, name = 'subscribe_for_tags' diff --git a/askbot/views/commands.py b/askbot/views/commands.py index 9b9e7af5..5b7e8f18 100644 --- a/askbot/views/commands.py +++ b/askbot/views/commands.py @@ -9,7 +9,7 @@ from django.conf import settings as django_settings from django.core import exceptions from django.core.urlresolvers import reverse from django.contrib.auth.decorators import login_required -from django.http import HttpResponse, HttpResponseRedirect +from django.http import HttpResponse, HttpResponseRedirect, Http404 from django.forms import ValidationError from django.shortcuts import get_object_or_404 from django.views.decorators import csrf @@ -518,6 +518,24 @@ def reopen(request, id):#re-open question request.user.message_set.create(message = unicode(e)) return HttpResponseRedirect(question.get_absolute_url()) + +@decorators.ajax_only +def swap_question_with_answer(request): + """receives two json parameters - answer id + and new question title + the view is made to be used only by the site administrator + or moderators + """ + if request.user.is_authenticated(): + if request.user.is_administrator() or request.user.is_moderator(): + answer = models.Answer.objects.get(id = request.POST['answer_id']) + new_question = answer.swap_with_question(new_title = request.POST['new_title']) + return { + 'id': new_question.id, + 'slug': new_question.slug + } + raise Http404 + #askbot-user communication system def read_message(request):#marks message a read if request.method == "POST": |