##// END OF EJS Templates
Parse tripcode for post sync
neko259 -
r1557:68d42ef1 default
parent child Browse files
Show More
@@ -1,160 +1,161 b''
1 import logging
1 import logging
2
2
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.db import models, transaction
6 from django.db import models, transaction
7 from django.utils import timezone
7 from django.utils import timezone
8
8
9 import boards
9 import boards
10
10
11 from boards.models.user import Ban
11 from boards.models.user import Ban
12 from boards.mdx_neboard import Parser
12 from boards.mdx_neboard import Parser
13 from boards.models import PostImage, Attachment
13 from boards.models import PostImage, Attachment
14 from boards import utils
14 from boards import utils
15
15
16 __author__ = 'neko259'
16 __author__ = 'neko259'
17
17
18 IMAGE_TYPES = (
18 IMAGE_TYPES = (
19 'jpeg',
19 'jpeg',
20 'jpg',
20 'jpg',
21 'png',
21 'png',
22 'bmp',
22 'bmp',
23 'gif',
23 'gif',
24 )
24 )
25
25
26 POSTS_PER_DAY_RANGE = 7
26 POSTS_PER_DAY_RANGE = 7
27 NO_IP = '0.0.0.0'
27 NO_IP = '0.0.0.0'
28
28
29
29
30 class PostManager(models.Manager):
30 class PostManager(models.Manager):
31 @transaction.atomic
31 @transaction.atomic
32 def create_post(self, title: str, text: str, file=None, thread=None,
32 def create_post(self, title: str, text: str, file=None, thread=None,
33 ip=NO_IP, tags: list=None, opening_posts: list=None,
33 ip=NO_IP, tags: list=None, opening_posts: list=None,
34 tripcode='', monochrome=False, images=[]):
34 tripcode='', monochrome=False, images=[]):
35 """
35 """
36 Creates new post
36 Creates new post
37 """
37 """
38
38
39 if thread is not None and thread.is_archived():
39 if thread is not None and thread.is_archived():
40 raise Exception('Cannot post into an archived thread')
40 raise Exception('Cannot post into an archived thread')
41
41
42 if not utils.is_anonymous_mode():
42 if not utils.is_anonymous_mode():
43 is_banned = Ban.objects.filter(ip=ip).exists()
43 is_banned = Ban.objects.filter(ip=ip).exists()
44 else:
44 else:
45 is_banned = False
45 is_banned = False
46
46
47 # TODO Raise specific exception and catch it in the views
47 # TODO Raise specific exception and catch it in the views
48 if is_banned:
48 if is_banned:
49 raise Exception("This user is banned")
49 raise Exception("This user is banned")
50
50
51 if not tags:
51 if not tags:
52 tags = []
52 tags = []
53 if not opening_posts:
53 if not opening_posts:
54 opening_posts = []
54 opening_posts = []
55
55
56 posting_time = timezone.now()
56 posting_time = timezone.now()
57 new_thread = False
57 new_thread = False
58 if not thread:
58 if not thread:
59 thread = boards.models.thread.Thread.objects.create(
59 thread = boards.models.thread.Thread.objects.create(
60 bump_time=posting_time, last_edit_time=posting_time,
60 bump_time=posting_time, last_edit_time=posting_time,
61 monochrome=monochrome)
61 monochrome=monochrome)
62 list(map(thread.tags.add, tags))
62 list(map(thread.tags.add, tags))
63 boards.models.thread.Thread.objects.process_oldest_threads()
63 boards.models.thread.Thread.objects.process_oldest_threads()
64 new_thread = True
64 new_thread = True
65
65
66 pre_text = Parser().preparse(text)
66 pre_text = Parser().preparse(text)
67
67
68 post = self.create(title=title,
68 post = self.create(title=title,
69 text=pre_text,
69 text=pre_text,
70 pub_time=posting_time,
70 pub_time=posting_time,
71 poster_ip=ip,
71 poster_ip=ip,
72 thread=thread,
72 thread=thread,
73 last_edit_time=posting_time,
73 last_edit_time=posting_time,
74 tripcode=tripcode,
74 tripcode=tripcode,
75 opening=new_thread)
75 opening=new_thread)
76 post.threads.add(thread)
76 post.threads.add(thread)
77
77
78 logger = logging.getLogger('boards.post.create')
78 logger = logging.getLogger('boards.post.create')
79
79
80 logger.info('Created post [{}] with text [{}] by {}'.format(post,
80 logger.info('Created post [{}] with text [{}] by {}'.format(post,
81 post.get_text(),post.poster_ip))
81 post.get_text(),post.poster_ip))
82
82
83 if file:
83 if file:
84 self._add_file_to_post(file, post)
84 self._add_file_to_post(file, post)
85 for image in images:
85 for image in images:
86 post.images.add(image)
86 post.images.add(image)
87
87
88 post.connect_threads(opening_posts)
88 post.connect_threads(opening_posts)
89 post.set_global_id()
89 post.set_global_id()
90
90
91 # Thread needs to be bumped only when the post is already created
91 # Thread needs to be bumped only when the post is already created
92 if not new_thread:
92 if not new_thread:
93 thread.last_edit_time = posting_time
93 thread.last_edit_time = posting_time
94 thread.bump()
94 thread.bump()
95 thread.save()
95 thread.save()
96
96
97 return post
97 return post
98
98
99 def delete_posts_by_ip(self, ip):
99 def delete_posts_by_ip(self, ip):
100 """
100 """
101 Deletes all posts of the author with same IP
101 Deletes all posts of the author with same IP
102 """
102 """
103
103
104 posts = self.filter(poster_ip=ip)
104 posts = self.filter(poster_ip=ip)
105 for post in posts:
105 for post in posts:
106 post.delete()
106 post.delete()
107
107
108 @utils.cached_result()
108 @utils.cached_result()
109 def get_posts_per_day(self) -> float:
109 def get_posts_per_day(self) -> float:
110 """
110 """
111 Gets average count of posts per day for the last 7 days
111 Gets average count of posts per day for the last 7 days
112 """
112 """
113
113
114 day_end = date.today()
114 day_end = date.today()
115 day_start = day_end - timedelta(POSTS_PER_DAY_RANGE)
115 day_start = day_end - timedelta(POSTS_PER_DAY_RANGE)
116
116
117 day_time_start = timezone.make_aware(datetime.combine(
117 day_time_start = timezone.make_aware(datetime.combine(
118 day_start, dtime()), timezone.get_current_timezone())
118 day_start, dtime()), timezone.get_current_timezone())
119 day_time_end = timezone.make_aware(datetime.combine(
119 day_time_end = timezone.make_aware(datetime.combine(
120 day_end, dtime()), timezone.get_current_timezone())
120 day_end, dtime()), timezone.get_current_timezone())
121
121
122 posts_per_period = float(self.filter(
122 posts_per_period = float(self.filter(
123 pub_time__lte=day_time_end,
123 pub_time__lte=day_time_end,
124 pub_time__gte=day_time_start).count())
124 pub_time__gte=day_time_start).count())
125
125
126 ppd = posts_per_period / POSTS_PER_DAY_RANGE
126 ppd = posts_per_period / POSTS_PER_DAY_RANGE
127
127
128 return ppd
128 return ppd
129
129
130 @transaction.atomic
130 @transaction.atomic
131 def import_post(self, title: str, text: str, pub_time: str, global_id,
131 def import_post(self, title: str, text: str, pub_time: str, global_id,
132 opening_post=None, tags=list(), files=list()):
132 opening_post=None, tags=list(), files=list(),
133 tripcode=None):
133 is_opening = opening_post is None
134 is_opening = opening_post is None
134 if is_opening:
135 if is_opening:
135 thread = boards.models.thread.Thread.objects.create(
136 thread = boards.models.thread.Thread.objects.create(
136 bump_time=pub_time, last_edit_time=pub_time)
137 bump_time=pub_time, last_edit_time=pub_time)
137 list(map(thread.tags.add, tags))
138 list(map(thread.tags.add, tags))
138 else:
139 else:
139 thread = opening_post.get_thread()
140 thread = opening_post.get_thread()
140
141
141 post = self.create(title=title, text=text,
142 post = self.create(title=title, text=text,
142 pub_time=pub_time,
143 pub_time=pub_time,
143 poster_ip=NO_IP,
144 poster_ip=NO_IP,
144 last_edit_time=pub_time,
145 last_edit_time=pub_time,
145 global_id=global_id,
146 global_id=global_id,
146 opening=is_opening,
147 opening=is_opening,
147 thread=thread)
148 thread=thread, tripcode=tripcode)
148
149
149 # TODO Add files
150 # TODO Add files
150 for file in files:
151 for file in files:
151 self._add_file_to_post(file, post)
152 self._add_file_to_post(file, post)
152
153
153 post.threads.add(thread)
154 post.threads.add(thread)
154
155
155 def _add_file_to_post(self, file, post):
156 def _add_file_to_post(self, file, post):
156 file_type = file.name.split('.')[-1].lower()
157 file_type = file.name.split('.')[-1].lower()
157 if file_type in IMAGE_TYPES:
158 if file_type in IMAGE_TYPES:
158 post.images.add(PostImage.objects.create_with_hash(file))
159 post.images.add(PostImage.objects.create_with_hash(file))
159 else:
160 else:
160 post.attachments.add(Attachment.objects.create_with_hash(file))
161 post.attachments.add(Attachment.objects.create_with_hash(file))
@@ -1,275 +1,276 b''
1 import xml.etree.ElementTree as et
1 import xml.etree.ElementTree as et
2
2
3 from boards.models.attachment.downloaders import download
3 from boards.models.attachment.downloaders import download
4 from boards.utils import get_file_mimetype, get_file_hash
4 from boards.utils import get_file_mimetype, get_file_hash
5 from django.db import transaction
5 from django.db import transaction
6 from boards.models import KeyPair, GlobalId, Signature, Post, Tag
6 from boards.models import KeyPair, GlobalId, Signature, Post, Tag
7
7
8 EXCEPTION_NODE = 'Sync node returned an error: {}'
8 EXCEPTION_NODE = 'Sync node returned an error: {}'
9 EXCEPTION_OP = 'Load the OP first'
9 EXCEPTION_OP = 'Load the OP first'
10 EXCEPTION_DOWNLOAD = 'File was not downloaded'
10 EXCEPTION_DOWNLOAD = 'File was not downloaded'
11 EXCEPTION_HASH = 'File hash does not match attachment hash'
11 EXCEPTION_HASH = 'File hash does not match attachment hash'
12 EXCEPTION_SIGNATURE = 'Invalid model signature for {}'
12 EXCEPTION_SIGNATURE = 'Invalid model signature for {}'
13 ENCODING_UNICODE = 'unicode'
13 ENCODING_UNICODE = 'unicode'
14
14
15 TAG_MODEL = 'model'
15 TAG_MODEL = 'model'
16 TAG_REQUEST = 'request'
16 TAG_REQUEST = 'request'
17 TAG_RESPONSE = 'response'
17 TAG_RESPONSE = 'response'
18 TAG_ID = 'id'
18 TAG_ID = 'id'
19 TAG_STATUS = 'status'
19 TAG_STATUS = 'status'
20 TAG_MODELS = 'models'
20 TAG_MODELS = 'models'
21 TAG_TITLE = 'title'
21 TAG_TITLE = 'title'
22 TAG_TEXT = 'text'
22 TAG_TEXT = 'text'
23 TAG_THREAD = 'thread'
23 TAG_THREAD = 'thread'
24 TAG_PUB_TIME = 'pub-time'
24 TAG_PUB_TIME = 'pub-time'
25 TAG_SIGNATURES = 'signatures'
25 TAG_SIGNATURES = 'signatures'
26 TAG_SIGNATURE = 'signature'
26 TAG_SIGNATURE = 'signature'
27 TAG_CONTENT = 'content'
27 TAG_CONTENT = 'content'
28 TAG_ATTACHMENTS = 'attachments'
28 TAG_ATTACHMENTS = 'attachments'
29 TAG_ATTACHMENT = 'attachment'
29 TAG_ATTACHMENT = 'attachment'
30 TAG_TAGS = 'tags'
30 TAG_TAGS = 'tags'
31 TAG_TAG = 'tag'
31 TAG_TAG = 'tag'
32 TAG_ATTACHMENT_REFS = 'attachment-refs'
32 TAG_ATTACHMENT_REFS = 'attachment-refs'
33 TAG_ATTACHMENT_REF = 'attachment-ref'
33 TAG_ATTACHMENT_REF = 'attachment-ref'
34 TAG_TRIPCODE = 'tripcode'
34 TAG_TRIPCODE = 'tripcode'
35
35
36 TYPE_GET = 'get'
36 TYPE_GET = 'get'
37
37
38 ATTR_VERSION = 'version'
38 ATTR_VERSION = 'version'
39 ATTR_TYPE = 'type'
39 ATTR_TYPE = 'type'
40 ATTR_NAME = 'name'
40 ATTR_NAME = 'name'
41 ATTR_VALUE = 'value'
41 ATTR_VALUE = 'value'
42 ATTR_MIMETYPE = 'mimetype'
42 ATTR_MIMETYPE = 'mimetype'
43 ATTR_KEY = 'key'
43 ATTR_KEY = 'key'
44 ATTR_REF = 'ref'
44 ATTR_REF = 'ref'
45 ATTR_URL = 'url'
45 ATTR_URL = 'url'
46
46
47 STATUS_SUCCESS = 'success'
47 STATUS_SUCCESS = 'success'
48
48
49
49
50 class SyncException(Exception):
50 class SyncException(Exception):
51 pass
51 pass
52
52
53
53
54 class SyncManager:
54 class SyncManager:
55 @staticmethod
55 @staticmethod
56 def generate_response_get(model_list: list):
56 def generate_response_get(model_list: list):
57 response = et.Element(TAG_RESPONSE)
57 response = et.Element(TAG_RESPONSE)
58
58
59 status = et.SubElement(response, TAG_STATUS)
59 status = et.SubElement(response, TAG_STATUS)
60 status.text = STATUS_SUCCESS
60 status.text = STATUS_SUCCESS
61
61
62 models = et.SubElement(response, TAG_MODELS)
62 models = et.SubElement(response, TAG_MODELS)
63
63
64 for post in model_list:
64 for post in model_list:
65 model = et.SubElement(models, TAG_MODEL)
65 model = et.SubElement(models, TAG_MODEL)
66 model.set(ATTR_NAME, 'post')
66 model.set(ATTR_NAME, 'post')
67
67
68 global_id = post.global_id
68 global_id = post.global_id
69
69
70 images = post.images.all()
70 images = post.images.all()
71 attachments = post.attachments.all()
71 attachments = post.attachments.all()
72 if global_id.content:
72 if global_id.content:
73 model.append(et.fromstring(global_id.content))
73 model.append(et.fromstring(global_id.content))
74 if len(images) > 0 or len(attachments) > 0:
74 if len(images) > 0 or len(attachments) > 0:
75 attachment_refs = et.SubElement(model, TAG_ATTACHMENT_REFS)
75 attachment_refs = et.SubElement(model, TAG_ATTACHMENT_REFS)
76 for image in images:
76 for image in images:
77 SyncManager._attachment_to_xml(
77 SyncManager._attachment_to_xml(
78 None, attachment_refs, image.image.file,
78 None, attachment_refs, image.image.file,
79 image.hash, image.image.url)
79 image.hash, image.image.url)
80 for file in attachments:
80 for file in attachments:
81 SyncManager._attachment_to_xml(
81 SyncManager._attachment_to_xml(
82 None, attachment_refs, file.file.file,
82 None, attachment_refs, file.file.file,
83 file.hash, file.file.url)
83 file.hash, file.file.url)
84 else:
84 else:
85 content_tag = et.SubElement(model, TAG_CONTENT)
85 content_tag = et.SubElement(model, TAG_CONTENT)
86
86
87 tag_id = et.SubElement(content_tag, TAG_ID)
87 tag_id = et.SubElement(content_tag, TAG_ID)
88 global_id.to_xml_element(tag_id)
88 global_id.to_xml_element(tag_id)
89
89
90 title = et.SubElement(content_tag, TAG_TITLE)
90 title = et.SubElement(content_tag, TAG_TITLE)
91 title.text = post.title
91 title.text = post.title
92
92
93 text = et.SubElement(content_tag, TAG_TEXT)
93 text = et.SubElement(content_tag, TAG_TEXT)
94 text.text = post.get_sync_text()
94 text.text = post.get_sync_text()
95
95
96 thread = post.get_thread()
96 thread = post.get_thread()
97 if post.is_opening():
97 if post.is_opening():
98 tag_tags = et.SubElement(content_tag, TAG_TAGS)
98 tag_tags = et.SubElement(content_tag, TAG_TAGS)
99 for tag in thread.get_tags():
99 for tag in thread.get_tags():
100 tag_tag = et.SubElement(tag_tags, TAG_TAG)
100 tag_tag = et.SubElement(tag_tags, TAG_TAG)
101 tag_tag.text = tag.name
101 tag_tag.text = tag.name
102 else:
102 else:
103 tag_thread = et.SubElement(content_tag, TAG_THREAD)
103 tag_thread = et.SubElement(content_tag, TAG_THREAD)
104 thread_id = et.SubElement(tag_thread, TAG_ID)
104 thread_id = et.SubElement(tag_thread, TAG_ID)
105 thread.get_opening_post().global_id.to_xml_element(thread_id)
105 thread.get_opening_post().global_id.to_xml_element(thread_id)
106
106
107 pub_time = et.SubElement(content_tag, TAG_PUB_TIME)
107 pub_time = et.SubElement(content_tag, TAG_PUB_TIME)
108 pub_time.text = str(post.get_pub_time_str())
108 pub_time.text = str(post.get_pub_time_str())
109
109
110 if post.tripcode:
110 if post.tripcode:
111 tripcode = et.SubElement(content_tag, TAG_TRIPCODE)
111 tripcode = et.SubElement(content_tag, TAG_TRIPCODE)
112 tripcode.text = post.tripcode
112 tripcode.text = post.tripcode
113
113
114 if len(images) > 0 or len(attachments) > 0:
114 if len(images) > 0 or len(attachments) > 0:
115 attachments_tag = et.SubElement(content_tag, TAG_ATTACHMENTS)
115 attachments_tag = et.SubElement(content_tag, TAG_ATTACHMENTS)
116 attachment_refs = et.SubElement(model, TAG_ATTACHMENT_REFS)
116 attachment_refs = et.SubElement(model, TAG_ATTACHMENT_REFS)
117
117
118 for image in images:
118 for image in images:
119 SyncManager._attachment_to_xml(
119 SyncManager._attachment_to_xml(
120 attachments_tag, attachment_refs, image.image.file,
120 attachments_tag, attachment_refs, image.image.file,
121 image.hash, image.image.url)
121 image.hash, image.image.url)
122 for file in attachments:
122 for file in attachments:
123 SyncManager._attachment_to_xml(
123 SyncManager._attachment_to_xml(
124 attachments_tag, attachment_refs, file.file.file,
124 attachments_tag, attachment_refs, file.file.file,
125 file.hash, file.file.url)
125 file.hash, file.file.url)
126
126
127 global_id.content = et.tostring(content_tag, ENCODING_UNICODE)
127 global_id.content = et.tostring(content_tag, ENCODING_UNICODE)
128 global_id.save()
128 global_id.save()
129
129
130 signatures_tag = et.SubElement(model, TAG_SIGNATURES)
130 signatures_tag = et.SubElement(model, TAG_SIGNATURES)
131 post_signatures = global_id.signature_set.all()
131 post_signatures = global_id.signature_set.all()
132 if post_signatures:
132 if post_signatures:
133 signatures = post_signatures
133 signatures = post_signatures
134 else:
134 else:
135 key = KeyPair.objects.get(public_key=global_id.key)
135 key = KeyPair.objects.get(public_key=global_id.key)
136 signature = Signature(
136 signature = Signature(
137 key_type=key.key_type,
137 key_type=key.key_type,
138 key=key.public_key,
138 key=key.public_key,
139 signature=key.sign(global_id.content),
139 signature=key.sign(global_id.content),
140 global_id=global_id,
140 global_id=global_id,
141 )
141 )
142 signature.save()
142 signature.save()
143 signatures = [signature]
143 signatures = [signature]
144 for signature in signatures:
144 for signature in signatures:
145 signature_tag = et.SubElement(signatures_tag, TAG_SIGNATURE)
145 signature_tag = et.SubElement(signatures_tag, TAG_SIGNATURE)
146 signature_tag.set(ATTR_TYPE, signature.key_type)
146 signature_tag.set(ATTR_TYPE, signature.key_type)
147 signature_tag.set(ATTR_VALUE, signature.signature)
147 signature_tag.set(ATTR_VALUE, signature.signature)
148 signature_tag.set(ATTR_KEY, signature.key)
148 signature_tag.set(ATTR_KEY, signature.key)
149
149
150 return et.tostring(response, ENCODING_UNICODE)
150 return et.tostring(response, ENCODING_UNICODE)
151
151
152 @staticmethod
152 @staticmethod
153 @transaction.atomic
153 @transaction.atomic
154 def parse_response_get(response_xml, hostname):
154 def parse_response_get(response_xml, hostname):
155 tag_root = et.fromstring(response_xml)
155 tag_root = et.fromstring(response_xml)
156 tag_status = tag_root.find(TAG_STATUS)
156 tag_status = tag_root.find(TAG_STATUS)
157 if STATUS_SUCCESS == tag_status.text:
157 if STATUS_SUCCESS == tag_status.text:
158 tag_models = tag_root.find(TAG_MODELS)
158 tag_models = tag_root.find(TAG_MODELS)
159 for tag_model in tag_models:
159 for tag_model in tag_models:
160 tag_content = tag_model.find(TAG_CONTENT)
160 tag_content = tag_model.find(TAG_CONTENT)
161
161
162 content_str = et.tostring(tag_content, ENCODING_UNICODE)
162 content_str = et.tostring(tag_content, ENCODING_UNICODE)
163 signatures = SyncManager._verify_model(content_str, tag_model)
163 signatures = SyncManager._verify_model(content_str, tag_model)
164
164
165 tag_id = tag_content.find(TAG_ID)
165 tag_id = tag_content.find(TAG_ID)
166 global_id, exists = GlobalId.from_xml_element(tag_id)
166 global_id, exists = GlobalId.from_xml_element(tag_id)
167
167
168 if exists:
168 if exists:
169 print('Post with same ID already exists')
169 print('Post with same ID already exists')
170 else:
170 else:
171 global_id.content = content_str
171 global_id.content = content_str
172 global_id.save()
172 global_id.save()
173 for signature in signatures:
173 for signature in signatures:
174 signature.global_id = global_id
174 signature.global_id = global_id
175 signature.save()
175 signature.save()
176
176
177 title = tag_content.find(TAG_TITLE).text or ''
177 title = tag_content.find(TAG_TITLE).text or ''
178 text = tag_content.find(TAG_TEXT).text or ''
178 text = tag_content.find(TAG_TEXT).text or ''
179 pub_time = tag_content.find(TAG_PUB_TIME).text
179 pub_time = tag_content.find(TAG_PUB_TIME).text
180 tripcode = tag_content.find(TAG_TRIPCODE).text
180
181
181 thread = tag_content.find(TAG_THREAD)
182 thread = tag_content.find(TAG_THREAD)
182 tags = []
183 tags = []
183 if thread:
184 if thread:
184 thread_id = thread.find(TAG_ID)
185 thread_id = thread.find(TAG_ID)
185 op_global_id, exists = GlobalId.from_xml_element(thread_id)
186 op_global_id, exists = GlobalId.from_xml_element(thread_id)
186 if exists:
187 if exists:
187 opening_post = Post.objects.get(global_id=op_global_id)
188 opening_post = Post.objects.get(global_id=op_global_id)
188 else:
189 else:
189 raise SyncException(EXCEPTION_OP)
190 raise SyncException(EXCEPTION_OP)
190 else:
191 else:
191 opening_post = None
192 opening_post = None
192 tag_tags = tag_content.find(TAG_TAGS)
193 tag_tags = tag_content.find(TAG_TAGS)
193 for tag_tag in tag_tags:
194 for tag_tag in tag_tags:
194 tag, created = Tag.objects.get_or_create(
195 tag, created = Tag.objects.get_or_create(
195 name=tag_tag.text)
196 name=tag_tag.text)
196 tags.append(tag)
197 tags.append(tag)
197
198
198 # TODO Check that the replied posts are already present
199 # TODO Check that the replied posts are already present
199 # before adding new ones
200 # before adding new ones
200
201
201 files = []
202 files = []
202 tag_attachments = tag_content.find(TAG_ATTACHMENTS) or list()
203 tag_attachments = tag_content.find(TAG_ATTACHMENTS) or list()
203 tag_refs = tag_model.find(TAG_ATTACHMENT_REFS)
204 tag_refs = tag_model.find(TAG_ATTACHMENT_REFS)
204 for attachment in tag_attachments:
205 for attachment in tag_attachments:
205 tag_ref = tag_refs.find("{}[@ref='{}']".format(
206 tag_ref = tag_refs.find("{}[@ref='{}']".format(
206 TAG_ATTACHMENT_REF, attachment.text))
207 TAG_ATTACHMENT_REF, attachment.text))
207 url = tag_ref.get(ATTR_URL)
208 url = tag_ref.get(ATTR_URL)
208 attached_file = download(hostname + url)
209 attached_file = download(hostname + url)
209 if attached_file is None:
210 if attached_file is None:
210 raise SyncException(EXCEPTION_DOWNLOAD)
211 raise SyncException(EXCEPTION_DOWNLOAD)
211
212
212 hash = get_file_hash(attached_file)
213 hash = get_file_hash(attached_file)
213 if hash != attachment.text:
214 if hash != attachment.text:
214 raise SyncException(EXCEPTION_HASH)
215 raise SyncException(EXCEPTION_HASH)
215
216
216 files.append(attached_file)
217 files.append(attached_file)
217
218
218 Post.objects.import_post(
219 Post.objects.import_post(
219 title=title, text=text, pub_time=pub_time,
220 title=title, text=text, pub_time=pub_time,
220 opening_post=opening_post, tags=tags,
221 opening_post=opening_post, tags=tags,
221 global_id=global_id, files=files)
222 global_id=global_id, files=files, tripcode=tripcode)
222 else:
223 else:
223 raise SyncException(EXCEPTION_NODE.format(tag_status.text))
224 raise SyncException(EXCEPTION_NODE.format(tag_status.text))
224
225
225 @staticmethod
226 @staticmethod
226 def generate_response_pull():
227 def generate_response_pull():
227 response = et.Element(TAG_RESPONSE)
228 response = et.Element(TAG_RESPONSE)
228
229
229 status = et.SubElement(response, TAG_STATUS)
230 status = et.SubElement(response, TAG_STATUS)
230 status.text = STATUS_SUCCESS
231 status.text = STATUS_SUCCESS
231
232
232 models = et.SubElement(response, TAG_MODELS)
233 models = et.SubElement(response, TAG_MODELS)
233
234
234 for post in Post.objects.all():
235 for post in Post.objects.all():
235 tag_id = et.SubElement(models, TAG_ID)
236 tag_id = et.SubElement(models, TAG_ID)
236 post.global_id.to_xml_element(tag_id)
237 post.global_id.to_xml_element(tag_id)
237
238
238 return et.tostring(response, ENCODING_UNICODE)
239 return et.tostring(response, ENCODING_UNICODE)
239
240
240 @staticmethod
241 @staticmethod
241 def _verify_model(content_str, tag_model):
242 def _verify_model(content_str, tag_model):
242 """
243 """
243 Verifies all signatures for a single model.
244 Verifies all signatures for a single model.
244 """
245 """
245
246
246 signatures = []
247 signatures = []
247
248
248 tag_signatures = tag_model.find(TAG_SIGNATURES)
249 tag_signatures = tag_model.find(TAG_SIGNATURES)
249 for tag_signature in tag_signatures:
250 for tag_signature in tag_signatures:
250 signature_type = tag_signature.get(ATTR_TYPE)
251 signature_type = tag_signature.get(ATTR_TYPE)
251 signature_value = tag_signature.get(ATTR_VALUE)
252 signature_value = tag_signature.get(ATTR_VALUE)
252 signature_key = tag_signature.get(ATTR_KEY)
253 signature_key = tag_signature.get(ATTR_KEY)
253
254
254 signature = Signature(key_type=signature_type,
255 signature = Signature(key_type=signature_type,
255 key=signature_key,
256 key=signature_key,
256 signature=signature_value)
257 signature=signature_value)
257
258
258 if not KeyPair.objects.verify(signature, content_str):
259 if not KeyPair.objects.verify(signature, content_str):
259 raise SyncException(EXCEPTION_SIGNATURE.format(content_str))
260 raise SyncException(EXCEPTION_SIGNATURE.format(content_str))
260
261
261 signatures.append(signature)
262 signatures.append(signature)
262
263
263 return signatures
264 return signatures
264
265
265 @staticmethod
266 @staticmethod
266 def _attachment_to_xml(tag_attachments, tag_refs, file, hash, url):
267 def _attachment_to_xml(tag_attachments, tag_refs, file, hash, url):
267 if tag_attachments is not None:
268 if tag_attachments is not None:
268 mimetype = get_file_mimetype(file)
269 mimetype = get_file_mimetype(file)
269 attachment = et.SubElement(tag_attachments, TAG_ATTACHMENT)
270 attachment = et.SubElement(tag_attachments, TAG_ATTACHMENT)
270 attachment.set(ATTR_MIMETYPE, mimetype)
271 attachment.set(ATTR_MIMETYPE, mimetype)
271 attachment.text = hash
272 attachment.text = hash
272
273
273 attachment_ref = et.SubElement(tag_refs, TAG_ATTACHMENT_REF)
274 attachment_ref = et.SubElement(tag_refs, TAG_ATTACHMENT_REF)
274 attachment_ref.set(ATTR_REF, hash)
275 attachment_ref.set(ATTR_REF, hash)
275 attachment_ref.set(ATTR_URL, url)
276 attachment_ref.set(ATTR_URL, url)
General Comments 0
You need to be logged in to leave comments. Login now