##// END OF EJS Templates
Serialize timestamp before passing to tag. Fail if the passed timestamp is invalid and cannot be parsed
neko259 -
r2122:edce8526 default
parent child Browse files
Show More
@@ -1,66 +1,66
1 1 import xml.etree.ElementTree as et
2 2
3 3 from boards.models import Post, Tag
4 4
5 5 TAG_THREAD = 'thread'
6 6 TAG_TAGS = 'tags'
7 7 TAG_TAG = 'tag'
8 8 TAG_TIME_FROM = 'timestamp_from'
9 9
10 10
11 11 class PostFilter:
12 12 def __init__(self, content=None):
13 13 self.content = content
14 14
15 15 def filter(self, posts):
16 16 return posts
17 17
18 18 def add_filter(self, model_tag, value):
19 19 return model_tag
20 20
21 21
22 22 class ThreadFilter(PostFilter):
23 23 def filter(self, posts):
24 24 op_id = self.content.text
25 25
26 26 op = Post.objects.filter(opening=True, id=op_id).first()
27 27 if op:
28 28 return posts.filter(thread=op.get_thread())
29 29 else:
30 30 return posts.none()
31 31
32 32 def add_filter(self, model_tag, value):
33 33 thread_tag = et.SubElement(model_tag, TAG_THREAD)
34 34 thread_tag.text = str(value)
35 35
36 36
37 37 class TagsFilter(PostFilter):
38 38 def filter(self, posts):
39 39 tags = []
40 40 for tag_tag in self.content:
41 41 try:
42 42 tags.append(Tag.objects.get_by_alias(tag_tag.text))
43 43 except Tag.DoesNotExist:
44 44 pass
45 45
46 46 if tags:
47 47 return posts.filter(thread__tags__in=tags)
48 48 else:
49 49 return posts.none()
50 50
51 51 def add_filter(self, model_tag, value):
52 52 tags_tag = et.SubElement(model_tag, TAG_TAGS)
53 53 for tag_name in value:
54 54 tag_tag = et.SubElement(tags_tag, TAG_TAG)
55 55 tag_tag.text = tag_name
56 56
57 57
58 58 class TimestampFromFilter(PostFilter):
59 59 def filter(self, posts):
60 60 from_time = self.content.text
61 61 return posts.filter(pub_time__gt=from_time)
62 62
63 63 def add_filter(self, model_tag, value):
64 64 tags_from_time = et.SubElement(model_tag, TAG_TIME_FROM)
65 tags_from_time.text = value
65 tags_from_time.text = str(value)
66 66
@@ -1,137 +1,140
1 1 import re
2 2 import logging
3 3 import xml.etree.ElementTree as ET
4 4
5 5 import httplib2
6 6 from django.core.management import BaseCommand
7 7 from django.utils.dateparse import parse_datetime
8 8
9 9 from boards.models import GlobalId, KeyPair
10 10 from boards.models.post.sync import SyncManager, TAG_ID, TAG_UPDATE_TIME
11 11
12 12 __author__ = 'neko259'
13 13
14 14
15 15 REGEX_GLOBAL_ID = re.compile(r'(\w+)::([\w\+/]+)::(\d+)')
16 16
17 17
18 18 class Command(BaseCommand):
19 19 help = 'Send a sync or get request to the server.'
20 20
21 21 def add_arguments(self, parser):
22 22 parser.add_argument('url', type=str, help='Server root url')
23 23 parser.add_argument('--global-id', type=str, default='',
24 24 help='Post global ID')
25 25 parser.add_argument('--split-query', type=int, default=1,
26 26 help='Split GET query into separate by the given'
27 27 ' number of posts in one')
28 28 parser.add_argument('--thread', type=int,
29 29 help='Get posts of one specific thread')
30 30 parser.add_argument('--tags', type=str,
31 31 help='Get posts of the tags, comma-separated')
32 32 parser.add_argument('--time-from', type=str,
33 33 help='Get posts from the given timestamp')
34 34
35 35 def handle(self, *args, **options):
36 36 logger = logging.getLogger('boards.sync')
37 37
38 38 url = options.get('url')
39 39
40 40 list_url = url + 'api/sync/list/'
41 41 get_url = url + 'api/sync/get/'
42 42 file_url = url[:-1]
43 43
44 44 global_id_str = options.get('global_id')
45 45 if global_id_str:
46 46 match = REGEX_GLOBAL_ID.match(global_id_str)
47 47 if match:
48 48 key_type = match.group(1)
49 49 key = match.group(2)
50 50 local_id = match.group(3)
51 51
52 52 global_id = GlobalId(key_type=key_type, key=key,
53 53 local_id=local_id)
54 54
55 55 xml = SyncManager.generate_request_get([global_id])
56 56 h = httplib2.Http()
57 57 response, content = h.request(get_url, method="POST", body=xml)
58 58
59 59 SyncManager.parse_response_get(content, file_url)
60 60 else:
61 61 raise Exception('Invalid global ID')
62 62 else:
63 63 logger.info('Running LIST request...')
64 64 h = httplib2.Http()
65 65
66 66 tags = []
67 67 tags_str = options.get('tags')
68 68 if tags_str:
69 69 tags = tags_str.split(',')
70 70
71 71 timestamp_str = options.get('time_from')
72 72 timestamp = None
73 73 if timestamp_str:
74 74 timestamp = parse_datetime(timestamp_str)
75 if not timestamp:
76 raise Exception('Timestamp {} cannot be parsed'.format(
77 timestamp_str))
75 78
76 79 xml = SyncManager.generate_request_list(
77 80 opening_post=options.get('thread'), tags=tags,
78 81 timestamp_from=timestamp).encode()
79 82 response, content = h.request(list_url, method="POST", body=xml)
80 83 if response.status != 200:
81 84 raise Exception('Server returned error {}'.format(response.status))
82 85
83 86 logger.info('Processing response...')
84 87
85 88 root = ET.fromstring(content)
86 89 status = root.findall('status')[0].text
87 90 if status == 'success':
88 91 ids_to_sync = list()
89 92
90 93 models = root.findall('models')[0]
91 94 for model in models:
92 95 self.add_to_sync_list(ids_to_sync, logger, model)
93 96 logger.info('Starting sync...')
94 97
95 98 if len(ids_to_sync) > 0:
96 99 limit = options.get('split_query', len(ids_to_sync))
97 100 for offset in range(0, len(ids_to_sync), limit):
98 101 xml = SyncManager.generate_request_get(ids_to_sync[offset:offset + limit])
99 102 h = httplib2.Http()
100 103 logger.info('Running GET request...')
101 104 response, content = h.request(get_url, method="POST", body=xml)
102 105 logger.info('Processing response...')
103 106
104 107 SyncManager.parse_response_get(content, file_url)
105 108
106 109 logger.info('Sync completed successfully')
107 110 else:
108 111 logger.info('Nothing to get, everything synced')
109 112 else:
110 113 raise Exception('Invalid response status')
111 114
112 115 def add_to_sync_list(self, ids_to_sync, logger, model):
113 116 tag_id = model.find(TAG_ID)
114 117 global_id, exists = GlobalId.from_xml_element(tag_id)
115 118 from_this_board = self._is_from_this_board(global_id)
116 119 if from_this_board:
117 120 # If the post originates from this board, no need to process
118 121 # it again, nobody else could modify it
119 122 logger.debug('NO SYNC Processed post {}'.format(global_id))
120 123 else:
121 124 tag_update_time = model.find(TAG_UPDATE_TIME)
122 125 if tag_update_time:
123 126 update_time = tag_update_time.text
124 127 else:
125 128 update_time = None
126 129 if not exists or update_time is None or global_id.post.last_edit_time < parse_datetime(
127 130 update_time):
128 131 logger.debug('SYNC Processed post {}'.format(global_id))
129 132 ids_to_sync.append(global_id)
130 133 else:
131 134 logger.debug('NO SYNC Processed post {}'.format(global_id))
132 135
133 136 def _is_from_this_board(self, global_id):
134 137 from_this_board = KeyPair.objects.filter(
135 138 key_type=global_id.key_type,
136 139 public_key=global_id.key).exists()
137 140 return from_this_board
General Comments 0
You need to be logged in to leave comments. Login now