##// END OF EJS Templates
Don't allow parsing a post when its thread is not parsed yet
neko259 -
r1838:c7821a56 default
parent child Browse files
Show More
@@ -1,378 +1,379 b''
1 import xml.etree.ElementTree as et
1 import xml.etree.ElementTree as et
2 import logging
2 import logging
3 from xml.etree import ElementTree
3 from xml.etree import ElementTree
4
4
5 from boards.abstracts.exceptions import SyncException
5 from boards.abstracts.exceptions import SyncException
6 from boards.abstracts.sync_filters import ThreadFilter
6 from boards.abstracts.sync_filters import ThreadFilter
7 from boards.models import KeyPair, GlobalId, Signature, Post, Tag
7 from boards.models import KeyPair, GlobalId, Signature, Post, Tag
8 from boards.models.attachment.downloaders import download
8 from boards.models.attachment.downloaders import download
9 from boards.models.signature import TAG_REQUEST, ATTR_TYPE, TYPE_GET, \
9 from boards.models.signature import TAG_REQUEST, ATTR_TYPE, TYPE_GET, \
10 ATTR_VERSION, TAG_MODEL, ATTR_NAME, TAG_ID, TYPE_LIST
10 ATTR_VERSION, TAG_MODEL, ATTR_NAME, TAG_ID, TYPE_LIST
11 from boards.utils import get_file_mimetype, get_file_hash
11 from boards.utils import get_file_mimetype, get_file_hash
12 from django.db import transaction
12 from django.db import transaction
13
13
14 EXCEPTION_NODE = 'Sync node returned an error: {}.'
14 EXCEPTION_NODE = 'Sync node returned an error: {}.'
15 EXCEPTION_DOWNLOAD = 'File was not downloaded.'
15 EXCEPTION_DOWNLOAD = 'File was not downloaded.'
16 EXCEPTION_HASH = 'File hash does not match attachment hash.'
16 EXCEPTION_HASH = 'File hash does not match attachment hash.'
17 EXCEPTION_SIGNATURE = 'Invalid model signature for {}.'
17 EXCEPTION_SIGNATURE = 'Invalid model signature for {}.'
18 EXCEPTION_AUTHOR_SIGNATURE = 'Model {} has no author signature.'
18 EXCEPTION_AUTHOR_SIGNATURE = 'Model {} has no author signature.'
19 EXCEPTION_THREAD = 'No thread exists for post {}'
19 ENCODING_UNICODE = 'unicode'
20 ENCODING_UNICODE = 'unicode'
20
21
21 TAG_MODEL = 'model'
22 TAG_MODEL = 'model'
22 TAG_REQUEST = 'request'
23 TAG_REQUEST = 'request'
23 TAG_RESPONSE = 'response'
24 TAG_RESPONSE = 'response'
24 TAG_ID = 'id'
25 TAG_ID = 'id'
25 TAG_STATUS = 'status'
26 TAG_STATUS = 'status'
26 TAG_MODELS = 'models'
27 TAG_MODELS = 'models'
27 TAG_TITLE = 'title'
28 TAG_TITLE = 'title'
28 TAG_TEXT = 'text'
29 TAG_TEXT = 'text'
29 TAG_THREAD = 'thread'
30 TAG_THREAD = 'thread'
30 TAG_PUB_TIME = 'pub-time'
31 TAG_PUB_TIME = 'pub-time'
31 TAG_SIGNATURES = 'signatures'
32 TAG_SIGNATURES = 'signatures'
32 TAG_SIGNATURE = 'signature'
33 TAG_SIGNATURE = 'signature'
33 TAG_CONTENT = 'content'
34 TAG_CONTENT = 'content'
34 TAG_ATTACHMENTS = 'attachments'
35 TAG_ATTACHMENTS = 'attachments'
35 TAG_ATTACHMENT = 'attachment'
36 TAG_ATTACHMENT = 'attachment'
36 TAG_TAGS = 'tags'
37 TAG_TAGS = 'tags'
37 TAG_TAG = 'tag'
38 TAG_TAG = 'tag'
38 TAG_ATTACHMENT_REFS = 'attachment-refs'
39 TAG_ATTACHMENT_REFS = 'attachment-refs'
39 TAG_ATTACHMENT_REF = 'attachment-ref'
40 TAG_ATTACHMENT_REF = 'attachment-ref'
40 TAG_TRIPCODE = 'tripcode'
41 TAG_TRIPCODE = 'tripcode'
41 TAG_VERSION = 'version'
42 TAG_VERSION = 'version'
42
43
43 TYPE_GET = 'get'
44 TYPE_GET = 'get'
44
45
45 ATTR_VERSION = 'version'
46 ATTR_VERSION = 'version'
46 ATTR_TYPE = 'type'
47 ATTR_TYPE = 'type'
47 ATTR_NAME = 'name'
48 ATTR_NAME = 'name'
48 ATTR_VALUE = 'value'
49 ATTR_VALUE = 'value'
49 ATTR_MIMETYPE = 'mimetype'
50 ATTR_MIMETYPE = 'mimetype'
50 ATTR_KEY = 'key'
51 ATTR_KEY = 'key'
51 ATTR_REF = 'ref'
52 ATTR_REF = 'ref'
52 ATTR_URL = 'url'
53 ATTR_URL = 'url'
53 ATTR_ID_TYPE = 'id-type'
54 ATTR_ID_TYPE = 'id-type'
54
55
55 ID_TYPE_MD5 = 'md5'
56 ID_TYPE_MD5 = 'md5'
56 ID_TYPE_URL = 'url'
57 ID_TYPE_URL = 'url'
57
58
58 STATUS_SUCCESS = 'success'
59 STATUS_SUCCESS = 'success'
59
60
60
61
61 logger = logging.getLogger('boards.sync')
62 logger = logging.getLogger('boards.sync')
62
63
63
64
64 class SyncManager:
65 class SyncManager:
65 @staticmethod
66 @staticmethod
66 def generate_response_get(model_list: list):
67 def generate_response_get(model_list: list):
67 response = et.Element(TAG_RESPONSE)
68 response = et.Element(TAG_RESPONSE)
68
69
69 status = et.SubElement(response, TAG_STATUS)
70 status = et.SubElement(response, TAG_STATUS)
70 status.text = STATUS_SUCCESS
71 status.text = STATUS_SUCCESS
71
72
72 models = et.SubElement(response, TAG_MODELS)
73 models = et.SubElement(response, TAG_MODELS)
73
74
74 for post in model_list:
75 for post in model_list:
75 model = et.SubElement(models, TAG_MODEL)
76 model = et.SubElement(models, TAG_MODEL)
76 model.set(ATTR_NAME, 'post')
77 model.set(ATTR_NAME, 'post')
77
78
78 global_id = post.global_id
79 global_id = post.global_id
79
80
80 attachments = post.attachments.all()
81 attachments = post.attachments.all()
81 if global_id.content:
82 if global_id.content:
82 model.append(et.fromstring(global_id.content))
83 model.append(et.fromstring(global_id.content))
83 if len(attachments) > 0:
84 if len(attachments) > 0:
84 internal_attachments = False
85 internal_attachments = False
85 for attachment in attachments:
86 for attachment in attachments:
86 if attachment.is_internal():
87 if attachment.is_internal():
87 internal_attachments = True
88 internal_attachments = True
88 break
89 break
89
90
90 if internal_attachments:
91 if internal_attachments:
91 attachment_refs = et.SubElement(model, TAG_ATTACHMENT_REFS)
92 attachment_refs = et.SubElement(model, TAG_ATTACHMENT_REFS)
92 for file in attachments:
93 for file in attachments:
93 SyncManager._attachment_to_xml(
94 SyncManager._attachment_to_xml(
94 None, attachment_refs, file)
95 None, attachment_refs, file)
95 else:
96 else:
96 content_tag = et.SubElement(model, TAG_CONTENT)
97 content_tag = et.SubElement(model, TAG_CONTENT)
97
98
98 tag_id = et.SubElement(content_tag, TAG_ID)
99 tag_id = et.SubElement(content_tag, TAG_ID)
99 global_id.to_xml_element(tag_id)
100 global_id.to_xml_element(tag_id)
100
101
101 title = et.SubElement(content_tag, TAG_TITLE)
102 title = et.SubElement(content_tag, TAG_TITLE)
102 title.text = post.title
103 title.text = post.title
103
104
104 text = et.SubElement(content_tag, TAG_TEXT)
105 text = et.SubElement(content_tag, TAG_TEXT)
105 text.text = post.get_sync_text()
106 text.text = post.get_sync_text()
106
107
107 thread = post.get_thread()
108 thread = post.get_thread()
108 if post.is_opening():
109 if post.is_opening():
109 tag_tags = et.SubElement(content_tag, TAG_TAGS)
110 tag_tags = et.SubElement(content_tag, TAG_TAGS)
110 for tag in thread.get_tags():
111 for tag in thread.get_tags():
111 tag_tag = et.SubElement(tag_tags, TAG_TAG)
112 tag_tag = et.SubElement(tag_tags, TAG_TAG)
112 tag_tag.text = tag.name
113 tag_tag.text = tag.name
113 else:
114 else:
114 tag_thread = et.SubElement(content_tag, TAG_THREAD)
115 tag_thread = et.SubElement(content_tag, TAG_THREAD)
115 thread_id = et.SubElement(tag_thread, TAG_ID)
116 thread_id = et.SubElement(tag_thread, TAG_ID)
116 thread.get_opening_post().global_id.to_xml_element(thread_id)
117 thread.get_opening_post().global_id.to_xml_element(thread_id)
117
118
118 pub_time = et.SubElement(content_tag, TAG_PUB_TIME)
119 pub_time = et.SubElement(content_tag, TAG_PUB_TIME)
119 pub_time.text = str(post.get_pub_time_str())
120 pub_time.text = str(post.get_pub_time_str())
120
121
121 if post.tripcode:
122 if post.tripcode:
122 tripcode = et.SubElement(content_tag, TAG_TRIPCODE)
123 tripcode = et.SubElement(content_tag, TAG_TRIPCODE)
123 tripcode.text = post.tripcode
124 tripcode.text = post.tripcode
124
125
125 if len(attachments) > 0:
126 if len(attachments) > 0:
126 attachments_tag = et.SubElement(content_tag, TAG_ATTACHMENTS)
127 attachments_tag = et.SubElement(content_tag, TAG_ATTACHMENTS)
127
128
128 internal_attachments = False
129 internal_attachments = False
129 for attachment in attachments:
130 for attachment in attachments:
130 if attachment.is_internal():
131 if attachment.is_internal():
131 internal_attachments = True
132 internal_attachments = True
132 break
133 break
133
134
134 if internal_attachments:
135 if internal_attachments:
135 attachment_refs = et.SubElement(model, TAG_ATTACHMENT_REFS)
136 attachment_refs = et.SubElement(model, TAG_ATTACHMENT_REFS)
136 else:
137 else:
137 attachment_refs = None
138 attachment_refs = None
138
139
139 for file in attachments:
140 for file in attachments:
140 SyncManager._attachment_to_xml(
141 SyncManager._attachment_to_xml(
141 attachments_tag, attachment_refs, file)
142 attachments_tag, attachment_refs, file)
142 version_tag = et.SubElement(content_tag, TAG_VERSION)
143 version_tag = et.SubElement(content_tag, TAG_VERSION)
143 version_tag.text = str(post.version)
144 version_tag.text = str(post.version)
144
145
145 global_id.content = et.tostring(content_tag, ENCODING_UNICODE)
146 global_id.content = et.tostring(content_tag, ENCODING_UNICODE)
146 global_id.save()
147 global_id.save()
147
148
148 signatures_tag = et.SubElement(model, TAG_SIGNATURES)
149 signatures_tag = et.SubElement(model, TAG_SIGNATURES)
149 post_signatures = global_id.signature_set.all()
150 post_signatures = global_id.signature_set.all()
150 if post_signatures:
151 if post_signatures:
151 signatures = post_signatures
152 signatures = post_signatures
152 else:
153 else:
153 key = KeyPair.objects.get(public_key=global_id.key)
154 key = KeyPair.objects.get(public_key=global_id.key)
154 signature = Signature(
155 signature = Signature(
155 key_type=key.key_type,
156 key_type=key.key_type,
156 key=key.public_key,
157 key=key.public_key,
157 signature=key.sign(global_id.content),
158 signature=key.sign(global_id.content),
158 global_id=global_id,
159 global_id=global_id,
159 )
160 )
160 signature.save()
161 signature.save()
161 signatures = [signature]
162 signatures = [signature]
162 for signature in signatures:
163 for signature in signatures:
163 signature_tag = et.SubElement(signatures_tag, TAG_SIGNATURE)
164 signature_tag = et.SubElement(signatures_tag, TAG_SIGNATURE)
164 signature_tag.set(ATTR_TYPE, signature.key_type)
165 signature_tag.set(ATTR_TYPE, signature.key_type)
165 signature_tag.set(ATTR_VALUE, signature.signature)
166 signature_tag.set(ATTR_VALUE, signature.signature)
166 signature_tag.set(ATTR_KEY, signature.key)
167 signature_tag.set(ATTR_KEY, signature.key)
167
168
168 return et.tostring(response, ENCODING_UNICODE)
169 return et.tostring(response, ENCODING_UNICODE)
169
170
170 @staticmethod
171 @staticmethod
171 def parse_response_get(response_xml, hostname):
172 def parse_response_get(response_xml, hostname):
172 tag_root = et.fromstring(response_xml)
173 tag_root = et.fromstring(response_xml)
173 tag_status = tag_root.find(TAG_STATUS)
174 tag_status = tag_root.find(TAG_STATUS)
174 if STATUS_SUCCESS == tag_status.text:
175 if STATUS_SUCCESS == tag_status.text:
175 tag_models = tag_root.find(TAG_MODELS)
176 tag_models = tag_root.find(TAG_MODELS)
176 for tag_model in tag_models:
177 for tag_model in tag_models:
177 SyncManager.parse_post(tag_model, hostname)
178 SyncManager.parse_post(tag_model, hostname)
178 else:
179 else:
179 raise SyncException(EXCEPTION_NODE.format(tag_status.text))
180 raise SyncException(EXCEPTION_NODE.format(tag_status.text))
180
181
181 @staticmethod
182 @staticmethod
182 @transaction.atomic
183 @transaction.atomic
183 def parse_post(tag_model, hostname):
184 def parse_post(tag_model, hostname):
184 tag_content = tag_model.find(TAG_CONTENT)
185 tag_content = tag_model.find(TAG_CONTENT)
185
186
186 content_str = et.tostring(tag_content, ENCODING_UNICODE)
187 content_str = et.tostring(tag_content, ENCODING_UNICODE)
187
188
188 tag_id = tag_content.find(TAG_ID)
189 tag_id = tag_content.find(TAG_ID)
189 global_id, exists = GlobalId.from_xml_element(tag_id)
190 global_id, exists = GlobalId.from_xml_element(tag_id)
190 signatures = SyncManager._verify_model(global_id, content_str, tag_model)
191 signatures = SyncManager._verify_model(global_id, content_str, tag_model)
191
192
192 version = int(tag_content.find(TAG_VERSION).text)
193 version = int(tag_content.find(TAG_VERSION).text)
193 is_old = exists and global_id.post.version < version
194 is_old = exists and global_id.post.version < version
194 if exists and not is_old:
195 if exists and not is_old:
195 print('Post with same ID exists and is up to date.')
196 print('Post with same ID exists and is up to date.')
196 else:
197 else:
197 global_id.content = content_str
198 global_id.content = content_str
198 global_id.save()
199 global_id.save()
199 for signature in signatures:
200 for signature in signatures:
200 signature.global_id = global_id
201 signature.global_id = global_id
201 signature.save()
202 signature.save()
202
203
203 title = tag_content.find(TAG_TITLE).text or ''
204 title = tag_content.find(TAG_TITLE).text or ''
204 text = tag_content.find(TAG_TEXT).text or ''
205 text = tag_content.find(TAG_TEXT).text or ''
205 pub_time = tag_content.find(TAG_PUB_TIME).text
206 pub_time = tag_content.find(TAG_PUB_TIME).text
206 tripcode_tag = tag_content.find(TAG_TRIPCODE)
207 tripcode_tag = tag_content.find(TAG_TRIPCODE)
207 if tripcode_tag is not None:
208 if tripcode_tag is not None:
208 tripcode = tripcode_tag.text or ''
209 tripcode = tripcode_tag.text or ''
209 else:
210 else:
210 tripcode = ''
211 tripcode = ''
211
212
212 thread = tag_content.find(TAG_THREAD)
213 thread = tag_content.find(TAG_THREAD)
213 tags = []
214 tags = []
214 if thread:
215 if thread:
215 thread_id = thread.find(TAG_ID)
216 thread_id = thread.find(TAG_ID)
216 op_global_id, exists = GlobalId.from_xml_element(thread_id)
217 op_global_id, exists = GlobalId.from_xml_element(thread_id)
217 if exists:
218 if exists:
218 opening_post = Post.objects.get(global_id=op_global_id)
219 opening_post = Post.objects.get(global_id=op_global_id)
219 else:
220 else:
220 logger.debug('No thread exists for post {}'.format(global_id))
221 raise Exception(EXCEPTION_THREAD.format(global_id))
221 else:
222 else:
222 opening_post = None
223 opening_post = None
223 tag_tags = tag_content.find(TAG_TAGS)
224 tag_tags = tag_content.find(TAG_TAGS)
224 for tag_tag in tag_tags:
225 for tag_tag in tag_tags:
225 tag, created = Tag.objects.get_or_create(
226 tag, created = Tag.objects.get_or_create(
226 name=tag_tag.text)
227 name=tag_tag.text)
227 tags.append(tag)
228 tags.append(tag)
228
229
229 # TODO Check that the replied posts are already present
230 # TODO Check that the replied posts are already present
230 # before adding new ones
231 # before adding new ones
231
232
232 files = []
233 files = []
233 urls = []
234 urls = []
234 tag_attachments = tag_content.find(TAG_ATTACHMENTS) or list()
235 tag_attachments = tag_content.find(TAG_ATTACHMENTS) or list()
235 tag_refs = tag_model.find(TAG_ATTACHMENT_REFS)
236 tag_refs = tag_model.find(TAG_ATTACHMENT_REFS)
236 for attachment in tag_attachments:
237 for attachment in tag_attachments:
237 if attachment.get(ATTR_ID_TYPE) == ID_TYPE_URL:
238 if attachment.get(ATTR_ID_TYPE) == ID_TYPE_URL:
238 urls.append(attachment.text)
239 urls.append(attachment.text)
239 else:
240 else:
240 tag_ref = tag_refs.find("{}[@ref='{}']".format(
241 tag_ref = tag_refs.find("{}[@ref='{}']".format(
241 TAG_ATTACHMENT_REF, attachment.text))
242 TAG_ATTACHMENT_REF, attachment.text))
242 url = tag_ref.get(ATTR_URL)
243 url = tag_ref.get(ATTR_URL)
243 attached_file = download(hostname + url, validate=False)
244 attached_file = download(hostname + url, validate=False)
244 if attached_file is None:
245 if attached_file is None:
245 raise SyncException(EXCEPTION_DOWNLOAD)
246 raise SyncException(EXCEPTION_DOWNLOAD)
246
247
247 hash = get_file_hash(attached_file)
248 hash = get_file_hash(attached_file)
248 if hash != attachment.text:
249 if hash != attachment.text:
249 raise SyncException(EXCEPTION_HASH)
250 raise SyncException(EXCEPTION_HASH)
250
251
251 files.append(attached_file)
252 files.append(attached_file)
252
253
253 if is_old:
254 if is_old:
254 post = global_id.post
255 post = global_id.post
255 Post.objects.update_post(
256 Post.objects.update_post(
256 post, title=title, text=text, pub_time=pub_time,
257 post, title=title, text=text, pub_time=pub_time,
257 tags=tags, files=files, file_urls=urls,
258 tags=tags, files=files, file_urls=urls,
258 tripcode=tripcode, version=version)
259 tripcode=tripcode, version=version)
259 logger.debug('Parsed updated post {}'.format(global_id))
260 logger.debug('Parsed updated post {}'.format(global_id))
260 else:
261 else:
261 Post.objects.import_post(
262 Post.objects.import_post(
262 title=title, text=text, pub_time=pub_time,
263 title=title, text=text, pub_time=pub_time,
263 opening_post=opening_post, tags=tags,
264 opening_post=opening_post, tags=tags,
264 global_id=global_id, files=files,
265 global_id=global_id, files=files,
265 file_urls=urls, tripcode=tripcode,
266 file_urls=urls, tripcode=tripcode,
266 version=version)
267 version=version)
267 logger.debug('Parsed new post {}'.format(global_id))
268 logger.debug('Parsed new post {}'.format(global_id))
268
269
269 @staticmethod
270 @staticmethod
270 def generate_response_list(filters):
271 def generate_response_list(filters):
271 response = et.Element(TAG_RESPONSE)
272 response = et.Element(TAG_RESPONSE)
272
273
273 status = et.SubElement(response, TAG_STATUS)
274 status = et.SubElement(response, TAG_STATUS)
274 status.text = STATUS_SUCCESS
275 status.text = STATUS_SUCCESS
275
276
276 models = et.SubElement(response, TAG_MODELS)
277 models = et.SubElement(response, TAG_MODELS)
277
278
278 posts = Post.objects.prefetch_related('global_id')
279 posts = Post.objects.prefetch_related('global_id')
279 for post_filter in filters:
280 for post_filter in filters:
280 posts = post_filter.filter(posts)
281 posts = post_filter.filter(posts)
281
282
282 for post in posts:
283 for post in posts:
283 tag_model = et.SubElement(models, TAG_MODEL)
284 tag_model = et.SubElement(models, TAG_MODEL)
284 tag_id = et.SubElement(tag_model, TAG_ID)
285 tag_id = et.SubElement(tag_model, TAG_ID)
285 post.global_id.to_xml_element(tag_id)
286 post.global_id.to_xml_element(tag_id)
286 tag_version = et.SubElement(tag_model, TAG_VERSION)
287 tag_version = et.SubElement(tag_model, TAG_VERSION)
287 tag_version.text = str(post.version)
288 tag_version.text = str(post.version)
288
289
289 return et.tostring(response, ENCODING_UNICODE)
290 return et.tostring(response, ENCODING_UNICODE)
290
291
291 @staticmethod
292 @staticmethod
292 def _verify_model(global_id, content_str, tag_model):
293 def _verify_model(global_id, content_str, tag_model):
293 """
294 """
294 Verifies all signatures for a single model.
295 Verifies all signatures for a single model.
295 """
296 """
296
297
297 signatures = []
298 signatures = []
298
299
299 tag_signatures = tag_model.find(TAG_SIGNATURES)
300 tag_signatures = tag_model.find(TAG_SIGNATURES)
300 has_author_signature = False
301 has_author_signature = False
301 for tag_signature in tag_signatures:
302 for tag_signature in tag_signatures:
302 signature_type = tag_signature.get(ATTR_TYPE)
303 signature_type = tag_signature.get(ATTR_TYPE)
303 signature_value = tag_signature.get(ATTR_VALUE)
304 signature_value = tag_signature.get(ATTR_VALUE)
304 signature_key = tag_signature.get(ATTR_KEY)
305 signature_key = tag_signature.get(ATTR_KEY)
305
306
306 if global_id.key_type == signature_type and\
307 if global_id.key_type == signature_type and\
307 global_id.key == signature_key:
308 global_id.key == signature_key:
308 has_author_signature = True
309 has_author_signature = True
309
310
310 signature = Signature(key_type=signature_type,
311 signature = Signature(key_type=signature_type,
311 key=signature_key,
312 key=signature_key,
312 signature=signature_value)
313 signature=signature_value)
313
314
314 if not KeyPair.objects.verify(signature, content_str):
315 if not KeyPair.objects.verify(signature, content_str):
315 raise SyncException(EXCEPTION_SIGNATURE.format(content_str))
316 raise SyncException(EXCEPTION_SIGNATURE.format(content_str))
316
317
317 signatures.append(signature)
318 signatures.append(signature)
318 if not has_author_signature:
319 if not has_author_signature:
319 raise SyncException(EXCEPTION_AUTHOR_SIGNATURE.format(content_str))
320 raise SyncException(EXCEPTION_AUTHOR_SIGNATURE.format(content_str))
320
321
321 return signatures
322 return signatures
322
323
323 @staticmethod
324 @staticmethod
324 def _attachment_to_xml(tag_attachments, tag_refs, attachment):
325 def _attachment_to_xml(tag_attachments, tag_refs, attachment):
325 if tag_attachments is not None:
326 if tag_attachments is not None:
326 attachment_tag = et.SubElement(tag_attachments, TAG_ATTACHMENT)
327 attachment_tag = et.SubElement(tag_attachments, TAG_ATTACHMENT)
327 if attachment.is_internal():
328 if attachment.is_internal():
328 mimetype = get_file_mimetype(attachment.file.file)
329 mimetype = get_file_mimetype(attachment.file.file)
329 attachment_tag.set(ATTR_MIMETYPE, mimetype)
330 attachment_tag.set(ATTR_MIMETYPE, mimetype)
330 attachment_tag.set(ATTR_ID_TYPE, ID_TYPE_MD5)
331 attachment_tag.set(ATTR_ID_TYPE, ID_TYPE_MD5)
331 attachment_tag.text = attachment.hash
332 attachment_tag.text = attachment.hash
332 else:
333 else:
333 attachment_tag.set(ATTR_ID_TYPE, ID_TYPE_URL)
334 attachment_tag.set(ATTR_ID_TYPE, ID_TYPE_URL)
334 attachment_tag.text = attachment.url
335 attachment_tag.text = attachment.url
335
336
336 if tag_refs is not None:
337 if tag_refs is not None:
337 attachment_ref = et.SubElement(tag_refs, TAG_ATTACHMENT_REF)
338 attachment_ref = et.SubElement(tag_refs, TAG_ATTACHMENT_REF)
338 attachment_ref.set(ATTR_REF, attachment.hash)
339 attachment_ref.set(ATTR_REF, attachment.hash)
339 attachment_ref.set(ATTR_URL, attachment.file.url)
340 attachment_ref.set(ATTR_URL, attachment.file.url)
340
341
341 @staticmethod
342 @staticmethod
342 def generate_request_get(global_id_list: list):
343 def generate_request_get(global_id_list: list):
343 """
344 """
344 Form a get request from a list of ModelId objects.
345 Form a get request from a list of ModelId objects.
345 """
346 """
346
347
347 request = et.Element(TAG_REQUEST)
348 request = et.Element(TAG_REQUEST)
348 request.set(ATTR_TYPE, TYPE_GET)
349 request.set(ATTR_TYPE, TYPE_GET)
349 request.set(ATTR_VERSION, '1.0')
350 request.set(ATTR_VERSION, '1.0')
350
351
351 model = et.SubElement(request, TAG_MODEL)
352 model = et.SubElement(request, TAG_MODEL)
352 model.set(ATTR_VERSION, '1.0')
353 model.set(ATTR_VERSION, '1.0')
353 model.set(ATTR_NAME, 'post')
354 model.set(ATTR_NAME, 'post')
354
355
355 for global_id in global_id_list:
356 for global_id in global_id_list:
356 tag_id = et.SubElement(model, TAG_ID)
357 tag_id = et.SubElement(model, TAG_ID)
357 global_id.to_xml_element(tag_id)
358 global_id.to_xml_element(tag_id)
358
359
359 return et.tostring(request, 'unicode')
360 return et.tostring(request, 'unicode')
360
361
361 @staticmethod
362 @staticmethod
362 def generate_request_list(opening_post=None):
363 def generate_request_list(opening_post=None):
363 """
364 """
364 Form a pull request from a list of ModelId objects.
365 Form a pull request from a list of ModelId objects.
365 """
366 """
366
367
367 request = et.Element(TAG_REQUEST)
368 request = et.Element(TAG_REQUEST)
368 request.set(ATTR_TYPE, TYPE_LIST)
369 request.set(ATTR_TYPE, TYPE_LIST)
369 request.set(ATTR_VERSION, '1.0')
370 request.set(ATTR_VERSION, '1.0')
370
371
371 model = et.SubElement(request, TAG_MODEL)
372 model = et.SubElement(request, TAG_MODEL)
372 model.set(ATTR_VERSION, '1.0')
373 model.set(ATTR_VERSION, '1.0')
373 model.set(ATTR_NAME, 'post')
374 model.set(ATTR_NAME, 'post')
374
375
375 if opening_post:
376 if opening_post:
376 ThreadFilter().add_filter(model, opening_post)
377 ThreadFilter().add_filter(model, opening_post)
377
378
378 return et.tostring(request, 'unicode') No newline at end of file
379 return et.tostring(request, 'unicode')
General Comments 0
You need to be logged in to leave comments. Login now