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