##// END OF EJS Templates
Speed up referenced posts getting a bit
neko259 -
r397:7372aab3 default
parent child Browse files
Show More
@@ -1,272 +1,272 b''
1 1 import os
2 2 from random import random
3 3 import time
4 4 import math
5 5 import re
6 6
7 7 from django.db import models
8 8 from django.http import Http404
9 9 from django.utils import timezone
10 10 from markupfield.fields import MarkupField
11 11
12 12 from neboard import settings
13 13 from boards import settings as boards_settings
14 14 from boards import thumbs
15 15
16 16 BAN_REASON_AUTO = 'Auto'
17 17
18 18 IMAGE_THUMB_SIZE = (200, 150)
19 19
20 20 TITLE_MAX_LENGTH = 50
21 21
22 22 DEFAULT_MARKUP_TYPE = 'markdown'
23 23
24 24 NO_PARENT = -1
25 25 NO_IP = '0.0.0.0'
26 26 UNKNOWN_UA = ''
27 27 ALL_PAGES = -1
28 28 IMAGES_DIRECTORY = 'images/'
29 29 FILE_EXTENSION_DELIMITER = '.'
30 30
31 31 SETTING_MODERATE = "moderate"
32 32
33 33 REGEX_REPLY = re.compile('>>(\d+)')
34 34
35 35
36 36 class PostManager(models.Manager):
37 37
38 38 def create_post(self, title, text, image=None, thread=None,
39 39 ip=NO_IP, tags=None, user=None):
40 40 posting_time = timezone.now()
41 41
42 42 post = self.create(title=title,
43 43 text=text,
44 44 pub_time=posting_time,
45 45 thread=thread,
46 46 image=image,
47 47 poster_ip=ip,
48 48 poster_user_agent=UNKNOWN_UA,
49 49 last_edit_time=posting_time,
50 50 bump_time=posting_time,
51 51 user=user)
52 52
53 53 if tags:
54 54 linked_tags = []
55 55 for tag in tags:
56 56 tag_linked_tags = tag.get_linked_tags()
57 57 if len(tag_linked_tags) > 0:
58 58 linked_tags.extend(tag_linked_tags)
59 59
60 60 tags.extend(linked_tags)
61 61 map(post.tags.add, tags)
62 62 for tag in tags:
63 63 tag.threads.add(post)
64 64
65 65 if thread:
66 66 thread.replies.add(post)
67 67 thread.bump()
68 68 thread.last_edit_time = posting_time
69 69 thread.save()
70 70 else:
71 71 self._delete_old_threads()
72 72
73 73 self.connect_replies(post)
74 74
75 75 return post
76 76
77 77 def delete_post(self, post):
78 78 if post.replies.count() > 0:
79 79 map(self.delete_post, post.replies.all())
80 80
81 81 # Update thread's last edit time
82 82 thread = post.thread
83 83 if thread:
84 84 thread.last_edit_time = timezone.now()
85 85 thread.save()
86 86
87 87 post.delete()
88 88
89 89 def delete_posts_by_ip(self, ip):
90 90 posts = self.filter(poster_ip=ip)
91 91 map(self.delete_post, posts)
92 92
93 93 def get_threads(self, tag=None, page=ALL_PAGES,
94 94 order_by='-bump_time'):
95 95 if tag:
96 96 threads = tag.threads
97 97
98 98 if threads.count() == 0:
99 99 raise Http404
100 100 else:
101 101 threads = self.filter(thread=None)
102 102
103 103 threads = threads.order_by(order_by)
104 104
105 105 if page != ALL_PAGES:
106 106 thread_count = threads.count()
107 107
108 108 if page < self._get_page_count(thread_count):
109 109 start_thread = page * settings.THREADS_PER_PAGE
110 110 end_thread = min(start_thread + settings.THREADS_PER_PAGE,
111 111 thread_count)
112 112 threads = threads[start_thread:end_thread]
113 113
114 114 return threads
115 115
116 116 def get_thread(self, opening_post_id):
117 117 try:
118 118 opening_post = self.get(id=opening_post_id, thread=None)
119 119 except Post.DoesNotExist:
120 120 raise Http404
121 121
122 122 if opening_post.replies:
123 123 thread = [opening_post]
124 124 thread.extend(opening_post.replies.all().order_by('pub_time'))
125 125
126 126 return thread
127 127
128 128 def get_thread_page_count(self, tag=None):
129 129 if tag:
130 130 threads = self.filter(thread=None, tags=tag)
131 131 else:
132 132 threads = self.filter(thread=None)
133 133
134 134 return self._get_page_count(threads.count())
135 135
136 136 def _delete_old_threads(self):
137 137 """
138 138 Preserves maximum thread count. If there are too many threads,
139 139 delete the old ones.
140 140 """
141 141
142 142 # TODO Move old threads to the archive instead of deleting them.
143 143 # Maybe make some 'old' field in the model to indicate the thread
144 144 # must not be shown and be able for replying.
145 145
146 146 threads = self.get_threads()
147 147 thread_count = threads.count()
148 148
149 149 if thread_count > settings.MAX_THREAD_COUNT:
150 150 num_threads_to_delete = thread_count - settings.MAX_THREAD_COUNT
151 151 old_threads = threads[thread_count - num_threads_to_delete:]
152 152
153 153 map(self.delete_post, old_threads)
154 154
155 155 def connect_replies(self, post):
156 156 """Connect replies to a post to show them as a refmap"""
157 157
158 158 for reply_number in re.finditer(REGEX_REPLY, post.text.raw):
159 159 post_id = reply_number.group(1)
160 160 ref_post = self.filter(id=post_id)
161 161 if ref_post.count() > 0:
162 162 referenced_post = ref_post[0]
163 163 referenced_post.referenced_posts.add(post)
164 164 referenced_post.last_edit_time = post.pub_time
165 165 referenced_post.save()
166 166
167 167 def _get_page_count(self, thread_count):
168 168 return int(math.ceil(thread_count / float(settings.THREADS_PER_PAGE)))
169 169
170 170
171 171 class Post(models.Model):
172 172 """A post is a message."""
173 173
174 174 objects = PostManager()
175 175
176 176 class Meta:
177 177 app_label = 'boards'
178 178
179 179 def _update_image_filename(self, filename):
180 180 """Get unique image filename"""
181 181
182 182 path = IMAGES_DIRECTORY
183 183 new_name = str(int(time.mktime(time.gmtime())))
184 184 new_name += str(int(random() * 1000))
185 185 new_name += FILE_EXTENSION_DELIMITER
186 186 new_name += filename.split(FILE_EXTENSION_DELIMITER)[-1:][0]
187 187
188 188 return os.path.join(path, new_name)
189 189
190 190 title = models.CharField(max_length=TITLE_MAX_LENGTH)
191 191 pub_time = models.DateTimeField()
192 192 text = MarkupField(default_markup_type=DEFAULT_MARKUP_TYPE,
193 193 escape_html=False)
194 194
195 195 image_width = models.IntegerField(default=0)
196 196 image_height = models.IntegerField(default=0)
197 197
198 198 image = thumbs.ImageWithThumbsField(upload_to=_update_image_filename,
199 199 blank=True, sizes=(IMAGE_THUMB_SIZE,),
200 200 width_field='image_width',
201 201 height_field='image_height')
202 202
203 203 poster_ip = models.GenericIPAddressField()
204 204 poster_user_agent = models.TextField()
205 205
206 206 thread = models.ForeignKey('Post', null=True, default=None)
207 207 tags = models.ManyToManyField('Tag')
208 208 last_edit_time = models.DateTimeField()
209 209 bump_time = models.DateTimeField()
210 210 user = models.ForeignKey('User', null=True, default=None)
211 211
212 212 replies = models.ManyToManyField('Post', symmetrical=False, null=True,
213 213 blank=True, related_name='re+')
214 214 referenced_posts = models.ManyToManyField('Post', symmetrical=False,
215 215 null=True,
216 216 blank=True, related_name='rfp+')
217 217
218 218 def __unicode__(self):
219 219 return '#' + str(self.id) + ' ' + self.title + ' (' + \
220 220 self.text.raw[:50] + ')'
221 221
222 222 def get_title(self):
223 223 title = self.title
224 224 if len(title) == 0:
225 225 title = self.text.raw[:20]
226 226
227 227 return title
228 228
229 229 def get_reply_count(self):
230 230 return self.replies.count()
231 231
232 232 def get_images_count(self):
233 233 images_count = 1 if self.image else 0
234 234 images_count += self.replies.filter(image_width__gt=0).count()
235 235
236 236 return images_count
237 237
238 238 def can_bump(self):
239 239 """Check if the thread can be bumped by replying"""
240 240
241 241 post_count = self.get_reply_count()
242 242
243 243 return post_count <= settings.MAX_POSTS_PER_THREAD
244 244
245 245 def bump(self):
246 246 """Bump (move to up) thread"""
247 247
248 248 if self.can_bump():
249 249 self.bump_time = timezone.now()
250 250
251 251 def get_last_replies(self):
252 252 if settings.LAST_REPLIES_COUNT > 0:
253 253 reply_count = self.get_reply_count()
254 254
255 255 if reply_count > 0:
256 256 reply_count_to_show = min(settings.LAST_REPLIES_COUNT,
257 257 reply_count)
258 258 last_replies = self.replies.all().order_by('pub_time')[
259 259 reply_count - reply_count_to_show:]
260 260
261 261 return last_replies
262 262
263 263 def get_tags(self):
264 264 """Get a sorted tag list"""
265 265
266 266 return self.tags.order_by('name')
267 267
268 268 def get_sorted_referenced_posts(self):
269 269 return self.referenced_posts.order_by('id')
270 270
271 271 def is_referenced(self):
272 return self.referenced_posts.count() > 0
272 return self.referenced_posts.all().exists()
General Comments 0
You need to be logged in to leave comments. Login now