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