##// END OF EJS Templates
Added PULL protocol method implementation without any filters
neko259 -
r1321:055856f7 decentral
parent child Browse files
Show More
@@ -1,59 +1,59 b''
1 import re
1 import re
2 import urllib.parse
3 import httplib2
4 import xml.etree.ElementTree as ET
2 import xml.etree.ElementTree as ET
5
3
4 import httplib2
6 from django.core.management import BaseCommand
5 from django.core.management import BaseCommand
6
7 from boards.models import GlobalId
7 from boards.models import GlobalId
8 from boards.models.post.sync import SyncManager
8 from boards.models.post.sync import SyncManager
9
9
10 __author__ = 'neko259'
10 __author__ = 'neko259'
11
11
12
12
13 REGEX_GLOBAL_ID = re.compile(r'(\w+)::([\w\+/]+)::(\d+)')
13 REGEX_GLOBAL_ID = re.compile(r'(\w+)::([\w\+/]+)::(\d+)')
14
14
15
15
16 class Command(BaseCommand):
16 class Command(BaseCommand):
17 help = 'Send a sync or get request to the server.' + \
17 help = 'Send a sync or get request to the server.'
18 'sync_with_server <server_url> [post_global_id]'
19
18
20 def add_arguments(self, parser):
19 def add_arguments(self, parser):
21 parser.add_argument('url', type=str)
20 parser.add_argument('url', type=str)
22 parser.add_argument('global_id', type=str)
21 parser.add_argument('--global_id', type=str, default='',
22 help='Post global ID')
23
23
24 def handle(self, *args, **options):
24 def handle(self, *args, **options):
25 url = options.get('url')
25 url = options.get('url')
26 global_id_str = options.get('global_id')
26 global_id_str = options.get('global_id')
27 if global_id_str:
27 if global_id_str:
28 match = REGEX_GLOBAL_ID.match(global_id_str)
28 match = REGEX_GLOBAL_ID.match(global_id_str)
29 if match:
29 if match:
30 key_type = match.group(1)
30 key_type = match.group(1)
31 key = match.group(2)
31 key = match.group(2)
32 local_id = match.group(3)
32 local_id = match.group(3)
33
33
34 global_id = GlobalId(key_type=key_type, key=key,
34 global_id = GlobalId(key_type=key_type, key=key,
35 local_id=local_id)
35 local_id=local_id)
36
36
37 xml = GlobalId.objects.generate_request_get([global_id])
37 xml = GlobalId.objects.generate_request_get([global_id])
38 # body = urllib.parse.urlencode(data)
38 # body = urllib.parse.urlencode(data)
39 h = httplib2.Http()
39 h = httplib2.Http()
40 response, content = h.request(url, method="POST", body=xml)
40 response, content = h.request(url, method="POST", body=xml)
41
41
42 SyncManager.parse_response_get(content)
42 SyncManager.parse_response_get(content)
43 else:
43 else:
44 raise Exception('Invalid global ID')
44 raise Exception('Invalid global ID')
45 else:
45 else:
46 h = httplib2.Http()
46 h = httplib2.Http()
47 response, content = h.request(url, method="POST")
47 xml = GlobalId.objects.generate_request_pull()
48 response, content = h.request(url, method="POST", body=xml)
48
49
49 print(content)
50 print(content)
50
51
51 root = ET.fromstring(content)
52 root = ET.fromstring(content)
52 status = root.findall('status')[0].text
53 status = root.findall('status')[0].text
53 if status == 'success':
54 if status == 'success':
54 models = root.findall('models')[0]
55 models = root.findall('models')[0]
55 for model in models:
56 for model in models:
56 model_content = model[0]
57 print(ET.tostring(model))
57 print(model_content.findall('text')[0].text)
58 else:
58 else:
59 raise Exception('Invalid response status')
59 raise Exception('Invalid response status')
@@ -1,175 +1,190 b''
1 import xml.etree.ElementTree as et
1 import xml.etree.ElementTree as et
2 from django.db import transaction
2 from django.db import transaction
3 from boards.models import KeyPair, GlobalId, Signature, Post, Tag
3 from boards.models import KeyPair, GlobalId, Signature, Post, Tag
4
4
5 ENCODING_UNICODE = 'unicode'
5 ENCODING_UNICODE = 'unicode'
6
6
7 TAG_MODEL = 'model'
7 TAG_MODEL = 'model'
8 TAG_REQUEST = 'request'
8 TAG_REQUEST = 'request'
9 TAG_RESPONSE = 'response'
9 TAG_RESPONSE = 'response'
10 TAG_ID = 'id'
10 TAG_ID = 'id'
11 TAG_STATUS = 'status'
11 TAG_STATUS = 'status'
12 TAG_MODELS = 'models'
12 TAG_MODELS = 'models'
13 TAG_TITLE = 'title'
13 TAG_TITLE = 'title'
14 TAG_TEXT = 'text'
14 TAG_TEXT = 'text'
15 TAG_THREAD = 'thread'
15 TAG_THREAD = 'thread'
16 TAG_PUB_TIME = 'pub-time'
16 TAG_PUB_TIME = 'pub-time'
17 TAG_SIGNATURES = 'signatures'
17 TAG_SIGNATURES = 'signatures'
18 TAG_SIGNATURE = 'signature'
18 TAG_SIGNATURE = 'signature'
19 TAG_CONTENT = 'content'
19 TAG_CONTENT = 'content'
20 TAG_ATTACHMENTS = 'attachments'
20 TAG_ATTACHMENTS = 'attachments'
21 TAG_ATTACHMENT = 'attachment'
21 TAG_ATTACHMENT = 'attachment'
22 TAG_TAGS = 'tags'
22 TAG_TAGS = 'tags'
23 TAG_TAG = 'tag'
23 TAG_TAG = 'tag'
24
24
25 TYPE_GET = 'get'
25 TYPE_GET = 'get'
26
26
27 ATTR_VERSION = 'version'
27 ATTR_VERSION = 'version'
28 ATTR_TYPE = 'type'
28 ATTR_TYPE = 'type'
29 ATTR_NAME = 'name'
29 ATTR_NAME = 'name'
30 ATTR_VALUE = 'value'
30 ATTR_VALUE = 'value'
31 ATTR_MIMETYPE = 'mimetype'
31 ATTR_MIMETYPE = 'mimetype'
32 ATTR_KEY = 'key'
32 ATTR_KEY = 'key'
33
33
34 STATUS_SUCCESS = 'success'
34 STATUS_SUCCESS = 'success'
35
35
36
36
37 class SyncManager:
37 class SyncManager:
38 @staticmethod
38 @staticmethod
39 def generate_response_get(model_list: list):
39 def generate_response_get(model_list: list):
40 response = et.Element(TAG_RESPONSE)
40 response = et.Element(TAG_RESPONSE)
41
41
42 status = et.SubElement(response, TAG_STATUS)
42 status = et.SubElement(response, TAG_STATUS)
43 status.text = STATUS_SUCCESS
43 status.text = STATUS_SUCCESS
44
44
45 models = et.SubElement(response, TAG_MODELS)
45 models = et.SubElement(response, TAG_MODELS)
46
46
47 for post in model_list:
47 for post in model_list:
48 model = et.SubElement(models, TAG_MODEL)
48 model = et.SubElement(models, TAG_MODEL)
49 model.set(ATTR_NAME, 'post')
49 model.set(ATTR_NAME, 'post')
50
50
51 content_tag = et.SubElement(model, TAG_CONTENT)
51 content_tag = et.SubElement(model, TAG_CONTENT)
52
52
53 tag_id = et.SubElement(content_tag, TAG_ID)
53 tag_id = et.SubElement(content_tag, TAG_ID)
54 post.global_id.to_xml_element(tag_id)
54 post.global_id.to_xml_element(tag_id)
55
55
56 title = et.SubElement(content_tag, TAG_TITLE)
56 title = et.SubElement(content_tag, TAG_TITLE)
57 title.text = post.title
57 title.text = post.title
58
58
59 text = et.SubElement(content_tag, TAG_TEXT)
59 text = et.SubElement(content_tag, TAG_TEXT)
60 text.text = post.get_sync_text()
60 text.text = post.get_sync_text()
61
61
62 thread = post.get_thread()
62 thread = post.get_thread()
63 if post.is_opening():
63 if post.is_opening():
64 tag_tags = et.SubElement(content_tag, TAG_TAGS)
64 tag_tags = et.SubElement(content_tag, TAG_TAGS)
65 for tag in thread.get_tags():
65 for tag in thread.get_tags():
66 tag_tag = et.SubElement(tag_tags, TAG_TAG)
66 tag_tag = et.SubElement(tag_tags, TAG_TAG)
67 tag_tag.text = tag.name
67 tag_tag.text = tag.name
68 else:
68 else:
69 tag_thread = et.SubElement(content_tag, TAG_THREAD)
69 tag_thread = et.SubElement(content_tag, TAG_THREAD)
70 thread_id = et.SubElement(tag_thread, TAG_ID)
70 thread_id = et.SubElement(tag_thread, TAG_ID)
71 thread.get_opening_post().global_id.to_xml_element(thread_id)
71 thread.get_opening_post().global_id.to_xml_element(thread_id)
72
72
73 pub_time = et.SubElement(content_tag, TAG_PUB_TIME)
73 pub_time = et.SubElement(content_tag, TAG_PUB_TIME)
74 pub_time.text = str(post.get_pub_time_str())
74 pub_time.text = str(post.get_pub_time_str())
75
75
76 signatures_tag = et.SubElement(model, TAG_SIGNATURES)
76 signatures_tag = et.SubElement(model, TAG_SIGNATURES)
77 post_signatures = post.global_id.signature_set.all()
77 post_signatures = post.global_id.signature_set.all()
78 if post_signatures:
78 if post_signatures:
79 signatures = post_signatures
79 signatures = post_signatures
80 # TODO Adding signature to a post is not yet added. For now this
80 # TODO Adding signature to a post is not yet added. For now this
81 # block is useless
81 # block is useless
82 else:
82 else:
83 # TODO Maybe the signature can be computed only once after
83 # TODO Maybe the signature can be computed only once after
84 # the post is added? Need to add some on_save signal queue
84 # the post is added? Need to add some on_save signal queue
85 # and add this there.
85 # and add this there.
86 key = KeyPair.objects.get(public_key=post.global_id.key)
86 key = KeyPair.objects.get(public_key=post.global_id.key)
87 signatures = [Signature(
87 signatures = [Signature(
88 key_type=key.key_type,
88 key_type=key.key_type,
89 key=key.public_key,
89 key=key.public_key,
90 signature=key.sign(et.tostring(content_tag, ENCODING_UNICODE)),
90 signature=key.sign(et.tostring(content_tag, ENCODING_UNICODE)),
91 )]
91 )]
92 for signature in signatures:
92 for signature in signatures:
93 signature_tag = et.SubElement(signatures_tag, TAG_SIGNATURE)
93 signature_tag = et.SubElement(signatures_tag, TAG_SIGNATURE)
94 signature_tag.set(ATTR_TYPE, signature.key_type)
94 signature_tag.set(ATTR_TYPE, signature.key_type)
95 signature_tag.set(ATTR_VALUE, signature.signature)
95 signature_tag.set(ATTR_VALUE, signature.signature)
96 signature_tag.set(ATTR_KEY, signature.key)
96 signature_tag.set(ATTR_KEY, signature.key)
97
97
98 return et.tostring(response, ENCODING_UNICODE)
98 return et.tostring(response, ENCODING_UNICODE)
99
99
100 @staticmethod
100 @staticmethod
101 @transaction.atomic
101 @transaction.atomic
102 def parse_response_get(response_xml):
102 def parse_response_get(response_xml):
103 tag_root = et.fromstring(response_xml)
103 tag_root = et.fromstring(response_xml)
104 tag_status = tag_root.find(TAG_STATUS)
104 tag_status = tag_root.find(TAG_STATUS)
105 if STATUS_SUCCESS == tag_status.text:
105 if STATUS_SUCCESS == tag_status.text:
106 tag_models = tag_root.find(TAG_MODELS)
106 tag_models = tag_root.find(TAG_MODELS)
107 for tag_model in tag_models:
107 for tag_model in tag_models:
108 tag_content = tag_model.find(TAG_CONTENT)
108 tag_content = tag_model.find(TAG_CONTENT)
109
109
110 signatures = SyncManager._verify_model(tag_content, tag_model)
110 signatures = SyncManager._verify_model(tag_content, tag_model)
111
111
112 tag_id = tag_content.find(TAG_ID)
112 tag_id = tag_content.find(TAG_ID)
113 global_id, exists = GlobalId.from_xml_element(tag_id)
113 global_id, exists = GlobalId.from_xml_element(tag_id)
114
114
115 if exists:
115 if exists:
116 print('Post with same ID already exists')
116 print('Post with same ID already exists')
117 else:
117 else:
118 global_id.save()
118 global_id.save()
119 for signature in signatures:
119 for signature in signatures:
120 signature.global_id = global_id
120 signature.global_id = global_id
121 signature.save()
121 signature.save()
122
122
123 title = tag_content.find(TAG_TITLE).text
123 title = tag_content.find(TAG_TITLE).text
124 text = tag_content.find(TAG_TEXT).text
124 text = tag_content.find(TAG_TEXT).text
125 pub_time = tag_content.find(TAG_PUB_TIME).text
125 pub_time = tag_content.find(TAG_PUB_TIME).text
126
126
127 thread = tag_content.find(TAG_THREAD)
127 thread = tag_content.find(TAG_THREAD)
128 tags = []
128 tags = []
129 if thread:
129 if thread:
130 opening_post = Post.objects.get(
130 opening_post = Post.objects.get(
131 id=thread.find(TAG_ID).text)
131 id=thread.find(TAG_ID).text)
132 else:
132 else:
133 opening_post = None
133 opening_post = None
134 tag_tags = tag_content.find(TAG_TAGS)
134 tag_tags = tag_content.find(TAG_TAGS)
135 for tag_tag in tag_tags:
135 for tag_tag in tag_tags:
136 tag, created = Tag.objects.get_or_create(name=tag_tag.text)
136 tag, created = Tag.objects.get_or_create(name=tag_tag.text)
137 tags.append(tag)
137 tags.append(tag)
138
138
139 # TODO Check that the replied posts are already present
139 # TODO Check that the replied posts are already present
140 # before adding new ones
140 # before adding new ones
141
141
142 # TODO Get images
142 # TODO Get images
143
143
144 post = Post.objects.import_post(
144 post = Post.objects.import_post(
145 title=title, text=text, pub_time=pub_time,
145 title=title, text=text, pub_time=pub_time,
146 opening_post=opening_post, tags=tags,
146 opening_post=opening_post, tags=tags,
147 global_id=global_id)
147 global_id=global_id)
148 else:
148 else:
149 # TODO Throw an exception?
149 # TODO Throw an exception?
150 pass
150 pass
151
151
152 @staticmethod
152 @staticmethod
153 def generate_response_pull():
154 response = et.Element(TAG_RESPONSE)
155
156 status = et.SubElement(response, TAG_STATUS)
157 status.text = STATUS_SUCCESS
158
159 models = et.SubElement(response, TAG_MODELS)
160
161 for post in Post.objects.all():
162 tag_id = et.SubElement(models, TAG_ID)
163 post.global_id.to_xml_element(tag_id)
164
165 return et.tostring(response, ENCODING_UNICODE)
166
167 @staticmethod
153 def _verify_model(tag_content, tag_model):
168 def _verify_model(tag_content, tag_model):
154 """
169 """
155 Verifies all signatures for a single model.
170 Verifies all signatures for a single model.
156 """
171 """
157
172
158 signatures = []
173 signatures = []
159
174
160 tag_signatures = tag_model.find(TAG_SIGNATURES)
175 tag_signatures = tag_model.find(TAG_SIGNATURES)
161 for tag_signature in tag_signatures:
176 for tag_signature in tag_signatures:
162 signature_type = tag_signature.get(ATTR_TYPE)
177 signature_type = tag_signature.get(ATTR_TYPE)
163 signature_value = tag_signature.get(ATTR_VALUE)
178 signature_value = tag_signature.get(ATTR_VALUE)
164 signature_key = tag_signature.get(ATTR_KEY)
179 signature_key = tag_signature.get(ATTR_KEY)
165
180
166 signature = Signature(key_type=signature_type,
181 signature = Signature(key_type=signature_type,
167 key=signature_key,
182 key=signature_key,
168 signature=signature_value)
183 signature=signature_value)
169 signatures.append(signature)
184 signatures.append(signature)
170
185
171 if not KeyPair.objects.verify(
186 if not KeyPair.objects.verify(
172 signature, et.tostring(tag_content, ENCODING_UNICODE)):
187 signature, et.tostring(tag_content, ENCODING_UNICODE)):
173 raise Exception('Invalid model signature')
188 raise Exception('Invalid model signature')
174
189
175 return signatures
190 return signatures
@@ -1,121 +1,137 b''
1 import xml.etree.ElementTree as et
1 import xml.etree.ElementTree as et
2 from django.db import models
2 from django.db import models
3
3
4
4
5 TAG_MODEL = 'model'
5 TAG_MODEL = 'model'
6 TAG_REQUEST = 'request'
6 TAG_REQUEST = 'request'
7 TAG_ID = 'id'
7 TAG_ID = 'id'
8
8
9 TYPE_GET = 'get'
9 TYPE_GET = 'get'
10 TYPE_PULL = 'pull'
10
11
11 ATTR_VERSION = 'version'
12 ATTR_VERSION = 'version'
12 ATTR_TYPE = 'type'
13 ATTR_TYPE = 'type'
13 ATTR_NAME = 'name'
14 ATTR_NAME = 'name'
14
15
15 ATTR_KEY = 'key'
16 ATTR_KEY = 'key'
16 ATTR_KEY_TYPE = 'type'
17 ATTR_KEY_TYPE = 'type'
17 ATTR_LOCAL_ID = 'local-id'
18 ATTR_LOCAL_ID = 'local-id'
18
19
19
20
20 class GlobalIdManager(models.Manager):
21 class GlobalIdManager(models.Manager):
21 def generate_request_get(self, global_id_list: list):
22 def generate_request_get(self, global_id_list: list):
22 """
23 """
23 Form a get request from a list of ModelId objects.
24 Form a get request from a list of ModelId objects.
24 """
25 """
25
26
26 request = et.Element(TAG_REQUEST)
27 request = et.Element(TAG_REQUEST)
27 request.set(ATTR_TYPE, TYPE_GET)
28 request.set(ATTR_TYPE, TYPE_GET)
28 request.set(ATTR_VERSION, '1.0')
29 request.set(ATTR_VERSION, '1.0')
29
30
30 model = et.SubElement(request, TAG_MODEL)
31 model = et.SubElement(request, TAG_MODEL)
31 model.set(ATTR_VERSION, '1.0')
32 model.set(ATTR_VERSION, '1.0')
32 model.set(ATTR_NAME, 'post')
33 model.set(ATTR_NAME, 'post')
33
34
34 for global_id in global_id_list:
35 for global_id in global_id_list:
35 tag_id = et.SubElement(model, TAG_ID)
36 tag_id = et.SubElement(model, TAG_ID)
36 global_id.to_xml_element(tag_id)
37 global_id.to_xml_element(tag_id)
37
38
38 return et.tostring(request, 'unicode')
39 return et.tostring(request, 'unicode')
39
40
41 def generate_request_pull(self):
42 """
43 Form a pull request from a list of ModelId objects.
44 """
45
46 request = et.Element(TAG_REQUEST)
47 request.set(ATTR_TYPE, TYPE_PULL)
48 request.set(ATTR_VERSION, '1.0')
49
50 model = et.SubElement(request, TAG_MODEL)
51 model.set(ATTR_VERSION, '1.0')
52 model.set(ATTR_NAME, 'post')
53
54 return et.tostring(request, 'unicode')
55
40 def global_id_exists(self, global_id):
56 def global_id_exists(self, global_id):
41 """
57 """
42 Checks if the same global id already exists in the system.
58 Checks if the same global id already exists in the system.
43 """
59 """
44
60
45 return self.filter(key=global_id.key,
61 return self.filter(key=global_id.key,
46 key_type=global_id.key_type,
62 key_type=global_id.key_type,
47 local_id=global_id.local_id).exists()
63 local_id=global_id.local_id).exists()
48
64
49
65
50 class GlobalId(models.Model):
66 class GlobalId(models.Model):
51 class Meta:
67 class Meta:
52 app_label = 'boards'
68 app_label = 'boards'
53
69
54 objects = GlobalIdManager()
70 objects = GlobalIdManager()
55
71
56 def __init__(self, *args, **kwargs):
72 def __init__(self, *args, **kwargs):
57 models.Model.__init__(self, *args, **kwargs)
73 models.Model.__init__(self, *args, **kwargs)
58
74
59 if 'key' in kwargs and 'key_type' in kwargs and 'local_id' in kwargs:
75 if 'key' in kwargs and 'key_type' in kwargs and 'local_id' in kwargs:
60 self.key = kwargs['key']
76 self.key = kwargs['key']
61 self.key_type = kwargs['key_type']
77 self.key_type = kwargs['key_type']
62 self.local_id = kwargs['local_id']
78 self.local_id = kwargs['local_id']
63
79
64 key = models.TextField()
80 key = models.TextField()
65 key_type = models.TextField()
81 key_type = models.TextField()
66 local_id = models.IntegerField()
82 local_id = models.IntegerField()
67
83
68 def __str__(self):
84 def __str__(self):
69 return '%s::%s::%d' % (self.key_type, self.key, self.local_id)
85 return '%s::%s::%d' % (self.key_type, self.key, self.local_id)
70
86
71 def to_xml_element(self, element: et.Element):
87 def to_xml_element(self, element: et.Element):
72 """
88 """
73 Exports global id to an XML element.
89 Exports global id to an XML element.
74 """
90 """
75
91
76 element.set(ATTR_KEY, self.key)
92 element.set(ATTR_KEY, self.key)
77 element.set(ATTR_KEY_TYPE, self.key_type)
93 element.set(ATTR_KEY_TYPE, self.key_type)
78 element.set(ATTR_LOCAL_ID, str(self.local_id))
94 element.set(ATTR_LOCAL_ID, str(self.local_id))
79
95
80 @staticmethod
96 @staticmethod
81 def from_xml_element(element: et.Element):
97 def from_xml_element(element: et.Element):
82 """
98 """
83 Parses XML id tag and gets global id from it.
99 Parses XML id tag and gets global id from it.
84
100
85 Arguments:
101 Arguments:
86 element -- the XML 'id' element
102 element -- the XML 'id' element
87
103
88 Returns:
104 Returns:
89 global_id -- id itself
105 global_id -- id itself
90 exists -- True if the global id was taken from database, False if it
106 exists -- True if the global id was taken from database, False if it
91 did not exist and was created.
107 did not exist and was created.
92 """
108 """
93
109
94 try:
110 try:
95 return GlobalId.objects.get(key=element.get(ATTR_KEY),
111 return GlobalId.objects.get(key=element.get(ATTR_KEY),
96 key_type=element.get(ATTR_KEY_TYPE),
112 key_type=element.get(ATTR_KEY_TYPE),
97 local_id=int(element.get(
113 local_id=int(element.get(
98 ATTR_LOCAL_ID))), True
114 ATTR_LOCAL_ID))), True
99 except GlobalId.DoesNotExist:
115 except GlobalId.DoesNotExist:
100 return GlobalId(key=element.get(ATTR_KEY),
116 return GlobalId(key=element.get(ATTR_KEY),
101 key_type=element.get(ATTR_KEY_TYPE),
117 key_type=element.get(ATTR_KEY_TYPE),
102 local_id=int(element.get(ATTR_LOCAL_ID))), False
118 local_id=int(element.get(ATTR_LOCAL_ID))), False
103
119
104
120
105 class Signature(models.Model):
121 class Signature(models.Model):
106 class Meta:
122 class Meta:
107 app_label = 'boards'
123 app_label = 'boards'
108
124
109 def __init__(self, *args, **kwargs):
125 def __init__(self, *args, **kwargs):
110 models.Model.__init__(self, *args, **kwargs)
126 models.Model.__init__(self, *args, **kwargs)
111
127
112 if 'key' in kwargs and 'key_type' in kwargs and 'signature' in kwargs:
128 if 'key' in kwargs and 'key_type' in kwargs and 'signature' in kwargs:
113 self.key_type = kwargs['key_type']
129 self.key_type = kwargs['key_type']
114 self.key = kwargs['key']
130 self.key = kwargs['key']
115 self.signature = kwargs['signature']
131 self.signature = kwargs['signature']
116
132
117 key_type = models.TextField()
133 key_type = models.TextField()
118 key = models.TextField()
134 key = models.TextField()
119 signature = models.TextField()
135 signature = models.TextField()
120
136
121 global_id = models.ForeignKey('GlobalId')
137 global_id = models.ForeignKey('GlobalId')
@@ -1,91 +1,91 b''
1 from django.conf.urls import patterns, url
1 from django.conf.urls import patterns, url
2 from django.views.i18n import javascript_catalog
2 from django.views.i18n import javascript_catalog
3
3
4 from boards import views
4 from boards import views
5 from boards.rss import AllThreadsFeed, TagThreadsFeed, ThreadPostsFeed
5 from boards.rss import AllThreadsFeed, TagThreadsFeed, ThreadPostsFeed
6 from boards.views import api, tag_threads, all_threads, \
6 from boards.views import api, tag_threads, all_threads, \
7 settings, all_tags, feed
7 settings, all_tags, feed
8 from boards.views.authors import AuthorsView
8 from boards.views.authors import AuthorsView
9 from boards.views.notifications import NotificationView
9 from boards.views.notifications import NotificationView
10 from boards.views.search import BoardSearchView
10 from boards.views.search import BoardSearchView
11 from boards.views.static import StaticPageView
11 from boards.views.static import StaticPageView
12 from boards.views.preview import PostPreviewView
12 from boards.views.preview import PostPreviewView
13 from boards.views.sync import get_post_sync_data, response_get
13 from boards.views.sync import get_post_sync_data, response_get, response_pull
14 from boards.views.random import RandomImageView
14 from boards.views.random import RandomImageView
15
15
16
16
17 js_info_dict = {
17 js_info_dict = {
18 'packages': ('boards',),
18 'packages': ('boards',),
19 }
19 }
20
20
21 urlpatterns = patterns('',
21 urlpatterns = patterns('',
22 # /boards/
22 # /boards/
23 url(r'^$', all_threads.AllThreadsView.as_view(), name='index'),
23 url(r'^$', all_threads.AllThreadsView.as_view(), name='index'),
24
24
25 # /boards/tag/tag_name/
25 # /boards/tag/tag_name/
26 url(r'^tag/(?P<tag_name>\w+)/$', tag_threads.TagView.as_view(),
26 url(r'^tag/(?P<tag_name>\w+)/$', tag_threads.TagView.as_view(),
27 name='tag'),
27 name='tag'),
28
28
29 # /boards/thread/
29 # /boards/thread/
30 url(r'^thread/(?P<post_id>\d+)/$', views.thread.NormalThreadView.as_view(),
30 url(r'^thread/(?P<post_id>\d+)/$', views.thread.NormalThreadView.as_view(),
31 name='thread'),
31 name='thread'),
32 url(r'^thread/(?P<post_id>\d+)/mode/gallery/$', views.thread.GalleryThreadView.as_view(),
32 url(r'^thread/(?P<post_id>\d+)/mode/gallery/$', views.thread.GalleryThreadView.as_view(),
33 name='thread_gallery'),
33 name='thread_gallery'),
34 url(r'^thread/(?P<post_id>\d+)/mode/tree/$', views.thread.TreeThreadView.as_view(),
34 url(r'^thread/(?P<post_id>\d+)/mode/tree/$', views.thread.TreeThreadView.as_view(),
35 name='thread_tree'),
35 name='thread_tree'),
36 # /feed/
36 # /feed/
37 url(r'^feed/$', views.feed.FeedView.as_view(), name='feed'),
37 url(r'^feed/$', views.feed.FeedView.as_view(), name='feed'),
38
38
39 url(r'^settings/$', settings.SettingsView.as_view(), name='settings'),
39 url(r'^settings/$', settings.SettingsView.as_view(), name='settings'),
40 url(r'^tags/(?P<query>\w+)?/?$', all_tags.AllTagsView.as_view(), name='tags'),
40 url(r'^tags/(?P<query>\w+)?/?$', all_tags.AllTagsView.as_view(), name='tags'),
41 url(r'^authors/$', AuthorsView.as_view(), name='authors'),
41 url(r'^authors/$', AuthorsView.as_view(), name='authors'),
42
42
43 url(r'^banned/$', views.banned.BannedView.as_view(), name='banned'),
43 url(r'^banned/$', views.banned.BannedView.as_view(), name='banned'),
44 url(r'^staticpage/(?P<name>\w+)/$', StaticPageView.as_view(),
44 url(r'^staticpage/(?P<name>\w+)/$', StaticPageView.as_view(),
45 name='staticpage'),
45 name='staticpage'),
46
46
47 url(r'^random/$', RandomImageView.as_view(), name='random'),
47 url(r'^random/$', RandomImageView.as_view(), name='random'),
48
48
49 # RSS feeds
49 # RSS feeds
50 url(r'^rss/$', AllThreadsFeed()),
50 url(r'^rss/$', AllThreadsFeed()),
51 url(r'^page/(?P<page>\d+)/rss/$', AllThreadsFeed()),
51 url(r'^page/(?P<page>\d+)/rss/$', AllThreadsFeed()),
52 url(r'^tag/(?P<tag_name>\w+)/rss/$', TagThreadsFeed()),
52 url(r'^tag/(?P<tag_name>\w+)/rss/$', TagThreadsFeed()),
53 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/rss/$', TagThreadsFeed()),
53 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/rss/$', TagThreadsFeed()),
54 url(r'^thread/(?P<post_id>\d+)/rss/$', ThreadPostsFeed()),
54 url(r'^thread/(?P<post_id>\d+)/rss/$', ThreadPostsFeed()),
55
55
56 # i18n
56 # i18n
57 url(r'^jsi18n/$', javascript_catalog, js_info_dict,
57 url(r'^jsi18n/$', javascript_catalog, js_info_dict,
58 name='js_info_dict'),
58 name='js_info_dict'),
59
59
60 # API
60 # API
61 url(r'^api/post/(?P<post_id>\d+)/$', api.get_post, name="get_post"),
61 url(r'^api/post/(?P<post_id>\d+)/$', api.get_post, name="get_post"),
62 url(r'^api/diff_thread/$', api.api_get_threaddiff, name="get_thread_diff"),
62 url(r'^api/diff_thread/$', api.api_get_threaddiff, name="get_thread_diff"),
63 url(r'^api/threads/(?P<count>\w+)/$', api.api_get_threads,
63 url(r'^api/threads/(?P<count>\w+)/$', api.api_get_threads,
64 name='get_threads'),
64 name='get_threads'),
65 url(r'^api/tags/$', api.api_get_tags, name='get_tags'),
65 url(r'^api/tags/$', api.api_get_tags, name='get_tags'),
66 url(r'^api/thread/(?P<opening_post_id>\w+)/$', api.api_get_thread_posts,
66 url(r'^api/thread/(?P<opening_post_id>\w+)/$', api.api_get_thread_posts,
67 name='get_thread'),
67 name='get_thread'),
68 url(r'^api/add_post/(?P<opening_post_id>\w+)/$', api.api_add_post,
68 url(r'^api/add_post/(?P<opening_post_id>\w+)/$', api.api_add_post,
69 name='add_post'),
69 name='add_post'),
70 url(r'^api/notifications/(?P<username>\w+)/$', api.api_get_notifications,
70 url(r'^api/notifications/(?P<username>\w+)/$', api.api_get_notifications,
71 name='api_notifications'),
71 name='api_notifications'),
72 url(r'^api/preview/$', api.api_get_preview, name='preview'),
72 url(r'^api/preview/$', api.api_get_preview, name='preview'),
73
73
74 # Sync protocol API
74 # Sync protocol API
75 url(r'^api/sync/pull/$', api.sync_pull, name='api_sync_pull'),
75 url(r'^api/sync/pull/$', response_pull, name='api_sync_pull'),
76 url(r'^api/sync/get/$', response_get, name='api_sync_pull'),
76 url(r'^api/sync/get/$', response_get, name='api_sync_pull'),
77 # TODO 'get' request
77 # TODO 'get' request
78
78
79 # Search
79 # Search
80 url(r'^search/$', BoardSearchView.as_view(), name='search'),
80 url(r'^search/$', BoardSearchView.as_view(), name='search'),
81
81
82 # Notifications
82 # Notifications
83 url(r'^notifications/(?P<username>\w+)$', NotificationView.as_view(), name='notifications'),
83 url(r'^notifications/(?P<username>\w+)$', NotificationView.as_view(), name='notifications'),
84
84
85 # Post preview
85 # Post preview
86 url(r'^preview/$', PostPreviewView.as_view(), name='preview'),
86 url(r'^preview/$', PostPreviewView.as_view(), name='preview'),
87
87
88 url(r'^post_xml/(?P<post_id>\d+)$', get_post_sync_data,
88 url(r'^post_xml/(?P<post_id>\d+)$', get_post_sync_data,
89 name='post_sync_data'),
89 name='post_sync_data'),
90
90
91 )
91 )
@@ -1,258 +1,243 b''
1 import json
1 import json
2 import logging
2 import logging
3
3
4 import xml.etree.ElementTree as ET
4 import xml.etree.ElementTree as ET
5
5
6 from django.db import transaction
6 from django.db import transaction
7 from django.http import HttpResponse
7 from django.http import HttpResponse
8 from django.shortcuts import get_object_or_404
8 from django.shortcuts import get_object_or_404
9 from django.core import serializers
9 from django.core import serializers
10
10
11 from boards.forms import PostForm, PlainErrorList
11 from boards.forms import PostForm, PlainErrorList
12 from boards.models import Post, Thread, Tag, GlobalId
12 from boards.models import Post, Thread, Tag, GlobalId
13 from boards.models.post.sync import SyncManager
13 from boards.models.post.sync import SyncManager
14 from boards.utils import datetime_to_epoch
14 from boards.utils import datetime_to_epoch
15 from boards.views.thread import ThreadView
15 from boards.views.thread import ThreadView
16 from boards.models.user import Notification
16 from boards.models.user import Notification
17 from boards.mdx_neboard import Parser
17 from boards.mdx_neboard import Parser
18
18
19
19
20 __author__ = 'neko259'
20 __author__ = 'neko259'
21
21
22 PARAMETER_TRUNCATED = 'truncated'
22 PARAMETER_TRUNCATED = 'truncated'
23 PARAMETER_TAG = 'tag'
23 PARAMETER_TAG = 'tag'
24 PARAMETER_OFFSET = 'offset'
24 PARAMETER_OFFSET = 'offset'
25 PARAMETER_DIFF_TYPE = 'type'
25 PARAMETER_DIFF_TYPE = 'type'
26 PARAMETER_POST = 'post'
26 PARAMETER_POST = 'post'
27 PARAMETER_UPDATED = 'updated'
27 PARAMETER_UPDATED = 'updated'
28 PARAMETER_LAST_UPDATE = 'last_update'
28 PARAMETER_LAST_UPDATE = 'last_update'
29 PARAMETER_THREAD = 'thread'
29 PARAMETER_THREAD = 'thread'
30 PARAMETER_UIDS = 'uids'
30 PARAMETER_UIDS = 'uids'
31
31
32 DIFF_TYPE_HTML = 'html'
32 DIFF_TYPE_HTML = 'html'
33 DIFF_TYPE_JSON = 'json'
33 DIFF_TYPE_JSON = 'json'
34
34
35 STATUS_OK = 'ok'
35 STATUS_OK = 'ok'
36 STATUS_ERROR = 'error'
36 STATUS_ERROR = 'error'
37
37
38 logger = logging.getLogger(__name__)
38 logger = logging.getLogger(__name__)
39
39
40
40
41 @transaction.atomic
41 @transaction.atomic
42 def api_get_threaddiff(request):
42 def api_get_threaddiff(request):
43 """
43 """
44 Gets posts that were changed or added since time
44 Gets posts that were changed or added since time
45 """
45 """
46
46
47 thread_id = request.POST.get(PARAMETER_THREAD)
47 thread_id = request.POST.get(PARAMETER_THREAD)
48 uids_str = request.POST.get(PARAMETER_UIDS).strip()
48 uids_str = request.POST.get(PARAMETER_UIDS).strip()
49 uids = uids_str.split(' ')
49 uids = uids_str.split(' ')
50
50
51 thread = get_object_or_404(Post, id=thread_id).get_thread()
51 thread = get_object_or_404(Post, id=thread_id).get_thread()
52
52
53 json_data = {
53 json_data = {
54 PARAMETER_UPDATED: [],
54 PARAMETER_UPDATED: [],
55 PARAMETER_LAST_UPDATE: None, # TODO Maybe this can be removed already?
55 PARAMETER_LAST_UPDATE: None, # TODO Maybe this can be removed already?
56 }
56 }
57 posts = Post.objects.filter(threads__in=[thread]).exclude(uid__in=uids)
57 posts = Post.objects.filter(threads__in=[thread]).exclude(uid__in=uids)
58
58
59 diff_type = request.GET.get(PARAMETER_DIFF_TYPE, DIFF_TYPE_HTML)
59 diff_type = request.GET.get(PARAMETER_DIFF_TYPE, DIFF_TYPE_HTML)
60
60
61 for post in posts:
61 for post in posts:
62 json_data[PARAMETER_UPDATED].append(get_post_data(post.id, diff_type,
62 json_data[PARAMETER_UPDATED].append(get_post_data(post.id, diff_type,
63 request))
63 request))
64 json_data[PARAMETER_LAST_UPDATE] = str(thread.last_edit_time)
64 json_data[PARAMETER_LAST_UPDATE] = str(thread.last_edit_time)
65
65
66 return HttpResponse(content=json.dumps(json_data))
66 return HttpResponse(content=json.dumps(json_data))
67
67
68
68
69 def api_add_post(request, opening_post_id):
69 def api_add_post(request, opening_post_id):
70 """
70 """
71 Adds a post and return the JSON response for it
71 Adds a post and return the JSON response for it
72 """
72 """
73
73
74 opening_post = get_object_or_404(Post, id=opening_post_id)
74 opening_post = get_object_or_404(Post, id=opening_post_id)
75
75
76 logger.info('Adding post via api...')
76 logger.info('Adding post via api...')
77
77
78 status = STATUS_OK
78 status = STATUS_OK
79 errors = []
79 errors = []
80
80
81 if request.method == 'POST':
81 if request.method == 'POST':
82 form = PostForm(request.POST, request.FILES, error_class=PlainErrorList)
82 form = PostForm(request.POST, request.FILES, error_class=PlainErrorList)
83 form.session = request.session
83 form.session = request.session
84
84
85 if form.need_to_ban:
85 if form.need_to_ban:
86 # Ban user because he is suspected to be a bot
86 # Ban user because he is suspected to be a bot
87 # _ban_current_user(request)
87 # _ban_current_user(request)
88 status = STATUS_ERROR
88 status = STATUS_ERROR
89 if form.is_valid():
89 if form.is_valid():
90 post = ThreadView().new_post(request, form, opening_post,
90 post = ThreadView().new_post(request, form, opening_post,
91 html_response=False)
91 html_response=False)
92 if not post:
92 if not post:
93 status = STATUS_ERROR
93 status = STATUS_ERROR
94 else:
94 else:
95 logger.info('Added post #%d via api.' % post.id)
95 logger.info('Added post #%d via api.' % post.id)
96 else:
96 else:
97 status = STATUS_ERROR
97 status = STATUS_ERROR
98 errors = form.as_json_errors()
98 errors = form.as_json_errors()
99
99
100 response = {
100 response = {
101 'status': status,
101 'status': status,
102 'errors': errors,
102 'errors': errors,
103 }
103 }
104
104
105 return HttpResponse(content=json.dumps(response))
105 return HttpResponse(content=json.dumps(response))
106
106
107
107
108 def get_post(request, post_id):
108 def get_post(request, post_id):
109 """
109 """
110 Gets the html of a post. Used for popups. Post can be truncated if used
110 Gets the html of a post. Used for popups. Post can be truncated if used
111 in threads list with 'truncated' get parameter.
111 in threads list with 'truncated' get parameter.
112 """
112 """
113
113
114 post = get_object_or_404(Post, id=post_id)
114 post = get_object_or_404(Post, id=post_id)
115 truncated = PARAMETER_TRUNCATED in request.GET
115 truncated = PARAMETER_TRUNCATED in request.GET
116
116
117 return HttpResponse(content=post.get_view(truncated=truncated))
117 return HttpResponse(content=post.get_view(truncated=truncated))
118
118
119
119
120 def api_get_threads(request, count):
120 def api_get_threads(request, count):
121 """
121 """
122 Gets the JSON thread opening posts list.
122 Gets the JSON thread opening posts list.
123 Parameters that can be used for filtering:
123 Parameters that can be used for filtering:
124 tag, offset (from which thread to get results)
124 tag, offset (from which thread to get results)
125 """
125 """
126
126
127 if PARAMETER_TAG in request.GET:
127 if PARAMETER_TAG in request.GET:
128 tag_name = request.GET[PARAMETER_TAG]
128 tag_name = request.GET[PARAMETER_TAG]
129 if tag_name is not None:
129 if tag_name is not None:
130 tag = get_object_or_404(Tag, name=tag_name)
130 tag = get_object_or_404(Tag, name=tag_name)
131 threads = tag.get_threads().filter(archived=False)
131 threads = tag.get_threads().filter(archived=False)
132 else:
132 else:
133 threads = Thread.objects.filter(archived=False)
133 threads = Thread.objects.filter(archived=False)
134
134
135 if PARAMETER_OFFSET in request.GET:
135 if PARAMETER_OFFSET in request.GET:
136 offset = request.GET[PARAMETER_OFFSET]
136 offset = request.GET[PARAMETER_OFFSET]
137 offset = int(offset) if offset is not None else 0
137 offset = int(offset) if offset is not None else 0
138 else:
138 else:
139 offset = 0
139 offset = 0
140
140
141 threads = threads.order_by('-bump_time')
141 threads = threads.order_by('-bump_time')
142 threads = threads[offset:offset + int(count)]
142 threads = threads[offset:offset + int(count)]
143
143
144 opening_posts = []
144 opening_posts = []
145 for thread in threads:
145 for thread in threads:
146 opening_post = thread.get_opening_post()
146 opening_post = thread.get_opening_post()
147
147
148 # TODO Add tags, replies and images count
148 # TODO Add tags, replies and images count
149 post_data = get_post_data(opening_post.id, include_last_update=True)
149 post_data = get_post_data(opening_post.id, include_last_update=True)
150 post_data['bumpable'] = thread.can_bump()
150 post_data['bumpable'] = thread.can_bump()
151 post_data['archived'] = thread.archived
151 post_data['archived'] = thread.archived
152
152
153 opening_posts.append(post_data)
153 opening_posts.append(post_data)
154
154
155 return HttpResponse(content=json.dumps(opening_posts))
155 return HttpResponse(content=json.dumps(opening_posts))
156
156
157
157
158 # TODO Test this
158 # TODO Test this
159 def api_get_tags(request):
159 def api_get_tags(request):
160 """
160 """
161 Gets all tags or user tags.
161 Gets all tags or user tags.
162 """
162 """
163
163
164 # TODO Get favorite tags for the given user ID
164 # TODO Get favorite tags for the given user ID
165
165
166 tags = Tag.objects.get_not_empty_tags()
166 tags = Tag.objects.get_not_empty_tags()
167
167
168 term = request.GET.get('term')
168 term = request.GET.get('term')
169 if term is not None:
169 if term is not None:
170 tags = tags.filter(name__contains=term)
170 tags = tags.filter(name__contains=term)
171
171
172 tag_names = [tag.name for tag in tags]
172 tag_names = [tag.name for tag in tags]
173
173
174 return HttpResponse(content=json.dumps(tag_names))
174 return HttpResponse(content=json.dumps(tag_names))
175
175
176
176
177 # TODO The result can be cached by the thread last update time
177 # TODO The result can be cached by the thread last update time
178 # TODO Test this
178 # TODO Test this
179 def api_get_thread_posts(request, opening_post_id):
179 def api_get_thread_posts(request, opening_post_id):
180 """
180 """
181 Gets the JSON array of thread posts
181 Gets the JSON array of thread posts
182 """
182 """
183
183
184 opening_post = get_object_or_404(Post, id=opening_post_id)
184 opening_post = get_object_or_404(Post, id=opening_post_id)
185 thread = opening_post.get_thread()
185 thread = opening_post.get_thread()
186 posts = thread.get_replies()
186 posts = thread.get_replies()
187
187
188 json_data = {
188 json_data = {
189 'posts': [],
189 'posts': [],
190 'last_update': None,
190 'last_update': None,
191 }
191 }
192 json_post_list = []
192 json_post_list = []
193
193
194 for post in posts:
194 for post in posts:
195 json_post_list.append(get_post_data(post.id))
195 json_post_list.append(get_post_data(post.id))
196 json_data['last_update'] = datetime_to_epoch(thread.last_edit_time)
196 json_data['last_update'] = datetime_to_epoch(thread.last_edit_time)
197 json_data['posts'] = json_post_list
197 json_data['posts'] = json_post_list
198
198
199 return HttpResponse(content=json.dumps(json_data))
199 return HttpResponse(content=json.dumps(json_data))
200
200
201
201
202 def api_get_notifications(request, username):
202 def api_get_notifications(request, username):
203 last_notification_id_str = request.GET.get('last', None)
203 last_notification_id_str = request.GET.get('last', None)
204 last_id = int(last_notification_id_str) if last_notification_id_str is not None else None
204 last_id = int(last_notification_id_str) if last_notification_id_str is not None else None
205
205
206 posts = Notification.objects.get_notification_posts(username=username,
206 posts = Notification.objects.get_notification_posts(username=username,
207 last=last_id)
207 last=last_id)
208
208
209 json_post_list = []
209 json_post_list = []
210 for post in posts:
210 for post in posts:
211 json_post_list.append(get_post_data(post.id))
211 json_post_list.append(get_post_data(post.id))
212 return HttpResponse(content=json.dumps(json_post_list))
212 return HttpResponse(content=json.dumps(json_post_list))
213
213
214
214
215 def api_get_post(request, post_id):
215 def api_get_post(request, post_id):
216 """
216 """
217 Gets the JSON of a post. This can be
217 Gets the JSON of a post. This can be
218 used as and API for external clients.
218 used as and API for external clients.
219 """
219 """
220
220
221 post = get_object_or_404(Post, id=post_id)
221 post = get_object_or_404(Post, id=post_id)
222
222
223 json = serializers.serialize("json", [post], fields=(
223 json = serializers.serialize("json", [post], fields=(
224 "pub_time", "_text_rendered", "title", "text", "image",
224 "pub_time", "_text_rendered", "title", "text", "image",
225 "image_width", "image_height", "replies", "tags"
225 "image_width", "image_height", "replies", "tags"
226 ))
226 ))
227
227
228 return HttpResponse(content=json)
228 return HttpResponse(content=json)
229
229
230
230
231 # TODO Remove this method and use post method directly
231 # TODO Remove this method and use post method directly
232 def get_post_data(post_id, format_type=DIFF_TYPE_JSON, request=None,
232 def get_post_data(post_id, format_type=DIFF_TYPE_JSON, request=None,
233 include_last_update=False):
233 include_last_update=False):
234 post = get_object_or_404(Post, id=post_id)
234 post = get_object_or_404(Post, id=post_id)
235 return post.get_post_data(format_type=format_type, request=request,
235 return post.get_post_data(format_type=format_type, request=request,
236 include_last_update=include_last_update)
236 include_last_update=include_last_update)
237
237
238
238
239 def api_get_preview(request):
239 def api_get_preview(request):
240 raw_text = request.POST['raw_text']
240 raw_text = request.POST['raw_text']
241
241
242 parser = Parser()
242 parser = Parser()
243 return HttpResponse(content=parser.parse(parser.preparse(raw_text)))
243 return HttpResponse(content=parser.parse(parser.preparse(raw_text)))
244
245
246 # TODO Make a separate module for sync API methods
247 def sync_pull(request):
248 """
249 Return 'pull' request response for all posts.
250 """
251 request_xml = request.get('xml')
252 if request_xml is None:
253 posts = Post.objects.all()
254 else:
255 pass # TODO Parse the XML and get filters from it
256
257 xml = SyncManager.generate_response_get(posts)
258 return HttpResponse(content=xml)
@@ -1,49 +1,56 b''
1 import xml.etree.ElementTree as et
1 import xml.etree.ElementTree as et
2 from django.http import HttpResponse, Http404
2 from django.http import HttpResponse, Http404
3 from boards.models import GlobalId, Post
3 from boards.models import GlobalId, Post
4 from boards.models.post.sync import SyncManager
4 from boards.models.post.sync import SyncManager
5
5
6
6
7 def response_pull(request):
7 def response_pull(request):
8 pass
8 request_xml = request.body
9
10 if request_xml is None:
11 return HttpResponse(content='Use the API')
12
13 response_xml = SyncManager.generate_response_pull()
14
15 return HttpResponse(content=response_xml)
9
16
10
17
11 def response_get(request):
18 def response_get(request):
12 """
19 """
13 Processes a GET request with post ID list and returns the posts XML list.
20 Processes a GET request with post ID list and returns the posts XML list.
14 Request should contain an 'xml' post attribute with the actual request XML.
21 Request should contain an 'xml' post attribute with the actual request XML.
15 """
22 """
16
23
17 request_xml = request.body
24 request_xml = request.body
18
25
19 if request_xml is None:
26 if request_xml is None:
20 return HttpResponse(content='Use the API')
27 return HttpResponse(content='Use the API')
21
28
22 posts = []
29 posts = []
23
30
24 root_tag = et.fromstring(request_xml)
31 root_tag = et.fromstring(request_xml)
25 model_tag = root_tag[0]
32 model_tag = root_tag[0]
26 for id_tag in model_tag:
33 for id_tag in model_tag:
27 global_id, exists = GlobalId.from_xml_element(id_tag)
34 global_id, exists = GlobalId.from_xml_element(id_tag)
28 if exists:
35 if exists:
29 posts.append(Post.objects.get(global_id=global_id))
36 posts.append(Post.objects.get(global_id=global_id))
30
37
31 response_xml = SyncManager.generate_response_get(posts)
38 response_xml = SyncManager.generate_response_get(posts)
32
39
33 return HttpResponse(content=response_xml)
40 return HttpResponse(content=response_xml)
34
41
35
42
36 def get_post_sync_data(request, post_id):
43 def get_post_sync_data(request, post_id):
37 try:
44 try:
38 post = Post.objects.get(id=post_id)
45 post = Post.objects.get(id=post_id)
39 except Post.DoesNotExist:
46 except Post.DoesNotExist:
40 raise Http404()
47 raise Http404()
41
48
42 content = 'Global ID: %s\n\nXML: %s' \
49 content = 'Global ID: %s\n\nXML: %s' \
43 % (post.global_id, SyncManager.generate_response_get([post]))
50 % (post.global_id, SyncManager.generate_response_get([post]))
44
51
45
52
46 return HttpResponse(
53 return HttpResponse(
47 content_type='text/plain',
54 content_type='text/plain',
48 content=content,
55 content=content,
49 ) No newline at end of file
56 )
General Comments 0
You need to be logged in to leave comments. Login now