##// END OF EJS Templates
Added images and attachments to the XML post response
neko259 -
r1506:fcdf00d7 decentral
parent child Browse files
Show More
@@ -1,201 +1,218 b''
1 import xml.etree.ElementTree as et
1 import xml.etree.ElementTree as et
2
3 from boards.utils import get_file_mimetype
2 from django.db import transaction
4 from django.db import transaction
3 from boards.models import KeyPair, GlobalId, Signature, Post, Tag
5 from boards.models import KeyPair, GlobalId, Signature, Post, Tag
4
6
5 ENCODING_UNICODE = 'unicode'
7 ENCODING_UNICODE = 'unicode'
6
8
7 TAG_MODEL = 'model'
9 TAG_MODEL = 'model'
8 TAG_REQUEST = 'request'
10 TAG_REQUEST = 'request'
9 TAG_RESPONSE = 'response'
11 TAG_RESPONSE = 'response'
10 TAG_ID = 'id'
12 TAG_ID = 'id'
11 TAG_STATUS = 'status'
13 TAG_STATUS = 'status'
12 TAG_MODELS = 'models'
14 TAG_MODELS = 'models'
13 TAG_TITLE = 'title'
15 TAG_TITLE = 'title'
14 TAG_TEXT = 'text'
16 TAG_TEXT = 'text'
15 TAG_THREAD = 'thread'
17 TAG_THREAD = 'thread'
16 TAG_PUB_TIME = 'pub-time'
18 TAG_PUB_TIME = 'pub-time'
17 TAG_SIGNATURES = 'signatures'
19 TAG_SIGNATURES = 'signatures'
18 TAG_SIGNATURE = 'signature'
20 TAG_SIGNATURE = 'signature'
19 TAG_CONTENT = 'content'
21 TAG_CONTENT = 'content'
20 TAG_ATTACHMENTS = 'attachments'
22 TAG_ATTACHMENTS = 'attachments'
21 TAG_ATTACHMENT = 'attachment'
23 TAG_ATTACHMENT = 'attachment'
22 TAG_TAGS = 'tags'
24 TAG_TAGS = 'tags'
23 TAG_TAG = 'tag'
25 TAG_TAG = 'tag'
24
26
25 TYPE_GET = 'get'
27 TYPE_GET = 'get'
26
28
27 ATTR_VERSION = 'version'
29 ATTR_VERSION = 'version'
28 ATTR_TYPE = 'type'
30 ATTR_TYPE = 'type'
29 ATTR_NAME = 'name'
31 ATTR_NAME = 'name'
30 ATTR_VALUE = 'value'
32 ATTR_VALUE = 'value'
31 ATTR_MIMETYPE = 'mimetype'
33 ATTR_MIMETYPE = 'mimetype'
32 ATTR_KEY = 'key'
34 ATTR_KEY = 'key'
33
35
34 STATUS_SUCCESS = 'success'
36 STATUS_SUCCESS = 'success'
35
37
36
38
37 class SyncManager:
39 class SyncManager:
38 @staticmethod
40 @staticmethod
39 def generate_response_get(model_list: list):
41 def generate_response_get(model_list: list):
40 response = et.Element(TAG_RESPONSE)
42 response = et.Element(TAG_RESPONSE)
41
43
42 status = et.SubElement(response, TAG_STATUS)
44 status = et.SubElement(response, TAG_STATUS)
43 status.text = STATUS_SUCCESS
45 status.text = STATUS_SUCCESS
44
46
45 models = et.SubElement(response, TAG_MODELS)
47 models = et.SubElement(response, TAG_MODELS)
46
48
47 for post in model_list:
49 for post in model_list:
48 model = et.SubElement(models, TAG_MODEL)
50 model = et.SubElement(models, TAG_MODEL)
49 model.set(ATTR_NAME, 'post')
51 model.set(ATTR_NAME, 'post')
50
52
51 content_tag = et.SubElement(model, TAG_CONTENT)
53 content_tag = et.SubElement(model, TAG_CONTENT)
52
54
53 tag_id = et.SubElement(content_tag, TAG_ID)
55 tag_id = et.SubElement(content_tag, TAG_ID)
54 post.global_id.to_xml_element(tag_id)
56 post.global_id.to_xml_element(tag_id)
55
57
56 title = et.SubElement(content_tag, TAG_TITLE)
58 title = et.SubElement(content_tag, TAG_TITLE)
57 title.text = post.title
59 title.text = post.title
58
60
59 text = et.SubElement(content_tag, TAG_TEXT)
61 text = et.SubElement(content_tag, TAG_TEXT)
60 text.text = post.get_sync_text()
62 text.text = post.get_sync_text()
61
63
62 thread = post.get_thread()
64 thread = post.get_thread()
63 if post.is_opening():
65 if post.is_opening():
64 tag_tags = et.SubElement(content_tag, TAG_TAGS)
66 tag_tags = et.SubElement(content_tag, TAG_TAGS)
65 for tag in thread.get_tags():
67 for tag in thread.get_tags():
66 tag_tag = et.SubElement(tag_tags, TAG_TAG)
68 tag_tag = et.SubElement(tag_tags, TAG_TAG)
67 tag_tag.text = tag.name
69 tag_tag.text = tag.name
68 else:
70 else:
69 tag_thread = et.SubElement(content_tag, TAG_THREAD)
71 tag_thread = et.SubElement(content_tag, TAG_THREAD)
70 thread_id = et.SubElement(tag_thread, TAG_ID)
72 thread_id = et.SubElement(tag_thread, TAG_ID)
71 thread.get_opening_post().global_id.to_xml_element(thread_id)
73 thread.get_opening_post().global_id.to_xml_element(thread_id)
72
74
73 pub_time = et.SubElement(content_tag, TAG_PUB_TIME)
75 pub_time = et.SubElement(content_tag, TAG_PUB_TIME)
74 pub_time.text = str(post.get_pub_time_str())
76 pub_time.text = str(post.get_pub_time_str())
75
77
78 images = post.images.all()
79 attachments = post.attachments.all()
80 if len(images) > 0 or len(attachments) > 0:
81 attachments_tag = et.SubElement(content_tag, TAG_ATTACHMENTS)
82 for image in images:
83 mimetype = get_file_mimetype(image.image.file)
84 attachment = et.SubElement(attachments_tag, TAG_ATTACHMENT)
85 attachment.set(ATTR_MIMETYPE, mimetype)
86 attachment.text = image.hash
87 for file in attachments:
88 mimetype = get_file_mimetype(file.file.file)
89 attachment = et.SubElement(attachments_tag, TAG_ATTACHMENT)
90 attachment.set(ATTR_MIMETYPE, mimetype)
91 attachment.text = file.hash
92
76 signatures_tag = et.SubElement(model, TAG_SIGNATURES)
93 signatures_tag = et.SubElement(model, TAG_SIGNATURES)
77 post_signatures = post.global_id.signature_set.all()
94 post_signatures = post.global_id.signature_set.all()
78 if post_signatures:
95 if post_signatures:
79 signatures = post_signatures
96 signatures = post_signatures
80 # TODO Adding signature to a post is not yet added. For now this
97 # TODO Adding signature to a post is not yet added. For now this
81 # block is useless
98 # block is useless
82 else:
99 else:
83 # TODO Maybe the signature can be computed only once after
100 # TODO Maybe the signature can be computed only once after
84 # the post is added? Need to add some on_save signal queue
101 # the post is added? Need to add some on_save signal queue
85 # and add this there.
102 # and add this there.
86 key = KeyPair.objects.get(public_key=post.global_id.key)
103 key = KeyPair.objects.get(public_key=post.global_id.key)
87 signature = Signature(
104 signature = Signature(
88 key_type=key.key_type,
105 key_type=key.key_type,
89 key=key.public_key,
106 key=key.public_key,
90 signature=key.sign(et.tostring(content_tag, encoding=ENCODING_UNICODE)),
107 signature=key.sign(et.tostring(content_tag, encoding=ENCODING_UNICODE)),
91 global_id=post.global_id,
108 global_id=post.global_id,
92 )
109 )
93 signature.save()
110 signature.save()
94 signatures = [signature]
111 signatures = [signature]
95 for signature in signatures:
112 for signature in signatures:
96 signature_tag = et.SubElement(signatures_tag, TAG_SIGNATURE)
113 signature_tag = et.SubElement(signatures_tag, TAG_SIGNATURE)
97 signature_tag.set(ATTR_TYPE, signature.key_type)
114 signature_tag.set(ATTR_TYPE, signature.key_type)
98 signature_tag.set(ATTR_VALUE, signature.signature)
115 signature_tag.set(ATTR_VALUE, signature.signature)
99 signature_tag.set(ATTR_KEY, signature.key)
116 signature_tag.set(ATTR_KEY, signature.key)
100
117
101 return et.tostring(response, ENCODING_UNICODE)
118 return et.tostring(response, ENCODING_UNICODE)
102
119
103 @staticmethod
120 @staticmethod
104 @transaction.atomic
121 @transaction.atomic
105 def parse_response_get(response_xml):
122 def parse_response_get(response_xml):
106 tag_root = et.fromstring(response_xml)
123 tag_root = et.fromstring(response_xml)
107 tag_status = tag_root.find(TAG_STATUS)
124 tag_status = tag_root.find(TAG_STATUS)
108 if STATUS_SUCCESS == tag_status.text:
125 if STATUS_SUCCESS == tag_status.text:
109 tag_models = tag_root.find(TAG_MODELS)
126 tag_models = tag_root.find(TAG_MODELS)
110 for tag_model in tag_models:
127 for tag_model in tag_models:
111 tag_content = tag_model.find(TAG_CONTENT)
128 tag_content = tag_model.find(TAG_CONTENT)
112
129
113 signatures = SyncManager._verify_model(tag_content, tag_model)
130 signatures = SyncManager._verify_model(tag_content, tag_model)
114
131
115 tag_id = tag_content.find(TAG_ID)
132 tag_id = tag_content.find(TAG_ID)
116 global_id, exists = GlobalId.from_xml_element(tag_id)
133 global_id, exists = GlobalId.from_xml_element(tag_id)
117
134
118 if exists:
135 if exists:
119 print('Post with same ID already exists')
136 print('Post with same ID already exists')
120 else:
137 else:
121 global_id.save()
138 global_id.save()
122 for signature in signatures:
139 for signature in signatures:
123 signature.global_id = global_id
140 signature.global_id = global_id
124 signature.save()
141 signature.save()
125
142
126 title = tag_content.find(TAG_TITLE).text
143 title = tag_content.find(TAG_TITLE).text
127 text = tag_content.find(TAG_TEXT).text
144 text = tag_content.find(TAG_TEXT).text
128 pub_time = tag_content.find(TAG_PUB_TIME).text
145 pub_time = tag_content.find(TAG_PUB_TIME).text
129
146
130 thread = tag_content.find(TAG_THREAD)
147 thread = tag_content.find(TAG_THREAD)
131 tags = []
148 tags = []
132 if thread:
149 if thread:
133 thread_id = thread.find(TAG_ID)
150 thread_id = thread.find(TAG_ID)
134 op_global_id, exists = GlobalId.from_xml_element(thread_id)
151 op_global_id, exists = GlobalId.from_xml_element(thread_id)
135 if exists:
152 if exists:
136 opening_post = Post.objects.get(global_id=op_global_id)
153 opening_post = Post.objects.get(global_id=op_global_id)
137 else:
154 else:
138 raise Exception('Load the OP first')
155 raise Exception('Load the OP first')
139 else:
156 else:
140 opening_post = None
157 opening_post = None
141 tag_tags = tag_content.find(TAG_TAGS)
158 tag_tags = tag_content.find(TAG_TAGS)
142 for tag_tag in tag_tags:
159 for tag_tag in tag_tags:
143 tag, created = Tag.objects.get_or_create(
160 tag, created = Tag.objects.get_or_create(
144 name=tag_tag.text)
161 name=tag_tag.text)
145 tags.append(tag)
162 tags.append(tag)
146
163
147 # TODO Check that the replied posts are already present
164 # TODO Check that the replied posts are already present
148 # before adding new ones
165 # before adding new ones
149
166
150 # TODO Get images
167 # TODO Get images
151
168
152 post = Post.objects.import_post(
169 post = Post.objects.import_post(
153 title=title, text=text, pub_time=pub_time,
170 title=title, text=text, pub_time=pub_time,
154 opening_post=opening_post, tags=tags,
171 opening_post=opening_post, tags=tags,
155 global_id=global_id)
172 global_id=global_id)
156 else:
173 else:
157 # TODO Throw an exception?
174 # TODO Throw an exception?
158 pass
175 pass
159
176
160 @staticmethod
177 @staticmethod
161 def generate_response_pull():
178 def generate_response_pull():
162 response = et.Element(TAG_RESPONSE)
179 response = et.Element(TAG_RESPONSE)
163
180
164 status = et.SubElement(response, TAG_STATUS)
181 status = et.SubElement(response, TAG_STATUS)
165 status.text = STATUS_SUCCESS
182 status.text = STATUS_SUCCESS
166
183
167 models = et.SubElement(response, TAG_MODELS)
184 models = et.SubElement(response, TAG_MODELS)
168
185
169 for post in Post.objects.all():
186 for post in Post.objects.all():
170 tag_id = et.SubElement(models, TAG_ID)
187 tag_id = et.SubElement(models, TAG_ID)
171 post.global_id.to_xml_element(tag_id)
188 post.global_id.to_xml_element(tag_id)
172
189
173 return et.tostring(response, ENCODING_UNICODE)
190 return et.tostring(response, ENCODING_UNICODE)
174
191
175 @staticmethod
192 @staticmethod
176 def _verify_model(tag_content, tag_model):
193 def _verify_model(tag_content, tag_model):
177 """
194 """
178 Verifies all signatures for a single model.
195 Verifies all signatures for a single model.
179 """
196 """
180
197
181 signatures = []
198 signatures = []
182
199
183 tag_signatures = tag_model.find(TAG_SIGNATURES)
200 tag_signatures = tag_model.find(TAG_SIGNATURES)
184 for tag_signature in tag_signatures:
201 for tag_signature in tag_signatures:
185 signature_type = tag_signature.get(ATTR_TYPE)
202 signature_type = tag_signature.get(ATTR_TYPE)
186 signature_value = tag_signature.get(ATTR_VALUE)
203 signature_value = tag_signature.get(ATTR_VALUE)
187 signature_key = tag_signature.get(ATTR_KEY)
204 signature_key = tag_signature.get(ATTR_KEY)
188
205
189 signature = Signature(key_type=signature_type,
206 signature = Signature(key_type=signature_type,
190 key=signature_key,
207 key=signature_key,
191 signature=signature_value)
208 signature=signature_value)
192
209
193 content = et.tostring(tag_content, ENCODING_UNICODE)
210 content = et.tostring(tag_content, ENCODING_UNICODE)
194
211
195 if not KeyPair.objects.verify(
212 if not KeyPair.objects.verify(
196 signature, content):
213 signature, content):
197 raise Exception('Invalid model signature for {}'.format(content))
214 raise Exception('Invalid model signature for {}'.format(content))
198
215
199 signatures.append(signature)
216 signatures.append(signature)
200
217
201 return signatures
218 return signatures
General Comments 0
You need to be logged in to leave comments. Login now