Show More
@@ -21,7 +21,7 b' class Command(BaseCommand):' | |||||
21 | parser.add_argument('url', type=str, help='Server root url') |
|
21 | parser.add_argument('url', type=str, help='Server root url') | |
22 | parser.add_argument('--global-id', type=str, default='', |
|
22 | parser.add_argument('--global-id', type=str, default='', | |
23 | help='Post global ID') |
|
23 | help='Post global ID') | |
24 |
parser.add_argument('--split-query', type=int, default=1 |
|
24 | parser.add_argument('--split-query', type=int, default=1, | |
25 | help='Split GET query into separate by the given' |
|
25 | help='Split GET query into separate by the given' | |
26 | ' number of posts in one') |
|
26 | ' number of posts in one') | |
27 |
|
27 |
@@ -138,7 +138,7 b' class PostManager(models.Manager):' | |||||
138 | @transaction.atomic |
|
138 | @transaction.atomic | |
139 | def import_post(self, title: str, text: str, pub_time: str, global_id, |
|
139 | def import_post(self, title: str, text: str, pub_time: str, global_id, | |
140 | opening_post=None, tags=list(), files=list(), |
|
140 | opening_post=None, tags=list(), files=list(), | |
141 | tripcode=None, version=1): |
|
141 | file_urls=list(), tripcode=None, version=1): | |
142 | is_opening = opening_post is None |
|
142 | is_opening = opening_post is None | |
143 | if is_opening: |
|
143 | if is_opening: | |
144 | thread = boards.models.thread.Thread.objects.create( |
|
144 | thread = boards.models.thread.Thread.objects.create( | |
@@ -160,6 +160,8 b' class PostManager(models.Manager):' | |||||
160 |
|
160 | |||
161 | for file in files: |
|
161 | for file in files: | |
162 | self._add_file_to_post(file, post) |
|
162 | self._add_file_to_post(file, post) | |
|
163 | for file_url in file_urls: | |||
|
164 | post.attachments.add(Attachment.objects.create_from_url(file_url)) | |||
163 |
|
165 | |||
164 | url_to_post = '[post]{}[/post]'.format(str(global_id)) |
|
166 | url_to_post = '[post]{}[/post]'.format(str(global_id)) | |
165 | replies = self.filter(text__contains=url_to_post) |
|
167 | replies = self.filter(text__contains=url_to_post) | |
@@ -168,7 +170,7 b' class PostManager(models.Manager):' | |||||
168 |
|
170 | |||
169 | @transaction.atomic |
|
171 | @transaction.atomic | |
170 | def update_post(self, post, title: str, text: str, pub_time: str, |
|
172 | def update_post(self, post, title: str, text: str, pub_time: str, | |
171 | tags=list(), files=list(), tripcode=None, version=1): |
|
173 | tags=list(), files=list(), file_urls=list(), tripcode=None, version=1): | |
172 | post.title = title |
|
174 | post.title = title | |
173 | post.text = text |
|
175 | post.text = text | |
174 | post.pub_time = pub_time |
|
176 | post.pub_time = pub_time | |
@@ -181,6 +183,8 b' class PostManager(models.Manager):' | |||||
181 | post.attachments.clear() |
|
183 | post.attachments.clear() | |
182 | for file in files: |
|
184 | for file in files: | |
183 | self._add_file_to_post(file, post) |
|
185 | self._add_file_to_post(file, post) | |
|
186 | for file_url in file_urls: | |||
|
187 | post.attachments.add(Attachment.objects.create_from_url(file_url)) | |||
184 |
|
188 | |||
185 | thread = post.get_thread() |
|
189 | thread = post.get_thread() | |
186 | thread.tags.clear() |
|
190 | thread.tags.clear() |
@@ -8,7 +8,6 b' from boards.utils import get_file_mimety' | |||||
8 | from django.db import transaction |
|
8 | from django.db import transaction | |
9 |
|
9 | |||
10 | EXCEPTION_NODE = 'Sync node returned an error: {}.' |
|
10 | EXCEPTION_NODE = 'Sync node returned an error: {}.' | |
11 | EXCEPTION_OP = 'Load the OP first.' |
|
|||
12 | EXCEPTION_DOWNLOAD = 'File was not downloaded.' |
|
11 | EXCEPTION_DOWNLOAD = 'File was not downloaded.' | |
13 | EXCEPTION_HASH = 'File hash does not match attachment hash.' |
|
12 | EXCEPTION_HASH = 'File hash does not match attachment hash.' | |
14 | EXCEPTION_SIGNATURE = 'Invalid model signature for {}.' |
|
13 | EXCEPTION_SIGNATURE = 'Invalid model signature for {}.' | |
@@ -165,96 +164,105 b' class SyncManager:' | |||||
165 | return et.tostring(response, ENCODING_UNICODE) |
|
164 | return et.tostring(response, ENCODING_UNICODE) | |
166 |
|
165 | |||
167 | @staticmethod |
|
166 | @staticmethod | |
168 | @transaction.atomic |
|
|||
169 | def parse_response_get(response_xml, hostname): |
|
167 | def parse_response_get(response_xml, hostname): | |
170 | tag_root = et.fromstring(response_xml) |
|
168 | tag_root = et.fromstring(response_xml) | |
171 | tag_status = tag_root.find(TAG_STATUS) |
|
169 | tag_status = tag_root.find(TAG_STATUS) | |
172 | if STATUS_SUCCESS == tag_status.text: |
|
170 | if STATUS_SUCCESS == tag_status.text: | |
173 | tag_models = tag_root.find(TAG_MODELS) |
|
171 | tag_models = tag_root.find(TAG_MODELS) | |
174 | for tag_model in tag_models: |
|
172 | for tag_model in tag_models: | |
175 | tag_content = tag_model.find(TAG_CONTENT) |
|
173 | SyncManager.parse_post(tag_model, hostname) | |
176 |
|
||||
177 | content_str = et.tostring(tag_content, ENCODING_UNICODE) |
|
|||
178 |
|
||||
179 | tag_id = tag_content.find(TAG_ID) |
|
|||
180 | global_id, exists = GlobalId.from_xml_element(tag_id) |
|
|||
181 | signatures = SyncManager._verify_model(global_id, content_str, tag_model) |
|
|||
182 |
|
||||
183 | version = int(tag_content.find(TAG_VERSION).text) |
|
|||
184 | is_old = exists and global_id.post.version < version |
|
|||
185 | if exists and not is_old: |
|
|||
186 | print('Post with same ID exists and is up to date.') |
|
|||
187 | else: |
|
|||
188 | global_id.content = content_str |
|
|||
189 | global_id.save() |
|
|||
190 | for signature in signatures: |
|
|||
191 | signature.global_id = global_id |
|
|||
192 | signature.save() |
|
|||
193 |
|
||||
194 | title = tag_content.find(TAG_TITLE).text or '' |
|
|||
195 | text = tag_content.find(TAG_TEXT).text or '' |
|
|||
196 | pub_time = tag_content.find(TAG_PUB_TIME).text |
|
|||
197 | tripcode_tag = tag_content.find(TAG_TRIPCODE) |
|
|||
198 | if tripcode_tag is not None: |
|
|||
199 | tripcode = tripcode_tag.text or '' |
|
|||
200 | else: |
|
|||
201 | tripcode = '' |
|
|||
202 |
|
||||
203 | thread = tag_content.find(TAG_THREAD) |
|
|||
204 | tags = [] |
|
|||
205 | if thread: |
|
|||
206 | thread_id = thread.find(TAG_ID) |
|
|||
207 | op_global_id, exists = GlobalId.from_xml_element(thread_id) |
|
|||
208 | if exists: |
|
|||
209 | opening_post = Post.objects.get(global_id=op_global_id) |
|
|||
210 | else: |
|
|||
211 | raise SyncException(EXCEPTION_OP) |
|
|||
212 | else: |
|
|||
213 | opening_post = None |
|
|||
214 | tag_tags = tag_content.find(TAG_TAGS) |
|
|||
215 | for tag_tag in tag_tags: |
|
|||
216 | tag, created = Tag.objects.get_or_create( |
|
|||
217 | name=tag_tag.text) |
|
|||
218 | tags.append(tag) |
|
|||
219 |
|
||||
220 | # TODO Check that the replied posts are already present |
|
|||
221 | # before adding new ones |
|
|||
222 |
|
||||
223 | files = [] |
|
|||
224 | tag_attachments = tag_content.find(TAG_ATTACHMENTS) or list() |
|
|||
225 | tag_refs = tag_model.find(TAG_ATTACHMENT_REFS) |
|
|||
226 | for attachment in tag_attachments: |
|
|||
227 | tag_ref = tag_refs.find("{}[@ref='{}']".format( |
|
|||
228 | TAG_ATTACHMENT_REF, attachment.text)) |
|
|||
229 | url = tag_ref.get(ATTR_URL) |
|
|||
230 | attached_file = download(hostname + url) |
|
|||
231 | if attached_file is None: |
|
|||
232 | raise SyncException(EXCEPTION_DOWNLOAD) |
|
|||
233 |
|
||||
234 | hash = get_file_hash(attached_file) |
|
|||
235 | if hash != attachment.text: |
|
|||
236 | raise SyncException(EXCEPTION_HASH) |
|
|||
237 |
|
||||
238 | files.append(attached_file) |
|
|||
239 |
|
||||
240 | if is_old: |
|
|||
241 | post = global_id.post |
|
|||
242 | Post.objects.update_post( |
|
|||
243 | post, title=title, text=text, pub_time=pub_time, |
|
|||
244 | tags=tags, files=files, tripcode=tripcode, |
|
|||
245 | version=version) |
|
|||
246 | logger.debug('Parsed updated post {}'.format(global_id)) |
|
|||
247 | else: |
|
|||
248 | Post.objects.import_post( |
|
|||
249 | title=title, text=text, pub_time=pub_time, |
|
|||
250 | opening_post=opening_post, tags=tags, |
|
|||
251 | global_id=global_id, files=files, tripcode=tripcode, |
|
|||
252 | version=version) |
|
|||
253 | logger.debug('Parsed new post {}'.format(global_id)) |
|
|||
254 | else: |
|
174 | else: | |
255 | raise SyncException(EXCEPTION_NODE.format(tag_status.text)) |
|
175 | raise SyncException(EXCEPTION_NODE.format(tag_status.text)) | |
256 |
|
176 | |||
257 | @staticmethod |
|
177 | @staticmethod | |
|
178 | @transaction.atomic | |||
|
179 | def parse_post(tag_model, hostname): | |||
|
180 | tag_content = tag_model.find(TAG_CONTENT) | |||
|
181 | ||||
|
182 | content_str = et.tostring(tag_content, ENCODING_UNICODE) | |||
|
183 | ||||
|
184 | tag_id = tag_content.find(TAG_ID) | |||
|
185 | global_id, exists = GlobalId.from_xml_element(tag_id) | |||
|
186 | signatures = SyncManager._verify_model(global_id, content_str, tag_model) | |||
|
187 | ||||
|
188 | version = int(tag_content.find(TAG_VERSION).text) | |||
|
189 | is_old = exists and global_id.post.version < version | |||
|
190 | if exists and not is_old: | |||
|
191 | print('Post with same ID exists and is up to date.') | |||
|
192 | else: | |||
|
193 | global_id.content = content_str | |||
|
194 | global_id.save() | |||
|
195 | for signature in signatures: | |||
|
196 | signature.global_id = global_id | |||
|
197 | signature.save() | |||
|
198 | ||||
|
199 | title = tag_content.find(TAG_TITLE).text or '' | |||
|
200 | text = tag_content.find(TAG_TEXT).text or '' | |||
|
201 | pub_time = tag_content.find(TAG_PUB_TIME).text | |||
|
202 | tripcode_tag = tag_content.find(TAG_TRIPCODE) | |||
|
203 | if tripcode_tag is not None: | |||
|
204 | tripcode = tripcode_tag.text or '' | |||
|
205 | else: | |||
|
206 | tripcode = '' | |||
|
207 | ||||
|
208 | thread = tag_content.find(TAG_THREAD) | |||
|
209 | tags = [] | |||
|
210 | if thread: | |||
|
211 | thread_id = thread.find(TAG_ID) | |||
|
212 | op_global_id, exists = GlobalId.from_xml_element(thread_id) | |||
|
213 | if exists: | |||
|
214 | opening_post = Post.objects.get(global_id=op_global_id) | |||
|
215 | else: | |||
|
216 | logger.debug('No thread exists for post {}'.format(global_id)) | |||
|
217 | else: | |||
|
218 | opening_post = None | |||
|
219 | tag_tags = tag_content.find(TAG_TAGS) | |||
|
220 | for tag_tag in tag_tags: | |||
|
221 | tag, created = Tag.objects.get_or_create( | |||
|
222 | name=tag_tag.text) | |||
|
223 | tags.append(tag) | |||
|
224 | ||||
|
225 | # TODO Check that the replied posts are already present | |||
|
226 | # before adding new ones | |||
|
227 | ||||
|
228 | files = [] | |||
|
229 | urls = [] | |||
|
230 | tag_attachments = tag_content.find(TAG_ATTACHMENTS) or list() | |||
|
231 | tag_refs = tag_model.find(TAG_ATTACHMENT_REFS) | |||
|
232 | for attachment in tag_attachments: | |||
|
233 | if attachment.get(ATTR_ID_TYPE) == ID_TYPE_URL: | |||
|
234 | urls.append(attachment.text) | |||
|
235 | else: | |||
|
236 | tag_ref = tag_refs.find("{}[@ref='{}']".format( | |||
|
237 | TAG_ATTACHMENT_REF, attachment.text)) | |||
|
238 | url = tag_ref.get(ATTR_URL) | |||
|
239 | attached_file = download(hostname + url) | |||
|
240 | if attached_file is None: | |||
|
241 | raise SyncException(EXCEPTION_DOWNLOAD) | |||
|
242 | ||||
|
243 | hash = get_file_hash(attached_file) | |||
|
244 | if hash != attachment.text: | |||
|
245 | raise SyncException(EXCEPTION_HASH) | |||
|
246 | ||||
|
247 | files.append(attached_file) | |||
|
248 | ||||
|
249 | if is_old: | |||
|
250 | post = global_id.post | |||
|
251 | Post.objects.update_post( | |||
|
252 | post, title=title, text=text, pub_time=pub_time, | |||
|
253 | tags=tags, files=files, file_urls=urls, | |||
|
254 | tripcode=tripcode, version=version) | |||
|
255 | logger.debug('Parsed updated post {}'.format(global_id)) | |||
|
256 | else: | |||
|
257 | Post.objects.import_post( | |||
|
258 | title=title, text=text, pub_time=pub_time, | |||
|
259 | opening_post=opening_post, tags=tags, | |||
|
260 | global_id=global_id, files=files, | |||
|
261 | file_urls=urls, tripcode=tripcode, | |||
|
262 | version=version) | |||
|
263 | logger.debug('Parsed new post {}'.format(global_id)) | |||
|
264 | ||||
|
265 | @staticmethod | |||
258 | def generate_response_list(): |
|
266 | def generate_response_list(): | |
259 | response = et.Element(TAG_RESPONSE) |
|
267 | response = et.Element(TAG_RESPONSE) | |
260 |
|
268 |
@@ -152,6 +152,7 b' Sample response:' | |||||
152 | --> |
|
152 | --> | |
153 | <attachments> |
|
153 | <attachments> | |
154 | <attachment mimetype="image/png" id-type="md5">TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5I</attachment> |
|
154 | <attachment mimetype="image/png" id-type="md5">TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5I</attachment> | |
|
155 | <attachment id-type="url">http://example.com/</attachment> | |||
155 | </attachments> |
|
156 | </attachments> | |
156 | </content> |
|
157 | </content> | |
157 | <!-- |
|
158 | <!-- |
General Comments 0
You need to be logged in to leave comments.
Login now