From 3b2f9ebad3131bb86045f3ac1d3b4f43b6d78398 Mon Sep 17 00:00:00 2001 From: hernani Date: Fri, 16 Apr 2010 12:47:02 +0000 Subject: [PATCH] better handling of the accepting answers workflow git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@38 0cfe37f9-358a-4d5e-be75-b63607b5c754 --- forum/activity.py | 13 ++++++------- forum/models/answer.py | 10 +++++++--- forum/models/question.py | 6 +++++- forum/models/tag.py | 2 +- forum/reputation.py | 37 +++++++++++++++++++++++-------------- forum/views/commands.py | 12 ++++-------- forum/views/decorators.py | 4 ++-- forum/views/readers.py | 14 +++++++------- 8 files changed, 55 insertions(+), 43 deletions(-) diff --git a/forum/activity.py b/forum/activity.py index 1f2d7f0..a58307b 100644 --- a/forum/activity.py +++ b/forum/activity.py @@ -3,6 +3,7 @@ from django.db.models.signals import post_save from forum.models import * from forum.models.base import marked_deleted from forum.models.meta import vote_canceled +from forum.models.answer import answer_accepted from forum.authentication import user_updated from forum.const import * @@ -33,7 +34,7 @@ post_save.connect(record_comment_event, sender=Comment) def record_revision_event(instance, created, **kwargs): if created and instance.revision <> 1 and instance.node.node_type in ('question', 'answer',): - activity_type = instance.node == 'question' and TYPE_ACTIVITY_UPDATE_QUESTION or TYPE_ACTIVITY_UPDATE_ANSWER + activity_type = instance.node.node_type == 'question' and TYPE_ACTIVITY_UPDATE_QUESTION or TYPE_ACTIVITY_UPDATE_ANSWER activity = Activity(user=instance.author, active_at=instance.revised_at, content_object=instance, activity_type=activity_type) activity.save() @@ -49,13 +50,11 @@ def record_award_event(instance, created, **kwargs): post_save.connect(record_award_event, sender=Award) -def record_answer_accepted(instance, created, **kwargs): - if not created and 'accepted' in instance.get_dirty_fields() and instance.accepted: - activity = Activity(user=instance.question.author, active_at=datetime.datetime.now(), \ - content_object=instance, activity_type=TYPE_ACTIVITY_MARK_ANSWER) - activity.save() +def record_answer_accepted(answer, user, **kwargs): + activity = Activity(user=user, active_at=datetime.datetime.now(), content_object=answer, activity_type=TYPE_ACTIVITY_MARK_ANSWER) + activity.save() -post_save.connect(record_answer_accepted, sender=Answer) +answer_accepted.connect(record_answer_accepted) def update_last_seen(instance, **kwargs): diff --git a/forum/models/answer.py b/forum/models/answer.py index bac79af..01e0aae 100644 --- a/forum/models/answer.py +++ b/forum/models/answer.py @@ -20,18 +20,20 @@ class Answer(QandA): self.accepted_at = datetime.datetime.now() self.accepted_by = user self.save() - self.question.answer_accepted = True + self.question.accepted_answer = self self.question.save() + answer_accepted.send(sender=Answer, answer=self, user=user) return True return False - def unmark_accepted(self): + def unmark_accepted(self, user): if self.accepted: self.accepted = False self.save() - self.question.answer_accepted = False + self.question.accepted_answer = None self.question.save() + answer_accepted_canceled.send(sender=Answer, answer=self, user=user) return True return False @@ -70,6 +72,8 @@ class Answer(QandA): def __unicode__(self): return self.html +answer_accepted = django.dispatch.Signal(providing_args=['answer', 'user']) +answer_accepted_canceled = django.dispatch.Signal(providing_args=['answer', 'user']) class AnswerRevision(NodeRevision): class Meta: diff --git a/forum/models/question.py b/forum/models/question.py index 3bf517c..485576d 100644 --- a/forum/models/question.py +++ b/forum/models/question.py @@ -5,7 +5,7 @@ from django.utils.translation import ugettext as _ question_view = django.dispatch.Signal(providing_args=['instance', 'user']) class Question(QandA): - answer_accepted = models.BooleanField(default=False) + accepted_answer = models.OneToOneField('Answer', null=True, related_name="question_accepting") closed = models.BooleanField(default=False) closed_by = models.ForeignKey(User, null=True, blank=True, related_name='closed_questions') closed_at = models.DateTimeField(null=True, blank=True) @@ -34,6 +34,10 @@ class Question(QandA): return self.title + @property + def answer_accepted(self): + return self.accepted_answer is not None + def delete(self): super(Question, self).delete() try: diff --git a/forum/models/tag.py b/forum/models/tag.py index cda2779..895dac0 100644 --- a/forum/models/tag.py +++ b/forum/models/tag.py @@ -8,7 +8,7 @@ class ActiveTagManager(UndeletedObjectManager): return super(UndeletedObjectManager, self).get_query_set().exclude(used_count=0) -class Tag(DeletableContent): +class Tag(BaseModel, DeletableContent): name = models.CharField(max_length=255, unique=True) created_by = models.ForeignKey(User, related_name='created_tags') marked_by = models.ManyToManyField(User, related_name="marked_tags", through="MarkedTag") diff --git a/forum/reputation.py b/forum/reputation.py index fd5ce63..4a0fe7e 100644 --- a/forum/reputation.py +++ b/forum/reputation.py @@ -1,5 +1,6 @@ from django.db.models.signals import post_save from forum.models.meta import vote_canceled +from forum.models.answer import answer_accepted, answer_accepted_canceled from forum.models import * from forum.const import * @@ -28,24 +29,32 @@ def on_flagged_item(instance, created, **kwargs): post_save.connect(on_flagged_item, sender=FlaggedItem) +def on_answer_accepted(answer, user, **kwargs): + if user == answer.question.author and not user == answer.author: + user.reputes.create( + value=int(settings.REP_GAIN_BY_ACCEPTING), question=answer.question, + reputation_type=TYPE_REPUTATION_GAIN_BY_ACCEPTING_ANSWER) -def on_answer_accepted_switch(instance, created, **kwargs): - if not created and 'accepted' in instance.get_dirty_fields() and ( - not instance.accepted_by == instance.question.author): - repute_type, repute_value = instance.accepted and ( - TYPE_REPUTATION_GAIN_BY_ANSWER_ACCEPTED, int(settings.REP_GAIN_BY_ACCEPTED)) or ( - TYPE_REPUTATION_LOST_BY_ACCEPTED_ANSWER_CANCELED, -int(settings.REP_LOST_BY_ACCEPTED_CANCELED)) + if not user == answer.author: + answer.author.reputes.create( + value=int(settings.REP_GAIN_BY_ACCEPTED), question=answer.question, + reputation_type=TYPE_REPUTATION_GAIN_BY_ANSWER_ACCEPTED) - instance.author.reputes.create(value=repute_value, question=instance.question, reputation_type=repute_type) - - if instance.accepted_by == instance.question.author: - repute_type, repute_value = instance.accepted and ( - TYPE_REPUTATION_GAIN_BY_ACCEPTING_ANSWER, int(settings.REP_GAIN_BY_ACCEPTING)) or ( - TYPE_REPUTATION_LOST_BY_CANCELLING_ACCEPTED_ANSWER, -int(settings.REP_LOST_BY_CANCELING_ACCEPTED)) +answer_accepted.connect(on_answer_accepted) - instance.question.author.reputes.create(value=repute_value, question=instance.question, reputation_type=repute_type) -post_save.connect(on_answer_accepted_switch, sender=Answer) +def on_answer_accepted_canceled(answer, user, **kwargs): + if user == answer.accepted_by: + user.reputes.create( + value=-int(settings.REP_LOST_BY_CANCELING_ACCEPTED), question=answer.question, + reputation_type=TYPE_REPUTATION_LOST_BY_CANCELLING_ACCEPTED_ANSWER) + + if not user == answer.author: + answer.author.reputes.create( + value=-int(settings.REP_LOST_BY_ACCEPTED_CANCELED), question=answer.question, + reputation_type=TYPE_REPUTATION_LOST_BY_ACCEPTED_ANSWER_CANCELED) + +answer_accepted_canceled.connect(on_answer_accepted) def on_vote(instance, created, **kwargs): diff --git a/forum/views/commands.py b/forum/views/commands.py index 794ed49..89f3fb8 100644 --- a/forum/views/commands.py +++ b/forum/views/commands.py @@ -274,17 +274,13 @@ def accept_answer(request, id): commands = {} if answer.accepted: - answer.unmark_accepted() + answer.unmark_accepted(user) commands['unmark_accepted'] = [answer.id] else: - try: - accepted = question.answers.get(accepted=True) - accepted.unmark_accepted() + if question.accepted_answer is not None: + accepted = question.accepted_answer + accepted.unmark_accepted(user) commands['unmark_accepted'] = [accepted.id] - except: - #import sys, traceback - #traceback.print_exc(file=sys.stdout) - pass answer.mark_accepted(user) commands['mark_accepted'] = [answer.id] diff --git a/forum/views/decorators.py b/forum/views/decorators.py index da51e1a..cf5f903 100644 --- a/forum/views/decorators.py +++ b/forum/views/decorators.py @@ -61,8 +61,8 @@ def command(func): response = func(request, *args, **kwargs) response['success'] = True except Exception, e: - import sys, traceback - traceback.print_exc(file=sys.stdout) + #import sys, traceback + #traceback.print_exc(file=sys.stdout) response = { 'success': False, diff --git a/forum/views/readers.py b/forum/views/readers.py index 819384f..15ac86b 100644 --- a/forum/views/readers.py +++ b/forum/views/readers.py @@ -60,7 +60,7 @@ def index(request): @decorators.render('questions.html', 'unanswered') def unanswered(request): - return question_list(request, Question.objects.filter(answer_accepted=False), + return question_list(request, Question.objects.filter(accepted_answer=None), _('Open questions without an accepted answer')) @decorators.render('questions.html', 'questions') @@ -186,16 +186,16 @@ def get_answer_sort_order(request): return (view_id, view_dic[view_id]) def update_question_view_times(request, question): - if not 'question_view_times' in request.session: - request.session['question_view_times'] = {} + if not 'last_seen_in_question' in request.session: + request.session['last_seen_in_question'] = {} - last_seen = request.session['question_view_times'].get(question.id,None) + last_seen = request.session['last_seen_in_question'].get(question.id,None) - if not last_seen or last_seen < question.last_activity_at: + if (not last_seen) or last_seen < question.last_activity_at: question_view.send(sender=update_question_view_times, instance=question, user=request.user) - request.session['question_view_times'][question.id] = datetime.datetime.now() + request.session['last_seen_in_question'][question.id] = datetime.datetime.now() - request.session['question_view_times'][question.id] = datetime.datetime.now() + request.session['last_seen_in_question'][question.id] = datetime.datetime.now() def question(request, id, slug): question = get_object_or_404(Question, id=id) -- 2.39.5