##// END OF EJS Templates
Use map() in python3 style
neko259 -
r770:d854d75e default
parent child Browse files
Show More
@@ -1,347 +1,346 b''
1 1 from datetime import datetime, timedelta, date
2 2 from datetime import time as dtime
3 3 import logging
4 4 import re
5 5
6 6 from django.core.cache import cache
7 7 from django.core.urlresolvers import reverse
8 8 from django.db import models, transaction
9 9 from django.template.loader import render_to_string
10 10 from django.utils import timezone
11 11 from markupfield.fields import MarkupField
12 12
13 13 from boards.models import PostImage
14 14 from boards.models.base import Viewable
15 15 from boards.models.thread import Thread
16 16
17 17
18 18 APP_LABEL_BOARDS = 'boards'
19 19
20 20 CACHE_KEY_PPD = 'ppd'
21 21 CACHE_KEY_POST_URL = 'post_url'
22 22
23 23 POSTS_PER_DAY_RANGE = 7
24 24
25 25 BAN_REASON_AUTO = 'Auto'
26 26
27 27 IMAGE_THUMB_SIZE = (200, 150)
28 28
29 29 TITLE_MAX_LENGTH = 200
30 30
31 31 DEFAULT_MARKUP_TYPE = 'bbcode'
32 32
33 33 # TODO This should be removed
34 34 NO_IP = '0.0.0.0'
35 35
36 36 # TODO Real user agent should be saved instead of this
37 37 UNKNOWN_UA = ''
38 38
39 39 REGEX_REPLY = re.compile(r'\[post\](\d+)\[/post\]')
40 40
41 41 logger = logging.getLogger(__name__)
42 42
43 43
44 44 class PostManager(models.Manager):
45 45 def create_post(self, title, text, image=None, thread=None, ip=NO_IP,
46 46 tags=None):
47 47 """
48 48 Creates new post
49 49 """
50 50
51 51 if not tags:
52 52 tags = []
53 53
54 54 posting_time = timezone.now()
55 55 if not thread:
56 56 thread = Thread.objects.create(bump_time=posting_time,
57 57 last_edit_time=posting_time)
58 58 new_thread = True
59 59 else:
60 60 thread.bump()
61 61 thread.last_edit_time = posting_time
62 62 thread.save()
63 63 new_thread = False
64 64
65 65 post = self.create(title=title,
66 66 text=text,
67 67 pub_time=posting_time,
68 68 thread_new=thread,
69 69 poster_ip=ip,
70 70 poster_user_agent=UNKNOWN_UA, # TODO Get UA at
71 71 # last!
72 72 last_edit_time=posting_time)
73 73
74 74 if image:
75 75 post_image = PostImage.objects.create(image=image)
76 76 post.images.add(post_image)
77 77 logger.info('Created image #%d for post #%d' % (post_image.id,
78 78 post.id))
79 79
80 80 thread.replies.add(post)
81 for tag in tags:
82 thread.add_tag(tag)
81 list(map(thread.add_tag, tags))
83 82
84 83 if new_thread:
85 84 Thread.objects.process_oldest_threads()
86 85 self.connect_replies(post)
87 86
88 87 logger.info('Created post #%d with title %s' % (post.id,
89 88 post.get_title()))
90 89
91 90 return post
92 91
93 92 def delete_post(self, post):
94 93 """
95 94 Deletes post and update or delete its thread
96 95 """
97 96
98 97 post_id = post.id
99 98
100 99 thread = post.get_thread()
101 100
102 101 if post.is_opening():
103 102 thread.delete()
104 103 else:
105 104 thread.last_edit_time = timezone.now()
106 105 thread.save()
107 106
108 107 post.delete()
109 108
110 109 logger.info('Deleted post #%d (%s)' % (post_id, post.get_title()))
111 110
112 111 def delete_posts_by_ip(self, ip):
113 112 """
114 113 Deletes all posts of the author with same IP
115 114 """
116 115
117 116 posts = self.filter(poster_ip=ip)
118 117 for post in posts:
119 118 self.delete_post(post)
120 119
121 120 def connect_replies(self, post):
122 121 """
123 122 Connects replies to a post to show them as a reflink map
124 123 """
125 124
126 125 for reply_number in re.finditer(REGEX_REPLY, post.text.raw):
127 126 post_id = reply_number.group(1)
128 127 ref_post = self.filter(id=post_id)
129 128 if ref_post.count() > 0:
130 129 referenced_post = ref_post[0]
131 130 referenced_post.referenced_posts.add(post)
132 131 referenced_post.last_edit_time = post.pub_time
133 132 referenced_post.build_refmap()
134 133 referenced_post.save(update_fields=['refmap', 'last_edit_time'])
135 134
136 135 referenced_thread = referenced_post.get_thread()
137 136 referenced_thread.last_edit_time = post.pub_time
138 137 referenced_thread.save(update_fields=['last_edit_time'])
139 138
140 139 def get_posts_per_day(self):
141 140 """
142 141 Gets average count of posts per day for the last 7 days
143 142 """
144 143
145 144 day_end = date.today()
146 145 day_start = day_end - timedelta(POSTS_PER_DAY_RANGE)
147 146
148 147 cache_key = CACHE_KEY_PPD + str(day_end)
149 148 ppd = cache.get(cache_key)
150 149 if ppd:
151 150 return ppd
152 151
153 152 day_time_start = timezone.make_aware(datetime.combine(
154 153 day_start, dtime()), timezone.get_current_timezone())
155 154 day_time_end = timezone.make_aware(datetime.combine(
156 155 day_end, dtime()), timezone.get_current_timezone())
157 156
158 157 posts_per_period = float(self.filter(
159 158 pub_time__lte=day_time_end,
160 159 pub_time__gte=day_time_start).count())
161 160
162 161 ppd = posts_per_period / POSTS_PER_DAY_RANGE
163 162
164 163 cache.set(cache_key, ppd)
165 164 return ppd
166 165
167 166
168 167 class Post(models.Model, Viewable):
169 168 """A post is a message."""
170 169
171 170 objects = PostManager()
172 171
173 172 class Meta:
174 173 app_label = APP_LABEL_BOARDS
175 174 ordering = ('id',)
176 175
177 176 title = models.CharField(max_length=TITLE_MAX_LENGTH)
178 177 pub_time = models.DateTimeField()
179 178 text = MarkupField(default_markup_type=DEFAULT_MARKUP_TYPE,
180 179 escape_html=False)
181 180
182 181 images = models.ManyToManyField(PostImage, null=True, blank=True,
183 182 related_name='ip+', db_index=True)
184 183
185 184 poster_ip = models.GenericIPAddressField()
186 185 poster_user_agent = models.TextField()
187 186
188 187 thread_new = models.ForeignKey('Thread', null=True, default=None,
189 188 db_index=True)
190 189 last_edit_time = models.DateTimeField()
191 190
192 191 referenced_posts = models.ManyToManyField('Post', symmetrical=False,
193 192 null=True,
194 193 blank=True, related_name='rfp+',
195 194 db_index=True)
196 195 refmap = models.TextField(null=True, blank=True)
197 196
198 197 def __unicode__(self):
199 198 return '#' + str(self.id) + ' ' + self.title + ' (' + \
200 199 self.text.raw[:50] + ')'
201 200
202 201 def get_title(self):
203 202 """
204 203 Gets original post title or part of its text.
205 204 """
206 205
207 206 title = self.title
208 207 if not title:
209 208 title = self.text.rendered
210 209
211 210 return title
212 211
213 212 def build_refmap(self):
214 213 """
215 214 Builds a replies map string from replies list. This is a cache to stop
216 215 the server from recalculating the map on every post show.
217 216 """
218 217 map_string = ''
219 218
220 219 first = True
221 220 for refpost in self.referenced_posts.all():
222 221 if not first:
223 222 map_string += ', '
224 223 map_string += '<a href="%s">&gt;&gt;%s</a>' % (refpost.get_url(),
225 224 refpost.id)
226 225 first = False
227 226
228 227 self.refmap = map_string
229 228
230 229 def get_sorted_referenced_posts(self):
231 230 return self.refmap
232 231
233 232 def is_referenced(self):
234 233 return len(self.refmap) > 0
235 234
236 235 def is_opening(self):
237 236 """
238 237 Checks if this is an opening post or just a reply.
239 238 """
240 239
241 240 return self.get_thread().get_opening_post_id() == self.id
242 241
243 242 @transaction.atomic
244 243 def add_tag(self, tag):
245 244 edit_time = timezone.now()
246 245
247 246 thread = self.get_thread()
248 247 thread.add_tag(tag)
249 248 self.last_edit_time = edit_time
250 249 self.save(update_fields=['last_edit_time'])
251 250
252 251 thread.last_edit_time = edit_time
253 252 thread.save(update_fields=['last_edit_time'])
254 253
255 254 @transaction.atomic
256 255 def remove_tag(self, tag):
257 256 edit_time = timezone.now()
258 257
259 258 thread = self.get_thread()
260 259 thread.remove_tag(tag)
261 260 self.last_edit_time = edit_time
262 261 self.save(update_fields=['last_edit_time'])
263 262
264 263 thread.last_edit_time = edit_time
265 264 thread.save(update_fields=['last_edit_time'])
266 265
267 266 def get_url(self, thread=None):
268 267 """
269 268 Gets full url to the post.
270 269 """
271 270
272 271 cache_key = CACHE_KEY_POST_URL + str(self.id)
273 272 link = cache.get(cache_key)
274 273
275 274 if not link:
276 275 if not thread:
277 276 thread = self.get_thread()
278 277
279 278 opening_id = thread.get_opening_post_id()
280 279
281 280 if self.id != opening_id:
282 281 link = reverse('thread', kwargs={
283 282 'post_id': opening_id}) + '#' + str(self.id)
284 283 else:
285 284 link = reverse('thread', kwargs={'post_id': self.id})
286 285
287 286 cache.set(cache_key, link)
288 287
289 288 return link
290 289
291 290 def get_thread(self):
292 291 """
293 292 Gets post's thread.
294 293 """
295 294
296 295 return self.thread_new
297 296
298 297 def get_referenced_posts(self):
299 298 return self.referenced_posts.only('id', 'thread_new')
300 299
301 300 def get_text(self):
302 301 return self.text
303 302
304 303 def get_view(self, moderator=False, need_open_link=False,
305 304 truncated=False, *args, **kwargs):
306 305 if 'is_opening' in kwargs:
307 306 is_opening = kwargs['is_opening']
308 307 else:
309 308 is_opening = self.is_opening()
310 309
311 310 if 'thread' in kwargs:
312 311 thread = kwargs['thread']
313 312 else:
314 313 thread = self.get_thread()
315 314
316 315 if 'can_bump' in kwargs:
317 316 can_bump = kwargs['can_bump']
318 317 else:
319 318 can_bump = thread.can_bump()
320 319
321 320 if is_opening:
322 321 opening_post_id = self.id
323 322 else:
324 323 opening_post_id = thread.get_opening_post_id()
325 324
326 325 return render_to_string('boards/post.html', {
327 326 'post': self,
328 327 'moderator': moderator,
329 328 'is_opening': is_opening,
330 329 'thread': thread,
331 330 'bumpable': can_bump,
332 331 'need_open_link': need_open_link,
333 332 'truncated': truncated,
334 333 'opening_post_id': opening_post_id,
335 334 })
336 335
337 336 def get_first_image(self):
338 337 return self.images.earliest('id')
339 338
340 339 def delete(self, using=None):
341 340 """
342 341 Deletes all post images and the post itself.
343 342 """
344 343
345 344 self.images.all().delete()
346 345
347 346 super(Post, self).delete(using)
General Comments 0
You need to be logged in to leave comments. Login now