##// END OF EJS Templates
Converting file name to a preudo-unique number instead of the original name.
neko259 -
r50:9ceb712a default
parent child Browse files
Show More
@@ -1,241 +1,248 b''
1 import os
1 import os
2 from random import random
2 import re
3 import re
3 from django.db import models
4 from django.db import models
4 from django.utils import timezone
5 from django.utils import timezone
5 import time
6 import time
6 import math
7 import math
7
8
8 from neboard import settings
9 from neboard import settings
9 from markupfield.fields import MarkupField
10 from markupfield.fields import MarkupField
10
11
11 import thumbs
12 import thumbs
12
13
13 NO_PARENT = -1
14 NO_PARENT = -1
14 NO_IP = '0.0.0.0'
15 NO_IP = '0.0.0.0'
15 UNKNOWN_UA = ''
16 UNKNOWN_UA = ''
16
17
17
18
18 def update_image_filename(instance, filename):
19 """Get unique image filename"""
20
21 path = 'images/'
22 new_name = str(int(time.mktime(time.gmtime()))) + '_' + filename
23 return os.path.join(path, new_name)
24
25
26 class PostManager(models.Manager):
19 class PostManager(models.Manager):
27 ALL_PAGES = -1
20 ALL_PAGES = -1
28
21
29 def create_post(self, title, text, image=None, parent_id=NO_PARENT,
22 def create_post(self, title, text, image=None, parent_id=NO_PARENT,
30 ip=NO_IP, tags=None):
23 ip=NO_IP, tags=None):
31 post = self.create(title=title,
24 post = self.create(title=title,
32 text=text,
25 text=text,
33 pub_time=timezone.now(),
26 pub_time=timezone.now(),
34 parent=parent_id,
27 parent=parent_id,
35 image=image,
28 image=image,
36 poster_ip=ip,
29 poster_ip=ip,
37 poster_user_agent=UNKNOWN_UA,
30 poster_user_agent=UNKNOWN_UA,
38 last_edit_time=timezone.now())
31 last_edit_time=timezone.now())
39
32
40 if tags:
33 if tags:
41 for tag in tags:
34 for tag in tags:
42 post.tags.add(tag)
35 post.tags.add(tag)
43
36
44 if parent_id != NO_PARENT:
37 if parent_id != NO_PARENT:
45 self._bump_thread(parent_id)
38 self._bump_thread(parent_id)
46 else:
39 else:
47 self._delete_old_threads()
40 self._delete_old_threads()
48
41
49 return post
42 return post
50
43
51 def delete_post(self, post):
44 def delete_post(self, post):
52 children = self.filter(parent=post.id)
45 children = self.filter(parent=post.id)
53 for child in children:
46 for child in children:
54 self.delete_post(child)
47 self.delete_post(child)
55 post.delete()
48 post.delete()
56
49
57 def delete_posts_by_ip(self, ip):
50 def delete_posts_by_ip(self, ip):
58 posts = self.filter(poster_ip=ip)
51 posts = self.filter(poster_ip=ip)
59 for post in posts:
52 for post in posts:
60 self.delete_post(post)
53 self.delete_post(post)
61
54
62 def get_threads(self, tag=None, page=ALL_PAGES):
55 def get_threads(self, tag=None, page=ALL_PAGES):
63 if tag:
56 if tag:
64 threads = self.filter(parent=NO_PARENT, tags=tag)
57 threads = self.filter(parent=NO_PARENT, tags=tag)
65 else:
58 else:
66 threads = self.filter(parent=NO_PARENT)
59 threads = self.filter(parent=NO_PARENT)
67 threads = list(threads.order_by('-last_edit_time'))
60 threads = list(threads.order_by('-last_edit_time'))
68
61
69 if page != self.ALL_PAGES:
62 if page != self.ALL_PAGES:
70 thread_count = len(threads)
63 thread_count = len(threads)
71
64
72 if page < self.get_thread_page_count(tag=tag):
65 if page < self.get_thread_page_count(tag=tag):
73 start_thread = page * settings.THREADS_PER_PAGE
66 start_thread = page * settings.THREADS_PER_PAGE
74 end_thread = min(start_thread + settings.THREADS_PER_PAGE,
67 end_thread = min(start_thread + settings.THREADS_PER_PAGE,
75 thread_count)
68 thread_count)
76 threads = threads[start_thread:end_thread]
69 threads = threads[start_thread:end_thread]
77
70
78 return threads
71 return threads
79
72
80 def get_thread(self, opening_post_id):
73 def get_thread(self, opening_post_id):
81 opening_post = self.get(id=opening_post_id)
74 opening_post = self.get(id=opening_post_id)
82
75
83 if opening_post.parent == NO_PARENT:
76 if opening_post.parent == NO_PARENT:
84 replies = self.filter(parent=opening_post_id)
77 replies = self.filter(parent=opening_post_id)
85
78
86 thread = [opening_post]
79 thread = [opening_post]
87 thread.extend(replies)
80 thread.extend(replies)
88
81
89 return thread
82 return thread
90
83
91 def exists(self, post_id):
84 def exists(self, post_id):
92 posts = self.filter(id=post_id)
85 posts = self.filter(id=post_id)
93
86
94 return len(posts) > 0
87 return len(posts) > 0
95
88
96 def get_thread_page_count(self, tag=None):
89 def get_thread_page_count(self, tag=None):
97 if tag:
90 if tag:
98 threads = self.filter(parent=NO_PARENT, tags=tag)
91 threads = self.filter(parent=NO_PARENT, tags=tag)
99 else:
92 else:
100 threads = self.filter(parent=NO_PARENT)
93 threads = self.filter(parent=NO_PARENT)
101
94
102 return int(math.ceil(len(threads) / float(settings.THREADS_PER_PAGE)))
95 return int(math.ceil(len(threads) / float(settings.THREADS_PER_PAGE)))
103
96
104
97
105 def _delete_old_threads(self):
98 def _delete_old_threads(self):
106 """
99 """
107 Preserves maximum thread count. If there are too many threads,
100 Preserves maximum thread count. If there are too many threads,
108 delete the old ones.
101 delete the old ones.
109 """
102 """
110
103
111 # TODO Try to find a better way to get the active thread count.
104 # TODO Try to find a better way to get the active thread count.
112
105
113 # TODO Move old threads to the archive instead of deleting them.
106 # TODO Move old threads to the archive instead of deleting them.
114 # Maybe make some 'old' field in the model to indicate the thread
107 # Maybe make some 'old' field in the model to indicate the thread
115 # must not be shown and be able for replying.
108 # must not be shown and be able for replying.
116
109
117 threads = self.get_threads()
110 threads = self.get_threads()
118 thread_count = len(threads)
111 thread_count = len(threads)
119
112
120 if thread_count > settings.MAX_THREAD_COUNT:
113 if thread_count > settings.MAX_THREAD_COUNT:
121 num_threads_to_delete = thread_count - settings.MAX_THREAD_COUNT
114 num_threads_to_delete = thread_count - settings.MAX_THREAD_COUNT
122 old_threads = threads[-num_threads_to_delete:]
115 old_threads = threads[-num_threads_to_delete:]
123
116
124 for thread in old_threads:
117 for thread in old_threads:
125 self.delete_post(thread)
118 self.delete_post(thread)
126
119
127 def _bump_thread(self, thread_id):
120 def _bump_thread(self, thread_id):
128 thread = self.get(id=thread_id)
121 thread = self.get(id=thread_id)
129
122
130 if thread.can_bump():
123 if thread.can_bump():
131 thread.last_edit_time = timezone.now()
124 thread.last_edit_time = timezone.now()
132 thread.save()
125 thread.save()
133
126
134
127
135 class TagManager(models.Manager):
128 class TagManager(models.Manager):
136 def get_not_empty_tags(self):
129 def get_not_empty_tags(self):
137 all_tags = self.all().order_by('name')
130 all_tags = self.all().order_by('name')
138 tags = []
131 tags = []
139 for tag in all_tags:
132 for tag in all_tags:
140 if not tag.is_empty():
133 if not tag.is_empty():
141 tags.append(tag)
134 tags.append(tag)
142
135
143 return tags
136 return tags
144
137
145
138
146 class Tag(models.Model):
139 class Tag(models.Model):
147 """
140 """
148 A tag is a text node assigned to the post. The tag serves as a board
141 A tag is a text node assigned to the post. The tag serves as a board
149 section. There can be multiple tags for each message
142 section. There can be multiple tags for each message
150 """
143 """
151
144
152 objects = TagManager()
145 objects = TagManager()
153
146
154 name = models.CharField(max_length=100)
147 name = models.CharField(max_length=100)
155 # TODO Connect the tag to its posts to check the number of threads for
148 # TODO Connect the tag to its posts to check the number of threads for
156 # the tag.
149 # the tag.
157
150
158 def __unicode__(self):
151 def __unicode__(self):
159 return self.name
152 return self.name
160
153
161 def is_empty(self):
154 def is_empty(self):
162 return self.get_post_count() == 0
155 return self.get_post_count() == 0
163
156
164 def get_post_count(self):
157 def get_post_count(self):
165 posts_with_tag = Post.objects.get_threads(tag=self)
158 posts_with_tag = Post.objects.get_threads(tag=self)
166 return len(posts_with_tag)
159 return len(posts_with_tag)
167
160
168
161
169 class Post(models.Model):
162 class Post(models.Model):
170 """A post is a message."""
163 """A post is a message."""
171
164
165 IMAGES_DIRECTORY = 'images/'
166 FILE_EXTENSION_DELIMITER = '.'
167
172 objects = PostManager()
168 objects = PostManager()
173
169
170 def _update_image_filename(self, filename):
171 """Get unique image filename"""
172
173 path = self.IMAGES_DIRECTORY
174 new_name = str(int(time.mktime(time.gmtime())))
175 new_name += str(int(random() * 1000))
176 new_name += self.FILE_EXTENSION_DELIMITER
177 new_name += filename.split(self.FILE_EXTENSION_DELIMITER)[-1:][0]
178
179 return os.path.join(path, new_name)
180
174 title = models.CharField(max_length=50)
181 title = models.CharField(max_length=50)
175 pub_time = models.DateTimeField()
182 pub_time = models.DateTimeField()
176 text = MarkupField(default_markup_type='markdown', escape_html=True)
183 text = MarkupField(default_markup_type='markdown', escape_html=True)
177 image = thumbs.ImageWithThumbsField(upload_to=update_image_filename,
184 image = thumbs.ImageWithThumbsField(upload_to=_update_image_filename,
178 blank=True, sizes=((200, 150),))
185 blank=True, sizes=((200, 150),))
179 poster_ip = models.IPAddressField()
186 poster_ip = models.IPAddressField()
180 poster_user_agent = models.TextField()
187 poster_user_agent = models.TextField()
181 parent = models.BigIntegerField()
188 parent = models.BigIntegerField()
182 tags = models.ManyToManyField(Tag)
189 tags = models.ManyToManyField(Tag)
183 last_edit_time = models.DateTimeField()
190 last_edit_time = models.DateTimeField()
184
191
185 regex_pretty = re.compile(r'^\d(0)+$')
192 regex_pretty = re.compile(r'^\d(0)+$')
186 regex_same = re.compile(r'^(.)\1+$')
193 regex_same = re.compile(r'^(.)\1+$')
187
194
188 def __unicode__(self):
195 def __unicode__(self):
189 return self.title + ' (' + self.text.raw + ')'
196 return self.title + ' (' + self.text.raw + ')'
190
197
191 def _get_replies(self):
198 def _get_replies(self):
192 return Post.objects.filter(parent=self.id)
199 return Post.objects.filter(parent=self.id)
193
200
194 def get_reply_count(self):
201 def get_reply_count(self):
195 return len(self._get_replies())
202 return len(self._get_replies())
196
203
197 def get_images_count(self):
204 def get_images_count(self):
198 images_count = 1 if self.image else 0
205 images_count = 1 if self.image else 0
199 for reply in self._get_replies():
206 for reply in self._get_replies():
200 if reply.image:
207 if reply.image:
201 images_count += 1
208 images_count += 1
202
209
203 return images_count
210 return images_count
204
211
205 def get_gets_count(self):
212 def get_gets_count(self):
206 gets_count = 1 if self.is_get() else 0
213 gets_count = 1 if self.is_get() else 0
207 for reply in self._get_replies():
214 for reply in self._get_replies():
208 if reply.is_get():
215 if reply.is_get():
209 gets_count += 1
216 gets_count += 1
210
217
211 return gets_count
218 return gets_count
212
219
213 def is_get(self):
220 def is_get(self):
214 """If the post has pretty id (1, 1000, 77777), than it is called GET"""
221 """If the post has pretty id (1, 1000, 77777), than it is called GET"""
215
222
216 first = self.id == 1
223 first = self.id == 1
217
224
218 id_str = str(self.id)
225 id_str = str(self.id)
219 pretty = self.regex_pretty.match(id_str)
226 pretty = self.regex_pretty.match(id_str)
220 same_digits = self.regex_same.match(id_str)
227 same_digits = self.regex_same.match(id_str)
221
228
222 return first or pretty or same_digits
229 return first or pretty or same_digits
223
230
224 def can_bump(self):
231 def can_bump(self):
225 """Check if the thread can be bumped by replying"""
232 """Check if the thread can be bumped by replying"""
226
233
227 replies_count = len(Post.objects.get_thread(self.id))
234 replies_count = len(Post.objects.get_thread(self.id))
228
235
229 return replies_count <= settings.MAX_POSTS_PER_THREAD
236 return replies_count <= settings.MAX_POSTS_PER_THREAD
230
237
231
238
232 class Admin(models.Model):
239 class Admin(models.Model):
233 """
240 """
234 Model for admin users
241 Model for admin users
235 """
242 """
236 name = models.CharField(max_length=100)
243 name = models.CharField(max_length=100)
237 password = models.CharField(max_length=100)
244 password = models.CharField(max_length=100)
238
245
239 def __unicode__(self):
246 def __unicode__(self):
240 return self.name + '/' + '*' * len(self.password)
247 return self.name + '/' + '*' * len(self.password)
241
248
General Comments 0
You need to be logged in to leave comments. Login now