##// END OF EJS Templates
Show raw post text in the log when created post
neko259 -
r2006:127660f1 default
parent child Browse files
Show More
@@ -1,291 +1,291
1 import logging
1 import logging
2 import re
2 import re
3 from datetime import datetime, timedelta, date
3 from datetime import datetime, timedelta, date
4 from datetime import time as dtime
4 from datetime import time as dtime
5
5
6 from django.core.exceptions import PermissionDenied
6 from django.core.exceptions import PermissionDenied
7 from django.db import models, transaction
7 from django.db import models, transaction
8 from django.dispatch import Signal
8 from django.dispatch import Signal
9 from django.shortcuts import redirect
9 from django.shortcuts import redirect
10 from django.utils import timezone
10 from django.utils import timezone
11
11
12 import boards
12 import boards
13 from boards import utils
13 from boards import utils
14 from boards.abstracts.exceptions import ArchiveException
14 from boards.abstracts.exceptions import ArchiveException
15 from boards.abstracts.constants import REGEX_TAGS, REGEX_REPLY
15 from boards.abstracts.constants import REGEX_TAGS, REGEX_REPLY
16 from boards.mdx_neboard import Parser
16 from boards.mdx_neboard import Parser
17 from boards.models import Attachment
17 from boards.models import Attachment
18 from boards.models.attachment import StickerPack, AttachmentSticker
18 from boards.models.attachment import StickerPack, AttachmentSticker
19 from boards.models.user import Ban
19 from boards.models.user import Ban
20
20
21 __author__ = 'neko259'
21 __author__ = 'neko259'
22
22
23 POSTS_PER_DAY_RANGE = 7
23 POSTS_PER_DAY_RANGE = 7
24 NO_IP = '0.0.0.0'
24 NO_IP = '0.0.0.0'
25
25
26
26
27 post_import_deps = Signal()
27 post_import_deps = Signal()
28
28
29 FORM_TEXT = 'text'
29 FORM_TEXT = 'text'
30 FORM_TAGS = 'tags'
30 FORM_TAGS = 'tags'
31
31
32 REFLINK_PREFIX = '>>'
32 REFLINK_PREFIX = '>>'
33
33
34
34
35 class PostManager(models.Manager):
35 class PostManager(models.Manager):
36 @transaction.atomic
36 @transaction.atomic
37 def create_post(self, title: str, text: str, files=[], thread=None,
37 def create_post(self, title: str, text: str, files=[], thread=None,
38 ip=NO_IP, tags: list=None,
38 ip=NO_IP, tags: list=None,
39 tripcode='', monochrome=False, images=[],
39 tripcode='', monochrome=False, images=[],
40 file_urls=[], stickerpack=False):
40 file_urls=[], stickerpack=False):
41 """
41 """
42 Creates new post
42 Creates new post
43 """
43 """
44
44
45 if thread is not None and thread.is_archived():
45 if thread is not None and thread.is_archived():
46 raise ArchiveException('Cannot post into an archived thread')
46 raise ArchiveException('Cannot post into an archived thread')
47
47
48 if not utils.is_anonymous_mode():
48 if not utils.is_anonymous_mode():
49 is_banned = Ban.objects.filter(ip=ip).exists()
49 is_banned = Ban.objects.filter(ip=ip).exists()
50 else:
50 else:
51 is_banned = False
51 is_banned = False
52
52
53 if is_banned:
53 if is_banned:
54 raise PermissionDenied()
54 raise PermissionDenied()
55
55
56 if not tags:
56 if not tags:
57 tags = []
57 tags = []
58
58
59 posting_time = timezone.now()
59 posting_time = timezone.now()
60 new_thread = False
60 new_thread = False
61 if not thread:
61 if not thread:
62 thread = boards.models.thread.Thread.objects.create(
62 thread = boards.models.thread.Thread.objects.create(
63 bump_time=posting_time, last_edit_time=posting_time,
63 bump_time=posting_time, last_edit_time=posting_time,
64 monochrome=monochrome, stickerpack=stickerpack)
64 monochrome=monochrome, stickerpack=stickerpack)
65 list(map(thread.tags.add, tags))
65 list(map(thread.tags.add, tags))
66 new_thread = True
66 new_thread = True
67
67
68 pre_text = Parser().preparse(text)
68 pre_text = Parser().preparse(text)
69
69
70 post = self.create(title=title,
70 post = self.create(title=title,
71 text=pre_text,
71 text=pre_text,
72 pub_time=posting_time,
72 pub_time=posting_time,
73 poster_ip=ip,
73 poster_ip=ip,
74 thread=thread,
74 thread=thread,
75 last_edit_time=posting_time,
75 last_edit_time=posting_time,
76 tripcode=tripcode,
76 tripcode=tripcode,
77 opening=new_thread)
77 opening=new_thread)
78
78
79 logger = logging.getLogger('boards.post.create')
79 logger = logging.getLogger('boards.post.create')
80
80
81 logger.info('Created post [{}] with text [{}] by {}'.format(post,
81 logger.info('Created post [{}] with text [{}] by {}'.format(post,
82 post.get_text(),post.poster_ip))
82 post.get_raw_text(), post.poster_ip))
83
83
84 for file in files:
84 for file in files:
85 self._add_file_to_post(file, post)
85 self._add_file_to_post(file, post)
86 for image in images:
86 for image in images:
87 post.attachments.add(image)
87 post.attachments.add(image)
88 for file_url in file_urls:
88 for file_url in file_urls:
89 post.attachments.add(Attachment.objects.create_from_url(file_url))
89 post.attachments.add(Attachment.objects.create_from_url(file_url))
90
90
91 post.set_global_id()
91 post.set_global_id()
92
92
93 # Thread needs to be bumped only when the post is already created
93 # Thread needs to be bumped only when the post is already created
94 if not new_thread:
94 if not new_thread:
95 thread.last_edit_time = posting_time
95 thread.last_edit_time = posting_time
96 thread.bump()
96 thread.bump()
97 thread.save()
97 thread.save()
98
98
99 self._create_stickers(post)
99 self._create_stickers(post)
100
100
101 return post
101 return post
102
102
103 def delete_posts_by_ip(self, ip):
103 def delete_posts_by_ip(self, ip):
104 """
104 """
105 Deletes all posts of the author with same IP
105 Deletes all posts of the author with same IP
106 """
106 """
107
107
108 posts = self.filter(poster_ip=ip)
108 posts = self.filter(poster_ip=ip)
109 for post in posts:
109 for post in posts:
110 post.delete()
110 post.delete()
111
111
112 @utils.cached_result()
112 @utils.cached_result()
113 def get_posts_per_day(self) -> float:
113 def get_posts_per_day(self) -> float:
114 """
114 """
115 Gets average count of posts per day for the last 7 days
115 Gets average count of posts per day for the last 7 days
116 """
116 """
117
117
118 day_end = date.today()
118 day_end = date.today()
119 day_start = day_end - timedelta(POSTS_PER_DAY_RANGE)
119 day_start = day_end - timedelta(POSTS_PER_DAY_RANGE)
120
120
121 day_time_start = timezone.make_aware(datetime.combine(
121 day_time_start = timezone.make_aware(datetime.combine(
122 day_start, dtime()), timezone.get_current_timezone())
122 day_start, dtime()), timezone.get_current_timezone())
123 day_time_end = timezone.make_aware(datetime.combine(
123 day_time_end = timezone.make_aware(datetime.combine(
124 day_end, dtime()), timezone.get_current_timezone())
124 day_end, dtime()), timezone.get_current_timezone())
125
125
126 posts_per_period = float(self.filter(
126 posts_per_period = float(self.filter(
127 pub_time__lte=day_time_end,
127 pub_time__lte=day_time_end,
128 pub_time__gte=day_time_start).count())
128 pub_time__gte=day_time_start).count())
129
129
130 ppd = posts_per_period / POSTS_PER_DAY_RANGE
130 ppd = posts_per_period / POSTS_PER_DAY_RANGE
131
131
132 return ppd
132 return ppd
133
133
134 def get_post_per_days(self, days) -> int:
134 def get_post_per_days(self, days) -> int:
135 day_end = date.today() + timedelta(1)
135 day_end = date.today() + timedelta(1)
136 day_start = day_end - timedelta(days)
136 day_start = day_end - timedelta(days)
137
137
138 day_time_start = timezone.make_aware(datetime.combine(
138 day_time_start = timezone.make_aware(datetime.combine(
139 day_start, dtime()), timezone.get_current_timezone())
139 day_start, dtime()), timezone.get_current_timezone())
140 day_time_end = timezone.make_aware(datetime.combine(
140 day_time_end = timezone.make_aware(datetime.combine(
141 day_end, dtime()), timezone.get_current_timezone())
141 day_end, dtime()), timezone.get_current_timezone())
142
142
143 return self.filter(
143 return self.filter(
144 pub_time__lte=day_time_end,
144 pub_time__lte=day_time_end,
145 pub_time__gte=day_time_start).count()
145 pub_time__gte=day_time_start).count()
146
146
147 @transaction.atomic
147 @transaction.atomic
148 def import_post(self, title: str, text: str, pub_time: str, global_id,
148 def import_post(self, title: str, text: str, pub_time: str, global_id,
149 opening_post=None, tags=list(), files=list(),
149 opening_post=None, tags=list(), files=list(),
150 file_urls=list(), tripcode=None, last_edit_time=None):
150 file_urls=list(), tripcode=None, last_edit_time=None):
151 is_opening = opening_post is None
151 is_opening = opening_post is None
152 if is_opening:
152 if is_opening:
153 thread = boards.models.thread.Thread.objects.create(
153 thread = boards.models.thread.Thread.objects.create(
154 bump_time=pub_time, last_edit_time=pub_time)
154 bump_time=pub_time, last_edit_time=pub_time)
155 list(map(thread.tags.add, tags))
155 list(map(thread.tags.add, tags))
156 else:
156 else:
157 thread = opening_post.get_thread()
157 thread = opening_post.get_thread()
158
158
159 post = self.create(title=title,
159 post = self.create(title=title,
160 text=text,
160 text=text,
161 pub_time=pub_time,
161 pub_time=pub_time,
162 poster_ip=NO_IP,
162 poster_ip=NO_IP,
163 last_edit_time=last_edit_time or pub_time,
163 last_edit_time=last_edit_time or pub_time,
164 global_id=global_id,
164 global_id=global_id,
165 opening=is_opening,
165 opening=is_opening,
166 thread=thread,
166 thread=thread,
167 tripcode=tripcode)
167 tripcode=tripcode)
168
168
169 for file in files:
169 for file in files:
170 self._add_file_to_post(file, post)
170 self._add_file_to_post(file, post)
171 for file_url in file_urls:
171 for file_url in file_urls:
172 post.attachments.add(Attachment.objects.create_from_url(file_url))
172 post.attachments.add(Attachment.objects.create_from_url(file_url))
173
173
174 url_to_post = '[post]{}[/post]'.format(str(global_id))
174 url_to_post = '[post]{}[/post]'.format(str(global_id))
175 replies = self.filter(text__contains=url_to_post)
175 replies = self.filter(text__contains=url_to_post)
176 for reply in replies:
176 for reply in replies:
177 post_import_deps.send(reply)
177 post_import_deps.send(reply)
178
178
179 @transaction.atomic
179 @transaction.atomic
180 def update_post(self, post, title: str, text: str, pub_time: str,
180 def update_post(self, post, title: str, text: str, pub_time: str,
181 tags=list(), files=list(), file_urls=list(), tripcode=None):
181 tags=list(), files=list(), file_urls=list(), tripcode=None):
182 post.title = title
182 post.title = title
183 post.text = text
183 post.text = text
184 post.pub_time = pub_time
184 post.pub_time = pub_time
185 post.tripcode = tripcode
185 post.tripcode = tripcode
186 post.save()
186 post.save()
187
187
188 post.clear_cache()
188 post.clear_cache()
189
189
190 post.attachments.clear()
190 post.attachments.clear()
191 for file in files:
191 for file in files:
192 self._add_file_to_post(file, post)
192 self._add_file_to_post(file, post)
193 for file_url in file_urls:
193 for file_url in file_urls:
194 post.attachments.add(Attachment.objects.create_from_url(file_url))
194 post.attachments.add(Attachment.objects.create_from_url(file_url))
195
195
196 thread = post.get_thread()
196 thread = post.get_thread()
197 thread.tags.clear()
197 thread.tags.clear()
198 list(map(thread.tags.add, tags))
198 list(map(thread.tags.add, tags))
199
199
200 def create_from_form(self, request, form, opening_post, html_response=True):
200 def create_from_form(self, request, form, opening_post, html_response=True):
201 ip = utils.get_client_ip(request)
201 ip = utils.get_client_ip(request)
202
202
203 data = form.cleaned_data
203 data = form.cleaned_data
204
204
205 title = form.get_title()
205 title = form.get_title()
206 text = data[FORM_TEXT]
206 text = data[FORM_TEXT]
207 files = form.get_files()
207 files = form.get_files()
208 file_urls = form.get_file_urls()
208 file_urls = form.get_file_urls()
209 images = form.get_images()
209 images = form.get_images()
210
210
211 text = self._remove_invalid_links(text)
211 text = self._remove_invalid_links(text)
212
212
213 if opening_post:
213 if opening_post:
214 post_thread = opening_post.get_thread()
214 post_thread = opening_post.get_thread()
215 monochrome = False
215 monochrome = False
216 stickerpack = False
216 stickerpack = False
217 tags = []
217 tags = []
218 else:
218 else:
219 tags = data[FORM_TAGS]
219 tags = data[FORM_TAGS]
220 monochrome = form.is_monochrome()
220 monochrome = form.is_monochrome()
221 stickerpack = form.is_stickerpack()
221 stickerpack = form.is_stickerpack()
222 post_thread = None
222 post_thread = None
223
223
224 post = self.create_post(title=title, text=text, files=files,
224 post = self.create_post(title=title, text=text, files=files,
225 thread=post_thread, ip=ip,
225 thread=post_thread, ip=ip,
226 tripcode=form.get_tripcode(),
226 tripcode=form.get_tripcode(),
227 images=images, file_urls=file_urls,
227 images=images, file_urls=file_urls,
228 monochrome=monochrome,
228 monochrome=monochrome,
229 stickerpack=stickerpack, tags=tags)
229 stickerpack=stickerpack, tags=tags)
230
230
231 if form.is_subscribe():
231 if form.is_subscribe():
232 from boards.abstracts.settingsmanager import get_settings_manager
232 from boards.abstracts.settingsmanager import get_settings_manager
233 settings_manager = get_settings_manager(request)
233 settings_manager = get_settings_manager(request)
234 settings_manager.add_or_read_fav_thread(
234 settings_manager.add_or_read_fav_thread(
235 post_thread.get_opening_post())
235 post_thread.get_opening_post())
236
236
237 if html_response:
237 if html_response:
238 return redirect(post.get_absolute_url())
238 return redirect(post.get_absolute_url())
239 else:
239 else:
240 return post
240 return post
241
241
242 def _add_file_to_post(self, file, post):
242 def _add_file_to_post(self, file, post):
243 post.attachments.add(Attachment.objects.create_with_hash(file))
243 post.attachments.add(Attachment.objects.create_with_hash(file))
244
244
245 def _create_stickers(self, post):
245 def _create_stickers(self, post):
246 thread = post.get_thread()
246 thread = post.get_thread()
247 stickerpack_thread = thread.is_stickerpack()
247 stickerpack_thread = thread.is_stickerpack()
248 if stickerpack_thread:
248 if stickerpack_thread:
249 logger = logging.getLogger('boards.stickers')
249 logger = logging.getLogger('boards.stickers')
250 if not post.is_opening():
250 if not post.is_opening():
251 has_title = len(post.title) > 0
251 has_title = len(post.title) > 0
252 has_one_attachment = post.attachments.count() == 1
252 has_one_attachment = post.attachments.count() == 1
253 opening_post = thread.get_opening_post()
253 opening_post = thread.get_opening_post()
254 valid_name = REGEX_TAGS.match(post.title)
254 valid_name = REGEX_TAGS.match(post.title)
255 if has_title and has_one_attachment and valid_name:
255 if has_title and has_one_attachment and valid_name:
256 existing_sticker = AttachmentSticker.objects.filter(
256 existing_sticker = AttachmentSticker.objects.filter(
257 name=post.get_title()).first()
257 name=post.get_title()).first()
258 attachment = post.attachments.first()
258 attachment = post.attachments.first()
259 if existing_sticker:
259 if existing_sticker:
260 existing_sticker.attachment = attachment
260 existing_sticker.attachment = attachment
261 existing_sticker.save()
261 existing_sticker.save()
262 logger.info('Updated sticker {} with new attachment'.format(existing_sticker))
262 logger.info('Updated sticker {} with new attachment'.format(existing_sticker))
263 else:
263 else:
264 try:
264 try:
265 stickerpack = StickerPack.objects.get(
265 stickerpack = StickerPack.objects.get(
266 name=opening_post.get_title(), tripcode=post.tripcode)
266 name=opening_post.get_title(), tripcode=post.tripcode)
267 sticker = AttachmentSticker.objects.create(
267 sticker = AttachmentSticker.objects.create(
268 stickerpack=stickerpack, name=post.get_title(),
268 stickerpack=stickerpack, name=post.get_title(),
269 attachment=attachment)
269 attachment=attachment)
270 logger.info('Created sticker {}'.format(sticker))
270 logger.info('Created sticker {}'.format(sticker))
271 except StickerPack.DoesNotExist:
271 except StickerPack.DoesNotExist:
272 pass
272 pass
273 else:
273 else:
274 stickerpack, created = StickerPack.objects.get_or_create(
274 stickerpack, created = StickerPack.objects.get_or_create(
275 name=post.get_title(), tripcode=post.tripcode)
275 name=post.get_title(), tripcode=post.tripcode)
276 if created:
276 if created:
277 logger.info('Created stickerpack {}'.format(stickerpack))
277 logger.info('Created stickerpack {}'.format(stickerpack))
278
278
279 def _remove_invalid_links(self, text):
279 def _remove_invalid_links(self, text):
280 """
280 """
281 Replace invalid links in posts so that they won't be parsed.
281 Replace invalid links in posts so that they won't be parsed.
282 Invalid links are links to non-existent posts
282 Invalid links are links to non-existent posts
283 """
283 """
284
284
285 for reply_number in re.finditer(REGEX_REPLY, text):
285 for reply_number in re.finditer(REGEX_REPLY, text):
286 post_id = reply_number.group(1)
286 post_id = reply_number.group(1)
287 post = self.filter(id=post_id)
287 post = self.filter(id=post_id)
288 if not post.exists():
288 if not post.exists():
289 text = text.replace(REFLINK_PREFIX + post_id, post_id)
289 text = text.replace(REFLINK_PREFIX + post_id, post_id)
290
290
291 return text
291 return text
General Comments 0
You need to be logged in to leave comments. Login now