##// END OF EJS Templates
Use update-time of a post instead of version
neko259 -
r1928:f3702378 default
parent child Browse files
Show More
@@ -0,0 +1,19 b''
1 # -*- coding: utf-8 -*-
2 # Generated by Django 1.11 on 2017-09-27 12:38
3 from __future__ import unicode_literals
4
5 from django.db import migrations
6
7
8 class Migration(migrations.Migration):
9
10 dependencies = [
11 ('boards', '0063_auto_20170301_1058'),
12 ]
13
14 operations = [
15 migrations.RemoveField(
16 model_name='post',
17 name='version',
18 ),
19 ]
@@ -16,7 +16,7 b' class PostAdmin(admin.ModelAdmin):'
16 exclude = ('referenced_posts', 'refmap', 'images', 'global_id')
16 exclude = ('referenced_posts', 'refmap', 'images', 'global_id')
17 readonly_fields = ('poster_ip', 'thread', 'linked_images',
17 readonly_fields = ('poster_ip', 'thread', 'linked_images',
18 'attachments', 'uid', 'url', 'pub_time', 'opening', 'linked_global_id',
18 'attachments', 'uid', 'url', 'pub_time', 'opening', 'linked_global_id',
19 'version', 'foreign', 'tags')
19 'foreign', 'tags')
20
20
21 def ban_poster(self, request, queryset):
21 def ban_poster(self, request, queryset):
22 bans = 0
22 bans = 0
@@ -63,7 +63,6 b' class PostAdmin(admin.ModelAdmin):'
63 return ', '.join([tag.get_name() for tag in obj.get_tags()])
63 return ', '.join([tag.get_name() for tag in obj.get_tags()])
64
64
65 def save_model(self, request, obj, form, change):
65 def save_model(self, request, obj, form, change):
66 obj.increment_version()
67 obj.save()
66 obj.save()
68 obj.clear_cache()
67 obj.clear_cache()
69
68
@@ -127,8 +126,6 b' class ThreadAdmin(admin.ModelAdmin):'
127
126
128 def save_model(self, request, obj, form, change):
127 def save_model(self, request, obj, form, change):
129 op = obj.get_opening_post()
128 op = obj.get_opening_post()
130 op.increment_version()
131 op.save(update_fields=['version'])
132 obj.save()
129 obj.save()
133 op.clear_cache()
130 op.clear_cache()
134
131
@@ -4,9 +4,10 b' import xml.etree.ElementTree as ET'
4
4
5 import httplib2
5 import httplib2
6 from django.core.management import BaseCommand
6 from django.core.management import BaseCommand
7 from django.utils.dateparse import parse_datetime
7
8
8 from boards.models import GlobalId
9 from boards.models import GlobalId
9 from boards.models.post.sync import SyncManager, TAG_ID, TAG_VERSION
10 from boards.models.post.sync import SyncManager, TAG_ID, TAG_UPDATE_TIME
10
11
11 __author__ = 'neko259'
12 __author__ = 'neko259'
12
13
@@ -85,12 +86,12 b' class Command(BaseCommand):'
85 for model in models:
86 for model in models:
86 tag_id = model.find(TAG_ID)
87 tag_id = model.find(TAG_ID)
87 global_id, exists = GlobalId.from_xml_element(tag_id)
88 global_id, exists = GlobalId.from_xml_element(tag_id)
88 tag_version = model.find(TAG_VERSION)
89 tag_update_time = model.find(TAG_UPDATE_TIME)
89 if tag_version is not None:
90 if tag_update_time:
90 version = int(tag_version.text) or 1
91 update_time = tag_update_time.text
91 else:
92 else:
92 version = 1
93 update_time = None
93 if not exists or global_id.post.version < version:
94 if not exists or update_time is None or global_id.post.last_edit_time < parse_datetime(update_time):
94 logger.debug('Processed (+) post {}'.format(global_id))
95 logger.debug('Processed (+) post {}'.format(global_id))
95 ids_to_sync.append(global_id)
96 ids_to_sync.append(global_id)
96 else:
97 else:
@@ -100,7 +100,6 b' class Post(models.Model, Viewable):'
100 tripcode = models.CharField(max_length=50, blank=True, default='')
100 tripcode = models.CharField(max_length=50, blank=True, default='')
101 opening = models.BooleanField(db_index=True)
101 opening = models.BooleanField(db_index=True)
102 hidden = models.BooleanField(default=False)
102 hidden = models.BooleanField(default=False)
103 version = models.IntegerField(default=1)
104
103
105 def __str__(self):
104 def __str__(self):
106 return 'P#{}/{}'.format(self.id, self.get_title())
105 return 'P#{}/{}'.format(self.id, self.get_title())
@@ -341,9 +340,6 b' class Post(models.Model, Viewable):'
341 def set_hidden(self, hidden):
340 def set_hidden(self, hidden):
342 self.hidden = hidden
341 self.hidden = hidden
343
342
344 def increment_version(self):
345 self.version = F('version') + 1
346
347 def clear_cache(self):
343 def clear_cache(self):
348 """
344 """
349 Clears sync data (content cache, signatures etc).
345 Clears sync data (content cache, signatures etc).
@@ -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 file_urls=list(), tripcode=None, version=1):
141 file_urls=list(), tripcode=None, last_edit_time=None):
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(
@@ -151,12 +151,11 b' class PostManager(models.Manager):'
151 text=text,
151 text=text,
152 pub_time=pub_time,
152 pub_time=pub_time,
153 poster_ip=NO_IP,
153 poster_ip=NO_IP,
154 last_edit_time=pub_time,
154 last_edit_time=last_edit_time or pub_time,
155 global_id=global_id,
155 global_id=global_id,
156 opening=is_opening,
156 opening=is_opening,
157 thread=thread,
157 thread=thread,
158 tripcode=tripcode,
158 tripcode=tripcode)
159 version=version)
160
159
161 for file in files:
160 for file in files:
162 self._add_file_to_post(file, post)
161 self._add_file_to_post(file, post)
@@ -170,12 +169,11 b' class PostManager(models.Manager):'
170
169
171 @transaction.atomic
170 @transaction.atomic
172 def update_post(self, post, title: str, text: str, pub_time: str,
171 def update_post(self, post, title: str, text: str, pub_time: str,
173 tags=list(), files=list(), file_urls=list(), tripcode=None, version=1):
172 tags=list(), files=list(), file_urls=list(), tripcode=None):
174 post.title = title
173 post.title = title
175 post.text = text
174 post.text = text
176 post.pub_time = pub_time
175 post.pub_time = pub_time
177 post.tripcode = tripcode
176 post.tripcode = tripcode
178 post.version = version
179 post.save()
177 post.save()
180
178
181 post.clear_cache()
179 post.clear_cache()
@@ -1,16 +1,17 b''
1 import logging
1 import xml.etree.ElementTree as et
2 import xml.etree.ElementTree as et
2 import logging
3
3 from xml.etree import ElementTree
4 from django.db import transaction
5 from django.utils.dateparse import parse_datetime
4
6
5 from boards.abstracts.exceptions import SyncException
7 from boards.abstracts.exceptions import SyncException
6 from boards.abstracts.sync_filters import ThreadFilter, TagsFilter,\
8 from boards.abstracts.sync_filters import ThreadFilter, TagsFilter, \
7 TimestampFromFilter
9 TimestampFromFilter
8 from boards.models import KeyPair, GlobalId, Signature, Post, Tag
10 from boards.models import KeyPair, GlobalId, Signature, Post, Tag
9 from boards.models.attachment.downloaders import download
11 from boards.models.attachment.downloaders import download
10 from boards.models.signature import TAG_REQUEST, ATTR_TYPE, TYPE_GET, \
12 from boards.models.signature import TAG_REQUEST, ATTR_TYPE, TYPE_GET, \
11 ATTR_VERSION, TAG_MODEL, ATTR_NAME, TAG_ID, TYPE_LIST
13 ATTR_VERSION, TAG_MODEL, ATTR_NAME, TAG_ID, TYPE_LIST
12 from boards.utils import get_file_mimetype, get_file_hash
14 from boards.utils import get_file_mimetype, get_file_hash
13 from django.db import transaction
14
15
15 EXCEPTION_NODE = 'Sync node returned an error: {}.'
16 EXCEPTION_NODE = 'Sync node returned an error: {}.'
16 EXCEPTION_DOWNLOAD = 'File was not downloaded.'
17 EXCEPTION_DOWNLOAD = 'File was not downloaded.'
@@ -30,6 +31,7 b" TAG_TITLE = 'title'"
30 TAG_TEXT = 'text'
31 TAG_TEXT = 'text'
31 TAG_THREAD = 'thread'
32 TAG_THREAD = 'thread'
32 TAG_PUB_TIME = 'pub-time'
33 TAG_PUB_TIME = 'pub-time'
34 TAG_UPDATE_TIME = 'update-time'
33 TAG_SIGNATURES = 'signatures'
35 TAG_SIGNATURES = 'signatures'
34 TAG_SIGNATURE = 'signature'
36 TAG_SIGNATURE = 'signature'
35 TAG_CONTENT = 'content'
37 TAG_CONTENT = 'content'
@@ -59,6 +61,8 b" ID_TYPE_URL = 'url'"
59
61
60 STATUS_SUCCESS = 'success'
62 STATUS_SUCCESS = 'success'
61
63
64 CURRENT_MODEL_VERSION = '1.1'
65
62
66
63 logger = logging.getLogger('boards.sync')
67 logger = logging.getLogger('boards.sync')
64
68
@@ -120,6 +124,9 b' class SyncManager:'
120 pub_time = et.SubElement(content_tag, TAG_PUB_TIME)
124 pub_time = et.SubElement(content_tag, TAG_PUB_TIME)
121 pub_time.text = str(post.get_pub_time_str())
125 pub_time.text = str(post.get_pub_time_str())
122
126
127 update_time = et.SubElement(content_tag, TAG_UPDATE_TIME)
128 update_time.text = str(post.last_edit_time)
129
123 if post.tripcode:
130 if post.tripcode:
124 tripcode = et.SubElement(content_tag, TAG_TRIPCODE)
131 tripcode = et.SubElement(content_tag, TAG_TRIPCODE)
125 tripcode.text = post.tripcode
132 tripcode.text = post.tripcode
@@ -141,8 +148,6 b' class SyncManager:'
141 for file in attachments:
148 for file in attachments:
142 SyncManager._attachment_to_xml(
149 SyncManager._attachment_to_xml(
143 attachments_tag, attachment_refs, file)
150 attachments_tag, attachment_refs, file)
144 version_tag = et.SubElement(content_tag, TAG_VERSION)
145 version_tag.text = str(post.version)
146
151
147 global_id.content = et.tostring(content_tag, ENCODING_UNICODE)
152 global_id.content = et.tostring(content_tag, ENCODING_UNICODE)
148 global_id.save()
153 global_id.save()
@@ -191,8 +196,8 b' class SyncManager:'
191 global_id, exists = GlobalId.from_xml_element(tag_id)
196 global_id, exists = GlobalId.from_xml_element(tag_id)
192 signatures = SyncManager._verify_model(global_id, content_str, tag_model)
197 signatures = SyncManager._verify_model(global_id, content_str, tag_model)
193
198
194 version = int(tag_content.find(TAG_VERSION).text)
199 update_time = tag_content.find(TAG_UPDATE_TIME).text
195 is_old = exists and global_id.post.version < version
200 is_old = exists and global_id.post.last_edit_time < parse_datetime(update_time)
196 if exists and not is_old:
201 if exists and not is_old:
197 logger.debug('Post {} exists and is up to date.'.format(global_id))
202 logger.debug('Post {} exists and is up to date.'.format(global_id))
198 else:
203 else:
@@ -204,13 +209,13 b' class SyncManager:'
204
209
205 title = tag_content.find(TAG_TITLE).text or ''
210 title = tag_content.find(TAG_TITLE).text or ''
206 text = tag_content.find(TAG_TEXT).text or ''
211 text = tag_content.find(TAG_TEXT).text or ''
207 pub_time = tag_content.find(TAG_PUB_TIME).text
208 tripcode_tag = tag_content.find(TAG_TRIPCODE)
212 tripcode_tag = tag_content.find(TAG_TRIPCODE)
209 if tripcode_tag is not None:
213 if tripcode_tag is not None:
210 tripcode = tripcode_tag.text or ''
214 tripcode = tripcode_tag.text or ''
211 else:
215 else:
212 tripcode = ''
216 tripcode = ''
213
217
218 pub_time = tag_content.find(TAG_PUB_TIME).text
214 thread = tag_content.find(TAG_THREAD)
219 thread = tag_content.find(TAG_THREAD)
215 tags = []
220 tags = []
216 if thread:
221 if thread:
@@ -257,15 +262,14 b' class SyncManager:'
257 Post.objects.update_post(
262 Post.objects.update_post(
258 post, title=title, text=text, pub_time=pub_time,
263 post, title=title, text=text, pub_time=pub_time,
259 tags=tags, files=files, file_urls=urls,
264 tags=tags, files=files, file_urls=urls,
260 tripcode=tripcode, version=version)
265 tripcode=tripcode, version=version, last_edit_time=update_time)
261 logger.debug('Parsed updated post {}'.format(global_id))
266 logger.debug('Parsed updated post {}'.format(global_id))
262 else:
267 else:
263 Post.objects.import_post(
268 Post.objects.import_post(
264 title=title, text=text, pub_time=pub_time,
269 title=title, text=text, pub_time=pub_time,
265 opening_post=opening_post, tags=tags,
270 opening_post=opening_post, tags=tags,
266 global_id=global_id, files=files,
271 global_id=global_id, files=files,
267 file_urls=urls, tripcode=tripcode,
272 file_urls=urls, tripcode=tripcode, last_edit_time=update_time)
268 version=version)
269 logger.debug('Parsed new post {}'.format(global_id))
273 logger.debug('Parsed new post {}'.format(global_id))
270
274
271 @staticmethod
275 @staticmethod
@@ -285,8 +289,8 b' class SyncManager:'
285 tag_model = et.SubElement(models, TAG_MODEL)
289 tag_model = et.SubElement(models, TAG_MODEL)
286 tag_id = et.SubElement(tag_model, TAG_ID)
290 tag_id = et.SubElement(tag_model, TAG_ID)
287 post.global_id.to_xml_element(tag_id)
291 post.global_id.to_xml_element(tag_id)
288 tag_version = et.SubElement(tag_model, TAG_VERSION)
292 update_time = et.SubElement(tag_model, TAG_UPDATE_TIME)
289 tag_version.text = str(post.version)
293 update_time.text = str(post.last_edit_time)
290
294
291 return et.tostring(response, ENCODING_UNICODE)
295 return et.tostring(response, ENCODING_UNICODE)
292
296
@@ -372,7 +376,7 b' class SyncManager:'
372 request.set(ATTR_VERSION, '1.0')
376 request.set(ATTR_VERSION, '1.0')
373
377
374 model = et.SubElement(request, TAG_MODEL)
378 model = et.SubElement(request, TAG_MODEL)
375 model.set(ATTR_VERSION, '1.0')
379 model.set(ATTR_VERSION, CURRENT_MODEL_VERSION)
376 model.set(ATTR_NAME, 'post')
380 model.set(ATTR_NAME, 'post')
377
381
378 if opening_post:
382 if opening_post:
@@ -186,7 +186,7 b' class Thread(models.Model):'
186 """
186 """
187 Gets replies with only fields that are used for viewing.
187 Gets replies with only fields that are used for viewing.
188 """
188 """
189 return self.get_replies().defer('text', 'last_edit_time', 'version')
189 return self.get_replies().defer('text', 'last_edit_time')
190
190
191 def get_top_level_replies(self) -> QuerySet:
191 def get_top_level_replies(self) -> QuerySet:
192 return self.get_replies().exclude(refposts__threads__in=[self])
192 return self.get_replies().exclude(refposts__threads__in=[self])
@@ -64,6 +64,7 b''
64 <button name="method" value="subscribe" class="not_fav">★ {% trans "Add to favorites" %}</button>
64 <button name="method" value="subscribe" class="not_fav">★ {% trans "Add to favorites" %}</button>
65 {% endif %}
65 {% endif %}
66 </form>
66 </form>
67 &bull;
67 <form action="{% url 'tag' tag.get_name %}" method="post" class="post-button-form">
68 <form action="{% url 'tag' tag.get_name %}" method="post" class="post-button-form">
68 {% if is_hidden %}
69 {% if is_hidden %}
69 <button name="method" value="unhide" class="fav">{% trans "Show" %}</button>
70 <button name="method" value="unhide" class="fav">{% trans "Show" %}</button>
@@ -71,6 +72,7 b''
71 <button name="method" value="hide" class="not_fav">{% trans "Hide" %}</button>
72 <button name="method" value="hide" class="not_fav">{% trans "Hide" %}</button>
72 {% endif %}
73 {% endif %}
73 </form>
74 </form>
75 &bull;
74 <a href="{% url 'tag_gallery' tag.get_name %}">{% trans 'Gallery' %}</a>
76 <a href="{% url 'tag_gallery' tag.get_name %}">{% trans 'Gallery' %}</a>
75 </p>
77 </p>
76 {% if tag.get_description %}
78 {% if tag.get_description %}
@@ -65,22 +65,22 b' class KeyTest(TestCase):'
65 '<models>'
65 '<models>'
66 '<model name="post">'
66 '<model name="post">'
67 '<content>'
67 '<content>'
68 '<id key="%s" local-id="%d" type="%s" />'
68 '<id key="{}" local-id="{}" type="{}" />'
69 '<title>test_title</title>'
69 '<title>test_title</title>'
70 '<text>[post]%s[/post]</text>'
70 '<text>[post]{}[/post]</text>'
71 '<thread><id key="%s" local-id="%d" type="%s" /></thread>'
71 '<thread><id key="{}" local-id="{}" type="{}" /></thread>'
72 '<pub-time>%s</pub-time>'
72 '<pub-time>{}</pub-time>'
73 '<version>%s</version>'
73 '<update-time>{}</update-time>'
74 '</content>' % (
74 '</content>'.format(
75 key.public_key,
75 key.public_key,
76 reply_post.id,
76 reply_post.id,
77 key.key_type,
77 key.key_type,
78 str(post.global_id),
78 post.global_id,
79 key.public_key,
79 key.public_key,
80 post.id,
80 post.id,
81 key.key_type,
81 key.key_type,
82 str(reply_post.get_pub_time_str()),
82 reply_post.get_pub_time_str(),
83 post.version,
83 reply_post.last_edit_time,
84 ) in response,
84 ) in response,
85 'Wrong XML generated for the GET response.')
85 'Wrong XML generated for the GET response.')
86
86
@@ -37,13 +37,13 b' class SyncTest(TestCase):'
37 '<models>'
37 '<models>'
38 '<model name="post">'
38 '<model name="post">'
39 '<content>'
39 '<content>'
40 '<id key="%s" local-id="%d" type="%s" />'
40 '<id key="{}" local-id="{}" type="{}" />'
41 '<title>%s</title>'
41 '<title>{}</title>'
42 '<text>%s</text>'
42 '<text>{}</text>'
43 '<tags><tag>%s</tag></tags>'
43 '<tags><tag>{}</tag></tags>'
44 '<pub-time>%s</pub-time>'
44 '<pub-time>{}</pub-time>'
45 '<version>%s</version>'
45 '<update-time>{}</update-time>'
46 '</content>' % (
46 '</content>'.format(
47 post.global_id.key,
47 post.global_id.key,
48 post.global_id.local_id,
48 post.global_id.local_id,
49 post.global_id.key_type,
49 post.global_id.key_type,
@@ -51,7 +51,7 b' class SyncTest(TestCase):'
51 post.get_sync_text(),
51 post.get_sync_text(),
52 post.get_thread().get_tags().first().get_name(),
52 post.get_thread().get_tags().first().get_name(),
53 post.get_pub_time_str(),
53 post.get_pub_time_str(),
54 post.version,
54 post.last_edit_time,
55 ) in response,
55 ) in response,
56 'Wrong response generated for the GET request.')
56 'Wrong response generated for the GET request.')
57
57
@@ -86,13 +86,13 b' class SyncTest(TestCase):'
86 '<models>'
86 '<models>'
87 '<model name="post">'
87 '<model name="post">'
88 '<content>'
88 '<content>'
89 '<id key="%s" local-id="%d" type="%s" />'
89 '<id key="{}" local-id="{}" type="{}" />'
90 '<title>%s</title>'
90 '<title>{}</title>'
91 '<text>%s</text>'
91 '<text>{}</text>'
92 '<tags><tag>%s</tag></tags>'
92 '<tags><tag>{}</tag></tags>'
93 '<pub-time>%s</pub-time>'
93 '<pub-time>{}</pub-time>'
94 '<version>%s</version>'
94 '<update-time>{}</update-time>'
95 '</content>' % (
95 '</content>'.format(
96 post.global_id.key,
96 post.global_id.key,
97 post.global_id.local_id,
97 post.global_id.local_id,
98 post.global_id.key_type,
98 post.global_id.key_type,
@@ -100,7 +100,6 b' class SyncTest(TestCase):'
100 post.get_sync_text(),
100 post.get_sync_text(),
101 post.get_thread().get_tags().first().get_name(),
101 post.get_thread().get_tags().first().get_name(),
102 post.get_pub_time_str(),
102 post.get_pub_time_str(),
103 post.version,
104 ) in response,
103 ) in response,
105 'Wrong response generated for the GET request.')
104 'Wrong response generated for the GET request.')
106
105
@@ -128,21 +127,21 b' class SyncTest(TestCase):'
128 '<models>'
127 '<models>'
129 '<model>'
128 '<model>'
130 '<id key="{}" local-id="{}" type="{}" />'
129 '<id key="{}" local-id="{}" type="{}" />'
131 '<version>{}</version>'
130 '<update-time>{}</update-time>'
132 '</model>'
131 '</model>'
133 '<model>'
132 '<model>'
134 '<id key="{}" local-id="{}" type="{}" />'
133 '<id key="{}" local-id="{}" type="{}" />'
135 '<version>{}</version>'
134 '<update-time>{}</update-time>'
136 '</model>'
135 '</model>'
137 '</models>'.format(
136 '</models>'.format(
138 post.global_id.key,
137 post.global_id.key,
139 post.global_id.local_id,
138 post.global_id.local_id,
140 post.global_id.key_type,
139 post.global_id.key_type,
141 post.version,
140 post.last_edit_time,
142 post2.global_id.key,
141 post2.global_id.key,
143 post2.global_id.local_id,
142 post2.global_id.local_id,
144 post2.global_id.key_type,
143 post2.global_id.key_type,
145 post2.version,
144 post2.last_edit_time,
146 ) in response_all,
145 ) in response_all,
147 'Wrong response generated for the LIST request for all posts.')
146 'Wrong response generated for the LIST request for all posts.')
148
147
@@ -173,13 +172,13 b' class SyncTest(TestCase):'
173 '<models>'
172 '<models>'
174 '<model>'
173 '<model>'
175 '<id key="{}" local-id="{}" type="{}" />'
174 '<id key="{}" local-id="{}" type="{}" />'
176 '<version>{}</version>'
175 '<update-time>{}</update-time>'
177 '</model>'
176 '</model>'
178 '</models>'.format(
177 '</models>'.format(
179 post.global_id.key,
178 post.global_id.key,
180 post.global_id.local_id,
179 post.global_id.local_id,
181 post.global_id.key_type,
180 post.global_id.key_type,
182 post.version,
181 post.last_edit_time,
183 ) in response_thread,
182 ) in response_thread,
184 'Wrong response generated for the LIST request for posts of '
183 'Wrong response generated for the LIST request for posts of '
185 'existing thread.')
184 'existing thread.')
@@ -240,13 +239,13 b' class SyncTest(TestCase):'
240 '<models>'
239 '<models>'
241 '<model>'
240 '<model>'
242 '<id key="{}" local-id="{}" type="{}" />'
241 '<id key="{}" local-id="{}" type="{}" />'
243 '<version>{}</version>'
242 '<update-time>{}</update_time>'
244 '</model>'
243 '</model>'
245 '</models>'.format(
244 '</models>'.format(
246 post2.global_id.key,
245 post2.global_id.key,
247 post2.global_id.local_id,
246 post2.global_id.local_id,
248 post2.global_id.key_type,
247 post2.global_id.key_type,
249 post2.version,
248 post2.last_edit_time,
250 ) in response_thread,
249 ) in response_thread,
251 'Wrong response generated for the LIST request for posts of '
250 'Wrong response generated for the LIST request for posts of '
252 'existing thread.')
251 'existing thread.')
@@ -97,7 +97,7 b' Sample response:'
97 <models>
97 <models>
98 <model>
98 <model>
99 <id key="id1" type="ecdsa" local-id="1">
99 <id key="id1" type="ecdsa" local-id="1">
100 <version>1</version>
100 <update-time>2017-01-01 00:00:00</update-time>
101 </model>
101 </model>
102 <model>
102 <model>
103 <id key="id1" type="ecdsa" local-id="2" />
103 <id key="id1" type="ecdsa" local-id="2" />
@@ -1,6 +1,6 b''
1 # 0 Title #
1 # 0 Title #
2
2
3 "post" model reference
3 "post" model reference of version 1.1
4
4
5 # 1 Description #
5 # 1 Description #
6
6
@@ -13,7 +13,7 b''
13 * title -- text field.
13 * title -- text field.
14 * text -- text field.
14 * text -- text field.
15 * pub-time -- timestamp (TBD: Define format).
15 * pub-time -- timestamp (TBD: Define format).
16 * version -- when post content changes, version should be incremented.
16 * update -- when post content changes, the update time should be incremented.
17
17
18 # 2.2 Optional fields #
18 # 2.2 Optional fields #
19
19
General Comments 0
You need to be logged in to leave comments. Login now