]> git.openstreetmap.org Git - osqa.git/blob - forum_modules/sximporter/importer.py
Reverting the merges due to unsuccessfull conflict resolvement.
[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     usernames = []
173     openids = set()
174     uidmapper = IdMapper()
175     #merged_users = []
176
177     owneruid = options.get('owneruid', None)
178     #check for empty values
179     if not owneruid:
180         owneruid = None
181
182     def callback(sxu):
183         create = True
184
185         if sxu.get('id') == '-1':
186             return
187         #print "\n".join(["%s : %s" % i for i in sxu.items()])
188         if int(sxu.get('id')) == int(owneruid):
189             osqau = orm.User.objects.get(id=1)
190             for assoc in orm.AuthKeyUserAssociation.objects.filter(user=osqau):
191                 openids.add(assoc.key)
192             uidmapper[owneruid] = 1
193             uidmapper[-1] = 1
194             create = False
195         else:
196             username = unicode(sxu.get('displayname',
197                                sxu.get('displaynamecleaned', sxu.get('realname', final_username_attempt(sxu)))))[:30]
198
199             if username in usernames:
200             #if options.get('mergesimilar', False) and sxu.get('email', 'INVALID') == user_by_name[username].email:
201             #    osqau = user_by_name[username]
202             #    create = False
203             #    uidmapper[sxu.get('id')] = osqau.id
204             #else:
205                 inc = 0
206
207                 while True:
208                     inc += 1
209                     totest = "%s %d" % (username[:29 - len(str(inc))], inc)
210
211                     if not totest in usernames:
212                         username = totest
213                         break          
214
215         sxbadges = sxu.get('badgesummary', None)
216         badges = {'1':'0', '2':'0', '3':'0'}
217
218         if sxbadges:
219             badges.update(dict([b.split('=') for b in sxbadges.split()]))
220
221         if create:
222             osqau = orm.User(
223                     id           = sxu.get('id'),
224                     username     = username,
225                     password     = '!',
226                     email        = sxu.get('email', ''),
227                     is_superuser = sxu.get('usertypeid') == '5',
228                     is_staff     = sxu.get('usertypeid') == '4',
229                     is_active    = True,
230                     date_joined  = readTime(sxu.get('creationdate')),
231                     last_seen    = readTime(sxu.get('lastaccessdate')),
232                     about         = sxu.get('aboutme', ''),
233                     date_of_birth = sxu.get('birthday', None) and readTime(sxu['birthday']) or None,
234                     email_isvalid = int(sxu.get('usertypeid')) > 2,
235                     website       = sxu.get('websiteurl', ''),
236                     reputation    = int(sxu.get('reputation')),
237                     gold          = int(badges['1']),
238                     silver        = int(badges['2']),
239                     bronze        = int(badges['3']),
240                     real_name     = sxu.get('realname', '')[:30],
241                     location      = sxu.get('location', ''),
242                     )
243
244             osqau.save()
245
246             user_joins = orm.Action(
247                     action_type = "userjoins",
248                     action_date = osqau.date_joined,
249                     user = osqau
250                     )
251             user_joins.save()
252
253             rep = orm.ActionRepute(
254                     value = 1,
255                     user = osqau,
256                     date = osqau.date_joined,
257                     action = user_joins
258                     )
259             rep.save()
260
261             try:
262                 orm.SubscriptionSettings.objects.get(user=osqau)
263             except:
264                 s = orm.SubscriptionSettings(user=osqau)
265                 s.save()
266
267             uidmapper[osqau.id] = osqau.id
268         else:
269             new_about = sxu.get('aboutme', None)
270             if new_about and osqau.about != new_about:
271                 if osqau.about:
272                     osqau.about = "%s\n|\n%s" % (osqau.about, new_about)
273                 else:
274                     osqau.about = new_about
275
276             osqau.username = sxu.get('displayname',
277                                      sxu.get('displaynamecleaned', sxu.get('realname', final_username_attempt(sxu))))
278             osqau.email = sxu.get('email', '')
279             osqau.reputation += int(sxu.get('reputation'))
280             osqau.gold += int(badges['1'])
281             osqau.silver += int(badges['2'])
282             osqau.bronze += int(badges['3'])
283
284             osqau.date_joined = readTime(sxu.get('creationdate'))
285             osqau.website = sxu.get('websiteurl', '')
286             osqau.date_of_birth = sxu.get('birthday', None) and readTime(sxu['birthday']) or None
287             osqau.location = sxu.get('location', '')
288             osqau.real_name = sxu.get('realname', '')
289
290             #merged_users.append(osqau.id)
291             osqau.save()
292
293         usernames.append(osqau.username)
294
295         openid = sxu.get('openid', None)
296         if openid and openidre.match(openid) and (not openid in openids):
297             assoc = orm.AuthKeyUserAssociation(user=osqau, key=openid, provider="openidurl")
298             assoc.save()
299             openids.add(openid)
300
301         openidalt = sxu.get('openidalt', None)
302         if openidalt and openidre.match(openidalt) and (not openidalt in openids):
303             assoc = orm.AuthKeyUserAssociation(user=osqau, key=openidalt, provider="openidurl")
304             assoc.save()
305             openids.add(openidalt)
306
307     readTable(path, "Users", callback)
308
309     if uidmapper[-1] == -1:
310         uidmapper[-1] = 1
311
312     return uidmapper
313
314 def tagsimport(dump, uidmap):
315 #tags = readTable(dump, "Tags")
316
317     tagmap = {}
318
319     def callback(sxtag):
320         otag = orm.Tag(
321                 id = int(sxtag['id']),
322                 name = sxtag['name'],
323                 used_count = int(sxtag['count']),
324                 created_by_id = uidmap[sxtag.get('userid', 1)],
325                 )
326         otag.save()
327
328         tagmap[otag.name] = otag
329
330     readTable(dump, "Tags", callback)
331
332     return tagmap
333
334 def add_post_state(name, post, action):
335     if not "(%s)" % name in post.state_string:
336         post.state_string = "%s(%s)" % (post.state_string, name)
337         post.save()
338
339     try:
340         state = orm.NodeState.objects.get(node=post, state_type=name)
341         state.action = action
342         state.save()
343     except:
344         state = orm.NodeState(node=post, state_type=name, action=action)
345         state.save()
346
347 def remove_post_state(name, post):
348     if "(%s)" % name in post.state_string:
349         try:
350             state = orm.NodeState.objects.get(state_type=name, post=post)
351             state.delete()
352         except:
353             pass
354     post.state_string = "".join("(%s)" % s for s in re.findall('\w+', post.state_string) if s != name)
355
356 def postimport(dump, uidmap, tagmap):
357 #history = {}
358 #accepted = {}
359     all = []
360
361     #for h in readTable(dump, "PostHistory"):
362     #    if not history.get(h.get('postid'), None):
363     #        history[h.get('postid')] = []
364     #
365     #    history[h.get('postid')].append(h)
366
367     #posts = readTable(dump, "Posts")
368
369     def callback(sxpost):
370         nodetype = (sxpost.get('posttypeid') == '1') and "nodetype" or "answer"
371
372         post = orm.Node(
373                 node_type = nodetype,
374                 id = sxpost['id'],
375                 added_at = readTime(sxpost['creationdate']),
376                 body = sxpost['body'],
377                 score = sxpost.get('score', 0),
378                 author_id = sxpost.get('deletiondate', None) and 1 or uidmap[sxpost.get('owneruserid', 1)]
379                 )
380
381         post.save()
382
383         create_action = orm.Action(
384                 action_type = (nodetype == "nodetype") and "ask" or "answer",
385                 user_id = post.author_id,
386                 node = post,
387                 action_date = post.added_at
388                 )
389
390         create_action.save()
391
392         if sxpost.get('lasteditoruserid', None):
393             revise_action = orm.Action(
394                     action_type = "revise",
395                     user_id = uidmap[sxpost.get('lasteditoruserid')],
396                     node = post,
397                     action_date = readTime(sxpost['lasteditdate']),
398                     )
399
400             revise_action.save()
401             post.last_edited = revise_action
402
403         if sxpost.get('communityowneddate', None):
404             wikify_action = orm.Action(
405                     action_type = "wikify",
406                     user_id = 1,
407                     node = post,
408                     action_date = readTime(sxpost['communityowneddate'])
409                     )
410
411             wikify_action.save()
412             add_post_state("wiki", post, wikify_action)
413
414         if sxpost.get('lastactivityuserid', None):
415             post.last_activity_by_id = uidmap[sxpost['lastactivityuserid']]
416             post.last_activity_at = readTime(sxpost['lastactivitydate'])
417
418         if sxpost.get('posttypeid') == '1': #question
419             post.node_type = "question"
420             post.title = sxpost['title']
421
422             tagnames = sxpost['tags'].replace(u'ö', '-').replace(u'é', '').replace(u'à', '')
423             post.tagnames = tagnames
424
425             post.extra_count = sxpost.get('viewcount', 0)
426
427             add_tags_to_post(post, tagmap)
428
429         else:
430             post.parent_id = sxpost['parentid']
431
432         post.save()
433
434         all.append(int(post.id))
435         create_and_activate_revision(post)
436
437         del post
438
439     readTable(dump, "Posts", callback)
440
441     return all
442
443 def comment_import(dump, uidmap, posts):
444 #comments = readTable(dump, "PostComments")
445     currid = IdIncrementer(max(posts))
446     mapping = {}
447
448     def callback(sxc):
449         currid.inc()
450         oc = orm.Node(
451                 id = currid.value,
452                 node_type = "comment",
453                 added_at = readTime(sxc['creationdate']),
454                 author_id = uidmap[sxc.get('userid', 1)],
455                 body = sxc['text'],
456                 parent_id = sxc.get('postid'),
457                 )
458
459         if sxc.get('deletiondate', None):
460             delete_action = orm.Action(
461                     action_type = "delete",
462                     user_id = uidmap[sxc['deletionuserid']],
463                     action_date = readTime(sxc['deletiondate'])
464                     )
465
466             oc.author_id = uidmap[sxc['deletionuserid']]
467             oc.save()
468
469             delete_action.node = oc
470             delete_action.save()
471
472             add_post_state("deleted", oc, delete_action)
473         else:
474             oc.author_id = uidmap[sxc.get('userid', 1)]
475             oc.save()
476
477         create_action = orm.Action(
478                 action_type = "comment",
479                 user_id = oc.author_id,
480                 node = oc,
481                 action_date = oc.added_at
482                 )
483
484         create_and_activate_revision(oc)
485
486         create_action.save()
487         oc.save()
488
489         posts.append(int(oc.id))
490         mapping[int(sxc['id'])] = int(oc.id)
491
492     readTable(dump, "PostComments", callback)
493     return posts, mapping
494
495
496 def add_tags_to_post(post, tagmap):
497     tags = [tag for tag in [tagmap.get(name.strip()) for name in post.tagnames.split(u' ') if name] if tag]
498     post.tagnames = " ".join([t.name for t in tags]).strip()
499     post.tags = tags
500
501
502 def create_and_activate_revision(post):
503     rev = orm.NodeRevision(
504             author_id = post.author_id,
505             body = post.body,
506             node_id = post.id,
507             revised_at = post.added_at,
508             revision = 1,
509             summary = 'Initial revision',
510             tagnames = post.tagnames,
511             title = post.title,
512             )
513
514     rev.save()
515     post.active_revision_id = rev.id
516     post.save()
517
518 def post_vote_import(dump, uidmap, posts):
519 #votes = readTable(dump, "Posts2Votes")
520     close_reasons = {}
521
522     def close_callback(r):
523         close_reasons[r['id']] = r['name']
524
525     readTable(dump, "CloseReasons", close_callback)
526
527     user2vote = []
528
529     def callback(sxv):
530         action = orm.Action(
531                 user_id=uidmap[sxv['userid']],
532                 action_date = readTime(sxv['creationdate']),
533                 )
534
535         if not int(sxv['postid']) in posts: return
536         node = orm.Node.objects.get(id=sxv['postid'])
537         action.node = node
538
539         if sxv['votetypeid'] == '1':
540             answer = node
541             question = orm.Node.objects.get(id=answer.parent_id)
542
543             action.action_type = "acceptanswer"
544             action.save()
545
546             answer.marked = True
547
548             question.extra_ref_id = answer.id
549
550             answer.save()
551             question.save()
552
553         elif sxv['votetypeid'] in ('2', '3'):
554             if not (action.node.id, action.user_id) in user2vote:
555                 user2vote.append((action.node.id, action.user_id))
556
557                 action.action_type = (sxv['votetypeid'] == '2') and "voteup" or "votedown"
558                 action.save()
559
560                 ov = orm.Vote(
561                         node_id = action.node.id,
562                         user_id = action.user_id,
563                         voted_at = action.action_date,
564                         value = sxv['votetypeid'] == '2' and 1 or -1,
565                         action = action
566                         )
567                 ov.save()
568             else:
569                 action.action_type = "unknown"
570                 action.save()
571
572         elif sxv['votetypeid'] in ('4', '12', '13'):
573             action.action_type = "flag"
574             action.save()
575
576             of = orm.Flag(
577                     node = action.node,
578                     user_id = action.user_id,
579                     flagged_at = action.action_date,
580                     reason = '',
581                     action = action
582                     )
583
584             of.save()
585
586         elif sxv['votetypeid'] == '5':
587             action.action_type = "favorite"
588             action.save()
589
590         elif sxv['votetypeid'] == '6':
591             action.action_type = "close"
592             action.extra = dbsafe_encode(close_reasons[sxv['comment']])
593             action.save()
594
595             node.marked = True
596             node.save()
597
598         elif sxv['votetypeid'] == '7':
599             action.action_type = "unknown"
600             action.save()
601
602             node.marked = False
603             node.save()
604
605             remove_post_state("closed", node)
606
607         elif sxv['votetypeid'] == '10':
608             action.action_type = "delete"
609             action.save()
610
611         elif sxv['votetypeid'] == '11':
612             action.action_type = "unknown"
613             action.save()
614
615             remove_post_state("deleted", node)
616
617         else:
618             action.action_type = "unknown"
619             action.save()
620
621         if sxv.get('targetrepchange', None):
622             rep = orm.ActionRepute(
623                     action = action,
624                     date = action.action_date,
625                     user_id = uidmap[sxv['targetuserid']],
626                     value = int(sxv['targetrepchange'])
627                     )
628
629             rep.save()
630
631         if sxv.get('voterrepchange', None):
632             rep = orm.ActionRepute(
633                     action = action,
634                     date = action.action_date,
635                     user_id = uidmap[sxv['userid']],
636                     value = int(sxv['voterrepchange'])
637                     )
638
639             rep.save()
640
641         if action.action_type in ("acceptanswer", "delete", "close"):
642             state = {"acceptanswer": "accepted", "delete": "deleted", "close": "closed"}[action.action_type]
643             add_post_state(state, node, action)
644
645     readTable(dump, "Posts2Votes", callback)
646
647
648 def comment_vote_import(dump, uidmap, comments):
649 #votes = readTable(dump, "Comments2Votes")
650     user2vote = []
651     comments2score = {}
652
653     def callback(sxv):
654         if sxv['votetypeid'] == "2":
655             comment_id = comments[int(sxv['postcommentid'])]
656             user_id = uidmap[sxv['userid']]
657
658             if not (comment_id, user_id) in user2vote:
659                 user2vote.append((comment_id, user_id))
660
661                 action = orm.Action(
662                         action_type = "voteupcomment",
663                         user_id = user_id,
664                         action_date = readTime(sxv['creationdate']),
665                         node_id = comment_id
666                         )
667                 action.save()
668
669                 ov = orm.Vote(
670                         node_id = comment_id,
671                         user_id = user_id,
672                         voted_at = action.action_date,
673                         value = 1,
674                         action = action
675                         )
676
677                 ov.save()
678
679                 if not comment_id in comments2score:
680                     comments2score[comment_id] = 1
681                 else:
682                     comments2score[comment_id] += 1
683
684     readTable(dump, "Comments2Votes", callback)
685
686     for cid, score in comments2score.items():
687         orm.Node.objects.filter(id=cid).update(score=score)
688
689
690 def badges_import(dump, uidmap, post_list):
691 #node_ctype = orm['contenttypes.contenttype'].objects.get(name='node')
692
693     sxbadges = {}
694
695     def sxcallback(b):
696         sxbadges[int(b['id'])] = b
697
698     readTable(dump, "Badges", sxcallback)
699
700     obadges = dict([(b.cls, b) for b in orm.Badge.objects.all()])
701     user_badge_count = {}
702
703     sx_to_osqa = {}
704
705     for id, sxb in sxbadges.items():
706         cls = "".join(sxb['name'].replace('&', 'And').split(' '))
707
708         if cls in obadges:
709             sx_to_osqa[id] = obadges[cls]
710         else:
711             osqab = orm.Badge(
712                     cls = cls,
713                     awarded_count = 0,
714                     type = sxb['class']
715                     )
716             osqab.save()
717             sx_to_osqa[id] = osqab
718
719     osqaawards = []
720
721     def callback(sxa):
722         badge = sx_to_osqa[int(sxa['badgeid'])]
723
724         user_id = uidmap[sxa['userid']]
725         if not user_badge_count.get(user_id, None):
726             user_badge_count[user_id] = 0
727
728         action = orm.Action(
729                 action_type = "award",
730                 user_id = user_id,
731                 action_date = readTime(sxa['date'])
732                 )
733
734         action.save()
735
736         osqaa = orm.Award(
737                 user_id = uidmap[sxa['userid']],
738                 badge = badge,
739                 node_id = post_list[user_badge_count[user_id]],
740                 awarded_at = action.action_date,
741                 action = action
742                 )
743
744         osqaa.save()
745         badge.awarded_count += 1
746         user_badge_count[user_id] += 1
747
748     readTable(dump, "Users2Badges", callback)
749
750     for badge in obadges.values():
751         badge.save()
752
753 def pages_import(dump, currid):
754     currid = IdIncrementer(currid)
755     registry = {}
756     #sx_pages = readTable(dump, "FlatPages")
757
758     def callback(sxp):
759         currid.inc()
760         page = orm.Node(
761                 id = currid.value,
762                 node_type = "page",
763                 title = sxp['name'],
764                 body = b64decode(sxp['value']),
765                 extra = dbsafe_encode({
766                 'path': sxp['url'][1:],
767                 'mimetype': sxp['contenttype'],
768                 'template': (sxp['usemaster'] == "true") and "default" or "none",
769                 'render': "html",
770                 'sidebar': "",
771                 'sidebar_wrap': True,
772                 'sidebar_render': "html",
773                 'comments': False
774                 }),
775                 author_id = 1
776                 )
777
778         create_and_activate_revision(page)
779
780         page.save()
781         registry[sxp['url'][1:]] = page.id
782
783         create_action = orm.Action(
784                 action_type = "newpage",
785                 user_id = page.author_id,
786                 node = page
787                 )
788
789         create_action.save()
790
791         if sxp['active'] == "true" and sxp['contenttype'] == "text/html":
792             pub_action = orm.Action(
793                     action_type = "publish",
794                     user_id = page.author_id,
795                     node = page
796                     )
797
798             pub_action.save()
799             add_post_state("published", page, pub_action)
800
801     readTable(dump, "FlatPages", callback)
802
803     kv = orm.KeyValue(key='STATIC_PAGE_REGISTRY', value=dbsafe_encode(registry))
804     kv.save()
805
806 sx2osqa_set_map = {
807 u'theme.html.name': 'APP_TITLE',
808 u'theme.html.footer': 'CUSTOM_FOOTER',
809 u'theme.html.sidebar': 'SIDEBAR_UPPER_TEXT',
810 u'theme.html.sidebar-low': 'SIDEBAR_LOWER_TEXT',
811 u'theme.html.welcome': 'APP_INTRO',
812 u'theme.html.head': 'CUSTOM_HEAD',
813 u'theme.html.header': 'CUSTOM_HEADER',
814 u'theme.css': 'CUSTOM_CSS',
815 }
816
817 html_codes = (
818 ('&amp;', '&'),
819 ('&lt;', '<'),
820 ('&gt;', '>'),
821 ('&quot;', '"'),
822 ('&#39;', "'"),
823 )
824
825 def html_decode(html):
826     html = force_unicode(html)
827
828     for args in html_codes:
829         html = html.replace(*args)
830
831     return html
832
833
834 def static_import(dump):
835 #sx_sets = readTable(dump, "ThemeTextResources")
836     sx_unknown = {}
837
838     def callback(set):
839         if unicode(set['name']) in sx2osqa_set_map:
840             try:
841                 kv = orm.KeyValue.objects.get(key=sx2osqa_set_map[set['name']])
842                 kv.value = dbsafe_encode(html_decode(set['value']))
843             except:
844                 kv = orm.KeyValue(
845                         key = sx2osqa_set_map[set['name']],
846                         value = dbsafe_encode(html_decode(set['value']))
847                         )
848
849             kv.save()
850         else:
851             sx_unknown[set['name']] = html_decode(set['value'])
852
853     readTable(dump, "ThemeTextResources", callback)
854
855     unknown = orm.KeyValue(key='SXIMPORT_UNKNOWN_SETS', value=dbsafe_encode(sx_unknown))
856     unknown.save()
857
858 def disable_triggers():
859     from south.db import db
860     if db.backend_name == "postgres":
861         db.execute_many(PG_DISABLE_TRIGGERS)
862         db.commit_transaction()
863         db.start_transaction()
864
865 def enable_triggers():
866     from south.db import db
867     if db.backend_name == "postgres":
868         db.start_transaction()
869         db.execute_many(PG_ENABLE_TRIGGERS)
870         db.commit_transaction()
871
872 def reset_sequences():
873     from south.db import db
874     if db.backend_name == "postgres":
875         db.start_transaction()
876         db.execute_many(PG_SEQUENCE_RESETS)
877         db.commit_transaction()
878
879 def reindex_fts():
880     from south.db import db
881     if db.backend_name == "postgres":
882         db.start_transaction()
883         db.execute_many("UPDATE forum_noderevision set id = id WHERE TRUE;")
884         db.commit_transaction()
885
886
887 def sximport(dump, options):
888     try:
889         disable_triggers()
890         triggers_disabled = True
891     except:
892         triggers_disabled = False
893
894     uidmap = userimport(dump, options)
895     tagmap = tagsimport(dump, uidmap)
896     gc.collect()
897
898     posts = postimport(dump, uidmap, tagmap)
899     gc.collect()
900
901     posts, comments = comment_import(dump, uidmap, posts)
902     gc.collect()
903
904     post_vote_import(dump, uidmap, posts)
905     gc.collect()
906
907     comment_vote_import(dump, uidmap, comments)
908     gc.collect()
909
910     badges_import(dump, uidmap, posts)
911
912     pages_import(dump, max(posts))
913     static_import(dump)
914     gc.collect()
915
916     from south.db import db
917     db.commit_transaction()
918
919     reset_sequences()
920
921     if triggers_disabled:
922         enable_triggers()
923         reindex_fts()
924
925
926 PG_DISABLE_TRIGGERS = """
927 ALTER table auth_user DISABLE TRIGGER ALL;
928 ALTER table auth_user_groups DISABLE TRIGGER ALL;
929 ALTER table auth_user_user_permissions DISABLE TRIGGER ALL;
930 ALTER table forum_keyvalue DISABLE TRIGGER ALL;
931 ALTER table forum_action DISABLE TRIGGER ALL;
932 ALTER table forum_actionrepute DISABLE TRIGGER ALL;
933 ALTER table forum_subscriptionsettings DISABLE TRIGGER ALL;
934 ALTER table forum_validationhash DISABLE TRIGGER ALL;
935 ALTER table forum_authkeyuserassociation DISABLE TRIGGER ALL;
936 ALTER table forum_tag DISABLE TRIGGER ALL;
937 ALTER table forum_markedtag DISABLE TRIGGER ALL;
938 ALTER table forum_node DISABLE TRIGGER ALL;
939 ALTER table forum_nodestate DISABLE TRIGGER ALL;
940 ALTER table forum_node_tags DISABLE TRIGGER ALL;
941 ALTER table forum_noderevision DISABLE TRIGGER ALL;
942 ALTER table forum_node_tags DISABLE TRIGGER ALL;
943 ALTER table forum_questionsubscription DISABLE TRIGGER ALL;
944 ALTER table forum_vote DISABLE TRIGGER ALL;
945 ALTER table forum_flag DISABLE TRIGGER ALL;
946 ALTER table forum_badge DISABLE TRIGGER ALL;
947 ALTER table forum_award DISABLE TRIGGER ALL;
948 ALTER table forum_openidnonce DISABLE TRIGGER ALL;
949 ALTER table forum_openidassociation DISABLE TRIGGER ALL;
950 """
951
952 PG_ENABLE_TRIGGERS = """
953 ALTER table auth_user ENABLE TRIGGER ALL;
954 ALTER table auth_user_groups ENABLE TRIGGER ALL;
955 ALTER table auth_user_user_permissions ENABLE TRIGGER ALL;
956 ALTER table forum_keyvalue ENABLE TRIGGER ALL;
957 ALTER table forum_action ENABLE TRIGGER ALL;
958 ALTER table forum_actionrepute ENABLE TRIGGER ALL;
959 ALTER table forum_subscriptionsettings ENABLE TRIGGER ALL;
960 ALTER table forum_validationhash ENABLE TRIGGER ALL;
961 ALTER table forum_authkeyuserassociation ENABLE TRIGGER ALL;
962 ALTER table forum_tag ENABLE TRIGGER ALL;
963 ALTER table forum_markedtag ENABLE TRIGGER ALL;
964 ALTER table forum_node ENABLE TRIGGER ALL;
965 ALTER table forum_nodestate ENABLE TRIGGER ALL;
966 ALTER table forum_node_tags ENABLE TRIGGER ALL;
967 ALTER table forum_noderevision ENABLE TRIGGER ALL;
968 ALTER table forum_node_tags ENABLE TRIGGER ALL;
969 ALTER table forum_questionsubscription ENABLE TRIGGER ALL;
970 ALTER table forum_vote ENABLE TRIGGER ALL;
971 ALTER table forum_flag ENABLE TRIGGER ALL;
972 ALTER table forum_badge ENABLE TRIGGER ALL;
973 ALTER table forum_award ENABLE TRIGGER ALL;
974 ALTER table forum_openidnonce ENABLE TRIGGER ALL;
975 ALTER table forum_openidassociation ENABLE TRIGGER ALL;
976 """
977
978 PG_SEQUENCE_RESETS = """
979 SELECT setval('"auth_user_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "auth_user";
980 SELECT setval('"auth_user_groups_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "auth_user_groups";
981 SELECT setval('"auth_user_user_permissions_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "auth_user_user_permissions";
982 SELECT setval('"forum_keyvalue_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_keyvalue";
983 SELECT setval('"forum_action_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_action";
984 SELECT setval('"forum_actionrepute_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_actionrepute";
985 SELECT setval('"forum_subscriptionsettings_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_subscriptionsettings";
986 SELECT setval('"forum_validationhash_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_validationhash";
987 SELECT setval('"forum_authkeyuserassociation_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_authkeyuserassociation";
988 SELECT setval('"forum_tag_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_tag";
989 SELECT setval('"forum_markedtag_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_markedtag";
990 SELECT setval('"forum_node_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_node";
991 SELECT setval('"forum_nodestate_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_nodestate";
992 SELECT setval('"forum_node_tags_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_node_tags";
993 SELECT setval('"forum_noderevision_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_noderevision";
994 SELECT setval('"forum_node_tags_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_node_tags";
995 SELECT setval('"forum_questionsubscription_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_questionsubscription";
996 SELECT setval('"forum_vote_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_vote";
997 SELECT setval('"forum_flag_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_flag";
998 SELECT setval('"forum_badge_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_badge";
999 SELECT setval('"forum_award_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_award";
1000 SELECT setval('"forum_openidnonce_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_openidnonce";
1001 SELECT setval('"forum_openidassociation_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_openidassociation";
1002 """
1003
1004
1005     
1006