DATE_AND_AUTHOR_INF_SECTION = 'DateAndAuthor'
OPTIONS_INF_SECTION = 'Options'
-DATETIME_FORMAT = "%a %b %d %H:%M:%S %Y"
+DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
+DATE_FORMAT = "%Y-%m-%d"
def Etree_pretty__write(self, file, node, encoding, namespaces,
level=0, identator=" "):
tag = ET.SubElement(el, tag_name)
if content:
- tag.text = unicode(content)
+ tag.text = unicode(content).encode('utf-8')
for k, v in attrs.items():
tag.set(k, unicode(v))
return
- if isinstance(v, (int, long, str, float, bool, dict, list, tuple)):
+ if isinstance(v, (int, long, str, unicode, float, bool, dict, list, tuple)):
if isinstance(v, tuple):
t = 'list'
else:
else:
domain = 'localhost'
- fname = "%s-%s.tar.gz" % (domain, now.strftime('%Y%m%d%H%M'))
+ fname = "%s-%s" % (domain, now.strftime('%Y%m%d%H%M'))
inf = ConfigParser.SafeConfigParser()
inf.add_section(DATE_AND_AUTHOR_INF_SECTION)
- inf.set(DATE_AND_AUTHOR_INF_SECTION, 'file-name', fname)
+ inf.set(DATE_AND_AUTHOR_INF_SECTION, 'file-name', "%s.tar.gz" % fname)
inf.set(DATE_AND_AUTHOR_INF_SECTION, 'author', unicode(user.id))
inf.set(DATE_AND_AUTHOR_INF_SECTION, 'site', djsettings.APP_URL)
inf.set(DATE_AND_AUTHOR_INF_SECTION, 'started', start_time.strftime(DATETIME_FORMAT))
state['overall']['status'] = _('Saving backup file')
set_state()
t.close()
- shutil.copyfile(LAST_BACKUP, os.path.join(selfsettings.EXPORTER_BACKUP_STORAGE, fname))
+ shutil.copyfile(LAST_BACKUP, os.path.join(selfsettings.EXPORTER_BACKUP_STORAGE, "%s.tar.gz" % fname))
+ shutil.copyfile(os.path.join(tmp, 'backup.inf'), os.path.join(selfsettings.EXPORTER_BACKUP_STORAGE, "%s.backup.inf" % fname))
+
def export_upfiles(tf):
def set_state():
full_state['time_started'] = diff_date(start_time)
- cache.set(CACHE_KEY, full_state, 60)
+ cache.set(CACHE_KEY, full_state)
set_state()
import traceback
logging.error("Error executing xml backup: \n %s" % (traceback.format_exc()))
- print traceback.format_exc()
finally:
xml.etree.ElementTree.ElementTree._write = original__write
del xml.etree.ElementTree._ElementInterface.add
el.add('password', u.password)
el.add('email', u.email, validated=u.email_isvalid and 'true' or 'false')
el.add('reputation', u.reputation)
- el.add('joindate', u.date_joined)
+ el.add('badges', bronze=u.bronze, silver=u.silver, gold=u.gold)
+ el.add('joindate', u.date_joined.strftime(DATETIME_FORMAT))
+ el.add('active', u.is_active and 'true' or 'false')
- el.add('firstname', u.first_name)
- el.add('lastname', u.last_name)
+ el.add('realname', u.real_name)
el.add('bio', u.about)
el.add('location', u.location)
el.add('website', u.website)
- el.add('birthdate', u.date_of_birth)
+ el.add('birthdate', u.date_of_birth and u.date_of_birth.strftime(DATE_FORMAT) or "")
roles = el.add('roles')
if not anon_data:
el.add('author', n.author.id)
- el.add('date', n.added_at)
+ el.add('date', n.added_at.strftime(DATETIME_FORMAT))
el.add('parent', n.parent and n.parent.id or "")
+ el.add('absparent', n.abs_parent and n.abs_parent or "")
+
+ act = el.add('lastactivity')
+ act.add('by', n.last_activity_by and n.last_activity_by.id or "")
+ act.add('at', n.last_activity_at and n.last_activity_at.strftime(DATETIME_FORMAT) or "")
el.add('title', n.title)
el.add('body', n.body)
for t in n.tagname_list():
tags.add('tag', t)
- revs = el.add('revisions', active=n.active_revision and n.active_revision or n.revisions.order_by('revision')[0])
+ revs = el.add('revisions', active=n.active_revision and n.active_revision.revision or n.revisions.order_by('revision')[0].revision)
for r in n.revisions.order_by('revision'):
rev = _add_tag(revs, 'revision')
rev.add('summary', r.summary)
if not anon_data:
rev.add('author', r.author.id)
- rev.add('date', r.revised_at)
+ rev.add('date', r.revised_at.strftime(DATETIME_FORMAT))
rev.add('title', r.title)
rev.add('body', r.body)
rev.add('tags', ", ".join(r.tagname_list()))
+ el.add('marked', n.marked and 'true' or 'false')
el.add('extraRef', n.extra_ref and n.extra_ref.id or "")
- make_extra(el.add('exraData'), n.extra)
+ make_extra(el.add('extraData'), n.extra)
+ el.add('extraCount', n.extra_count and n.extra_count or "")
@exporter_step(Action.objects.all(), 'actions', 'action', _('Actions'), 'action_date')
repute.add('value', r.value)
-@exporter_step(NodeState.objects.all(), 'states', 'state', _('Node states'), 'action__action_date')
-def export_states(s, el, anon_data):
- el.add('type', s.state_type)
- el.add('node', s.node.id)
- el.add('trigger', s.action.id)
+#@exporter_step(NodeState.objects.all(), 'states', 'state', _('Node states'), 'action__action_date')
+#def export_states(s, el, anon_data):
+# el.add('type', s.state_type)
+# el.add('node', s.node.id)
+# el.add('trigger', s.action.id)
-@exporter_step(Badge.objects.all(), 'badges', 'badge', _('Badges'), user_data=True)
-def export_badges(b, el, anon_data):
- el.add('type', ["", 'gold', 'silver', 'bronze'][b.type])
- el.add('name', b.cls)
- el.add('count', b.awarded_count)
+#@exporter_step(Badge.objects.all(), 'badges', 'badge', _('Badges'), user_data=True)
+#def export_badges(b, el, anon_data):
+# el.add('type', ["", 'gold', 'silver', 'bronze'][b.type])
+# el.add('name', b.cls)
+# el.add('count', b.awarded_count)
@exporter_step(Award.objects.all(), 'awards', 'award', _('Awards'), 'awarded_at', True)
def export_awards(a, el, anon_data):
el.add('badge', a.badge.cls)
- el.add('user', a.user)
+ el.add('user', a.user.id)
el.add('node', a.node and a.node.id or "")
el.add('trigger', a.trigger and a.trigger.id or "")
el.add('action', a.action.id)
--- /dev/null
+import os, tarfile, datetime
+
+from xml.sax import make_parser
+from xml.sax.handler import ContentHandler, ErrorHandler
+
+from exporter import TMP_FOLDER, DATETIME_FORMAT, DATE_FORMAT
+from orm import orm
+
+NO_DEFAULT = object()
+
+class ContentElement():
+ def __init__(self, content):
+ self._content = content
+
+ def content(self):
+ return self._content.strip()
+
+ def as_bool(self):
+ return self.content() == "true"
+
+ def as_date(self, default=NO_DEFAULT):
+ try:
+ return datetime.datetime.strptime(self.content(), DATE_FORMAT)
+ except:
+ if default == NO_DEFAULT:
+ return datetime.date.fromtimestamp(0)
+ else:
+ return default
+
+
+ def as_datetime(self, default=NO_DEFAULT):
+ try:
+ return datetime.datetime.strptime(self.content(), DATETIME_FORMAT)
+ except:
+ if default == NO_DEFAULT:
+ return datetime.datetime.fromtimestamp(0)
+ else:
+ return default
+
+ def as_int(self, default=0):
+ try:
+ return int(self.content())
+ except:
+ return default
+
+ def __str__(self):
+ return self.content()
+
+
+class RowElement(ContentElement):
+ def __init__(self, name, attrs, parent=None):
+ self.name = name.lower()
+ self.parent = parent
+ self.attrs = dict([(k.lower(), ContentElement(v)) for k, v in attrs.items()])
+ self._content = ''
+ self.sub_elements = {}
+
+ if parent:
+ parent.add(self)
+
+ def add_to_content(self, ch):
+ self._content += ch
+
+ def add(self, sub):
+ curr = self.sub_elements.get(sub.name, None)
+
+ if not curr:
+ curr = []
+ self.sub_elements[sub.name] = curr
+
+ curr.append(sub)
+
+ def get(self, name, default=None):
+ return self.sub_elements.get(name.lower(), [default])[-1]
+
+ def get_list(self, name):
+ return self.sub_elements.get(name.lower(), [])
+
+ def get_listc(self, name):
+ return [r.content() for r in self.get_list(name)]
+
+ def getc(self, name, default=""):
+ el = self.get(name, None)
+
+ if el:
+ return el.content()
+ else:
+ return default
+
+ def get_attr(self, name, default=""):
+ return self.attrs.get(name.lower(), default)
+
+ def as_pickled(self, default=None):
+ value_el = self.get('value')
+
+ if value_el:
+ return value_el._as_pickled(default)
+ else:
+ return default
+
+ TYPES_MAP = dict([(c.__name__, c) for c in (int, long, str, unicode, float)])
+
+ def _as_pickled(self, default=None):
+ type = self.get_attr('type').content()
+
+ try:
+ if type == 'dict':
+ return dict([ (item.get_attr('key'), item.as_pickled()) for item in self.get_list('item') ])
+ elif type == 'list':
+ return [item.as_pickled() for item in self.get_list('item')]
+ elif type == 'bool':
+ return self.content().lower() == 'true'
+ elif type in RowElement.TYPES_MAP:
+ return RowElement.TYPES_MAP[type](self.content())
+ else:
+ return self.content()
+ except:
+ return default
+
+
+
+
+class TableHandler(ContentHandler):
+ def __init__(self, root_name, row_name, callback, callback_args = []):
+ self.root_name = root_name.lower()
+ self.row_name = row_name.lower()
+ self.callback = callback
+ self.callback_args = callback_args
+
+ self._reset()
+
+ def _reset(self):
+ self.curr_element = None
+ self.in_tag = None
+
+ def startElement(self, name, attrs):
+ name = name.lower()
+
+ if name == self.root_name.lower():
+ pass
+ elif name == self.row_name:
+ self.curr_element = RowElement(name, attrs)
+ else:
+ self.curr_element = RowElement(name, attrs, self.curr_element)
+
+ def characters(self, ch):
+ if self.curr_element:
+ self.curr_element.add_to_content(ch)
+
+ def endElement(self, name):
+ name = name.lower()
+
+ if name == self.root_name:
+ pass
+ elif name == self.row_name:
+ self.callback(self.curr_element, *self.callback_args)
+ self._reset()
+ else:
+ self.curr_element = self.curr_element.parent
+
+
+class SaxErrorHandler(ErrorHandler):
+ def error(self, e):
+ raise e
+
+ def fatalError(self, e):
+ raise e
+
+ def warning(self, e):
+ raise e
+
+FILE_HANDLERS = []
+
+def start_import(fname, user):
+ #dump = tarfile.open(fname, 'r')
+ #dump.extractall(TMP_FOLDER)
+
+ for h in FILE_HANDLERS:
+ h(TMP_FOLDER, user)
+
+def file_handler(file_name, root_tag, el_tag, args_handler=None, pre_callback=None, post_callback=None):
+ def decorator(fn):
+ def decorated(location, current_user):
+ if pre_callback:
+ pre_callback(current_user)
+
+ if (args_handler):
+ args = args_handler(current_user)
+ else:
+ args = []
+
+ parser = make_parser()
+ handler = TableHandler(root_tag, el_tag, fn, args)
+ parser.setContentHandler(handler)
+ #parser.setErrorHandler(SaxErrorHandler())
+
+ parser.parse(os.path.join(location, file_name))
+
+ if post_callback:
+ post_callback()
+
+ FILE_HANDLERS.append(decorated)
+ return decorated
+ return decorator
+
+
+@file_handler('users.xml', 'users', 'user', args_handler=lambda u: [u])
+def user_import(row, current_user):
+ if str(current_user.id) == row.getc('id'):
+ return
+
+ roles = row.get('roles').get_listc('role')
+ valid_email = row.get('email').get_attr('validated').as_bool()
+ badges = row.get('badges')
+
+ user = orm.User(
+ id = row.getc('id'),
+ username = row.getc('username'),
+ password = row.getc('password'),
+ email = row.getc('email'),
+ email_isvalid= valid_email,
+ is_superuser = 'superuser' in roles,
+ is_staff = 'moderator' in roles,
+ is_active = True,
+ date_joined = row.get('joindate').as_datetime(),
+ about = row.getc('bio'),
+ date_of_birth = row.get('birthdate').as_date(None),
+ website = row.getc('website'),
+ reputation = row.get('reputation').as_int(),
+ gold = badges.get_attr('gold').as_int(),
+ silver = badges.get_attr('silver').as_int(),
+ bronze = badges.get_attr('bronze').as_int(),
+ real_name = row.getc('realname'),
+ location = row.getc('location'),
+ )
+
+ user.save()
+
+ authKeys = row.get('authKeys')
+
+ for key in authKeys.get_list('key'):
+ orm.AuthKeyUserAssociation(user=user, key=key.getc('key'), provider=key.getc('provider')).save()
+
+ notifications = row.get('notifications')
+
+ attributes = dict([(str(k), v.as_bool() and 'i' or 'n') for k, v in notifications.get('notify').attrs.items()])
+ attributes.update(dict([(str(k), v.as_bool()) for k, v in notifications.get('autoSubscribe').attrs.items()]))
+ attributes.update(dict([(str("notify_%s" % k), v.as_bool()) for k, v in notifications.get('notifyOnSubscribed').attrs.items()]))
+
+ orm.SubscriptionSettings(user=user, enable_notifications=notifications.get_attr('enabled').as_bool(), **attributes).save()
+
+def pre_tag_import(user):
+ tag_import.tag_mappings={}
+
+
+@file_handler('tags.xml', 'tags', 'tag', pre_callback=pre_tag_import)
+def tag_import(row):
+ tag = orm.Tag(name=row.getc('name'), used_count=row.get('used').as_int(), created_by_id=row.get('author').as_int())
+ tag.save()
+ tag_import.tag_mappings[tag.name] = tag
+
+
+def post_node_import():
+ tag_import.tag_mappings = None
+
+@file_handler('nodes.xml', 'nodes', 'node', args_handler=lambda u: [tag_import.tag_mappings], post_callback=post_node_import)
+def node_import(row, tags):
+
+ ntags = []
+
+ for t in row.get('tags').get_list('tag'):
+ ntags.append(tags[t.content()])
+
+ last_act = row.get('lastactivity')
+
+ node = orm.Node(
+ id = row.getc('id'),
+ node_type = row.getc('type'),
+ author_id = row.get('author').as_int(),
+ added_at = row.get('date').as_datetime(),
+ parent_id = row.get('parent').as_int(None),
+ abs_parent_id = row.get('absparent').as_int(None),
+
+ last_activity_by_id = last_act.get('by').as_int(None),
+ last_activity_at = last_act.get('at').as_datetime(None),
+
+ title = row.getc('title'),
+ body = row.getc('body'),
+ tagnames = " ".join([t.name for t in ntags]),
+
+ marked = row.get('marked').as_bool(),
+ extra_ref_id = row.get('extraRef').as_int(None),
+ extra_count = row.get('extraCount').as_int(0),
+ extra = row.get('extraData').as_pickled()
+ )
+
+ node.save()
+ node.tags = ntags
+
+ revisions = row.get('revisions')
+ active = revisions.get_attr('active').as_int()
+
+ for r in revisions.get_list('revision'):
+ rev = orm.NodeRevision(
+ author_id = r.getc('author'),
+ body = r.getc('body'),
+ node = node,
+ revised_at = r.get('date').as_datetime(),
+ revision = r.get('number').as_int(),
+ summary = r.getc('summary'),
+ tagnames = " ".join(r.getc('tags').split(',')),
+ title = r.getc('title'),
+ )
+
+ rev.save()
+ if rev.revision == active:
+ active = rev
+
+ node.active_revision = active
+ node.save()
+
+POST_ACTION = {}
+
+def post_action(*types):
+ def decorator(fn):
+ for t in types:
+ POST_ACTION[t] = fn
+ return fn
+ return decorator
+
+def post_action_import_callback():
+ with_state = orm.Node.objects.filter(id__in=orm.NodeState.objects.values_list('node_id', flat=True).distinct())
+
+ for n in with_state:
+ n.state_string = "".join(["(%s)" % s for s in n.states.values_list('state_type')])
+ n.save()
+
+@file_handler('actions.xml', 'actions', 'action', post_callback=post_action_import_callback)
+def actions_import(row):
+ action = orm.Action(
+ id = row.get('id').as_int(),
+ action_type = row.getc('type'),
+ action_date = row.get('date').as_datetime(),
+ node_id = row.get('node').as_int(None),
+ user_id = row.get('user').as_int(),
+ real_user_id = row.get('realUser').as_int(None),
+ ip = row.getc('ip'),
+ extra = row.get('extraData').as_pickled(),
+ )
+
+ canceled = row.get('canceled')
+ if canceled.get_attr('state').as_bool():
+ action.canceled_by_id = canceled.get('user').as_int()
+ action.canceled_at = canceled.get('date').as_datetime(),
+ action.canceled_ip = canceled.getc('ip')
+
+ action.save()
+
+ for r in row.get('reputes').get_list('repute'):
+ by_canceled = r.get_attr('byCanceled').as_bool()
+
+ orm.ActionRepute(
+ action = action,
+ user_id = r.get('user').as_int(),
+ value = r.get('value').as_int(),
+
+ date = by_canceled and action.canceled_at or action.action_date,
+ by_canceled = by_canceled
+ ).save()
+
+ if (not action.canceled) and action.action_type in POST_ACTION:
+ POST_ACTION[action.action_type](row, action)
+
+
+
+
+@post_action('voteup', 'votedown', 'voteupcomment')
+def vote_action(row, action):
+ orm.Vote(user_id=action.user_id, node_id=action.node_id, action=action,
+ voted_at=action.action_date, value=(action.action_type != 'votedown') and 1 or -1).save()
+
+def state_action(state):
+ def fn(row, action):
+ orm.NodeState(
+ state_type = state,
+ node_id = action.node_id,
+ action = action
+ ).save()
+ return fn
+
+post_action('wikify')(state_action('wiki'))
+post_action('delete')(state_action('deleted'))
+post_action('acceptanswer')(state_action('accepted'))
+post_action('publish')(state_action('published'))
+
+
+@post_action('flag')
+def flag_action(row, action):
+ orm.Flag(user_id=action.user_id, node_id=action.node_id, action=action, reason=action.extra).save()
+
+
+def award_import_args(user):
+ return [ dict([ (b.cls, b) for b in orm.Badge.objects.all() ]) ]
+
+
+@file_handler('awards.xml', 'awards', 'award', args_handler=award_import_args)
+def awards_import(row, badges):
+ award = orm.Award(
+ user_id = row.get('user').as_int(),
+ badge = badges[row.getc('badge')],
+ node_id = row.get('node').as_int(None),
+ action_id = row.get('action').as_int(None),
+ trigger_id = row.get('trigger').as_int(None)
+ ).save()
+
+
+
+
+
+
+
+
+
--- /dev/null
+from south.v2 import DataMigration\r
+from south.orm import FakeORM\r
+\r
+class Migration(DataMigration):\r
+ def forwards(self, orm):\r
+ pass\r
+\r
+\r
+ def backwards(self, orm):\r
+ "Write your backwards methods here."\r
+\r
+ models = {\r
+ 'auth.group': {\r
+ 'Meta': {'object_name': 'Group'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})\r
+ },\r
+ 'auth.permission': {\r
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+ },\r
+ 'auth.user': {\r
+ 'Meta': {'object_name': 'User'},\r
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),\r
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+ },\r
+ 'contenttypes.contenttype': {\r
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+ },\r
+ 'forum.action': {\r
+ 'Meta': {'object_name': 'Action'},\r
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'real_user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'proxied_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.actionrepute': {\r
+ 'Meta': {'object_name': 'ActionRepute'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.authkeyuserassociation': {\r
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.award': {\r
+ 'Meta': {'unique_together': "(('user', 'badge', 'node'),)", 'object_name': 'Award'},\r
+ 'action': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'award'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.Badge']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'trigger': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.badge': {\r
+ 'Meta': {'object_name': 'Badge'},\r
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['forum.Award']", 'to': "orm['forum.User']"}),\r
+ 'cls': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+ },\r
+ 'forum.flag': {\r
+ 'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Flag'},\r
+ 'action': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'flag'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+ 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flags'", 'to': "orm['forum.Node']"}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flags'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.keyvalue': {\r
+ 'Meta': {'object_name': 'KeyValue'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'value': ('forum.models.utils.PickledObjectField', [], {'null': 'True'})\r
+ },\r
+ 'forum.markedtag': {\r
+ 'Meta': {'object_name': 'MarkedTag'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.node': {\r
+ 'Meta': {'object_name': 'Node'},\r
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),\r
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'state_string': ('django.db.models.fields.TextField', [], {'default': "''"}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'symmetrical': 'False', 'to': "orm['forum.Tag']"}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+ },\r
+ 'forum.noderevision': {\r
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+ },\r
+ 'forum.nodestate': {\r
+ 'Meta': {'unique_together': "(('node', 'state_type'),)", 'object_name': 'NodeState'},\r
+ 'action': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'node_state'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'states'", 'to': "orm['forum.Node']"}),\r
+ 'state_type': ('django.db.models.fields.CharField', [], {'max_length': '16'})\r
+ },\r
+ 'forum.openidassociation': {\r
+ 'Meta': {'object_name': 'OpenIdAssociation'},\r
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+ },\r
+ 'forum.openidnonce': {\r
+ 'Meta': {'object_name': 'OpenIdNonce'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
+ },\r
+ 'forum.questionsubscription': {\r
+ 'Meta': {'object_name': 'QuestionSubscription'},\r
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 7, 1, 13, 6, 46, 789996)'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.subscriptionsettings': {\r
+ 'Meta': {'object_name': 'SubscriptionSettings'},\r
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'send_digest': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.tag': {\r
+ 'Meta': {'object_name': 'Tag'},\r
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'symmetrical': 'False', 'through': "orm['forum.MarkedTag']", 'to': "orm['forum.User']"}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.user': {\r
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'symmetrical': 'False', 'through': "orm['forum.QuestionSubscription']", 'to': "orm['forum.Node']"}),\r
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+ },\r
+ 'forum.userproperty': {\r
+ 'Meta': {'unique_together': "(('user', 'key'),)", 'object_name': 'UserProperty'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'properties'", 'to': "orm['forum.User']"}),\r
+ 'value': ('forum.models.utils.PickledObjectField', [], {'null': 'True'})\r
+ },\r
+ 'forum.validationhash': {\r
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 7, 2, 13, 6, 46, 883626)'}),\r
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.vote': {\r
+ 'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Vote'},\r
+ 'action': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'vote'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})\r
+ }\r
+ }\r
+\r
+ complete_apps = ['forum']\r
+\r
+orm = FakeORM(Migration, "forum")\r
+\r