]> git.openstreetmap.org Git - osqa.git/blob - forum_modules/sximporter/importer.py
Several improvements in the sx importer.
[osqa.git] / forum_modules / sximporter / importer.py
1 # -*- coding: utf-8 -*-
2
3 from xml.dom import minidom
4 from datetime import datetime, timedelta
5 import time
6 import re
7 import os
8 import gc
9 from django.utils.translation import ugettext as _
10 from django.template.defaultfilters import slugify
11 from forum.models.utils import dbsafe_encode
12 from orm import orm
13
14 from django.utils.encoding import force_unicode
15
16 try:
17     from cPickle import loads, dumps
18 except ImportError:
19     from pickle import loads, dumps
20
21 from copy import deepcopy
22 from base64 import b64encode, b64decode
23 from zlib import compress, decompress
24
25 from xml.sax import make_parser
26 from xml.sax.handler import ContentHandler
27
28 class SXTableHandler(ContentHandler):
29     def __init__(self, fname, callback):
30         self.in_row = False
31         self.el_data = {}
32         self.ch_data = ''
33
34         self.fname = fname.lower()
35         self.callback = callback
36
37     def startElement(self, name, attrs):
38         if name.lower() == self.fname:
39             pass
40         elif name.lower() == "row":
41             self.in_row = True
42
43     def characters(self, ch):
44         self.ch_data += ch
45
46     def endElement(self, name):
47         if name.lower() == self.fname:
48             pass
49         elif name.lower() == "row":
50             self.callback(self.el_data)
51
52             self.in_row = False
53             del self.el_data
54             self.el_data = {}
55         elif self.in_row:
56             self.el_data[name.lower()] = self.ch_data.strip()
57             del self.ch_data
58             self.ch_data = ''
59
60
61 def readTable(path, name, callback):
62     parser = make_parser()
63     handler = SXTableHandler(name, callback)
64     parser.setContentHandler(handler)
65
66     f = os.path.join(path, "%s.xml" % name)
67     parser.parse(f)
68
69
70 def dbsafe_encode(value):
71     return force_unicode(b64encode(compress(dumps(deepcopy(value)))))
72
73 def getText(el):
74     rc = ""
75     for node in el.childNodes:
76         if node.nodeType == node.TEXT_NODE:
77             rc = rc + node.data
78     return rc.strip()
79
80 msstrip = re.compile(r'^(.*)\.\d+')
81 def readTime(ts):
82     noms = msstrip.match(ts)
83     if noms:
84         ts = noms.group(1)
85
86     return datetime(*time.strptime(ts, '%Y-%m-%dT%H:%M:%S')[0:6])
87
88 #def readEl(el):
89 #    return dict([(n.tagName.lower(), getText(n)) for n in el.childNodes if n.nodeType == el.ELEMENT_NODE])
90
91 #def readTable(dump, name):
92 #    for e in minidom.parseString(dump.read("%s.xml" % name)).getElementsByTagName('row'):
93 #        yield readEl(e)
94 #return [readEl(e) for e in minidom.parseString(dump.read("%s.xml" % name)).getElementsByTagName('row')]
95
96 google_accounts_lookup = re.compile(r'^https?://www.google.com/accounts/')
97 yahoo_accounts_lookup = re.compile(r'^https?://me.yahoo.com/a/')
98
99 openid_lookups = [
100         re.compile(r'^https?://www.google.com/profiles/(?P<uname>\w+(\.\w+)*)/?$'),
101         re.compile(r'^https?://me.yahoo.com/(?P<uname>\w+(\.\w+)*)/?$'),
102         re.compile(r'^https?://openid.aol.com/(?P<uname>\w+(\.\w+)*)/?$'),
103         re.compile(r'^https?://(?P<uname>\w+(\.\w+)*).myopenid.com/?$'),
104         re.compile(r'^https?://flickr.com/(\w+/)*(?P<uname>\w+(\.\w+)*)/?$'),
105         re.compile(r'^https?://technorati.com/people/technorati/(?P<uname>\w+(\.\w+)*)/?$'),
106         re.compile(r'^https?://(?P<uname>\w+(\.\w+)*).wordpress.com/?$'),
107         re.compile(r'^https?://(?P<uname>\w+(\.\w+)*).blogspot.com/?$'),
108         re.compile(r'^https?://(?P<uname>\w+(\.\w+)*).livejournal.com/?$'),
109         re.compile(r'^https?://claimid.com/(?P<uname>\w+(\.\w+)*)/?$'),
110         re.compile(r'^https?://(?P<uname>\w+(\.\w+)*).pip.verisignlabs.com/?$'),
111         re.compile(r'^https?://getopenid.com/(?P<uname>\w+(\.\w+)*)/?$'),
112         re.compile(r'^https?://[\w\.]+/(\w+/)*(?P<uname>\w+(\.\w+)*)/?$'),
113         re.compile(r'^https?://(?P<uname>[\w\.]+)/?$'),
114         ]
115
116 def final_username_attempt(sxu):
117     openid = sxu.get('openid', None)
118
119     if openid:
120         if google_accounts_lookup.search(openid):
121             return UnknownGoogleUser(sxu.get('id'))
122         if yahoo_accounts_lookup.search(openid):
123             return UnknownYahooUser(sxu.get('id'))
124
125         for lookup in openid_lookups:
126             if lookup.search(openid):
127                 return lookup.search(openid).group('uname')
128
129     return UnknownUser(sxu.get('id'))
130
131 class UnknownUser(object):
132     def __init__(self, id):
133         self._id = id
134
135     def __str__(self):
136         return _("user-%(id)s") % {'id': self._id}
137
138     def __unicode__(self):
139         return self.__str__()
140
141     def encode(self, *args):
142         return self.__str__()
143
144 class UnknownGoogleUser(UnknownUser):
145     def __str__(self):
146         return _("user-%(id)s (google)") % {'id': self._id}
147
148 class UnknownYahooUser(UnknownUser):
149     def __str__(self):
150         return _("user-%(id)s (yahoo)") % {'id': self._id}
151
152
153 class IdMapper(dict):
154     def __getitem__(self, key):
155         key = int(key)
156         return super(IdMapper, self).get(key, 1)
157
158     def __setitem__(self, key, value):
159         super(IdMapper, self).__setitem__(int(key), int(value))
160
161 class IdIncrementer():
162     def __init__(self, initial):
163         self.value = initial
164
165     def inc(self):
166         self.value += 1
167
168 openidre = re.compile('^https?\:\/\/')
169 def userimport(path, options):
170 #users = readTable(dump, "Users")
171
172     user_by_name = {}
173     uidmapper = IdMapper()
174     #merged_users = []
175
176     owneruid = options.get('owneruid', None)
177     #check for empty values
178     if not owneruid:
179         owneruid = None
180
181     def callback(sxu):
182         create = True
183
184         if sxu.get('id') == '-1':
185             return
186         #print "\n".join(["%s : %s" % i for i in sxu.items()])
187         if int(sxu.get('id')) == int(owneruid):
188             osqau = orm.User.objects.get(id=1)
189             uidmapper[owneruid] = 1
190             uidmapper[-1] = 1
191             create = False
192         else:
193             username = sxu.get('displayname',
194                                sxu.get('displaynamecleaned', sxu.get('realname', final_username_attempt(sxu))))
195
196             if not isinstance(username, UnknownUser) and username in user_by_name:
197             #if options.get('mergesimilar', False) and sxu.get('email', 'INVALID') == user_by_name[username].email:
198             #    osqau = user_by_name[username]
199             #    create = False
200             #    uidmapper[sxu.get('id')] = osqau.id
201             #else:
202                 inc = 1
203                 while ("%s %d" % (username, inc)) in user_by_name:
204                     inc += 1
205
206                 username = "%s %d" % (username, inc)
207
208         sxbadges = sxu.get('badgesummary', None)
209         badges = {'1':'0', '2':'0', '3':'0'}
210
211         if sxbadges:
212             badges.update(dict([b.split('=') for b in sxbadges.split()]))
213
214         if create:
215             osqau = orm.User(
216                     id           = sxu.get('id'),
217                     username     = unicode(username),
218                     password     = '!',
219                     email        = sxu.get('email', ''),
220                     is_superuser = sxu.get('usertypeid') == '5',
221                     is_staff     = sxu.get('usertypeid') == '4',
222                     is_active    = True,
223                     date_joined  = readTime(sxu.get('creationdate')),
224                     last_seen    = readTime(sxu.get('lastaccessdate')),
225                     about         = sxu.get('aboutme', ''),
226                     date_of_birth = sxu.get('birthday', None) and readTime(sxu['birthday']) or None,
227                     email_isvalid = int(sxu.get('usertypeid')) > 2,
228                     website       = sxu.get('websiteurl', ''),
229                     reputation    = int(sxu.get('reputation')),
230                     gold          = int(badges['1']),
231                     silver        = int(badges['2']),
232                     bronze        = int(badges['3']),
233                     real_name     = sxu.get('realname', ''),
234                     location      = sxu.get('location', ''),
235                     )
236
237             osqau.save()
238
239             user_joins = orm.Action(
240                     action_type = "userjoins",
241                     action_date = osqau.date_joined,
242                     user = osqau
243                     )
244             user_joins.save()
245
246             rep = orm.ActionRepute(
247                     value = 1,
248                     user = osqau,
249                     date = osqau.date_joined,
250                     action = user_joins
251                     )
252             rep.save()
253
254             try:
255                 orm.SubscriptionSettings.objects.get(user=osqau)
256             except:
257                 s = orm.SubscriptionSettings(user=osqau)
258                 s.save()
259
260             uidmapper[osqau.id] = osqau.id
261         else:
262             new_about = sxu.get('aboutme', None)
263             if new_about and osqau.about != new_about:
264                 if osqau.about:
265                     osqau.about = "%s\n|\n%s" % (osqau.about, new_about)
266                 else:
267                     osqau.about = new_about
268
269             osqau.username = sxu.get('displayname',
270                                      sxu.get('displaynamecleaned', sxu.get('realname', final_username_attempt(sxu))))
271             osqau.email = sxu.get('email', '')
272             osqau.reputation += int(sxu.get('reputation'))
273             osqau.gold += int(badges['1'])
274             osqau.silver += int(badges['2'])
275             osqau.bronze += int(badges['3'])
276
277             osqau.date_joined = readTime(sxu.get('creationdate'))
278             osqau.website = sxu.get('websiteurl', '')
279             osqau.date_of_birth = sxu.get('birthday', None) and readTime(sxu['birthday']) or None
280             osqau.location = sxu.get('location', '')
281             osqau.real_name = sxu.get('realname', '')
282
283             #merged_users.append(osqau.id)
284             osqau.save()
285
286         user_by_name[osqau.username] = osqau
287
288         openid = sxu.get('openid', None)
289         if openid and openidre.match(openid):
290             assoc = orm.AuthKeyUserAssociation(user=osqau, key=openid, provider="openidurl")
291             assoc.save()
292
293     readTable(path, "Users", callback)
294
295     if uidmapper[-1] == -1:
296         uidmapper[-1] = 1
297
298     return uidmapper
299
300 def tagsimport(dump, uidmap):
301 #tags = readTable(dump, "Tags")
302
303     tagmap = {}
304
305     def callback(sxtag):
306         otag = orm.Tag(
307                 id = int(sxtag['id']),
308                 name = sxtag['name'],
309                 used_count = int(sxtag['count']),
310                 created_by_id = uidmap[sxtag.get('userid', 1)],
311                 )
312         otag.save()
313
314         tagmap[otag.name] = otag
315
316     readTable(dump, "Tags", callback)
317
318     return tagmap
319
320 def add_post_state(name, post, action):
321     if not "(%s)" % name in post.state_string:
322         post.state_string = "%s(%s)" % (post.state_string, name)
323         post.save()
324
325     try:
326         state = orm.NodeState.objects.get(node=post, state_type=name)
327         state.action = action
328         state.save()
329     except:
330         state = orm.NodeState(node=post, state_type=name, action=action)
331         state.save()
332
333 def remove_post_state(name, post):
334     if "(%s)" % name in post.state_string:
335         try:
336             state = orm.NodeState.objects.get(state_type=name, post=post)
337             state.delete()
338         except:
339             pass
340     post.state_string = "".join("(%s)" % s for s in re.findall('\w+', post.state_string) if s != name)
341
342 def postimport(dump, uidmap, tagmap):
343 #history = {}
344 #accepted = {}
345     all = []
346
347     #for h in readTable(dump, "PostHistory"):
348     #    if not history.get(h.get('postid'), None):
349     #        history[h.get('postid')] = []
350     #
351     #    history[h.get('postid')].append(h)
352
353     #posts = readTable(dump, "Posts")
354
355     def callback(sxpost):
356         nodetype = (sxpost.get('posttypeid') == '1') and "nodetype" or "answer"
357
358         post = orm.Node(
359                 node_type = nodetype,
360                 id = sxpost['id'],
361                 added_at = readTime(sxpost['creationdate']),
362                 body = sxpost['body'],
363                 score = sxpost.get('score', 0),
364                 author_id = sxpost.get('deletiondate', None) and 1 or uidmap[sxpost.get('owneruserid', 1)]
365                 )
366
367         post.save()
368
369         create_action = orm.Action(
370                 action_type = (nodetype == "nodetype") and "ask" or "answer",
371                 user_id = post.author_id,
372                 node = post,
373                 action_date = post.added_at
374                 )
375
376         create_action.save()
377
378         if sxpost.get('lasteditoruserid', None):
379             revise_action = orm.Action(
380                     action_type = "revise",
381                     user_id = uidmap[sxpost.get('lasteditoruserid')],
382                     node = post,
383                     action_date = readTime(sxpost['lasteditdate']),
384                     )
385
386             revise_action.save()
387             post.last_edited = revise_action
388
389         if sxpost.get('communityowneddate', None):
390             wikify_action = orm.Action(
391                     action_type = "wikify",
392                     user_id = 1,
393                     node = post,
394                     action_date = readTime(sxpost['communityowneddate'])
395                     )
396
397             wikify_action.save()
398             add_post_state("wiki", post, wikify_action)
399
400         if sxpost.get('lastactivityuserid', None):
401             post.last_activity_by_id = uidmap[sxpost['lastactivityuserid']]
402             post.last_activity_at = readTime(sxpost['lastactivitydate'])
403
404         if sxpost.get('posttypeid') == '1': #question
405             post.node_type = "question"
406             post.title = sxpost['title']
407
408             tagnames = sxpost['tags'].replace(u'ö', '-').replace(u'é', '').replace(u'à', '')
409             post.tagnames = tagnames
410
411             post.extra_count = sxpost.get('viewcount', 0)
412
413             add_tags_to_post(post, tagmap)
414
415         else:
416             post.parent_id = sxpost['parentid']
417
418         post.save()
419
420         all.append(int(post.id))
421
422         del post
423
424     readTable(dump, "Posts", callback)
425
426     return all
427
428 def comment_import(dump, uidmap, posts):
429 #comments = readTable(dump, "PostComments")
430     currid = IdIncrementer(max(posts))
431     mapping = {}
432
433     def callback(sxc):
434         currid.inc()
435         oc = orm.Node(
436                 id = currid.value,
437                 node_type = "comment",
438                 added_at = readTime(sxc['creationdate']),
439                 author_id = uidmap[sxc.get('userid', 1)],
440                 body = sxc['text'],
441                 parent_id = sxc.get('postid'),
442                 )
443
444         if sxc.get('deletiondate', None):
445             delete_action = orm.Action(
446                     action_type = "delete",
447                     user_id = uidmap[sxc['deletionuserid']],
448                     action_date = readTime(sxc['deletiondate'])
449                     )
450
451             oc.author_id = uidmap[sxc['deletionuserid']]
452             oc.save()
453
454             delete_action.node = oc
455             delete_action.save()
456
457             add_post_state("deleted", oc, delete_action)
458         else:
459             oc.author_id = uidmap[sxc.get('userid', 1)]
460             oc.save()
461
462         create_action = orm.Action(
463                 action_type = "comment",
464                 user_id = oc.author_id,
465                 node = oc,
466                 action_date = oc.added_at
467                 )
468
469         create_action.save()
470         oc.save()
471
472         posts.append(int(oc.id))
473         mapping[int(sxc['id'])] = int(oc.id)
474
475     readTable(dump, "PostComments", callback)
476     return posts, mapping
477
478
479 def add_tags_to_post(post, tagmap):
480     tags = [tag for tag in [tagmap.get(name.strip()) for name in post.tagnames.split(u' ') if name] if tag]
481     post.tagnames = " ".join([t.name for t in tags]).strip()
482     post.tags = tags
483     create_and_activate_revision(post)
484
485
486 def create_and_activate_revision(post):
487     rev = orm.NodeRevision(
488             author_id = post.author_id,
489             body = post.body,
490             node_id = post.id,
491             revised_at = post.added_at,
492             revision = 1,
493             summary = 'Initial revision',
494             tagnames = post.tagnames,
495             title = post.title,
496             )
497
498     rev.save()
499     post.active_revision_id = rev.id
500     post.save()
501
502 def post_vote_import(dump, uidmap, posts):
503 #votes = readTable(dump, "Posts2Votes")
504     close_reasons = {}
505
506     def close_callback(r):
507         close_reasons[r['id']] = r['name']
508
509     readTable(dump, "CloseReasons", close_callback)
510
511     user2vote = []
512
513     def callback(sxv):
514         action = orm.Action(
515                 user_id=uidmap[sxv['userid']],
516                 action_date = readTime(sxv['creationdate']),
517                 )
518
519         if not int(sxv['postid']) in posts: return
520         node = orm.Node.objects.get(id=sxv['postid'])
521         action.node = node
522
523         if sxv['votetypeid'] == '1':
524             answer = node
525             question = orm.Node.objects.get(id=answer.parent_id)
526
527             action.action_type = "acceptanswer"
528             action.save()
529
530             answer.marked = True
531
532             question.extra_ref_id = answer.id
533
534             answer.save()
535             question.save()
536
537         elif sxv['votetypeid'] in ('2', '3'):
538             if not (action.node.id, action.user_id) in user2vote:
539                 user2vote.append((action.node.id, action.user_id))
540
541                 action.action_type = (sxv['votetypeid'] == '2') and "voteup" or "votedown"
542                 action.save()
543
544                 ov = orm.Vote(
545                         node_id = action.node.id,
546                         user_id = action.user_id,
547                         voted_at = action.action_date,
548                         value = sxv['votetypeid'] == '2' and 1 or -1,
549                         action = action
550                         )
551                 ov.save()
552             else:
553                 action.action_type = "unknown"
554                 action.save()
555
556         elif sxv['votetypeid'] in ('4', '12', '13'):
557             action.action_type = "flag"
558             action.save()
559
560             of = orm.Flag(
561                     node = action.node,
562                     user_id = action.user_id,
563                     flagged_at = action.action_date,
564                     reason = '',
565                     action = action
566                     )
567
568             of.save()
569
570         elif sxv['votetypeid'] == '5':
571             action.action_type = "favorite"
572             action.save()
573
574         elif sxv['votetypeid'] == '6':
575             action.action_type = "close"
576             action.extra = dbsafe_encode(close_reasons[sxv['comment']])
577             action.save()
578
579             node.marked = True
580             node.save()
581
582         elif sxv['votetypeid'] == '7':
583             action.action_type = "unknown"
584             action.save()
585
586             node.marked = False
587             node.save()
588
589             remove_post_state("closed", node)
590
591         elif sxv['votetypeid'] == '10':
592             action.action_type = "delete"
593             action.save()
594
595         elif sxv['votetypeid'] == '11':
596             action.action_type = "unknown"
597             action.save()
598
599             remove_post_state("deleted", node)
600
601         else:
602             action.action_type = "unknown"
603             action.save()
604
605         if sxv.get('targetrepchange', None):
606             rep = orm.ActionRepute(
607                     action = action,
608                     date = action.action_date,
609                     user_id = uidmap[sxv['targetuserid']],
610                     value = int(sxv['targetrepchange'])
611                     )
612
613             rep.save()
614
615         if sxv.get('voterrepchange', None):
616             rep = orm.ActionRepute(
617                     action = action,
618                     date = action.action_date,
619                     user_id = uidmap[sxv['userid']],
620                     value = int(sxv['voterrepchange'])
621                     )
622
623             rep.save()
624
625         if action.action_type in ("acceptanswer", "delete", "close"):
626             state = {"acceptanswer": "accepted", "delete": "deleted", "close": "closed"}[action.action_type]
627             add_post_state(state, node, action)
628
629     readTable(dump, "Posts2Votes", callback)
630
631
632 def comment_vote_import(dump, uidmap, comments):
633 #votes = readTable(dump, "Comments2Votes")
634     user2vote = []
635     comments2score = {}
636
637     def callback(sxv):
638         if sxv['votetypeid'] == "2":
639             comment_id = comments[int(sxv['postcommentid'])]
640             user_id = uidmap[sxv['userid']]
641
642             if not (comment_id, user_id) in user2vote:
643                 user2vote.append((comment_id, user_id))
644
645                 action = orm.Action(
646                         action_type = "voteupcomment",
647                         user_id = user_id,
648                         action_date = readTime(sxv['creationdate']),
649                         node_id = comment_id
650                         )
651                 action.save()
652
653                 ov = orm.Vote(
654                         node_id = comment_id,
655                         user_id = user_id,
656                         voted_at = action.action_date,
657                         value = 1,
658                         action = action
659                         )
660
661                 ov.save()
662
663                 if not comment_id in comments2score:
664                     comments2score[comment_id] = 1
665                 else:
666                     comments2score[comment_id] += 1
667
668     readTable(dump, "Comments2Votes", callback)
669
670     for cid, score in comments2score.items():
671         orm.Node.objects.filter(id=cid).update(score=score)
672
673
674 def badges_import(dump, uidmap, post_list):
675 #node_ctype = orm['contenttypes.contenttype'].objects.get(name='node')
676
677     sxbadges = {}
678
679     def sxcallback(b):
680         sxbadges[int(b['id'])] = b
681
682     readTable(dump, "Badges", sxcallback)
683
684     obadges = dict([(b.cls, b) for b in orm.Badge.objects.all()])
685     user_badge_count = {}
686
687     sx_to_osqa = {}
688
689     for id, sxb in sxbadges.items():
690         cls = "".join(sxb['name'].replace('&', 'And').split(' '))
691
692         if cls in obadges:
693             sx_to_osqa[id] = obadges[cls]
694         else:
695             osqab = orm.Badge(
696                     cls = cls,
697                     awarded_count = 0,
698                     type = sxb['class']
699                     )
700             osqab.save()
701             sx_to_osqa[id] = osqab
702
703     osqaawards = []
704
705     def callback(sxa):
706         badge = sx_to_osqa[int(sxa['badgeid'])]
707
708         user_id = uidmap[sxa['userid']]
709         if not user_badge_count.get(user_id, None):
710             user_badge_count[user_id] = 0
711
712         action = orm.Action(
713                 action_type = "award",
714                 user_id = user_id,
715                 action_date = readTime(sxa['date'])
716                 )
717
718         action.save()
719
720         osqaa = orm.Award(
721                 user_id = uidmap[sxa['userid']],
722                 badge = badge,
723                 node_id = post_list[user_badge_count[user_id]],
724                 awarded_at = action.action_date,
725                 action = action
726                 )
727
728         osqaa.save()
729         badge.awarded_count += 1
730         user_badge_count[user_id] += 1
731
732     readTable(dump, "Users2Badges", callback)
733
734     for badge in obadges.values():
735         badge.save()
736
737 def pages_import(dump, currid):
738     currid = IdIncrementer(currid)
739     registry = {}
740     #sx_pages = readTable(dump, "FlatPages")
741
742     def callback(sxp):
743         currid.inc()
744         page = orm.Node(
745                 id = currid.value,
746                 node_type = "page",
747                 title = sxp['name'],
748                 body = b64decode(sxp['value']),
749                 extra = dbsafe_encode({
750                 'path': sxp['url'][1:],
751                 'mimetype': sxp['contenttype'],
752                 'template': (sxp['usemaster'] == "true") and "default" or "none",
753                 'render': "html",
754                 'sidebar': "",
755                 'sidebar_wrap': True,
756                 'sidebar_render': "html",
757                 'comments': False
758                 }),
759                 author_id = 1
760                 )
761
762         page.save()
763         registry[sxp['url'][1:]] = page.id
764
765         create_action = orm.Action(
766                 action_type = "newpage",
767                 user_id = page.author_id,
768                 node = page
769                 )
770
771         create_action.save()
772
773         if sxp['active'] == "true" and sxp['contenttype'] == "text/html":
774             pub_action = orm.Action(
775                     action_type = "publish",
776                     user_id = page.author_id,
777                     node = page
778                     )
779
780             pub_action.save()
781             add_post_state("published", page, pub_action)
782
783     readTable(dump, "FlatPages", callback)
784
785     kv = orm.KeyValue(key='STATIC_PAGE_REGISTRY', value=dbsafe_encode(registry))
786     kv.save()
787
788 sx2osqa_set_map = {
789 u'theme.html.name': 'APP_TITLE',
790 u'theme.html.footer': 'USE_CUSTOM_FOOTER',
791 u'theme.html.sidebar': 'SIDEBAR_UPPER_TEXT',
792 u'theme.html.sidebar-low': 'SIDEBAR_LOWER_TEXT',
793 u'theme.html.welcome': 'APP_INTRO',
794 u'theme.html.head': 'CUSTOM_HEAD',
795 u'theme.html.header': 'CUSTOM_HEADER'
796 }
797
798 html_codes = (
799 ('&amp;', '&'),
800 ('&lt;', '<'),
801 ('&gt;', '>'),
802 ('&quot;', '"'),
803 ('&#39;', "'"),
804 )
805
806 def html_decode(html):
807     html = force_unicode(html)
808
809     for args in html_codes:
810         html = html.replace(*args)
811
812     return html
813
814
815 def static_import(dump):
816 #sx_sets = readTable(dump, "ThemeTextResources")
817     sx_unknown = {}
818
819     def callback(set):
820         if unicode(set['name']) in sx2osqa_set_map:
821             kv = orm.KeyValue(
822                     key = sx2osqa_set_map[set['name']],
823                     value = dbsafe_encode(html_decode(set['value']))
824                     )
825
826             kv.save()
827         else:
828             sx_unknown[set['name']] = html_decode(set['value'])
829
830     readTable(dump, "ThemeTextResources", callback)
831
832     unknown = orm.KeyValue(key='SXIMPORT_UNKNOWN_SETS', value=dbsafe_encode(sx_unknown))
833     unknown.save()
834
835 def disable_triggers():
836     from south.db import db
837     if db.backend_name == "postgres":
838         db.execute_many(PG_DISABLE_TRIGGERS)
839         db.commit_transaction()
840         db.start_transaction()
841
842 def enable_triggers():
843     from south.db import db
844     if db.backend_name == "postgres":
845         db.start_transaction()
846         db.execute_many(PG_ENABLE_TRIGGERS)
847         db.commit_transaction()
848
849 def reset_sequences():
850     from south.db import db
851     if db.backend_name == "postgres":
852         db.start_transaction()
853         db.execute_many(PG_SEQUENCE_RESETS)
854         db.commit_transaction()
855
856
857 def sximport(dump, options):
858     disable_triggers()
859     uidmap = userimport(dump, options)
860     tagmap = tagsimport(dump, uidmap)
861     gc.collect()
862
863     posts = postimport(dump, uidmap, tagmap)
864     gc.collect()
865
866     posts, comments = comment_import(dump, uidmap, posts)
867     gc.collect()
868
869     post_vote_import(dump, uidmap, posts)
870     gc.collect()
871
872     comment_vote_import(dump, uidmap, comments)
873     gc.collect()
874
875     badges_import(dump, uidmap, posts)
876
877     pages_import(dump, max(posts))
878     static_import(dump)
879     gc.collect()
880
881     from south.db import db
882     db.commit_transaction()
883
884     reset_sequences()
885     enable_triggers()
886
887
888 PG_DISABLE_TRIGGERS = """
889 ALTER table auth_user DISABLE TRIGGER ALL;
890 ALTER table auth_user_groups DISABLE TRIGGER ALL;
891 ALTER table auth_user_user_permissions DISABLE TRIGGER ALL;
892 ALTER table forum_keyvalue DISABLE TRIGGER ALL;
893 ALTER table forum_action DISABLE TRIGGER ALL;
894 ALTER table forum_actionrepute DISABLE TRIGGER ALL;
895 ALTER table forum_subscriptionsettings DISABLE TRIGGER ALL;
896 ALTER table forum_validationhash DISABLE TRIGGER ALL;
897 ALTER table forum_authkeyuserassociation DISABLE TRIGGER ALL;
898 ALTER table forum_tag DISABLE TRIGGER ALL;
899 ALTER table forum_markedtag DISABLE TRIGGER ALL;
900 ALTER table forum_node DISABLE TRIGGER ALL;
901 ALTER table forum_nodestate DISABLE TRIGGER ALL;
902 ALTER table forum_node_tags DISABLE TRIGGER ALL;
903 ALTER table forum_noderevision DISABLE TRIGGER ALL;
904 ALTER table forum_node_tags DISABLE TRIGGER ALL;
905 ALTER table forum_questionsubscription DISABLE TRIGGER ALL;
906 ALTER table forum_vote DISABLE TRIGGER ALL;
907 ALTER table forum_flag DISABLE TRIGGER ALL;
908 ALTER table forum_badge DISABLE TRIGGER ALL;
909 ALTER table forum_award DISABLE TRIGGER ALL;
910 ALTER table forum_openidnonce DISABLE TRIGGER ALL;
911 ALTER table forum_openidassociation DISABLE TRIGGER ALL;
912 """
913
914 PG_ENABLE_TRIGGERS = """
915 ALTER table auth_user ENABLE TRIGGER ALL;
916 ALTER table auth_user_groups ENABLE TRIGGER ALL;
917 ALTER table auth_user_user_permissions ENABLE TRIGGER ALL;
918 ALTER table forum_keyvalue ENABLE TRIGGER ALL;
919 ALTER table forum_action ENABLE TRIGGER ALL;
920 ALTER table forum_actionrepute ENABLE TRIGGER ALL;
921 ALTER table forum_subscriptionsettings ENABLE TRIGGER ALL;
922 ALTER table forum_validationhash ENABLE TRIGGER ALL;
923 ALTER table forum_authkeyuserassociation ENABLE TRIGGER ALL;
924 ALTER table forum_tag ENABLE TRIGGER ALL;
925 ALTER table forum_markedtag ENABLE TRIGGER ALL;
926 ALTER table forum_node ENABLE TRIGGER ALL;
927 ALTER table forum_nodestate ENABLE TRIGGER ALL;
928 ALTER table forum_node_tags ENABLE TRIGGER ALL;
929 ALTER table forum_noderevision ENABLE TRIGGER ALL;
930 ALTER table forum_node_tags ENABLE TRIGGER ALL;
931 ALTER table forum_questionsubscription ENABLE TRIGGER ALL;
932 ALTER table forum_vote ENABLE TRIGGER ALL;
933 ALTER table forum_flag ENABLE TRIGGER ALL;
934 ALTER table forum_badge ENABLE TRIGGER ALL;
935 ALTER table forum_award ENABLE TRIGGER ALL;
936 ALTER table forum_openidnonce ENABLE TRIGGER ALL;
937 ALTER table forum_openidassociation ENABLE TRIGGER ALL;
938 """
939
940 PG_SEQUENCE_RESETS = """
941 SELECT setval('"auth_user_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "auth_user";
942 SELECT setval('"auth_user_groups_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "auth_user_groups";
943 SELECT setval('"auth_user_user_permissions_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "auth_user_user_permissions";
944 SELECT setval('"forum_keyvalue_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_keyvalue";
945 SELECT setval('"forum_action_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_action";
946 SELECT setval('"forum_actionrepute_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_actionrepute";
947 SELECT setval('"forum_subscriptionsettings_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_subscriptionsettings";
948 SELECT setval('"forum_validationhash_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_validationhash";
949 SELECT setval('"forum_authkeyuserassociation_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_authkeyuserassociation";
950 SELECT setval('"forum_tag_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_tag";
951 SELECT setval('"forum_markedtag_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_markedtag";
952 SELECT setval('"forum_node_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_node";
953 SELECT setval('"forum_nodestate_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_nodestate";
954 SELECT setval('"forum_node_tags_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_node_tags";
955 SELECT setval('"forum_noderevision_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_noderevision";
956 SELECT setval('"forum_node_tags_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_node_tags";
957 SELECT setval('"forum_questionsubscription_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_questionsubscription";
958 SELECT setval('"forum_vote_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_vote";
959 SELECT setval('"forum_flag_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_flag";
960 SELECT setval('"forum_badge_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_badge";
961 SELECT setval('"forum_award_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_award";
962 SELECT setval('"forum_openidnonce_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_openidnonce";
963 SELECT setval('"forum_openidassociation_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_openidassociation";
964 """
965
966
967     
968