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