4 class QuestionManager(models.Manager):
\r
6 def create_new(cls, title=None,author=None,added_at=None, wiki=False,tagnames=None,summary=None, text=None):
\r
10 added_at = added_at,
\r
11 last_activity_at = added_at,
\r
12 last_activity_by = author,
\r
14 tagnames = tagnames,
\r
19 question.last_edited_by = question.author
\r
20 question.last_edited_at = added_at
\r
21 question.wikified_at = added_at
\r
25 # create the first revision
\r
26 QuestionRevision.objects.create(
\r
27 question = question,
\r
29 title = question.title,
\r
31 revised_at = added_at,
\r
32 tagnames = question.tagnames,
\r
33 summary = CONST['default_version'],
\r
38 def update_tags(self, question, tagnames, user):
\r
40 Updates Tag associations for a question to match the given
\r
43 Returns ``True`` if tag usage counts were updated as a result,
\r
44 ``False`` otherwise.
\r
47 current_tags = list(question.tags.all())
\r
48 current_tagnames = set(t.name for t in current_tags)
\r
49 updated_tagnames = set(t for t in tagnames.split(' ') if t)
\r
52 removed_tags = [t for t in current_tags
\r
53 if t.name not in updated_tagnames]
\r
55 modified_tags.extend(removed_tags)
\r
56 question.tags.remove(*removed_tags)
\r
58 added_tagnames = updated_tagnames - current_tagnames
\r
60 added_tags = Tag.objects.get_or_create_multiple(added_tagnames,
\r
62 modified_tags.extend(added_tags)
\r
63 question.tags.add(*added_tags)
\r
66 Tag.objects.update_use_counts(modified_tags)
\r
71 def update_answer_count(self, question):
\r
73 Executes an UPDATE query to update denormalised data with the
\r
74 number of answers the given question has.
\r
77 # for some reasons, this Answer class failed to be imported,
\r
78 # although we have imported all classes from models on top.
\r
79 from answer import Answer
\r
80 self.filter(id=question.id).update(
\r
81 answer_count=Answer.objects.get_answers_from_question(question).filter(deleted=False).count())
\r
83 def update_view_count(self, question):
\r
85 update counter+1 when user browse question page
\r
87 self.filter(id=question.id).update(view_count = question.view_count + 1)
\r
89 def update_favorite_count(self, question):
\r
91 update favourite_count for given question
\r
93 self.filter(id=question.id).update(favourite_count = FavoriteQuestion.objects.filter(question=question).count())
\r
95 def get_similar_questions(self, question):
\r
97 Get 10 similar questions for given one.
\r
98 This will search the same tag list for give question(by exactly same string) first.
\r
99 Questions with the individual tags will be added to list if above questions are not full.
\r
101 #print datetime.datetime.now()
\r
102 questions = list(self.filter(tagnames = question.tagnames, deleted=False).all())
\r
104 tags_list = question.tags.all()
\r
105 for tag in tags_list:
\r
106 extend_questions = self.filter(tags__id = tag.id, deleted=False)[:50]
\r
107 for item in extend_questions:
\r
108 if item not in questions and len(questions) < 10:
\r
109 questions.append(item)
\r
111 #print datetime.datetime.now()
\r
114 class Question(Content, DeletableContent):
\r
115 title = models.CharField(max_length=300)
\r
116 tags = models.ManyToManyField('Tag', related_name='questions')
\r
117 answer_accepted = models.BooleanField(default=False)
\r
118 closed = models.BooleanField(default=False)
\r
119 closed_by = models.ForeignKey(User, null=True, blank=True, related_name='closed_questions')
\r
120 closed_at = models.DateTimeField(null=True, blank=True)
\r
121 close_reason = models.SmallIntegerField(choices=CLOSE_REASONS, null=True, blank=True)
\r
122 followed_by = models.ManyToManyField(User, related_name='followed_questions')
\r
124 # Denormalised data
\r
125 answer_count = models.PositiveIntegerField(default=0)
\r
126 view_count = models.PositiveIntegerField(default=0)
\r
127 favourite_count = models.PositiveIntegerField(default=0)
\r
128 last_activity_at = models.DateTimeField(default=datetime.datetime.now)
\r
129 last_activity_by = models.ForeignKey(User, related_name='last_active_in_questions')
\r
130 tagnames = models.CharField(max_length=125)
\r
131 summary = models.CharField(max_length=180)
\r
133 favorited_by = models.ManyToManyField(User, through='FavoriteQuestion', related_name='favorite_questions')
\r
135 objects = QuestionManager()
\r
137 class Meta(Content.Meta):
\r
138 db_table = u'question'
\r
141 super(Question, self).delete()
\r
145 logging.debug('problem pinging google did you register you sitemap with google?')
\r
147 def save(self, **kwargs):
\r
149 Overridden to manually manage addition of tags when the object
\r
152 This is required as we're using ``tagnames`` as the sole means of
\r
153 adding and editing tags.
\r
155 initial_addition = (self.id is None)
\r
157 super(Question, self).save(**kwargs)
\r
159 if initial_addition:
\r
160 tags = Tag.objects.get_or_create_multiple(self.tagname_list(),
\r
162 self.tags.add(*tags)
\r
163 Tag.objects.update_use_counts(tags)
\r
165 def tagname_list(self):
\r
166 """Creates a list of Tag names from the ``tagnames`` attribute."""
\r
167 return [name for name in self.tagnames.split(u' ')]
\r
169 def tagname_meta_generator(self):
\r
170 return u','.join([unicode(tag) for tag in self.tagname_list()])
\r
172 def get_absolute_url(self):
\r
173 return '%s%s' % (reverse('question', args=[self.id]), django_urlquote(slugify(self.title)))
\r
175 def has_favorite_by_user(self, user):
\r
176 if not user.is_authenticated():
\r
179 return FavoriteQuestion.objects.filter(question=self, user=user).count() > 0
\r
181 def get_answer_count_by_user(self, user_id):
\r
182 from answer import Answer
\r
183 query_set = Answer.objects.filter(author__id=user_id)
\r
184 return query_set.filter(question=self).count()
\r
186 def get_question_title(self):
\r
188 attr = CONST['closed']
\r
190 attr = CONST['deleted']
\r
193 if attr is not None:
\r
194 return u'%s %s' % (self.title, attr)
\r
198 def get_revision_url(self):
\r
199 return reverse('question_revisions', args=[self.id])
\r
201 def get_latest_revision(self):
\r
202 return self.revisions.all()[0]
\r
204 def get_last_update_info(self):
\r
205 when, who = self.post_get_last_update_info()
\r
207 answers = self.answers.all()
\r
208 if len(answers) > 0:
\r
210 a_when, a_who = a.post_get_last_update_info()
\r
217 def get_update_summary(self,last_reported_at=None,recipient_email=''):
\r
219 if self.last_edited_at and self.last_edited_at > last_reported_at:
\r
220 if self.last_edited_by.email != recipient_email:
\r
223 for comment in self.comments.all():
\r
224 if comment.added_at > last_reported_at and comment.user.email != recipient_email:
\r
225 comments.append(comment)
\r
227 answer_comments = []
\r
228 modified_answers = []
\r
229 commented_answers = []
\r
231 commented_answers = sets.Set([])
\r
232 for answer in self.answers.all():
\r
233 if (answer.added_at > last_reported_at and answer.author.email != recipient_email):
\r
234 new_answers.append(answer)
\r
235 if (answer.last_edited_at
\r
236 and answer.last_edited_at > last_reported_at
\r
237 and answer.last_edited_by.email != recipient_email):
\r
238 modified_answers.append(answer)
\r
239 for comment in answer.comments.all():
\r
240 if comment.added_at > last_reported_at and comment.user.email != recipient_email:
\r
241 commented_answers.add(answer)
\r
242 answer_comments.append(comment)
\r
245 if edited or new_answers or modified_answers or answer_comments:
\r
248 out.append(_('%(author)s modified the question') % {'author':self.last_edited_by.username})
\r
250 names = sets.Set(map(lambda x: x.author.username,new_answers))
\r
251 people = ', '.join(names)
\r
252 out.append(_('%(people)s posted %(new_answer_count)s new answers') \
\r
253 % {'new_answer_count':len(new_answers),'people':people})
\r
255 names = sets.Set(map(lambda x: x.user.username,comments))
\r
256 people = ', '.join(names)
\r
257 out.append(_('%(people)s commented the question') % {'people':people})
\r
258 if answer_comments:
\r
259 names = sets.Set(map(lambda x: x.user.username,answer_comments))
\r
260 people = ', '.join(names)
\r
261 if len(commented_answers) > 1:
\r
262 out.append(_('%(people)s commented answers') % {'people':people})
\r
264 out.append(_('%(people)s commented an answer') % {'people':people})
\r
265 url = settings.APP_URL + self.get_absolute_url()
\r
266 retval = '<a href="%s">%s</a>:<br>\n' % (url,self.title)
\r
267 out = map(lambda x: '<li>' + x + '</li>',out)
\r
268 retval += '<ul>' + '\n'.join(out) + '</ul><br>\n'
\r
273 def __unicode__(self):
\r
277 class QuestionView(models.Model):
\r
278 question = models.ForeignKey(Question, related_name='viewed')
\r
279 who = models.ForeignKey(User, related_name='question_views')
\r
280 when = models.DateTimeField()
\r
283 app_label = 'forum'
\r
285 class FavoriteQuestion(models.Model):
\r
286 """A favorite Question of a User."""
\r
287 question = models.ForeignKey(Question)
\r
288 user = models.ForeignKey(User, related_name='user_favorite_questions')
\r
289 added_at = models.DateTimeField(default=datetime.datetime.now)
\r
292 app_label = 'forum'
\r
293 db_table = u'favorite_question'
\r
294 def __unicode__(self):
\r
295 return '[%s] favorited at %s' %(self.user, self.added_at)
\r
297 class QuestionRevision(ContentRevision):
\r
298 """A revision of a Question."""
\r
299 question = models.ForeignKey(Question, related_name='revisions')
\r
300 title = models.CharField(max_length=300)
\r
301 tagnames = models.CharField(max_length=125)
\r
303 class Meta(ContentRevision.Meta):
\r
304 db_table = u'question_revision'
\r
305 ordering = ('-revision',)
\r
307 def get_question_title(self):
\r
308 return self.question.title
\r
310 def get_absolute_url(self):
\r
311 #print 'in QuestionRevision.get_absolute_url()'
\r
312 return reverse('question_revisions', args=[self.question.id])
\r
314 def save(self, **kwargs):
\r
315 """Looks up the next available revision number."""
\r
316 if not self.revision:
\r
317 self.revision = QuestionRevision.objects.filter(
\r
318 question=self.question).values_list('revision',
\r
320 super(QuestionRevision, self).save(**kwargs)
\r
322 def __unicode__(self):
\r
323 return u'revision %s of %s' % (self.revision, self.title)
\r
325 class AnonymousQuestion(AnonymousContent):
\r
326 title = models.CharField(max_length=300)
\r
327 tagnames = models.CharField(max_length=125)
\r
329 def publish(self,user):
\r
330 added_at = datetime.datetime.now()
\r
331 QuestionManager.create_new(title=self.title, author=user, added_at=added_at,
\r
332 wiki=self.wiki, tagnames=self.tagnames,
\r
333 summary=self.summary, text=self.text)
\r
336 from answer import Answer, AnswerManager
\r