]> git.openstreetmap.org Git - osqa.git/blob - forum/models/question.py
deleting the test file
[osqa.git] / forum / models / question.py
1 from base import *\r
2 from tag import Tag\r
3 \r
4 class QuestionManager(models.Manager):\r
5     @staticmethod\r
6     def create_new(cls, title=None,author=None,added_at=None, wiki=False,tagnames=None,summary=None, text=None):\r
7         question = Question(\r
8             title            = title,\r
9             author           = author,\r
10             added_at         = added_at,\r
11             last_activity_at = added_at,\r
12             last_activity_by = author,\r
13             wiki             = wiki,\r
14             tagnames         = tagnames,\r
15             html             = text,\r
16             summary          = summary\r
17         )\r
18         if question.wiki:\r
19             question.last_edited_by = question.author\r
20             question.last_edited_at = added_at\r
21             question.wikified_at = added_at\r
22 \r
23         question.save()\r
24 \r
25         # create the first revision\r
26         QuestionRevision.objects.create(\r
27             question   = question,\r
28             revision   = 1,\r
29             title      = question.title,\r
30             author     = author,\r
31             revised_at = added_at,\r
32             tagnames   = question.tagnames,\r
33             summary    = CONST['default_version'],\r
34             text       = text\r
35         )\r
36         return question\r
37 \r
38     def update_tags(self, question, tagnames, user):\r
39         """\r
40         Updates Tag associations for a question to match the given\r
41         tagname string.\r
42 \r
43         Returns ``True`` if tag usage counts were updated as a result,\r
44         ``False`` otherwise.\r
45         """\r
46 \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
50         modified_tags = []\r
51 \r
52         removed_tags = [t for t in current_tags\r
53                         if t.name not in updated_tagnames]\r
54         if removed_tags:\r
55             modified_tags.extend(removed_tags)\r
56             question.tags.remove(*removed_tags)\r
57 \r
58         added_tagnames = updated_tagnames - current_tagnames\r
59         if added_tagnames:\r
60             added_tags = Tag.objects.get_or_create_multiple(added_tagnames,\r
61                                                             user)\r
62             modified_tags.extend(added_tags)\r
63             question.tags.add(*added_tags)\r
64 \r
65         if modified_tags:\r
66             Tag.objects.update_use_counts(modified_tags)\r
67             return True\r
68 \r
69         return False\r
70 \r
71     def update_answer_count(self, question):\r
72         """\r
73         Executes an UPDATE query to update denormalised data with the\r
74         number of answers the given question has.\r
75         """\r
76 \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
82 \r
83     def update_view_count(self, question):\r
84         """\r
85         update counter+1 when user browse question page\r
86         """\r
87         self.filter(id=question.id).update(view_count = question.view_count + 1)\r
88 \r
89     def update_favorite_count(self, question):\r
90         """\r
91         update favourite_count for given question\r
92         """\r
93         self.filter(id=question.id).update(favourite_count = FavoriteQuestion.objects.filter(question=question).count())\r
94 \r
95     def get_similar_questions(self, question):\r
96         """\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
100         """\r
101         #print datetime.datetime.now()\r
102         questions = list(self.filter(tagnames = question.tagnames, deleted=False).all())\r
103 \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
110 \r
111         #print datetime.datetime.now()\r
112         return questions\r
113 \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
123 \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
132 \r
133     favorited_by         = models.ManyToManyField(User, through='FavoriteQuestion', related_name='favorite_questions') \r
134 \r
135     objects = QuestionManager()\r
136 \r
137     class Meta(Content.Meta):\r
138         db_table = u'question'\r
139 \r
140     def delete(self):\r
141         super(Question, self).delete()\r
142         try:\r
143             ping_google()\r
144         except Exception:\r
145             logging.debug('problem pinging google did you register you sitemap with google?')\r
146 \r
147     def save(self, **kwargs):\r
148         """\r
149         Overridden to manually manage addition of tags when the object\r
150         is first saved.\r
151 \r
152         This is required as we're using ``tagnames`` as the sole means of\r
153         adding and editing tags.\r
154         """\r
155         initial_addition = (self.id is None)\r
156         \r
157         super(Question, self).save(**kwargs)\r
158 \r
159         if initial_addition:\r
160             tags = Tag.objects.get_or_create_multiple(self.tagname_list(),\r
161                                                       self.author)\r
162             self.tags.add(*tags)\r
163             Tag.objects.update_use_counts(tags)\r
164 \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
168 \r
169     def tagname_meta_generator(self):\r
170         return u','.join([unicode(tag) for tag in self.tagname_list()])\r
171 \r
172     def get_absolute_url(self):\r
173         return '%s%s' % (reverse('question', args=[self.id]), django_urlquote(slugify(self.title)))\r
174 \r
175     def has_favorite_by_user(self, user):\r
176         if not user.is_authenticated():\r
177             return False\r
178 \r
179         return FavoriteQuestion.objects.filter(question=self, user=user).count() > 0\r
180 \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
185 \r
186     def get_question_title(self):\r
187         if self.closed:\r
188             attr = CONST['closed']\r
189         elif self.deleted:\r
190             attr = CONST['deleted']\r
191         else:\r
192             attr = None\r
193         if attr is not None:\r
194             return u'%s %s' % (self.title, attr)\r
195         else:\r
196             return self.title\r
197 \r
198     def get_revision_url(self):\r
199         return reverse('question_revisions', args=[self.id])\r
200 \r
201     def get_latest_revision(self):\r
202         return self.revisions.all()[0]\r
203 \r
204     def get_last_update_info(self):\r
205         when, who = self.post_get_last_update_info()\r
206 \r
207         answers = self.answers.all()\r
208         if len(answers) > 0:\r
209             for a in answers:\r
210                 a_when, a_who = a.post_get_last_update_info()\r
211                 if a_when > when:\r
212                     when = a_when\r
213                     who = a_who\r
214 \r
215         return when, who\r
216 \r
217     def get_update_summary(self,last_reported_at=None,recipient_email=''):\r
218         edited = False\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
221                 edited = True\r
222         comments = []\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
226         new_answers = []\r
227         answer_comments = []\r
228         modified_answers = []\r
229         commented_answers = []\r
230         import sets\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
243 \r
244         #create the report\r
245         if edited or new_answers or modified_answers or answer_comments:\r
246             out = []\r
247             if edited:\r
248                 out.append(_('%(author)s modified the question') % {'author':self.last_edited_by.username})\r
249             if new_answers:\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
254             if comments:\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
263                 else:\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
269             return retval\r
270         else:\r
271             return None\r
272 \r
273     def __unicode__(self):\r
274         return self.title\r
275 \r
276         \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
281 \r
282     class Meta:\r
283         app_label = 'forum'\r
284 \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
290 \r
291     class Meta:\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
296 \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
302 \r
303     class Meta(ContentRevision.Meta):\r
304         db_table = u'question_revision'\r
305         ordering = ('-revision',)\r
306 \r
307     def get_question_title(self):\r
308         return self.question.title\r
309 \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
313 \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
319                                                     flat=True)[0] + 1\r
320         super(QuestionRevision, self).save(**kwargs)\r
321 \r
322     def __unicode__(self):\r
323         return u'revision %s of %s' % (self.revision, self.title)\r
324 \r
325 class AnonymousQuestion(AnonymousContent):\r
326     title = models.CharField(max_length=300)\r
327     tagnames = models.CharField(max_length=125)\r
328 \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
334         self.delete()\r
335 \r
336 from answer import Answer, AnswerManager\r