- if not request.user.is_authenticated():
- response_data['allowed'] = 0
- response_data['success'] = 0
-
- elif request.is_ajax() and request.method == 'POST':
- question = get_object_or_404(Question, id=id)
- vote_type = request.POST.get('type')
-
- #accept answer
- if vote_type == '0':
- answer_id = request.POST.get('postId')
- answer = get_object_or_404(Answer, id=answer_id)
- # make sure question author is current user
- if question.author == request.user:
- # answer user who is also question author is not allow to accept answer
- if answer.author == question.author:
- response_data['success'] = 0
- response_data['allowed'] = -1
- # check if answer has been accepted already
- elif answer.accepted:
- auth.onAnswerAcceptCanceled(answer, request.user)
- response_data['status'] = 1
- else:
- # set other answers in this question not accepted first
- for answer_of_question in Answer.objects.get_answers_from_question(question, request.user):
- if answer_of_question != answer and answer_of_question.accepted:
- auth.onAnswerAcceptCanceled(answer_of_question, request.user)
-
- #make sure retrieve data again after above author changes, they may have related data
- answer = get_object_or_404(Answer, id=answer_id)
- auth.onAnswerAccept(answer, request.user)
- else:
- response_data['allowed'] = 0
- response_data['success'] = 0
- # favorite
- elif vote_type == '4':
- has_favorited = False
- fav_questions = FavoriteQuestion.objects.filter(question=question)
- # if the same question has been favorited before, then delete it
- if fav_questions is not None:
- for item in fav_questions:
- if item.user == request.user:
- item.delete()
- response_data['status'] = 1
- response_data['count'] = len(fav_questions) - 1
- if response_data['count'] < 0:
- response_data['count'] = 0
- has_favorited = True
- # if above deletion has not been executed, just insert a new favorite question
- if not has_favorited:
- new_item = FavoriteQuestion(question=question, user=request.user)
- new_item.save()
- response_data['count'] = FavoriteQuestion.objects.filter(question=question).count()
- Question.objects.update_favorite_count(question)
-
- elif vote_type in ['1', '2', '5', '6']:
- post_id = id
- post = question
- vote_score = 1
- if vote_type in ['5', '6']:
- answer_id = request.POST.get('postId')
- answer = get_object_or_404(Answer, id=answer_id)
- post_id = answer_id
- post = answer
- if vote_type in ['2', '6']:
- vote_score = -1
-
- if post.author == request.user:
- response_data['allowed'] = -1
- elif not __can_vote(vote_score, request.user):
- response_data['allowed'] = -2
- elif post.votes.filter(user=request.user).count() > 0:
- vote = post.votes.filter(user=request.user)[0]
- # unvote should be less than certain time
- if (datetime.datetime.now().day - vote.voted_at.day) >= auth.VOTE_RULES['scope_deny_unvote_days']:
- response_data['status'] = 2
- else:
- voted = vote.vote
- if voted > 0:
- # cancel upvote
- auth.onUpVotedCanceled(vote, post, request.user)
-
- else:
- # cancel downvote
- auth.onDownVotedCanceled(vote, post, request.user)
-
- response_data['status'] = 1
- response_data['count'] = post.score
- elif Vote.objects.get_votes_count_today_from_user(request.user) >= auth.VOTE_RULES['scope_votes_per_user_per_day']:
- response_data['allowed'] = -3
- else:
- vote = Vote(user=request.user, content_object=post, vote=vote_score, voted_at=datetime.datetime.now())
- if vote_score > 0:
- # upvote
- auth.onUpVoted(vote, post, request.user)
- else:
- # downvote
- auth.onDownVoted(vote, post, request.user)
-
- votes_left = auth.VOTE_RULES['scope_votes_per_user_per_day'] - Vote.objects.get_votes_count_today_from_user(request.user)
- if votes_left <= auth.VOTE_RULES['scope_warn_votes_left']:
- response_data['message'] = u'%s votes left' % votes_left
- response_data['count'] = post.score
- elif vote_type in ['7', '8']:
- post = question
- post_id = id
- if vote_type == '8':
- post_id = request.POST.get('postId')
- post = get_object_or_404(Answer, id=post_id)
-
- if FlaggedItem.objects.get_flagged_items_count_today(request.user) >= auth.VOTE_RULES['scope_flags_per_user_per_day']:
- response_data['allowed'] = -3
- elif not auth.can_flag_offensive(request.user):
- response_data['allowed'] = -2
- elif post.flagged_items.filter(user=request.user).count() > 0:
- response_data['status'] = 1
- else:
- item = FlaggedItem(user=request.user, content_object=post, flagged_at=datetime.datetime.now())
- auth.onFlaggedItem(item, post, request.user)
- response_data['count'] = post.offensive_flag_count
- # send signal when question or answer be marked offensive
- mark_offensive.send(sender=post.__class__, instance=post, mark_by=request.user)
- elif vote_type in ['9', '10']:
- post = question
- post_id = id
- if vote_type == '10':
- post_id = request.POST.get('postId')
- post = get_object_or_404(Answer, id=post_id)
-
- if not auth.can_delete_post(request.user, post):
- response_data['allowed'] = -2
- elif post.deleted == True:
- logging.debug('debug restoring post in view')
- auth.onDeleteCanceled(post, request.user)
- response_data['status'] = 1
- else:
- auth.onDeleted(post, request.user)
- delete_post_or_answer.send(sender=post.__class__, instance=post, delete_by=request.user)
- elif vote_type == '11':#subscribe q updates
- user = request.user
- if user.is_authenticated():
- if user not in question.followed_by.all():
- question.followed_by.add(user)
- if settings.EMAIL_VALIDATION == 'on' and user.email_isvalid == False:
- response_data['message'] = \
- _('subscription saved, %(email)s needs validation, see %(details_url)s') \
- % {'email':user.email,'details_url':reverse('faq') + '#validate'}
- feed_setting = EmailFeedSetting.objects.get(subscriber=user,feed_type='q_sel')
- if feed_setting.frequency == 'n':
- feed_setting.frequency = 'd'
- feed_setting.save()
- if 'message' in response_data:
- response_data['message'] += '<br/>'
- response_data['message'] = _('email update frequency has been set to daily')
- #response_data['status'] = 1
- #responst_data['allowed'] = 1
- else:
- pass
- #response_data['status'] = 0
- #response_data['allowed'] = 0
- elif vote_type == '12':#unsubscribe q updates
- user = request.user
- if user.is_authenticated():
- if user in question.followed_by.all():
- question.followed_by.remove(user)
+ favorite = FavoriteAction.objects.get(canceled=False, node=node, user=request.user)
+ favorite.cancel(ip=request.META['REMOTE_ADDR'])
+ added = False
+ except ObjectDoesNotExist:
+ FavoriteAction(node=node, user=request.user, ip=request.META['REMOTE_ADDR']).save()
+ added = True
+
+ return {
+ 'commands': {
+ 'update_favorite_count': [added and 1 or -1],
+ 'update_favorite_mark': [added and 'on' or 'off']
+ }
+ }
+
+@decorate.withfn(command)
+def comment(request, id):
+ post = get_object_or_404(Node, id=id)
+ user = request.user
+
+ if not user.is_authenticated():
+ raise AnonymousNotAllowedException(_('comment'))
+
+ if not request.method == 'POST':
+ raise CommandException(_("Invalid request"))
+
+ comment_text = request.POST.get('comment', '').strip()
+
+ if not len(comment_text):
+ raise CommandException(_("Comment is empty"))
+
+ if len(comment_text) < settings.FORM_MIN_COMMENT_BODY:
+ raise CommandException(_("At least %d characters required on comment body.") % settings.FORM_MIN_COMMENT_BODY)
+
+ if len(comment_text) > settings.FORM_MAX_COMMENT_BODY:
+ raise CommandException(_("No more than %d characters on comment body.") % settings.FORM_MAX_COMMENT_BODY)
+
+ if 'id' in request.POST:
+ comment = get_object_or_404(Comment, id=request.POST['id'])
+
+ if not user.can_edit_comment(comment):
+ raise NotEnoughRepPointsException( _('edit comments'))
+
+ comment = ReviseAction(user=user, node=comment, ip=request.META['REMOTE_ADDR']).save(
+ data=dict(text=comment_text)).node
+ else:
+ if not user.can_comment(post):
+ raise NotEnoughRepPointsException( _('comment'))
+
+ comment = CommentAction(user=user, ip=request.META['REMOTE_ADDR']).save(
+ data=dict(text=comment_text, parent=post)).node
+
+ if comment.active_revision.revision == 1:
+ return {
+ 'commands': {
+ 'insert_comment': [
+ id, comment.id, comment.comment, user.decorated_name, user.get_profile_url(),
+ reverse('delete_comment', kwargs={'id': comment.id}),
+ reverse('node_markdown', kwargs={'id': comment.id}),
+ reverse('convert_comment', kwargs={'id': comment.id}),
+ user.can_convert_comment_to_answer(comment),
+ bool(settings.SHOW_LATEST_COMMENTS_FIRST)
+ ]
+ }
+ }
+ else:
+ return {
+ 'commands': {
+ 'update_comment': [comment.id, comment.comment]
+ }
+ }
+
+@decorate.withfn(command)
+def node_markdown(request, id):
+ user = request.user
+
+ if not user.is_authenticated():
+ raise AnonymousNotAllowedException(_('accept answers'))
+
+ node = get_object_or_404(Node, id=id)
+ return HttpResponse(node.active_revision.body, content_type="text/plain")
+
+
+@decorate.withfn(command)
+def accept_answer(request, id):
+ if settings.DISABLE_ACCEPTING_FEATURE:
+ raise Http404()
+
+ user = request.user
+
+ if not user.is_authenticated():
+ raise AnonymousNotAllowedException(_('accept answers'))
+
+ answer = get_object_or_404(Answer, id=id)
+ question = answer.question
+
+ if not user.can_accept_answer(answer):
+ raise CommandException(_("Sorry but you cannot accept the answer"))
+
+ commands = {}
+
+ if answer.nis.accepted:
+ answer.nstate.accepted.cancel(user, ip=request.META['REMOTE_ADDR'])
+ commands['unmark_accepted'] = [answer.id]
+ else:
+ if settings.MAXIMUM_ACCEPTED_ANSWERS and (question.accepted_count >= settings.MAXIMUM_ACCEPTED_ANSWERS):
+ raise CommandException(ungettext("This question already has an accepted answer.",
+ "Sorry but this question has reached the limit of accepted answers.", int(settings.MAXIMUM_ACCEPTED_ANSWERS)))
+
+ if settings.MAXIMUM_ACCEPTED_PER_USER and question.accepted_count:
+ accepted_from_author = question.accepted_answers.filter(author=answer.author).count()
+
+ if accepted_from_author >= settings.MAXIMUM_ACCEPTED_PER_USER:
+ raise CommandException(ungettext("The author of this answer already has an accepted answer in this question.",
+ "Sorry but the author of this answer has reached the limit of accepted answers per question.", int(settings.MAXIMUM_ACCEPTED_PER_USER)))
+
+
+ AcceptAnswerAction(node=answer, user=user, ip=request.META['REMOTE_ADDR']).save()
+
+ # If the request is not an AJAX redirect to the answer URL rather than to the home page
+ if not request.is_ajax():
+ msg = _("""
+ Congratulations! You've accepted an answer.
+ """)
+
+ # Notify the user with a message that an answer has been accepted
+ messages.info(request, msg)
+
+ # Redirect URL should include additional get parameters that might have been attached
+ redirect_url = answer.parent.get_absolute_url() + "?accepted_answer=true&%s" % smart_unicode(urlencode(request.GET))
+
+ return HttpResponseRedirect(redirect_url)
+
+ commands['mark_accepted'] = [answer.id]
+
+ return {'commands': commands}
+
+@decorate.withfn(command)
+def delete_post(request, id):
+ post = get_object_or_404(Node, id=id)
+ user = request.user
+
+ if not user.is_authenticated():
+ raise AnonymousNotAllowedException(_('delete posts'))
+
+ if not (user.can_delete_post(post)):
+ raise NotEnoughRepPointsException(_('delete posts'))
+
+ ret = {'commands': {}}
+
+ if post.nis.deleted:
+ post.nstate.deleted.cancel(user, ip=request.META['REMOTE_ADDR'])
+ ret['commands']['unmark_deleted'] = [post.node_type, id]
+ else:
+ DeleteAction(node=post, user=user, ip=request.META['REMOTE_ADDR']).save()
+
+ ret['commands']['mark_deleted'] = [post.node_type, id]
+
+ return ret
+
+@decorate.withfn(command)
+def close(request, id, close):
+ if close and not request.POST:
+ return render_to_response('node/report.html', {'types': settings.CLOSE_TYPES})
+
+ question = get_object_or_404(Question, id=id)
+ user = request.user
+
+ if not user.is_authenticated():
+ raise AnonymousNotAllowedException(_('close questions'))
+
+ if question.nis.closed:
+ if not user.can_reopen_question(question):
+ raise NotEnoughRepPointsException(_('reopen questions'))
+
+ question.nstate.closed.cancel(user, ip=request.META['REMOTE_ADDR'])
+ else:
+ if not request.user.can_close_question(question):
+ raise NotEnoughRepPointsException(_('close questions'))
+
+ reason = request.POST.get('prompt', '').strip()
+
+ if not len(reason):
+ raise CommandException(_("Reason is empty"))
+
+ CloseAction(node=question, user=user, extra=reason, ip=request.META['REMOTE_ADDR']).save()
+
+ return RefreshPageCommand()
+
+@decorate.withfn(command)
+def wikify(request, id):
+ node = get_object_or_404(Node, id=id)
+ user = request.user
+
+ if not user.is_authenticated():
+ raise AnonymousNotAllowedException(_('mark posts as community wiki'))
+
+ if node.nis.wiki:
+ if not user.can_cancel_wiki(node):
+ raise NotEnoughRepPointsException(_('cancel a community wiki post'))
+
+ if node.nstate.wiki.action_type == "wikify":
+ node.nstate.wiki.cancel()