summaryrefslogtreecommitdiffstats
path: root/forum
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-04-25 17:15:26 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-04-25 17:15:26 -0400
commitcc8337da9046bff5243672e20f1dea9c18b00da6 (patch)
tree77ade69869105f1838df5e8616bb994844507cec /forum
parent3122fb8a2599944e623c8e21f285a9e4dd9e132a (diff)
parent02510a462392dd2e9e46e945d51efb374e0dc06f (diff)
downloadaskbot-cc8337da9046bff5243672e20f1dea9c18b00da6.tar.gz
askbot-cc8337da9046bff5243672e20f1dea9c18b00da6.tar.bz2
askbot-cc8337da9046bff5243672e20f1dea9c18b00da6.zip
merged newer ui branch to master
Diffstat (limited to 'forum')
-rw-r--r--forum/LICENSE14
-rwxr-xr-xforum/const.py41
-rw-r--r--forum/cron/README5
-rwxr-xr-xforum/cron/multi_award_badges5
-rwxr-xr-xforum/cron/multi_award_badges_virtualenv10
-rwxr-xr-xforum/cron/once_award_badges14
-rwxr-xr-xforum/cron/once_award_badges_virtualenv10
-rw-r--r--forum/cron/send_email_alerts5
-rw-r--r--forum/cron/send_email_alerts_virtualenv10
-rw-r--r--forum/documentation/HOW_TO_DEBUG39
-rw-r--r--forum/documentation/INSTALL288
-rw-r--r--forum/documentation/INSTALL.pip31
-rw-r--r--forum/documentation/INSTALL.webfaction345
-rw-r--r--forum/documentation/ROADMAP.rst88
-rw-r--r--forum/documentation/TODO.rst63
-rw-r--r--forum/documentation/UPGRADE24
-rw-r--r--forum/documentation/WISH_LIST55
-rw-r--r--forum/documentation/askbot-requirements.txt9
-rwxr-xr-xforum/forms.py119
-rw-r--r--forum/importers/__init__.py0
-rw-r--r--forum/importers/stackexchange/ANOMALIES14
-rw-r--r--forum/importers/stackexchange/README62
-rw-r--r--forum/importers/stackexchange/__init__.py0
-rw-r--r--forum/importers/stackexchange/management/__init__.py0
-rw-r--r--forum/importers/stackexchange/management/commands/__init__.py0
-rw-r--r--forum/importers/stackexchange/management/commands/load_stackexchange.py804
-rw-r--r--forum/importers/stackexchange/models.py266
-rw-r--r--forum/importers/stackexchange/parse_models.py225
-rw-r--r--forum/middleware/view_log.py74
-rw-r--r--forum/migrations/0001_initial.py780
-rw-r--r--forum/migrations/0002_auto__add_field_answer_text__chg_field_answer_html__add_field_question.py368
-rw-r--r--forum/migrations/0003_copy_denorm_text_record_to_posts_for_fulltext_search.py354
-rw-r--r--forum/migrations/0004_install_full_text_indexes_for_mysql.py389
-rw-r--r--forum/migrations/__init__.py0
-rwxr-xr-xforum/models/__init__.py3
-rwxr-xr-xforum/models/answer.py5
-rwxr-xr-xforum/models/base.py40
-rwxr-xr-xforum/models/question.py150
-rwxr-xr-xforum/models/tag.py4
-rw-r--r--forum/search/README5
-rw-r--r--forum/search/__init__.py0
-rw-r--r--forum/search/indexer.py9
-rw-r--r--forum/search/sphinx/README4
-rw-r--r--forum/search/sphinx/sphinx.conf127
-rw-r--r--forum/search/state_manager.py152
-rw-r--r--forum/skins/default/media/images/logo.gifbin1496 -> 2272 bytes
-rwxr-xr-xforum/skins/default/media/style/style.css174
-rw-r--r--forum/skins/default/templates/about.html2
-rw-r--r--forum/skins/default/templates/ask.html2
-rw-r--r--forum/skins/default/templates/ask_form.html66
-rw-r--r--forum/skins/default/templates/base.html16
-rw-r--r--forum/skins/default/templates/base_content.html1
-rw-r--r--forum/skins/default/templates/book.html2
-rw-r--r--forum/skins/default/templates/faq.html2
-rw-r--r--forum/skins/default/templates/feedback.html2
-rw-r--r--forum/skins/default/templates/header.html68
-rw-r--r--forum/skins/default/templates/index.html7
-rw-r--r--forum/skins/default/templates/index_.html7
-rw-r--r--forum/skins/default/templates/input_bar.html45
-rw-r--r--forum/skins/default/templates/question.html15
-rw-r--r--forum/skins/default/templates/question_list.html2
-rw-r--r--forum/skins/default/templates/question_summary_list_roll.html2
-rw-r--r--forum/skins/default/templates/questions.html245
-rw-r--r--forum/skins/default/templates/tag_selector.html9
-rw-r--r--forum/skins/default/templates/tags.html9
-rw-r--r--forum/skins/default/templates/user.html2
-rw-r--r--forum/skins/default/templates/user_reputation.html7
-rw-r--r--forum/skins/default/templates/user_stats.html2
-rw-r--r--forum/skins/default/templates/users.html2
-rw-r--r--forum/skins/default/templates/users_questions.html2
-rw-r--r--forum/sql_scripts/091111_upgrade_evgeny.sql1
-rw-r--r--forum/sql_scripts/091208_upgrade_evgeny.sql1
-rw-r--r--forum/sql_scripts/091208_upgrade_evgeny_1.sql1
-rw-r--r--forum/sql_scripts/100108_upgrade_ef.sql4
-rw-r--r--forum/sql_scripts/badges.sql37
-rw-r--r--forum/sql_scripts/cnprog.xml1498
-rw-r--r--forum/sql_scripts/cnprog_new_install.sql811
-rw-r--r--forum/sql_scripts/cnprog_new_install_2009_02_28.sql456
-rw-r--r--forum/sql_scripts/cnprog_new_install_2009_03_31.sql891
-rw-r--r--forum/sql_scripts/cnprog_new_install_2009_04_07.sql24
-rw-r--r--forum/sql_scripts/cnprog_new_install_2009_04_09.sql904
-rw-r--r--forum/sql_scripts/drop-all-tables.sh4
-rw-r--r--forum/sql_scripts/drop-auth.sql8
-rw-r--r--forum/sql_scripts/pg_fts_install.sql38
-rw-r--r--forum/sql_scripts/update_2009_01_13_001.sql62
-rw-r--r--forum/sql_scripts/update_2009_01_13_002.sql1
-rw-r--r--forum/sql_scripts/update_2009_01_18_001.sql62
-rw-r--r--forum/sql_scripts/update_2009_01_24.sql2
-rw-r--r--forum/sql_scripts/update_2009_01_25_001.sql2
-rw-r--r--forum/sql_scripts/update_2009_02_26_001.sql19
-rw-r--r--forum/sql_scripts/update_2009_04_10_001.sql3
-rw-r--r--forum/sql_scripts/update_2009_07_05_EF.sql3
-rw-r--r--forum/sql_scripts/update_2009_12_24_001.sql5
-rw-r--r--forum/sql_scripts/update_2009_12_27_001.sql3
-rw-r--r--forum/sql_scripts/update_2009_12_27_002.sql1
-rwxr-xr-xforum/sql_scripts/update_2010_01_23.sql9
-rw-r--r--forum/sql_scripts/update_2010_02_22.sql1
-rwxr-xr-xforum/templatetags/extra_tags.py77
-rwxr-xr-xforum/utils/decorators.py1
-rw-r--r--forum/views/readers.py351
-rwxr-xr-xforum/views/users.py15
-rwxr-xr-xforum/views/writers.py10
102 files changed, 10507 insertions, 499 deletions
diff --git a/forum/LICENSE b/forum/LICENSE
new file mode 100644
index 00000000..803781c5
--- /dev/null
+++ b/forum/LICENSE
@@ -0,0 +1,14 @@
+Copyright (C) 2009. Chen Gang
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
diff --git a/forum/const.py b/forum/const.py
index 4c107572..bc9a7a8f 100755
--- a/forum/const.py
+++ b/forum/const.py
@@ -32,6 +32,46 @@ TYPE_REPUTATION = (
(-8, 'lose_by_upvote_canceled'),
)
+#do not translate these!!!
+POST_SORT_METHODS = (
+ ('latest', _('newest')),
+ ('oldest', _('oldest')),
+ ('active', _('active')),
+ ('inactive', _('inactive')),
+ ('hottest', _('hottest')),
+ ('coldest', _('coldest')),
+ ('mostvoted', _('most voted')),
+ ('leastvoted', _('least voted')),
+ ('relevant', _('relevance')),
+ )
+#todo: add assertion here that all sort methods are unique
+#because they are keys to the hash used in implementations of Q.run_advanced_search
+
+DEFAULT_POST_SORT_METHOD = 'active'
+POST_SCOPE_LIST = (
+ ('all', _('all')),
+ ('unanswered', _('unanswered')),
+ ('favorite', _('favorite')),
+ )
+DEFAULT_POST_SCOPE = 'all'
+DEFAULT_QUESTIONS_PAGE_SIZE = 30
+PAGE_SIZES = (10,30,50)
+
+UNANSWERED_MEANING_LIST = ('NO_ANSWERS','NO_UPVOTED_ANSWERS','NO_ACCEPTED_ANSWERS')
+UNANSWERED_MEANING = 'NO_ACCEPTED_ANSWERS'
+assert(UNANSWERED_MEANING in UNANSWERED_MEANING_LIST)
+
+#todo:
+#this probably needs to be language-specific
+#and selectable/changeable from the admin interface
+#however it will be hard to expect that people will type
+#correct regexes - plus this must be an anchored regex
+#to do full string match
+TAG_REGEX = r'^[a-z0-9\+\.\-]+$'
+TAG_SPLIT_REGEX = r'[ ,]+'
+MAX_TAG_LENGTH = 20 #default 20 chars
+MAX_TAGS_PER_POST = 5 #no more than five tags
+
TYPE_ACTIVITY_ASK_QUESTION=1
TYPE_ACTIVITY_ANSWER=2
TYPE_ACTIVITY_COMMENT_QUESTION=3
@@ -91,3 +131,4 @@ CONST = {
#how to filter questions by tags in email digests?
TAG_EMAIL_FILTER_CHOICES = (('ignored', _('exclude ignored tags')),('interesting',_('allow only selected tags')))
MAX_ALERTS_PER_EMAIL = 7
+USERS_PAGE_SIZE = 28
diff --git a/forum/cron/README b/forum/cron/README
new file mode 100644
index 00000000..d5573150
--- /dev/null
+++ b/forum/cron/README
@@ -0,0 +1,5 @@
+this directory contains sample commands to be executed
+by cron
+
+files with names ending "virtuanenv" should work under Python virtualenv system
+other files - with standard unix setup
diff --git a/forum/cron/multi_award_badges b/forum/cron/multi_award_badges
new file mode 100755
index 00000000..3d768772
--- /dev/null
+++ b/forum/cron/multi_award_badges
@@ -0,0 +1,5 @@
+#!/bin/sh
+PYTHONPATH=/path/to/dir_above_askbot_site
+export PYTHONPATH
+PROJECT_ROOT=$PYTHONPATH/askbot_site
+python manage.py multi_award_badges >> $PROJECT_ROOT/log/cron_badges.log 2>&1
diff --git a/forum/cron/multi_award_badges_virtualenv b/forum/cron/multi_award_badges_virtualenv
new file mode 100755
index 00000000..4230fb22
--- /dev/null
+++ b/forum/cron/multi_award_badges_virtualenv
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+WORKON_HOME=~/envs/askbot
+PROJECT_ROOT=~/webapps/askbot_server/projects/askbot/
+
+# activate virtual environment
+. $WORKON_HOME/bin/activate
+
+cd $PROJECT_ROOT
+python manage.py multi_award_badges >> $PROJECT_ROOT/log/cron_badges.log 2>&1
diff --git a/forum/cron/once_award_badges b/forum/cron/once_award_badges
new file mode 100755
index 00000000..069656ca
--- /dev/null
+++ b/forum/cron/once_award_badges
@@ -0,0 +1,14 @@
+#!/bin/sh
+PYTHONPATH=/path/to/dir_above_askbot_site
+export PYTHONPATH
+PROJECT_ROOT=$PYTHONPATH/askbot_site
+python manage.py once_award_badges >> $PROJECT_ROOT/log/cron_badges.log 2>&1
+
+
+#!/bin/sh
+PYTHONPATH=/usr/local/sites/askbot_production
+export PYTHONPATH
+PROJECT_ROOT=$PYTHONPATH/robofaqs
+python $PROJECT_ROOT/manage.py once_award_badges >> $PROJECT_ROOT/log/cron_badges.log 2>&1
+python $PROJECT_ROOT/manage.py multi_award_badges >> $PROJECT_ROOT/log/cron_badges.log 2>&1
+python $PROJECT_ROOT/manage.py send_email_alerts >> $PROJECT_ROOT/log/cron_email.log 2>&1 \ No newline at end of file
diff --git a/forum/cron/once_award_badges_virtualenv b/forum/cron/once_award_badges_virtualenv
new file mode 100755
index 00000000..0011981c
--- /dev/null
+++ b/forum/cron/once_award_badges_virtualenv
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+WORKON_HOME=~/envs/askbot
+PROJECT_ROOT=~/webapps/askbot_server/projects/askbot/
+
+# activate virtual environment
+. $WORKON_HOME/bin/activate
+
+cd $PROJECT_ROOT
+python manage.py once_award_badges >> $PROJECT_ROOT/log/cron_badges.log 2>&1
diff --git a/forum/cron/send_email_alerts b/forum/cron/send_email_alerts
new file mode 100644
index 00000000..7581a88c
--- /dev/null
+++ b/forum/cron/send_email_alerts
@@ -0,0 +1,5 @@
+#!/bin/sh
+PYTHONPATH=/path/to/dir_above_askbot_site
+export PYTHONPATH
+PROJECT_ROOT=$PYTHONPATH/askbot_site
+/path/to/python $PROJECT_ROOT/manage.py send_email_alerts
diff --git a/forum/cron/send_email_alerts_virtualenv b/forum/cron/send_email_alerts_virtualenv
new file mode 100644
index 00000000..2f1b64d0
--- /dev/null
+++ b/forum/cron/send_email_alerts_virtualenv
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+WORKON_HOME=~/envs/askbot
+PROJECT_ROOT=~/webapps/askbot_server/projects/askbot/
+
+# activate virtual environment
+. $WORKON_HOME/bin/activate
+
+cd $PROJECT_ROOT
+python manage.py send_email_alerts >> $PROJECT_ROOT/log/cron_mail.log 2>&1
diff --git a/forum/documentation/HOW_TO_DEBUG b/forum/documentation/HOW_TO_DEBUG
new file mode 100644
index 00000000..fbbdb1f7
--- /dev/null
+++ b/forum/documentation/HOW_TO_DEBUG
@@ -0,0 +1,39 @@
+1) LOGGING
+Please remember that log files may contain plaintext passwords, etc.
+
+Please do not add print statements - at least do not commit them to git
+because in some environments printing to stdout causes errors
+
+Instead use python logging this way:
+--------------------------------
+#somewere on top of file
+import logging
+
+#anywhere below
+logging.debug('this maybe works')
+logging.error('have big error!')
+#or even
+logging.debug('') #this will add time, line number, function and file record
+#sometimes useful record for call tracing on its own
+#etc - take a look at http://docs.python.org/library/logging.html
+-------------------------------
+
+in Askbot logging is currently set up in settings_local.py.dist
+please update it if you need - in older revs logging strings have less info
+
+messages of interest can be grepped out of the log file by module/file/function name
+e.g. to take out all django_authopenid logs run:
+>grep 'askbot\/django_authopenid' log/django.askbot.log | sed 's/^.*MSG: //'
+in the example above 'sed' call truncates out a long prefix
+and makes output look more meaningful
+
+2) DJANGO DEBUG TOOLBAR
+askbot works with django debug toolbar
+if debugging under apache server, check
+that debug toolbar media is loaded correctly
+if toolbar is enabled but you do not see it, possibly some Alias statement
+in apache config is wrong in your VirtualHost or elsewhere
+
+3) If you discover new debugging techniques, please add here.
+Possible areas to improve - at this point there is no SQL query logging,
+as well as request data and http header.
diff --git a/forum/documentation/INSTALL b/forum/documentation/INSTALL
new file mode 100644
index 00000000..73714566
--- /dev/null
+++ b/forum/documentation/INSTALL
@@ -0,0 +1,288 @@
+CONTENTS
+------------------
+A. PREREQUISITES
+B. INSTALLATION
+ 1. Settings file
+ 2. Database
+ 3. Running Askbot in the development server
+ 4. Installation under Apache/WSGI
+ 5. Full text search
+ 6. Email subscriptions
+ 7. Sitemap
+ 8. Miscellaneous
+C. CONFIGURATION PARAMETERS (settings_local.py)
+D. CUSTOMIZATION
+
+
+A. PREREQUISITES
+-----------------------------------------------
+Note: by default all installation activity is made in the superuser 'root' account.
+This can be achieved either by logging in as root (su root),
+or - if you have program sudo installed - prefix all commands with sudo.
+So sodo will be listed below as optional.
+
+0. We recommend you to use python-setuptools to install pre-requirement libraries.
+If you haven't installed it, please try to install it first.
+e.g, [sudo] apt-get install python-setuptools
+
+1. Python2.5/2.6, Django v1.1.1
+
+1A If you are using MySQL, mysql client for python must be installed
+[sudo] easy_install mysql-python
+
+2. Python-openid v2.2
+http://openidenabled.com/python-openid/
+[sudo] easy_install python-openid
+
+4. html5lib
+http://code.google.com/p/html5lib/
+Used for HTML sanitizer
+[sudo] easy_install html5lib
+
+5. Markdown2
+http://code.google.com/p/python-markdown2/
+[sudo] easy_install markdown2
+
+6. Django Debug Toolbar
+http://github.com/robhudson/django-debug-toolbar/tree/master
+
+7. djangosphinx (optional - for full text questions+answer+tag)
+http://github.com/dcramer/django-sphinx/tree/master/djangosphinx
+
+8. sphinx search engine (optional, works together with djangosphinx)
+http://sphinxsearch.com/downloads.html
+
+9. recaptcha_django
+http://code.google.com/p/recaptcha-django/
+
+10. python recaptcha module
+http://code.google.com/p/recaptcha/
+Notice that you will need to register with recaptcha.net and receive
+recaptcha public and private keys that need to be saved in your
+settings_local.py file
+
+11. South
+http://south.aeracode.org/docs/installation.html
+Used for database schema and data migrations
+[sudo] easy_install South
+
+EXTRA DEPENDENCIES FOR PYTHON 2.4
+* hashlib (made standard in python 2.5)
+
+NOTES: django_authopenid is included into Askbot code
+and is significantly modified. http://code.google.com/p/django-authopenid/
+no need to install this library
+
+B. INSTALLATION
+
+NOTE: If you want to upgrade software, not install from scratch -
+ take a look into forum/documentation/UPGRADE
+
+-----------------------------------------------
+0. Make sure you have all above python libraries installed.
+
+ DO NOT name the main directory 'askbot' - this name is reserved
+ for the future name of the app file itself.
+
+ make askbot installation server-readable on Linux command might be:
+ chown -R yourlogin:apache /path/to/askbot-site
+
+ directories:
+ /path/to/askbot-site/forum/upfiles
+ /path/to/askbot-site/log
+ must be server writable
+
+ on Linux type chmod
+ chmod -R g+w /path/to/askbot-site/forum/upfiles
+ chmod -R g+w /path/to/askbot-site/log
+
+ above it is assumed that webserver runs under group named "apache"
+
+1. Settings file
+
+Copy settings_local.py.dist to settings_local.py and
+update all your settings. Check settings.py and update
+it as well if necessory.
+Section C explains configuration paramaters.
+
+Minimally required modification of settings_local.py are
+DATABASE_NAME
+DATABASE_USER
+DATABASE_PASSWORD
+DATABASE_ENGINE
+
+If you set these up, and your database is ready (see section 2),
+run (note that application 'forum' is under control of south migration system:
+
+python manage.py syncdb #create tables for anything not under control of migration system
+python manage.py migrate forum #run migration command - will apply all migrations in sequence
+
+Now you are ready to test your installation:
+
+python manage.py runserver `hostname -i`:8000
+(choose another port number if you wish)
+
+and askbot should be running - if you have any issues at this point (or later:)
+please post them at http://askbot.org/meta
+
+2. Database
+
+Prepare your database by using the same database/account
+configuration from above.
+
+If your host has database manager in the control panel - you
+can use that or you can create database by typing commands manually
+
+on MySQL the commands are:
+
+create database askbot DEFAULT CHARACTER SET UTF8 COLLATE utf8_general_ci;
+grant all on askbot.* to 'askbot'@'localhost';
+
+And then run :
+
+python manage.py syncdb
+python manage.py migrate
+
+3. Running Askbot on the development server
+
+Run "python manage.py runserver" to startup django
+development environment.
+(Under Linux you can use command "python manage.py runserver `hostname -i`:8000",
+where you can use any other available number for the port)
+
+you might want to have DEBUG=True in the beginning of settings.py
+when using the test server
+
+4. Installation under Apache/WSGI
+
+The main wsgi script is in the file django.wsgi
+it does not need to be modified
+
+4.1 Configure webserver
+Settings below are not perfect but may be a good starting point
+
+---------
+WSGISocketPrefix /path/to/socket/sock #must be readable and writable by apache
+WSGIPythonHome /usr/local #must be readable by apache
+WSGIPythonEggs /var/python/eggs #must be readable and writable by apache
+
+#NOTE: all urs below will need to be adjusted if
+#settings.FORUM_SCRIPT_ALIAS !='' (e.g. = 'forum/')
+#this allows "rooting" forum at http://example.com/forum, if you like
+<VirtualHost ...your ip...:80>
+ ServerAdmin forum@example.com
+ DocumentRoot /path/to/askbot-site
+ ServerName example.com
+
+ #run mod_wsgi process for django in daemon mode
+ #this allows avoiding confused timezone settings when
+ #another application runs in the same virtual host
+ WSGIDaemonProcess askbot
+ WSGIProcessGroup askbot
+
+ #force all content to be served as static files
+ #otherwise django will be crunching images through itself wasting time
+ Alias /m/ /path/to/askbot-site/forum/skins/
+ Alias /upfiles/ /path/to/askbot-site/forum/upfiles/
+ <Directory /path/to/askbot-site/forum/skins>
+ Order deny,allow
+ Allow from all
+ </Directory>
+
+ #this is your wsgi script described in the prev section
+ WSGIScriptAlias / /path/to/askbot-site/django.wsgi
+
+ #this will force admin interface to work only
+ #through https (optional)
+ #"nimda" is the secret spelling of "admin" ;)
+ <Location "/nimda">
+ RewriteEngine on
+ RewriteRule /nimda(.*)$ https://example.com/nimda$1 [L,R=301]
+ </Location>
+ CustomLog /var/log/httpd/askbot/access_log common
+ ErrorLog /var/log/httpd/askbot/error_log
+</VirtualHost>
+#(optional) run admin interface under https
+<VirtualHost ..your ip..:443>
+ ServerAdmin forum@example.com
+ DocumentRoot /path/to/askbot-site
+ ServerName example.com
+ SSLEngine on
+ SSLCertificateFile /path/to/ssl-certificate/server.crt
+ SSLCertificateKeyFile /path/to/ssl-certificate/server.key
+ WSGIScriptAlias / /path/to/askbot-site/django.wsgi
+ CustomLog /var/log/httpd/askbot/access_log common
+ ErrorLog /var/log/httpd/askbot/error_log
+ DirectoryIndex index.html
+</VirtualHost>
+-------------
+
+5. Full text search (using sphinx search)
+
+ Currently full text search works only with sphinx search engine
+ And builtin PostgreSQL (postgres only >= 8.3???)
+
+ 5.1 Instructions for Sphinx search setup
+ Sphinx at this time supports only MySQL and PostgreSQL databases
+ to enable this, install sphinx search engine and djangosphinx
+
+ configure sphinx, sample configuration can be found in
+ sphinx/sphinx.conf file usually goes somewhere in /etc tree
+
+ build askbot index first time manually
+
+ % indexer --config /path/to/sphinx.conf --index askbot
+
+ setup cron job to rebuild index periodically with command
+ your crontab entry may be something like
+
+ 0 9,15,21 * * * /usr/local/bin/indexer --config /etc/sphinx/sphinx.conf --all --rotate >/dev/null 2>&1
+ adjust it as necessary this one will reindex three times a day at 9am 3pm and 9pm
+
+ if your forum grows very big ( good luck with that :) you'll
+ need to two search indices one diff index and one main
+ please refer to online sphinx search documentation for the information
+ on the subject http://sphinxsearch.com/docs/
+
+ in settings_local.py set
+ USE_SPHINX_SEARCH=True
+ adjust other settings that have SPHINX_* prefix accordingly
+ remember that there must be trailing comma in parentheses for
+ SHPINX_SEARCH_INDICES tuple - particlarly with just one item!
+
+ in settings.py look for INSTALLED_APPS
+ and uncomment #'djangosphinx',
+
+
+6. Email subscriptions
+
+ This function at the moment requires Django 1.1
+
+ edit paths in the file forum/cron/send_email_alerts
+ set up a cron job to call forum/cron/send_email_alerts once or twice a day
+ subscription sender may be tested manually in shell
+ by calling forum/cron/send_email_alerts
+
+7. Sitemap
+Sitemap will be available at /<settings_local.FORUM_SCRIPT_ALIAS>sitemap.xml
+e.g yoursite.com/forum/sitemap.xml
+
+google will be pinged each time question, answer or
+comment is saved or a question deleted
+
+for this to be useful - do register you sitemap with Google at
+https://www.google.com/webmasters/tools/
+
+8. Miscellaneous
+
+There are some demo scripts under forum/sql_scripts folder,
+including badges and test accounts for CNProg.com. You
+don't need them to run your sample.
+
+C. Customization
+
+Other than settings_local.py the following will most likely need customization:
+* locale/*/django.po - language files that may also contain your site-specific messages
+ if you want to start with english messages file - look for words like "forum" and
+ "Askbot" in the msgstr lines
+* skins
diff --git a/forum/documentation/INSTALL.pip b/forum/documentation/INSTALL.pip
new file mode 100644
index 00000000..2f817ff8
--- /dev/null
+++ b/forum/documentation/INSTALL.pip
@@ -0,0 +1,31 @@
+* Install virtualenv and pip:
+ easy_install virtualenv
+ easy_install pip
+
+* Install MySQL:
+ sudo apt-get install mysql-client mysql-server
+
+* Install sphinxsearch. See:
+ [optional]
+ http://sphinxsearch.com/downloads.html
+ http://www.hackido.com/2009/01/install-sphinx-search-on-ubuntu.html
+ git://github.com/johnl/deb-sphinx-search.git
+
+* Install a virtual environment OUTSIDE of this directory:
+ pip install -E ~/env -r askbot-requirements.txt
+[there is discussion on the pinax forums about what it should be outside
+the source directory]
+
+* Notice that you will need to register with recaptcha.net and receive
+ recaptcha public and private keys that need to be saved in your
+ settings_local.py file
+
+* Start your environment:
+ source ~/env/bin/activate
+
+* Install mysql-python into your virtualenv, because we can't
+automagically install it with pip:
+ easy_install --prefix ~/env/ mysql-python
+
+For more information about why pip can't automatically install the
+MySQL driver, see this message: http://groups.google.com/group/python-virtualenv/msg/ea988085951c92b3
diff --git a/forum/documentation/INSTALL.webfaction b/forum/documentation/INSTALL.webfaction
new file mode 100644
index 00000000..a449ffe6
--- /dev/null
+++ b/forum/documentation/INSTALL.webfaction
@@ -0,0 +1,345 @@
+NOTE: this file may be a bit out of date
+
+Detailed instructions for installing Askbot on WebFaction
+
+Adapted from http://code.pinaxproject.com/wiki/DetailedPinaxWebfaction/
+
+Please email turian at gmail with any updates or corrections.
+
+
+Installing Askbot on Webfaction
+------------------------------------
+
+Details the steps for setting up Askbot on a Webfaction shared-hosting
+account, including email setup, using Apache2, mod_wsgi, psycopg2.
+
+If you want to search-and-replace through this file, you will need to replace:
+ askbot_server [name of Webfaction application, which will be in ~/webapps/]
+ askbot_static [name of Webfaction application for static media serving]
+ DOMAIN.com [domain name for Askbot site]
+ PORT [port number assigned by WebFaction to your mod_wsgi application]
+ SITENAME [name you give the Askbot site, which will contain the apache logs]
+ myaskbot [name of the Askbot project]
+ MAILBOX_USERNAME [username you give the email address]
+ MAILBOX_PASSWORD [password that webfaction gives to this email username]
+ AskbotDATABASE_NAME [username you give the database]
+ AskbotDATABASE_PASSWORD [password that webfaction gives to this database]
+ ~/envs/askbot [directory for the Askbot python environment, grep for 'env']
+ USERNAME [your WebFaction username]
+
+Some things I'm not sure about:
+
+Here's what I don't know how to do:
+ * Set up a nginx server for static media.
+ * Configure sphinx search
+ * Use PostgreSQL, not MySQL: http://askbot.net/question/13/can-i-use-askbot-with-postgresql
+
+
+Webfaction Control Panel
+--------------------------
+
+(Note: if you sign up and pick django it will create the application
+for you, website/subdomain and associate the two for you.)
+
+ If necessary, add or create any domains or subdomains you may need.
+
+ https://panel.webfaction.com/domain/list/
+
+ Let's call the domain DOMAIN.com.
+
+ Create a new Webfaction application with a "Type:" of "mod_wsgi
+ 2.5/Python2.5", naming it "askbot_server". (These instructions
+ might also work with mod_wsgi 2.0, if you like.)
+
+ https://panel.webfaction.com/app_/list
+
+ Note the port number assigned to the mod_wsgi application. Call
+ it PORT.
+
+ Create a new Webfaction website which will associate the subdomain
+ with the new askbot_server application. Give it name SITENAME, at least one
+ domain, and set it to use the askbot_server application for the site's
+ root location, "/".
+
+ https://panel.webfaction.com/site/list
+
+ You will need to create a database, typically one for each project
+ you create. Change the type to PostgreSql and modify the name (it
+ defaults to your webfaction account name) by adding an underscore
+ and a project-specific identifier such as "_askbot". Before
+ leaving this section of the control panel, you may wish to change
+ the password.
+
+ https://panel.webfaction.com/database/create
+
+ Call these AskbotDATABASE_NAME and AskbotDATABASE_PASSWORD.
+
+ Save the database password for later.
+
+ [The following I haven't figured out yet]
+ You will probably want to add a static media server. This is a
+ Webfaction application. I created one of type "Static only (no
+ .htaccess)" and with the name of "askbot_static".
+
+ https://panel.webfaction.com/app_/create
+
+ To configure email, you need an email mailbox. Add one here. Note
+ that your mailbox password shouldn't be the same password you use
+ to SSH to webfaction.
+
+ https://panel.webfaction.com/mailbox/list
+
+ Save the mail password for later.
+ We will call the username and password MAILBOX_USERNAME and
+ MAILBOX_PASSWORD, respectively.
+ You might also consider adding an email address like admin@DOMAIN.com,
+ here:
+
+ https://panel.webfaction.com/email/list
+
+
+Askbot Software
+--------------
+
+ Log onto webfaction and get the code. I use my fork because I have
+ a simple pip installation:
+ git://github.com/turian/askbot.git
+ In my situation, I keep source code in ~/utils/src, create
+ virtual environments in ~/envs/askbot, and create Pinax projects in
+ ~/webapps/askbot_server/projects.
+
+ You will need pip + virtualenv installed:
+
+ easy_install --prefix=~/utils/ pip
+ easy_install --prefix=~/utils/ virtualenv
+
+ cd ~/utils/src/
+ git clone git://github.com/turian/askbot.git
+ cd askbot
+
+ # We need python2.5 to be compatible with WSGI
+ python2.5 ~/utils/bin/pip install -E ~/envs/askbot -r askbot-requirements.txt
+ source ~/envs/askbot/bin/activate
+
+ # [Optional] If you want a MySQL database
+ easy_install-2.5 --prefix ~/envs/askbot/ mysql-python
+
+Additional Software
+-------------------
+
+ [Note that PostgreSQL installation doesn't work for me.]
+
+ You will need to install psycopg2 separately for PostgreSQL.
+ Psycopg2 requires a little fiddling. Continuing to
+ work in the ~/utils/src/ directory:
+
+ cd ~/utils/src/
+ wget http://initd.org/pub/software/psycopg/psycopg2-2.0.13.tar.gz
+ tar zxf psycopg2-2.0.13.tar.gz
+ cd psycopg2-2.0.13
+ nano setup.cfg
+
+ # edit the line reading "#pg_config=" so that it reads:
+ "pg_config=/usr/local/pgsql/bin/pg_config"
+
+ python2.5 setup.py build
+ python2.5 setup.py install
+
+
+Create a Project
+----------------
+
+ In Pinax, you clone a project from Askbot.
+ However, Askbot we just copy it.
+
+ cd ~/webapps/askbot_server
+ mkdir projects
+ cd projects
+ cp -R ~/utils/src/askbot myaskbot
+ cd myaskbot
+ export AskbotPROJECT=`pwd`
+
+ Make some directories, as described in the Askbot INSTALL file:
+ [okay I haven't actually done this yet]
+
+# mkdir -p $AskbotSITE/upfiles/
+# mkdir -p $AskbotLOG
+# sudo chown -R `whoami`:www-data $AskbotSITE
+# sudo chown -R `whoami`:www-data $AskbotLOG
+# chmod -R g+w $AskbotSITE/upfiles
+# chmod -R g+w $AskbotLOG
+
+
+ Edit the settings files:
+
+ cd $AskbotPROJECT
+ cp settings_local.py.dist settings_local.py
+ vi settings_local.py settings.py
+
+ Pay attention to the following settings:
+
+ DATABASE_ENGINE = 'mysql'
+ DATABASE_NAME = 'AskbotDATABASE_NAME'
+ DATABASE_USER = 'AskbotDATABASE_NAME'
+ DATABASE_PASSWORD = 'AskbotDATABASE_PASSWORD'
+
+ EMAIL_HOST='smtp.webfaction.com'
+ EMAIL_HOST_USER='MAILBOX_USERNAME'
+ EMAIL_HOST_PASSWORD='MAILBOX_PASSWORD'
+ EMAIL_PORT='25'
+ DEFAULT_FROM_EMAIL = 'MAILBOX_USERNAME@DOMAIN.com'
+ SERVER_EMAIL = 'MAILBOX_USERNAME@DOMAIN.com'
+ # The following setting might not be necessary, it's used in Pinax tho
+ CONTACT_EMAIL = "MAILBOX_USERNAME@DOMAIN.com"
+
+ APP_URL = 'http://DOMAIN.com' #used by email notif system and RSS
+
+ [Later on, the install instructions should talk about]
+ SERVE_MEDIA = False # [Not present, not ready yet]
+
+ Create a directory for logs:
+
+ cd $AskbotPROJECT
+ mkdir log
+
+ Modify mail cron scripts "cron/send_email_alerts" as follows:
+ [Pinax has cron/emit_notices.sh, cron/retry_deferred.sh,
+ cron/send_mail.sh, are these also necessary?]
+
+ #!/bin/sh
+
+ WORKON_HOME=~/envs/askbot
+ PROJECT_ROOT=~/webapps/askbot_server/projects/myaskbot/
+
+ # activate virtual environment
+ . $WORKON_HOME/bin/activate
+
+ cd $PROJECT_ROOT
+ python manage.py send_email_alerts >> $PROJECT_ROOT/log/cron_mail.log 2>&1
+
+ Use command "crontab -e" to add this script to your cron file, to run twice a day::
+
+ 1 0,12 * * * ~/webapps/askbot_server/projects/myaskbot/cron/send_email_alerts
+
+ [Configure sphinx]
+
+ Create the database tables, indices, and so forth:
+
+ python manage.py syncdb
+
+ [Ignore the following static media steps, I haven't tried them]
+ Build media directory links within the project and create symbolic
+ links on the static media server.
+ python manage.py build_media -all
+ mkdir ~/webapps/Askbot_STATIC/myaskbot
+ ln -sd ~/webapps/askbot_server/projects/myaskbot/site_media ~/webapps/Askbot_STATIC/myaskbot/site_media
+
+
+ Set up the badges:
+
+ 1. You should run the SQL commands in:
+
+ sql_scripts/badges.sql
+
+ 2. Edit paths in the file `cron/multi_award_badges`. (This
+ file doesn't yet exist in the git repositories, so just
+ copy `cron/send_email_alerts` and make sure the command
+ `multi_award_badges` is executed.)
+
+ 3. Run `cron/multi_award_badges` to make sure it works okay.
+
+ 4. Use `crontab -e` to call `cron/multi_award_badges` maybe
+ four times an hour.
+
+ 4,19,34,49 * * * * ~/webapps/askbot_server/projects/myaskbot/cron/multi_award_badges
+
+ 5. Repeat steps 1-4 for `cron/once_award_badges`.
+
+
+Configure Apache2
+----------------
+
+ Edit ~/webapps/askbot_server/apache2/conf/httpd.conf as follows::
+
+ ServerAdmin "MAILBOX_USERNAME@DOMAIN.com"
+ ServerRoot "/home/USERNAME/webapps/askbot_server/apache2"
+ ServerName DOMAIN.com
+
+ LoadModule dir_module modules/mod_dir.so
+ LoadModule env_module modules/mod_env.so
+ #LoadModule setenvif_module modules/mod_setenvif.so
+ LoadModule log_config_module modules/mod_log_config.so
+ LoadModule mime_module modules/mod_mime.so
+ LoadModule rewrite_module modules/mod_rewrite.so
+ LoadModule wsgi_module modules/mod_wsgi.so
+
+ KeepAlive Off
+ Listen PORT
+ LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+ CustomLog /home/USERNAME/logs/user/access_askbot_server_log combined
+ ErrorLog /home/USERNAME/logs/user/error_askbot_server_log
+ ServerLimit 2
+
+ #SetEnvIf X-Forwarded-SSL on HTTPS=1
+
+ WSGIPythonPath /home/USERNAME/envs/askbot/lib/python2.5/site-packages/
+ WSGIScriptAlias / /home/USERNAME/webapps/askbot_server/projects/myaskbot/django.wsgi
+
+ LoadModule alias_module modules/mod_alias.so
+ WSGIDaemonProcess askbotWSGI user=USERNAME group=USERNAME threads=25 python-path=/home/USERNAME/envs/askbot/lib/python2.5/site-packages
+ WSGIProcessGroup askbotWSGI
+
+ NameVirtualHost 127.0.0.1:PORT
+
+ #ErrorLog "logs/myaskbot_2009_05_06.log"
+ SetHandler none
+ #Alias /site_media /home/USERNAME/webapps/static/myaskbot/site_media
+
+ #force all content to be served as static files
+ #otherwise django will be crunching images through itself wasting time
+ Alias /content/ /home/USERNAME/webapps/askbot_server/projects/myaskbot/templates/content/
+ Alias /forum/admin/media/ /home/turian/envs/askbot/lib/python2.5/site-packages/django/contrib/admin/media/
+ #AliasMatch /([^/]*\.css) /home/USERNAME/webapps/askbot_server/projects/myaskbot/templates/content/style/$1
+ <Directory "/home/USERNAME/webapps/askbot_server/projects/myaskbot/templates/content">
+ # Order deny,allow
+ # Allow from all
+ </Directory>
+
+ If you want virtual hosts of the admin interface under HTTPS, please
+ look at Askbot's install file.
+
+ Edit ~/webapps/askbot_server/projects/myaskbot/deploy/django.wsgi as follows::
+
+ import os
+ import sys
+
+ # redirect sys.stdout to sys.stderr for bad libraries like geopy that uses
+ # print statements for optional import exceptions.
+ sys.stdout = sys.stderr
+
+ from os.path import abspath, dirname, join
+ from site import addsitedir
+
+ # add the virtual environment site-packages to the path
+ from site import addsitedir
+ addsitedir('/home/USERNAME/envs/askbot/lib/python2.5/site-packages')
+
+ sys.path.insert(0, abspath(join(dirname(__file__), "../")))
+ sys.path.append(abspath(dirname(__file__)))
+
+ from django.conf import settings
+ os.environ["DJANGO_SETTINGS_MODULE"] = "myaskbot.settings"
+
+ #print sys.path
+
+ from django.core.handlers.wsgi import WSGIHandler
+ application = WSGIHandler()
+
+And then you're up and running with:
+
+ ~/webapps/askbot_server/apache2/bin/stop
+ ~/webapps/askbot_server/apache2/bin/start
+
+You should log in to the admin interface (http://DOMAIN.com/admin/),
+and go to "Sites > Sites", and change the domain name that is used in
+all emails.
diff --git a/forum/documentation/ROADMAP.rst b/forum/documentation/ROADMAP.rst
new file mode 100644
index 00000000..c79e0ae4
--- /dev/null
+++ b/forum/documentation/ROADMAP.rst
@@ -0,0 +1,88 @@
+Intro
+=========
+ROADMAP aims to streamline activities of the Askbot open source project and
+to minimize ad-hoc approaches of "big-picture" level.
+
+Aksbot is a Question and Asnwer system for the normal people!
+
+Let's discuss stuff that goes into this file on
+http://groups.google.com/group/askbot
+
+Bacic principles of the project
+==================================
+Here they are:
+
+* our rule #1 is that all developers have commit right to the project
+ repository, but they must follow this ROADMAP and TODO -
+ to keep up with our own sanity.
+* we welcome contributions by other people and show tolerance
+ and patience - especially to the new team members.
+* when users who might not be tech-savvy ask questions -
+ we try to answer to the point and using their language
+ (i.e. not programmer jargon:)
+* we favor plain and minimalistic style of programming, but pay
+ attention to detail - especially details of user experience.
+
+We try do develop using the following workflow:
+
+* specify problem that we try to solve
+* create requirements that will guarantee a solution, once met
+* dream up some implementation ideas (maybe even some sketches on the paper)
+* discuss and decide on the best one
+* write and test code
+
+The process doesn't have to be this formal all the time, but trying to stick
+to some subset of this almost always helps!
+Especially it helps to iron out disagreements between
+individual programmers (which if you are one - you know are qute common
+- and they don't all end well :).
+
+Ad-hoc programming - i.e. simply go and add code - is not really encouraged.
+This works fine in the one person team or when the team consists of
+best friends, but is almost sure to fail in a heterogenous group.
+
+Architecture and Requirements
+=====================================
+Obviously Django and Python are pre-made choices - so this
+is not going to change any time soon. At this point all of
+the client side Javascript is written using jQuery library.
+
+Our basic principle is that Askbot should be a mashable Q&A component.
+Askbot is an application written in Python/Django. So it should be
+distributable as a Django App alone or as a whole site (by option).
+
+If we develop sub-systems that can be used in the broader scope -
+we package that thing as a separate django application (login system is one example).
+
+We will start using Google Closure library soon!
+
+Sub-systems
+-----------------
+* authentication system
+* Q&A system
+* admin interface
+* full text search
+* skins (directory forum/skins)
+
+Authentication system
+-------------------------
+Authentication system will be a separate django application
+
+Here is the discussion thread:
+* http://groups.google.com/group/askbot/browse_thread/thread/1916dfcf666dd56c
+
+Most of the requirements are listed in the first message
+
+Skins
+-----------
+Skins eventually must be upgrade-stable - that is people who created custom
+skins should not need to change anything if something changes in the code
+
+Admin interface
+-----------------------
+* extend forum/settings.py to list default settings of various groups
+* create Registry database table the will store setting values
+* leave only essential settings that go to the main django settings.py
+Create key-value storage
+* should some settings be accessible to admins and some to staff???
+ for example-secret keys probably should not be shared with staff members
diff --git a/forum/documentation/TODO.rst b/forum/documentation/TODO.rst
new file mode 100644
index 00000000..f202a3f7
--- /dev/null
+++ b/forum/documentation/TODO.rst
@@ -0,0 +1,63 @@
+note: there is also WISH_LIST. Here is only stuff that will be done soon.
+
+Site looks
+===========
+* make links within posts blue so that they are visible
+
+Code Cleanups
+==============
+* remove usage of EXTERNAL_LEGACY_LOGIN
+* clean up forum_modules:
+ * keep this directory for dependency modules that can be shared
+ by multiple apps,
+ * but move other things that are not shared
+ inside forum app directory
+ * one-by one convert "auto-discovery" modules into
+ regular explicit python imports
+* python2.4 incompatibilities
+ * datatime.datetime.strptime
+
+Bugs
+======
+* make sure that search feature covers questions and answers
+ (title, body, tags)
+
+Refactoring
+=============
+* merge search, question and index view functions into one
+
+Skins
+=======
+* organize templates and document them so that
+ skins could be more easily created by others
+ who are savvy enough
+* identify and maybe create snippet-type templates
+ and put them into a separate directory
+ for example:
+ * gravatar (currently a string in
+ forum/templatetags/extra_tags.py - try inclusion template
+ and see if it slows things down a lot)
+ * question body
+ * answer body
+ * datetime widget???
+* there is a separator line between posts
+ but it shows either before the post or after
+ it is nice that separator is lightweight -
+ based on css alone - but we need to fix it so that
+ it shows only between the posts as a joining item
+
+Features
+===========
+* new login system, please see
+ http://groups.google.com/group/askbot/browse_thread/thread/1916dfcf666dd56c
+ on a separate branch multi-auth-app, then merge
+* forum admin interface, some badge configuration
+
+Development environment
+==========================
+* set up environment for closure development
+
+Project website
+====================
+* Logo!!! Ideas?
+* Adopt Jekyll for project site and transition from Dango
diff --git a/forum/documentation/UPGRADE b/forum/documentation/UPGRADE
new file mode 100644
index 00000000..538b75a0
--- /dev/null
+++ b/forum/documentation/UPGRADE
@@ -0,0 +1,24 @@
+if you are upgrading this software, then
+
+* first download the newer version and write it over the old one.
+
+for the database migrations you will need to use django package called "south"
+
+Install it (if you don't have it yet) with:
+
+ easy_install South
+
+* 'south' must already be in the list of INSTALLED_APPS
+ otherwise you must have downloaded wrong version of Askbot
+
+if you are using south the very first time, then type:
+
+ python manage.py migrate forum 0001_initial --fake
+
+otherwise skip above step.
+
+Finally run
+
+ python manage.py migrate forum --auto
+
+then all relevant schema and data migrations will be applied
diff --git a/forum/documentation/WISH_LIST b/forum/documentation/WISH_LIST
new file mode 100644
index 00000000..2b53662c
--- /dev/null
+++ b/forum/documentation/WISH_LIST
@@ -0,0 +1,55 @@
+* smarter debug mode
+* The wonder bar (integrated the search / ask functionality)
+* The authentication system ???
+* allow multiple logins to the same account
+* allow multiple logins to the same account
+* more advanced templating/skinning system
+* per-tag email subscriptions
+* view for personalized news on the site
+* a little flag popping when there are news
+* drill-down mode for navigation by tags
+* improved admin console
+* sort out mess with profile - currently we patch django User
+
+* Some functionality should be moved out of the forums app, in the case
+that the forum app is restricted only to authenticated users:
+
+ (r'^%s/$' % _('signin/'), 'django_authopenid.views.signin'),
+ url(r'^%s$' % _('about/'), app.about, name='about'),
+ url(r'^%s$' % _('faq/'), app.faq, name='faq'),
+ url(r'^%s$' % _('privacy/'), app.privacy, name='privacy'),
+ url(r'^%s$' % _('logout/'), app.logout, name='logout'),
+ url(r'^%s$' % _('feedback/'), app.feedback, name='feedback'),
+ (r'^%sfb/' % _('account/'), include('fbconnect.urls')),
+ (r'^%s' % _('account/'), include('django_authopenid.urls')),
+
+Copied from old todo list:
+
+There are two kinds of things that can be done:
+refactorings (think of jogging in the morning, going to a spa, well make the code better :)
+new features (go to law school, get a job, do something real)
+Just a joke - pick yourself a task and work on it.
+
+==Refactoring==
+* validate HTML
+* set up loading of default settings from inside the /forum dir
+* automatic dependency checking for modules
+* propose how to rename directory forum --> askbot
+ without breaking things and keeping name of the project root
+ named the same way - askbot
+
+==New features==
+Whoever wants - pick a feature from the WISH_LIST
+add it here and start working on it
+If you are not starting immediately - leave it on the wishlist :)
+
+==Notes==
+1)after this is done most new suggested features
+ may be worked on easily since most of them
+ only require editing view functions and templates
+
+ However, anyone can work on new features anyway - you'll
+ just have to probably copy-paste your code into
+ the branch undergoing refactoring which involves
+ splitting the files. Auto merging across split points
+ is harder or impossible.
diff --git a/forum/documentation/askbot-requirements.txt b/forum/documentation/askbot-requirements.txt
new file mode 100644
index 00000000..66a37fbe
--- /dev/null
+++ b/forum/documentation/askbot-requirements.txt
@@ -0,0 +1,9 @@
+django>=1.1 # Note: email subscription sender job requires Django 1.1, everything else works with 1.0
+#mysql-python # Can't use with pip, see http://groups.google.com/group/python-virtualenv/msg/ea988085951c92b3
+python-openid
+html5lib
+markdown2
+git+git://github.com/robhudson/django-debug-toolbar.git
+git+git://github.com/dcramer/django-sphinx.git
+svn+http://recaptcha-django.googlecode.com/svn/trunk/
+svn+http://recaptcha.googlecode.com/svn/trunk/recaptcha-plugins/python/
diff --git a/forum/forms.py b/forum/forms.py
index e16db2c6..4139abb8 100755
--- a/forum/forms.py
+++ b/forum/forms.py
@@ -2,8 +2,10 @@ import re
from datetime import date
from django import forms
from models import *
-from const import *
+from const import * #todo: clean out import * thing
+from forum import const
from django.utils.translation import ugettext as _
+from django.utils.translation import ungettext
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from forum.utils.forms import NextUrlField, UserNameField, SetPasswordForm
@@ -59,22 +61,34 @@ class TagNamesField(forms.CharField):
if len(data) < 1:
raise forms.ValidationError(_('tags are required'))
- split_re = re.compile(r'[ ,]+')
- list = split_re.split(data)
- list_temp = []
- if len(list) > 5:
- raise forms.ValidationError(_('please use 5 tags or less'))
- for tag in list:
- if len(tag) > 20:
- raise forms.ValidationError(_('tags must be shorter than 20 characters'))
- #take tag regex from settings
- tagname_re = re.compile(r'[a-z0-9\w._#-]+',re.UNICODE)
- if not tagname_re.match(tag):
- raise forms.ValidationError(_('please use letters, numbers, and characters \'.-_#\''))
- # only keep one same tag
- if tag not in list_temp and len(tag.strip()) > 0:
- list_temp.append(tag)
- return u' '.join(list_temp)
+ split_re = re.compile(const.TAG_SPLIT_REGEX)
+ tag_strings = split_re.split(data)
+ out_tag_list = []
+ tag_count = len(tag_strings)
+ if tag_count > const.MAX_TAGS_PER_POST:
+ msg = ungettext(
+ 'please use %(tag_count)d tag or less',#odd but have to use to pluralize
+ 'please use %(tag_count)d tags or less',
+ tag_count) % {'tag_count':tag_count}
+ raise forms.ValidationError(msg)
+ for tag in tag_strings:
+ tag_length = len(tag)
+ if tag_length > const.MAX_TAG_LENGTH:
+ #singular form is odd in english, but required for pluralization
+ #in other languages
+ msg = ungettext('each tag must be shorter than %(max_chars)d character',#odd but added for completeness
+ 'each tag must be shorter than %(max_shars)d characters',
+ tag_length) % {'max_chars':tag_length}
+ raise forms.ValidationError(msg)
+
+ #todo - this needs to come from settings
+ tagname_re = re.compile(const.TAG_REGEX, re.UNICODE)
+ if not tagname_re.search(tag):
+ raise forms.ValidationError(_('use-these-chars-in-tags'))
+ #only keep unique tags
+ if tag not in out_tag_list:
+ out_tag_list.append(tag)
+ return u' '.join(out_tag_list)
class WikiField(forms.BooleanField):
def __init__(self, *args, **kwargs):
@@ -113,6 +127,77 @@ class ModerateUserForm(forms.ModelForm):
model = User
fields = ('is_approved',)
+class AdvancedSearchForm(forms.Form):
+ #nothing must be required in this form
+ #it is used by the main questions view
+ scope = forms.ChoiceField(choices=const.POST_SCOPE_LIST, required=False)
+ sort = forms.ChoiceField(choices=const.POST_SORT_METHODS, required=False)
+ query = forms.CharField(max_length=256, required=False)
+ reset_tags = forms.BooleanField(required=False)
+ reset_author = forms.BooleanField(required=False)
+ reset_query = forms.BooleanField(required=False)
+ start_over = forms.BooleanField(required=False)
+ tags = forms.CharField(max_length=256,required=False)
+ author = forms.IntegerField(required=False)
+ page_size = forms.ChoiceField(choices=const.PAGE_SIZES, required=False)
+ page = forms.IntegerField(required=False)
+
+ def clean_tags(self):
+ if 'tags' in self.cleaned_data:
+ tags_input = self.cleaned_data['tags'].strip()
+ split_re = re.compile(TAG_SPLIT_REGEX)
+ tag_strings = split_re.split(tags_input)
+ tagname_re = re.compile(const.TAG_REGEX, re.UNICODE)
+ out = set()
+ for s in tag_strings:
+ if tagname_re.search(s):
+ out.add(s)
+ if len(out) > 0:
+ self.cleaned_data['tags'] = out
+ else:
+ self.cleaned_data['tags'] = None
+ return self.cleaned_data['tags']
+
+ def clean_query(self):
+ if 'query' in self.cleaned_data:
+ q = self.cleaned_data['query'].strip()
+ if q == '':
+ q = None
+ self.cleaned_data['query'] = q
+ return self.cleaned_data['query']
+
+ def clean_page_size(self):
+ if 'page_size' in self.cleaned_data:
+ if self.cleaned_data['page_size'] == '':
+ self.cleaned_data['page_size'] = None
+ return self.cleaned_data['page_size']
+
+ def clean(self):
+ #todo rewrite
+ if self.cleaned_data['scope'] == '':
+ del self.cleaned_data['scope']
+ if self.cleaned_data['tags'] is None:
+ del self.cleaned_data['tags']
+ if self.cleaned_data['sort'] == '':
+ del self.cleaned_data['sort']
+ if self.cleaned_data['query'] == None:
+ del self.cleaned_data['query']
+ if self.cleaned_data['reset_tags'] == False:
+ del self.cleaned_data['reset_tags']
+ if self.cleaned_data['reset_author'] == False:
+ del self.cleaned_data['reset_author']
+ if self.cleaned_data['reset_query'] == False:
+ del self.cleaned_data['reset_query']
+ if self.cleaned_data['start_over'] == False:
+ del self.cleaned_data['start_over']
+ if self.cleaned_data['author'] is None:
+ del self.cleaned_data['author']
+ if self.cleaned_data['page'] is None:
+ del self.cleaned_data['page']
+ if self.cleaned_data['page_size'] is None:
+ del self.cleaned_data['page_size']
+ return self.cleaned_data
+
class NotARobotForm(forms.Form):
recaptcha = ReCaptchaField()
diff --git a/forum/importers/__init__.py b/forum/importers/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/forum/importers/__init__.py
diff --git a/forum/importers/stackexchange/ANOMALIES b/forum/importers/stackexchange/ANOMALIES
new file mode 100644
index 00000000..05a7dbdb
--- /dev/null
+++ b/forum/importers/stackexchange/ANOMALIES
@@ -0,0 +1,14 @@
+* several user accounts with same email
+* users with no openid
+* users with no email (hack: gravatar set to settings.ANONYMOUS_USER_EMAIL)
+* users with no screen name
+* users with no email and no screen name (25% in homeschool)
+* tag preferences are not stored explicitly (interesting/ignored)
+ maybe they are in se.User.preferences_raw
+ but the data there is not marked up and is kind of cryptic
+* we don't have Community user. SE has one with id=-1
+ this id may break the load script
+ potential break places are anywhere where is X.get_user() call
+ issues may happen with larger data sets where activity
+ of user "Community" is somehow reflected in a way
+ that load_stackexchange does not take care of
diff --git a/forum/importers/stackexchange/README b/forum/importers/stackexchange/README
new file mode 100644
index 00000000..598a8555
--- /dev/null
+++ b/forum/importers/stackexchange/README
@@ -0,0 +1,62 @@
+this app's function will be to:
+
+* install it's own tables (#todo: not yet automated)
+* read SE xml dump into DjangoDB (automated)
+* populate askbot database (automated)
+* remove SE tables (#todo: not done yet)
+
+Current process to load SE data into Askbot is:
+==============================================
+
+1) backup database
+
+2) unzip SE dump into dump_dir (any directory name)
+ you may want to make sure that your dump directory in .gitignore file
+ so that you don't publish it by mistake
+
+3) enable 'stackexchange' in the list of installed apps (probably aready in settings.py)
+
+4) (optional - create models.py for SE, which is included anyway) run:
+
+ #a) run in-place removal of xml namspace prefix to make parsing easier
+ perl -pi -w -e 's/xs://g' $SE_DUMP_PATH/xsd/*.xsd
+ cd stackexchange
+ python parse_models.py $SE_DUMP_PATH/xsd/*.xsd > models.py
+
+5) Install stackexchange models (as well as any other missing models)
+ python manage.py syncdb
+
+6) make sure that badges are installed
+ if not, run (example for mysql):
+
+ mysql -u user -p dbname < sql_scripts/badges.sql
+
+7) load SE data:
+
+ python manage.py load_stackexchange dump_dir
+
+ if anything doesn't go right - run 'python manage.py flush' and repeat
+ steps 6 and 7
+
+NOTES:
+============
+
+Here is the load script that I used for the testing
+it assumes that SE dump has been unzipped inside the tmp directory
+
+ #!/bin/sh$
+ python manage.py flush
+ #delete all data
+ mysql -u askbot -p aksbot < sql_scripts/badges.sql
+ python manage.py load_stackexchange tmp
+
+Untested parts are tagged with comments starting with
+#todo:
+
+The test set did not have all the usage cases of StackExchange represented so
+it may break with other sets.
+
+The job takes some time to run, especially
+content revisions and votes - may be optimized
+
+Some of the fringe cases are described in file stackexchange/ANOMALIES
diff --git a/forum/importers/stackexchange/__init__.py b/forum/importers/stackexchange/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/forum/importers/stackexchange/__init__.py
diff --git a/forum/importers/stackexchange/management/__init__.py b/forum/importers/stackexchange/management/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/forum/importers/stackexchange/management/__init__.py
diff --git a/forum/importers/stackexchange/management/commands/__init__.py b/forum/importers/stackexchange/management/commands/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/forum/importers/stackexchange/management/commands/__init__.py
diff --git a/forum/importers/stackexchange/management/commands/load_stackexchange.py b/forum/importers/stackexchange/management/commands/load_stackexchange.py
new file mode 100644
index 00000000..ee22e33a
--- /dev/null
+++ b/forum/importers/stackexchange/management/commands/load_stackexchange.py
@@ -0,0 +1,804 @@
+from django.core.management.base import BaseCommand
+from django.template.defaultfilters import slugify #todo: adopt unicode-aware slugify
+#todo: http://stackoverflow.com/questions/837828/how-to-use-a-slug-in-django
+import os
+import re
+import sys
+import forum.importers.stackexchange.parse_models as se_parser
+from xml.etree import ElementTree as et
+from django.db import models
+import forum.models as askbot
+import forum.importers.stackexchange.models as se
+from forum.forms import EditUserEmailFeedsForm
+from forum.utils.html import sanitize_html
+from django.conf import settings
+from django.contrib.auth.models import Message as DjangoMessage
+from django.utils.translation import ugettext as _
+#from markdown2 import Markdown
+#markdowner = Markdown(html4tags=True)
+
+xml_read_order = (
+ 'VoteTypes','UserTypes','Users','Users2Votes',
+ 'Badges','Users2Badges','CloseReasons','FlatPages',
+ 'MessageTypes','PostHistoryTypes','PostTypes','SchemaVersion',
+ 'Settings','SystemMessages','ThemeResources','ThemeTextResources',
+ 'ThrottleBucket','UserHistoryTypes','UserHistory',
+ 'Users2Badges','VoteTypes','Users2Votes','MessageTypes',
+ 'Posts','Posts2Votes','PostHistory','PostComments',
+ 'ModeratorMessages','Messages','Comments2Votes',
+ )
+
+#association tables SE item id --> ASKBOT item id
+#table associations are implied
+#todo: there is an issue that these may be inconsistent with the database
+USER = {}#SE User.id --> django(ASKBOT) User.id
+QUESTION = {}
+ANSWER = {}
+NAMESAKE_COUNT = {}# number of times user name was used - for X.get_screen_name
+
+class X(object):#
+ """class with methods for handling some details
+ of SE --> ASKBOT mapping
+ """
+ badge_type_map = {'1':'gold','2':'silver','3':'bronze'}
+
+ askbot_supported_id_providers = (
+ 'google','yahoo','aol','myopenid',
+ 'flickr','technorati',
+ 'wordpress','blogger','livejournal',
+ 'claimid','vidoop','verisign',
+ 'openidurl','facebook','local',
+ 'twitter' #oauth is not on this list, b/c it has no own url
+ )
+
+ #map SE VoteType -> askbot.User vote method
+ #created methods with the same call structure in askbot.User
+ #User.<vote_method>(post, timestamp=None, cancel=False)
+ vote_actions = {
+ 'UpMod':'upvote',
+ 'DownMod':'downvote',
+ 'AcceptedByOriginator':'accept_answer',
+ 'Offensive':'flag_post',
+ 'Favorite':'toggle_favorite_question',
+ }
+
+ #these modes cannot be mixed
+ #only wiki is assumed to be mixable
+ exclusive_revision_modes = (
+ 'initial','edit','rollback','lock',
+ 'migrate','close','merge','delete',
+ )
+
+ #badges whose names don't match exactly, but
+ #present in both SE and ASKBOT
+ badge_exceptions = {# SE --> ASKBOT
+ 'Citizen Patrol':'Citizen patrol',#single #todo: why sentence case?
+ 'Strunk &amp; White':'Strunk & White',#single
+ 'Civic Duty':'Civic duty',
+ }
+
+ revision_type_map = {
+ 'Initial Title':'initial',
+ 'Initial Body':'initial',
+ 'Initial Tags':'initial',
+ 'Edit Title':'edit',
+ 'Edit Body':'edit',
+ 'Edit Tags':'edit',
+ 'Rollback Title':'rollback',
+ 'Rollback Body':'rollback',
+ 'Rollback Tags':'rollback',
+ 'Post Closed':'close',
+ 'Post Reopened':'close',
+ 'Post Deleted':'delete',
+ 'Post Undeleted':'delete',
+ 'Post Locked':'lock',
+ 'Post Unlocked':'lock',
+ 'Community Owned':'wiki',
+ 'Post Migrated':'migrate',
+ 'Question Merged':'merge',
+ }
+
+ close_reason_map = {
+ 1:1,#duplicate
+ 2:2,#off-topic
+ 3:3,#subjective and argumentative
+ 4:4,#not a real question
+ 5:7,#offensive
+ 6:6,#irrelevant or outdated question
+ 7:9,#too localized
+ 10:8,#spam
+ }
+
+ @classmethod
+ def get_message_text(cls, se_m):
+ """try to intelligently translate
+ SE message to ASKBOT so that it makese sense in
+ our context
+ """
+ #todo: properly translate messages
+ #todo: maybe work through more instances of messages
+ if se_m.message_type.name == 'Badge Notification':
+ return se_m.text
+ else:
+ if 'you are now an administrator' in se_m.text:
+ return _('Congratulations, you are now an Administrator')
+ elif re.search(r'^You have \d+ new',se_m.text):
+ bits = se_m.text.split('.')
+ text = bits[0]
+ if se_m.user.id == -1:
+ return None
+ url = cls.get_user(se_m.user).get_profile_url()
+ return '<a href="%s?sort=responses">%s</a>' % (url,text)
+ return None
+
+ @classmethod
+ def get_post(cls, se_post):
+ #todo: fix this hack - either in-memory id association table
+ #or use database to store these associations
+ post_type = se_post.post_type.name
+ if post_type == 'Question':
+ return askbot.Question.objects.get(id=QUESTION[se_post.id].id)
+ elif post_type == 'Answer':
+ return askbot.Answer.objects.get(id=ANSWER[se_post.id].id)
+ else:
+ raise Exception('unknown post type %s' % post_type)
+
+ @classmethod
+ def get_close_reason(cls, se_reason):
+ #todo: this is a guess - have not seen real data
+ se_reason = int(se_reason)
+ return cls.close_reason_map[se_reason]
+
+ @classmethod
+ def get_user(cls, se_user):
+ #todo: same as get_post
+ return askbot.User.objects.get(id=USER[se_user.id].id)
+
+ @classmethod
+ def get_post_revision_group_types(cls, rev_group):
+ rev_types = {}
+ for rev in rev_group:
+ rev_type = cls.get_post_revision_type(rev)
+ rev_types[rev_type] = 1
+ rev_types = rev_types.keys()
+
+ #make sure that exclusive rev modes are not mixed
+ exclusive = cls.exclusive_revision_modes
+ if len(rev_types) > 1 and all([t in exclusive for t in rev_types]):
+ tstr = ','.join(rev_types)
+ gstr = ','.join([str(rev.id) for rev in rev_group])
+ msg = 'incompatible revision types %s in PostHistory %s' % (tstr,gstr)
+ raise Exception(msg)
+ return rev_types
+
+ @classmethod
+ def clean_tags(cls, tags):
+ tags = re.subn(r'\s+',' ',tags.strip())[0]
+ bits = tags.split(' ')
+ tags = ' '.join([bit[1:-1] for bit in bits])
+ tags = re.subn(r'\xf6','-',tags)[0]
+ return tags
+
+ @classmethod
+ def get_screen_name(cls, name):
+ """always returns unique screen name
+ even if there are multiple users in SE
+ with the same exact screen name
+ """
+ if name is None:
+ name = 'anonymous'
+ name = name.strip()
+ name = re.subn(r'\s+',' ',name)[0]#remove repeating spaces
+
+ try:
+ u = askbot.User.objects.get(username = name)
+ try:
+ if u.location:
+ name += ', %s' % u.location
+ if name in NAMESAKE_COUNT:
+ NAMESAKE_COUNT[name] += 1
+ name += ' %d' % NAMESAKE_COUNT[name]
+ else:
+ NAMESAKE_COUNT[name] = 1
+ except askbot.User.DoesNotExist:
+ pass
+ except askbot.User.DoesNotExist:
+ NAMESAKE_COUNT[name] = 1
+ return name
+
+ @classmethod
+ def get_email(cls, email):#todo: fix fringe case - user did not give email!
+ if email is None:
+ return settings.ANONYMOUS_USER_EMAIL
+ else:
+ assert(email != '')
+ return email
+
+ @classmethod
+ def get_post_revision_type(cls, rev):
+ rev_name = rev.post_history_type.name
+ rev_type = cls.revision_type_map.get(rev_name, None)
+ if rev_type is None:
+ raise Exception('dont understand revision type %s' % rev)
+ return rev_type
+
+ #crude method of getting id provider name from the url
+ @classmethod
+ def get_openid_provider_name(cls, openid_url):
+ openid_str = str(openid_url)
+ bits = openid_str.split('/')
+ base_url = bits[2] #assume this is base url
+ url_bits = base_url.split('.')
+ provider_name = url_bits[-2].lower()
+ if provider_name not in cls.askbot_supported_id_providers:
+ raise Exception('could not determine login provider for %s' % openid_url)
+ return provider_name
+
+ @staticmethod
+ def blankable(input):
+ if input is None:
+ return ''
+ else:
+ return input
+
+ @classmethod
+ def parse_badge_summary(cls, badge_summary):
+ (gold,silver,bronze) = (0,0,0)
+ if badge_summary:
+ if len(badge_summary) > 3:
+ print 'warning: guessing that badge summary is comma separated'
+ print 'have %s' % badge_summary
+ bits = badge_summary.split(',')
+ else:
+ bits = [badge_summary]
+ for bit in bits:
+ m = re.search(r'^(?P<type>[1-3])=(?P<count>\d+)$', bit)
+ if not m:
+ raise Exception('could not parse badge summary: %s' % badge_summary)
+ else:
+ badge_type = cls.badge_type_map[m.groupdict()['type']]
+ locals()[badge_type] = int(m.groupdict()['count'])
+ return (gold,silver,bronze)
+
+ @classmethod
+ def get_badge_name(cls, name):
+ return cls.badge_exceptions.get(name, name)
+
+class Command(BaseCommand):
+ help = 'Loads StackExchange data from unzipped directory of XML files into the ASKBOT database'
+ args = 'se_dump_dir'
+
+ def handle(self, *arg, **kwarg):
+ if len(arg) < 1 or not os.path.isdir(arg[0]):
+ print 'Error: first argument must be a directory with all the SE *.xml files'
+ sys.exit(1)
+
+ self.dump_path = arg[0]
+ #read the data into SE tables
+ for xml in xml_read_order:
+ xml_path = self.get_xml_path(xml)
+ table_name = self.get_table_name(xml)
+ self.load_xml_file(xml_path, table_name)
+
+ #this is important so that when we clean up messages
+ #automatically generated by the procedures below
+ #we do not delete old messages
+ #todo: unfortunately this may need to be redone
+ #when we upgrade to django 1.2 and definitely by 1.4 when
+ #the current message system will be replaced with the
+ #django messages framework
+ self.save_askbot_message_id_list()
+
+ #transfer data into ASKBOT tables
+ print 'Transferring users...',
+ sys.stdout.flush()
+ self.transfer_users()
+ print 'done.'
+ print 'Transferring content edits...',
+ sys.stdout.flush()
+ self.transfer_question_and_answer_activity()
+ print 'done.'
+ print 'Transferring view counts...',
+ sys.stdout.flush()
+ self.transfer_question_view_counts()
+ print 'done.'
+ print 'Transferring comments...',
+ sys.stdout.flush()
+ self.transfer_comments()
+ print 'done.'
+ print 'Transferring badges and badge awards...',
+ sys.stdout.flush()
+ self.transfer_badges()
+ print 'done.'
+ print 'Transferring votes...',
+ sys.stdout.flush()
+ self.transfer_votes()#includes favorites, accepts and flags
+ print 'done.'
+
+ self.cleanup_messages()#delete autogenerated messages
+ self.transfer_messages()
+
+ #todo: these are not clear how to go about
+ self.transfer_update_subscriptions()
+ self.transfer_tag_preferences()
+ self.transfer_meta_pages()
+
+ def save_askbot_message_id_list(self):
+ id_list = list(DjangoMessage.objects.all().values('id'))
+ self._askbot_message_id_list = id_list
+
+ def cleanup_messages(self):
+ """deletes messages generated by the load process
+ """
+ id_list = self._askbot_message_id_list
+ mset = DjangoMessage.objects.all().exclude(id__in=id_list)
+ mset.delete()
+
+ def transfer_messages(self):
+ """transfers some messages from
+ SE to ASKBOT
+ """
+ for m in se.Message.objects.all():
+ if m.is_read:
+ continue
+ if m.user.id == -1:
+ continue
+ u = X.get_user(m.user)
+ text = X.get_message_text(m)
+ if text:
+ u.message_set.create(
+ message=text,
+ )
+
+ def _process_post_initial_revision_group(self, rev_group):
+
+ title = None
+ text = None
+ tags = None
+ wiki = False
+ author = USER[rev_group[0].user.id]
+ added_at = rev_group[0].creation_date
+
+ for rev in rev_group:
+ rev_type = rev.post_history_type.name
+ if rev_type == 'Initial Title':
+ title = rev.text
+ elif rev_type == 'Initial Body':
+ text = rev.text
+ elif rev_type == 'Initial Tags':
+ tags = X.clean_tags(rev.text)
+ elif rev_type == 'Community Owned':
+ wiki = True
+ else:
+ raise Exception('unexpected revision type %s' % rev_type)
+
+ post_type = rev_group[0].post.post_type.name
+ if post_type == 'Question':
+ q = askbot.Question.objects.create_new(
+ title = title,
+ author = author,
+ added_at = added_at,
+ wiki = wiki,
+ tagnames = tags,
+ text = text
+ )
+ QUESTION[rev_group[0].post.id] = q
+ elif post_type == 'Answer':
+ q = X.get_post(rev_group[0].post.parent)
+ a = askbot.Answer.objects.create_new(
+ question = q,
+ author = author,
+ added_at = added_at,
+ wiki = wiki,
+ text = text,
+ )
+ ANSWER[rev_group[0].post.id] = a
+ else:
+ post_id = rev_group[0].post.id
+ raise Exception('unknown post type %s for id=%d' % (post_type, post_id))
+
+ def _process_post_edit_revision_group(self, rev_group):
+ #question apply edit
+ (title, text, tags) = (None, None, None)
+ for rev in rev_group:
+ rev_type = rev.post_history_type.name
+ if rev_type == 'Edit Title':
+ title = rev.text
+ elif rev_type == 'Edit Body':
+ text = rev.text
+ elif rev_type == 'Edit Tags':
+ tags = X.clean_tags(rev.text)
+ elif rev_type == 'Community Owned':
+ pass
+ else:
+ raise Exception('unexpected revision type %s' % rev_type)
+
+ rev0 = rev_group[0]
+ edited_by = USER[rev0.user.id]
+ edited_at = rev0.creation_date
+ comment = ';'.join([rev.comment for rev in rev_group if rev.comment])
+ post_type = rev0.post.post_type.name
+
+ if post_type == 'Question':
+ q = X.get_post(rev0.post)
+ q.apply_edit(
+ edited_at = edited_at,
+ edited_by = edited_by,
+ title = title,
+ text = text,
+ comment = comment,
+ tags = tags,
+ )
+ elif post_type == 'Answer':
+ a = X.get_post(rev0.post)
+ a.apply_edit(
+ edited_at = edited_at,
+ edited_by = edited_by,
+ text = text,
+ comment = comment,
+ )
+
+ def _make_post_wiki(self, rev_group):
+ #todo: untested
+ for rev in rev_group:
+ if rev.post_history_type.name == 'Community Owned':
+ p = X.get_post(rev.post)
+ u = X.get_user(rev.user)
+ t = rev.creation_date
+ p.wiki = True
+ p.wikified_at = t
+ p.wikified_by = u
+ self.mark_activity(p,u,t)
+ p.save()
+ return
+
+ def mark_activity(self,p,u,t):
+ """p,u,t - post, user, timestamp
+ """
+ if isinstance(p, askbot.Question):
+ p.last_activity_by = u
+ p.last_activity_at = t
+ elif isinstance(p, askbot.Answer):
+ p.question.last_activity_by = u
+ p.question.last_activity_at = t
+ p.question.save()
+
+ def _process_post_rollback_revision_group(self, rev_group):
+ #todo: don't know what to do here as there were no
+ #such data available
+ pass
+
+ def _process_post_lock_revision_group(self, rev_group):
+ #todo: untested
+ for rev in rev_group:
+ rev_type = rev.post_history_type.name
+ if rev_type.endswith('ocked'):
+ t = rev.creation_date
+ u = X.get_user(rev.user)
+ p = X.get_post(rev.post)
+ if rev_type == 'Post Locked':
+ p.locked = True
+ p.locked_by = u
+ p.locked_at = t
+ elif rev_type == 'Post Unlocked':
+ p.locked = False
+ p.locked_by = None
+ p.locked_at = None
+ else:
+ return
+ self.mark_activity(p,u,t)
+ p.save()
+ return
+
+ def _process_post_close_revision_group(self, rev_group):
+ #todo: untested
+ for rev in rev_group:
+ if rev.post.post_type.name != 'Question':
+ return
+ rev_type = rev.post_history_type.name
+ if rev_type in ('Post Closed', 'Post Reopened'):
+ t = rev.creation_date
+ u = X.get_user(rev.user)
+ p = X.get_post(rev.post)
+ if rev_type == 'Post Closed':
+ p.closed = True
+ p.closed_at = t
+ p.closed_by = u
+ p.close_reason = X.get_close_reason(rev.text)
+ elif rev_type == 'Post Reopened':
+ p.closed = False
+ p.closed_at = None
+ p.closed_by = None
+ p.close_reason = None
+ self.mark_activity(p,u,t)
+ p.save()
+ return
+
+ def _process_post_delete_revision_group(self, rev_group):
+ #todo: untested
+ for rev in rev_group:
+ rev_type = rev.post_history_type.name
+ if rev_type.endswith('eleted'):
+ t = rev.creation_date
+ u = X.get_user(rev.user)
+ p = X.get_post(rev.post)
+ if rev_type == 'Post Deleted':
+ p.deleted = True
+ p.deleted_at = t
+ p.deleted_by = u
+ elif rev_type == 'Post Undeleted':
+ p.deleted = False
+ p.deleted_at = None
+ p.deleted_by = None
+ self.mark_activity(p,u,t)
+ p.save()
+ return
+
+ def _process_post_revision_group(self, rev_group):
+ #determine revision type
+ #'initial','edit','rollback','lock',
+ #'migrate','close','merge','delete',
+ rev_types = X.get_post_revision_group_types(rev_group)
+ if 'initial' in rev_types:
+ self._process_post_initial_revision_group(rev_group)
+ elif 'edit' in rev_types:
+ self._process_post_edit_revision_group(rev_group)
+ elif 'rollback' in rev_types:
+ self._process_post_rollback_revision_group(rev_group)
+ elif 'lock' in rev_types:
+ self._process_post_lock_revision_group(rev_group)
+ elif 'close' in rev_types:
+ self._process_post_close_revision_group(rev_group)
+ elif 'delete' in rev_types:
+ self._process_post_delete_revision_group(rev_group)
+ else:
+ pass
+ #todo: rollback, lock, close and delete are
+ #not tested
+ #merge and migrate actions are ignored
+ #wiki is mixable with other groups, so process it in addition
+ if 'wiki' in rev_types:
+ self._make_post_wiki(rev_group)
+
+ def transfer_tag_preferences(self):
+ #todo: figure out where these are stored in SE
+ #maybe in se.User.preferences_raw?
+ pass
+
+ def transfer_question_and_answer_activity(self):
+ """transfers all question and answer
+ edits and related status changes
+ """
+ #assuming that there are only two post types
+ se_revs = se.PostHistory.objects.all()
+ #assuming that chronologial order is correct and there
+ #will be no problems of data integrity upon insertion of records
+ se_revs = se_revs.order_by('creation_date','revision_guid')
+ #todo: ignored fringe case - no revisions
+ c_guid = se_revs[0].revision_guid
+ c_group = []
+ #this loop groups revisions by revision id, then calls process function
+ #for the revision grup (elementary revisions posted at once)
+ for se_rev in se_revs:
+ if se_rev.revision_guid == c_guid:
+ c_group.append(se_rev)
+ else:
+ self._process_post_revision_group(c_group)
+ c_group = []
+ c_group.append(se_rev)
+ c_guid = se_rev.revision_guid
+ if len(c_group) != 0:
+ self._process_post_revision_group(c_group)
+
+ def transfer_comments(self):
+ for se_c in se.PostComment.objects.all():
+ if se_c.deletion_date:
+ print 'Warning deleted comment %d dropped' % se_c.id
+ continue
+ se_post = se_c.post
+ if se_post.post_type.name == 'Question':
+ askbot_post = QUESTION[se_post.id]
+ elif se_post.post_type.name == 'Answer':
+ askbot_post = ANSWER[se_post.id]
+
+ askbot_post.add_comment(
+ comment = se_c.text,
+ added_at = se_c.creation_date,
+ user = USER[se_c.user.id]
+ )
+
+ def _install_missing_badges(self):
+ self._missing_badges = {}
+ for se_b in se.Badge.objects.all():
+ name = X.get_badge_name(se_b.name)
+ try:
+ askbot.Badge.objects.get(name=name)
+ except:
+ self._missing_badges[name] = 0
+ if len(se_b.description) > 300:
+ print 'Warning truncated description for badge %d' % se_b.id
+ askbot.Badge.objects.create(
+ name = name,
+ slug = slugify(name),
+ description = se_b.description,
+ multiple = (not se_b.single),
+ type = se_b.class_type
+ )
+
+ def _award_badges(self):
+ #note: SE does not keep information on
+ #content-related badges like askbot does
+ for se_a in se.User2Badge.objects.all():
+ if se_a.user.id == -1:
+ continue #skip community user
+ u = USER[se_a.user.id]
+ badge_name = X.get_badge_name(se_a.badge.name)
+ b = askbot.Badge.objects.get(name=badge_name)
+ if b.multiple == False:
+ if b.award_badge.count() > 0:
+ continue
+ #todo: fake content object here b/c SE does not support this
+ #todo: but askbot requires related content object
+ askbot.Award.objects.create(
+ user=u,
+ badge=b,
+ awarded_at=se_a.date,
+ content_object=u,
+ )
+ if b.name in self._missing_badges:
+ self._missing_badges[b.name] += 1
+
+ def _cleanup_badges(self):
+ d = self._missing_badges
+ unused = [name for name in d.keys() if d[name] == 0]
+ askbot.Badge.objects.filter(name__in=unused).delete()
+ installed = [name for name in d.keys() if d[name] > 0]
+ print 'Warning - following unsupported badges were installed:'
+ print ', '.join(installed)
+
+ def transfer_badges(self):
+ #note: badge level is neglected
+ #1) install missing badges
+ self._install_missing_badges()
+ #2) award badges
+ self._award_badges()
+ #3) delete unused newly installed badges
+ self._cleanup_badges()
+ pass
+
+ def transfer_question_view_counts(self):
+ for se_q in se.Post.objects.filter(post_type__name='Question'):
+ q = X.get_post(se_q)
+ q.view_count = se_q.view_count
+ q.save()
+
+
+ def transfer_votes(self):
+ for v in se.Post2Vote.objects.all():
+ vote_type = v.vote_type.name
+ if not vote_type in X.vote_actions:
+ continue
+
+ u = X.get_user(v.user)
+ p = X.get_post(v.post)
+ m = X.vote_actions[vote_type]
+ vote_method = getattr(askbot.User, m)
+ vote_method(u, p, timestamp = v.creation_date)
+ if v.deletion_date:
+ vote_method(u, p, timestamp = v.deletion_date, cancel=True)
+
+ def transfer_update_subscriptions(self):
+ #todo: not clear where this is stored in SE
+ #maybe in se.User.preferences_raw?
+ pass
+
+ def transfer_meta_pages(self):
+ #here we actually don't have anything in the database yet
+ #so we can't do this
+ pass
+
+ def load_xml_file(self, xml_path, table_name):
+ tree = et.parse(xml_path)
+ print 'loading from %s to %s' % (xml_path, table_name) ,
+ model = models.get_model('stackexchange', table_name)
+ i = 0
+ for row in tree.findall('.//row'):
+ model_entry = model()
+ i += 1
+ for col in row.getchildren():
+ field_name = se_parser.parse_field_name(col.tag)
+ field_type = model._meta.get_field(field_name)
+ field_value = se_parser.parse_value(col.text, field_type)
+ setattr(model_entry, field_name, field_value)
+ model_entry.save()
+ print '... %d objects saved' % i
+
+ def get_table_name(self,xml):
+ return se_parser.get_table_name(xml)
+
+ def get_xml_path(self, xml):
+ xml_path = os.path.join(self.dump_path, xml + '.xml')
+ if not os.path.isfile(xml_path):
+ print 'Error: file %s not found' % xml_path
+ sys.exit(1)
+ return xml_path
+
+ def transfer_users(self):
+ for se_u in se.User.objects.all():
+ if se_u.id < 1:#skip the Community user
+ continue
+ u = askbot.User()
+ u_type = se_u.user_type.name
+ if u_type == 'Administrator':
+ u.is_superuser = True
+ elif u_type == 'Moderator':
+ u.is_staff = True
+ elif u_type not in ('Unregistered', 'Registered'):
+ raise Exception('unknown user type %s' % u_type)
+
+ #if user is not registered, no association record created
+ #we do not allow posting by users who are not authenticated
+ #probably they'll just have to "recover" their account by email
+ if u_type != 'Unregistered':
+ assert(se_u.open_id)#everybody must have open_id
+ u_auth = askbot.AuthKeyUserAssociation()
+ u_auth.key = se_u.open_id
+ u_auth.provider = X.get_openid_provider_name(se_u.open_id)
+ u_auth.added_at = se_u.creation_date
+
+ if se_u.open_id is None and se_u.email is None:
+ print 'Warning: SE user %d is not recoverable (no email or openid)'
+
+ u.reputation = 1#se_u.reputation, it's actually re-computed
+ u.last_seen = se_u.last_access_date
+ u.email = X.get_email(se_u.email)
+ u.location = X.blankable(se_u.location)
+ u.date_of_birth = se_u.birthday #dattime -> date
+ u.website = X.blankable(se_u.website_url)
+ u.about = X.blankable(se_u.about_me)
+ u.last_login = se_u.last_login_date
+ u.date_joined = se_u.creation_date
+ u.is_active = True #todo: this may not be the case
+
+ u.username = X.get_screen_name(se_u.display_name)
+ u.real_name = X.blankable(se_u.real_name)
+
+ (gold,silver,bronze) = X.parse_badge_summary(se_u.badge_summary)
+ u.gold = gold
+ u.silver = silver
+ u.bronze = bronze
+
+ #todo: we don't have these fields
+ #views - number of profile views?
+ #has_replies
+ #has_message
+ #opt_in_recruit
+ #last_login_ip
+ #open_id_alt - ??
+ #preferences_raw - not clear how to use
+ #display_name_cleaned - lowercased, srtipped name
+ #timed_penalty_date
+ #phone
+
+ #don't know how to handle these - there was no usage example
+ #password_id
+ #guid
+
+ #ignored
+ #last_email_date - this translates directly to EmailFeedSetting.reported_at
+
+ #save the data
+ u.save()
+ form = EditUserEmailFeedsForm()
+ form.reset()
+ if se_u.opt_in_email == True:#set up daily subscription on "own" items
+ form.initial['individually_selected'] = 'd'
+ form.initial['asked_by_me'] = 'd'
+ form.initial['answered_by_me'] = 'd'
+ #
+ form.save(user=u, save_unbound=True)
+
+ if 'u_auth' in locals():
+ u_auth.user = u
+ u_auth.save()
+ USER[se_u.id] = u
diff --git a/forum/importers/stackexchange/models.py b/forum/importers/stackexchange/models.py
new file mode 100644
index 00000000..a30a9859
--- /dev/null
+++ b/forum/importers/stackexchange/models.py
@@ -0,0 +1,266 @@
+from django.db import models
+class Badge(models.Model):
+ id = models.IntegerField(primary_key=True)
+ class_type = models.IntegerField(null=True)
+ name = models.CharField(max_length=50, null=True)
+ description = models.TextField(null=True)
+ single = models.NullBooleanField(null=True)
+ secret = models.NullBooleanField(null=True)
+ tag_based = models.NullBooleanField(null=True)
+ command = models.TextField(null=True)
+ award_frequency = models.IntegerField(null=True)
+
+class CloseReason(models.Model):
+ id = models.IntegerField(primary_key=True)
+ name = models.CharField(max_length=200, null=True)
+ description = models.CharField(max_length=256, null=True)
+ display_order = models.IntegerField(null=True)
+
+class Comment2Vote(models.Model):
+ id = models.IntegerField(primary_key=True)
+ post_comment = models.ForeignKey('PostComment', related_name='Comment2Vote_by_post_comment_set', null=True)
+ vote_type = models.ForeignKey('VoteType', related_name='Comment2Vote_by_vote_type_set', null=True)
+ creation_date = models.DateTimeField(null=True)
+ user = models.ForeignKey('User', related_name='Comment2Vote_by_user_set', null=True)
+ ip_address = models.CharField(max_length=40, null=True)
+ user_display_name = models.CharField(max_length=40, null=True)
+ deletion_date = models.DateTimeField(null=True)
+
+class FlatPage(models.Model):
+ id = models.IntegerField(primary_key=True)
+ name = models.CharField(max_length=50, null=True)
+ url = models.CharField(max_length=128, null=True)
+ value = models.TextField(null=True)
+ content_type = models.CharField(max_length=50, null=True)
+ active = models.NullBooleanField(null=True)
+ use_master = models.NullBooleanField(null=True)
+
+class Message(models.Model):
+ id = models.IntegerField(primary_key=True)
+ user = models.ForeignKey('User', related_name='Message_by_user_set', null=True)
+ message_type = models.ForeignKey('MessageType', related_name='Message_by_message_type_set', null=True)
+ is_read = models.NullBooleanField(null=True)
+ creation_date = models.DateTimeField(null=True)
+ text = models.TextField(null=True)
+ post = models.ForeignKey('Post', related_name='Message_by_post_set', null=True)
+
+class MessageType(models.Model):
+ id = models.IntegerField(primary_key=True)
+ name = models.CharField(max_length=50, null=True)
+ description = models.CharField(max_length=300, null=True)
+
+class ModeratorMessage(models.Model):
+ id = models.IntegerField(primary_key=True)
+ message_type = models.ForeignKey('MessageType', related_name='ModeratorMessage_by_message_type_set', null=True)
+ creation_date = models.DateTimeField(null=True)
+ creation_ip_address = models.CharField(max_length=40, null=True)
+ text = models.TextField(null=True)
+ user = models.ForeignKey('User', related_name='ModeratorMessage_by_user_set', null=True)
+ post = models.ForeignKey('Post', related_name='ModeratorMessage_by_post_set', null=True)
+ deletion_date = models.DateTimeField(null=True)
+ deletion_user = models.ForeignKey('User', related_name='ModeratorMessage_by_deletion_user_set', null=True)
+ deletion_ip_address = models.CharField(max_length=40, null=True)
+ user_display_name = models.CharField(max_length=40, null=True)
+
+class PostComment(models.Model):
+ id = models.IntegerField(primary_key=True)
+ post = models.ForeignKey('Post', related_name='PostComment_by_post_set', null=True)
+ text = models.TextField(null=True)
+ creation_date = models.DateTimeField(null=True)
+ ip_address = models.CharField(max_length=15, null=True)
+ user = models.ForeignKey('User', related_name='PostComment_by_user_set', null=True)
+ user_display_name = models.CharField(max_length=30, null=True)
+ deletion_date = models.DateTimeField(null=True)
+ deletion_user = models.ForeignKey('User', related_name='PostComment_by_deletion_user_set', null=True)
+ score = models.IntegerField(null=True)
+
+class PostHistoryType(models.Model):
+ id = models.IntegerField(primary_key=True)
+ name = models.CharField(max_length=50, null=True)
+ description = models.CharField(max_length=300, null=True)
+
+class PostHistory(models.Model):
+ id = models.IntegerField(primary_key=True)
+ post_history_type = models.ForeignKey('PostHistoryType', related_name='PostHistory_by_post_history_type_set', null=True)
+ post = models.ForeignKey('Post', related_name='PostHistory_by_post_set', null=True)
+ revision_guid = models.CharField(max_length=64, null=True)
+ creation_date = models.DateTimeField(null=True)
+ ip_address = models.CharField(max_length=40, null=True)
+ user = models.ForeignKey('User', related_name='PostHistory_by_user_set', null=True)
+ comment = models.CharField(max_length=400, null=True)
+ text = models.TextField(null=True)
+ user_display_name = models.CharField(max_length=40, null=True)
+ user_email = models.CharField(max_length=100, null=True)
+ user_website_url = models.CharField(max_length=200, null=True)
+
+class Post2Vote(models.Model):
+ id = models.IntegerField(primary_key=True)
+ post = models.ForeignKey('Post', related_name='Post2Vote_by_post_set', null=True)
+ user = models.ForeignKey('User', related_name='Post2Vote_by_user_set', null=True)
+ vote_type = models.ForeignKey('VoteType', related_name='Post2Vote_by_vote_type_set', null=True)
+ creation_date = models.DateTimeField(null=True)
+ deletion_date = models.DateTimeField(null=True)
+ target_user = models.ForeignKey('User', related_name='Post2Vote_by_target_user_set', null=True)
+ target_rep_change = models.IntegerField(null=True)
+ voter_rep_change = models.IntegerField(null=True)
+ comment = models.CharField(max_length=150, null=True)
+ ip_address = models.CharField(max_length=40, null=True)
+ linked_post = models.ForeignKey('Post', related_name='Post2Vote_by_linked_post_set', null=True)
+
+class Post(models.Model):
+ id = models.IntegerField(primary_key=True)
+ post_type = models.ForeignKey('PostType', related_name='Post_by_post_type_set', null=True)
+ creation_date = models.DateTimeField(null=True)
+ score = models.IntegerField(null=True)
+ view_count = models.IntegerField(null=True)
+ body = models.TextField(null=True)
+ owner_user = models.ForeignKey('User', related_name='Post_by_owner_user_set', null=True)
+ last_editor_user = models.ForeignKey('User', related_name='Post_by_last_editor_user_set', null=True)
+ last_edit_date = models.DateTimeField(null=True)
+ last_activity_date = models.DateTimeField(null=True)
+ last_activity_user = models.ForeignKey('User', related_name='Post_by_last_activity_user_set', null=True)
+ parent = models.ForeignKey('self', related_name='Post_by_parent_set', null=True)
+ accepted_answer = models.ForeignKey('self', related_name='Post_by_accepted_answer_set', null=True)
+ title = models.CharField(max_length=250, null=True)
+ tags = models.CharField(max_length=150, null=True)
+ community_owned_date = models.DateTimeField(null=True)
+ history_summary = models.CharField(max_length=150, null=True)
+ answer_score = models.IntegerField(null=True)
+ answer_count = models.IntegerField(null=True)
+ comment_count = models.IntegerField(null=True)
+ favorite_count = models.IntegerField(null=True)
+ deletion_date = models.DateTimeField(null=True)
+ closed_date = models.DateTimeField(null=True)
+ locked_date = models.DateTimeField(null=True)
+ locked_duration = models.IntegerField(null=True)
+ owner_display_name = models.CharField(max_length=40, null=True)
+ last_editor_display_name = models.CharField(max_length=40, null=True)
+ bounty_amount = models.IntegerField(null=True)
+ bounty_closes = models.DateTimeField(null=True)
+ bounty_closed = models.DateTimeField(null=True)
+ last_owner_email_date = models.DateTimeField(null=True)
+
+class PostType(models.Model):
+ id = models.IntegerField(primary_key=True)
+ name = models.CharField(max_length=50, null=True)
+ description = models.CharField(max_length=300, null=True)
+
+class SchemaVersion(models.Model):
+ version = models.IntegerField(null=True)
+
+class Setting(models.Model):
+ id = models.IntegerField(primary_key=True)
+ key = models.CharField(max_length=256, null=True)
+ value = models.TextField(null=True)
+
+class SystemMessage(models.Model):
+ id = models.IntegerField(primary_key=True)
+ user = models.ForeignKey('User', related_name='SystemMessage_by_user_set', null=True)
+ creation_date = models.DateTimeField(null=True)
+ text = models.TextField(null=True)
+ deletion_date = models.DateTimeField(null=True)
+ deletion_user = models.ForeignKey('User', related_name='SystemMessage_by_deletion_user_set', null=True)
+
+class Tag(models.Model):
+ id = models.IntegerField(primary_key=True)
+ name = models.CharField(max_length=50, null=True)
+ count = models.IntegerField(null=True)
+ user = models.ForeignKey('User', related_name='Tag_by_user_set', null=True)
+ creation_date = models.DateTimeField(null=True)
+ is_moderator_only = models.NullBooleanField(null=True)
+ is_required = models.NullBooleanField(null=True)
+ aliases = models.CharField(max_length=200, null=True)
+
+class ThemeResource(models.Model):
+ id = models.IntegerField(primary_key=True)
+ name = models.CharField(max_length=50, null=True)
+ value = models.TextField(null=True)
+ content_type = models.CharField(max_length=50, null=True)
+ version = models.CharField(max_length=6, null=True)
+
+class ThemeTextResource(models.Model):
+ id = models.IntegerField(primary_key=True)
+ name = models.CharField(max_length=50, null=True)
+ value = models.TextField(null=True)
+ content_type = models.CharField(max_length=50, null=True)
+
+class ThrottleBucket(models.Model):
+ id = models.IntegerField(primary_key=True)
+ type = models.CharField(max_length=256, null=True)
+ ip_address = models.CharField(max_length=64, null=True)
+ tokens = models.IntegerField(null=True)
+ last_update = models.DateTimeField(null=True)
+
+class UserHistoryType(models.Model):
+ id = models.IntegerField(primary_key=True)
+ name = models.CharField(max_length=50, null=True)
+ description = models.CharField(max_length=300, null=True)
+
+class UserHistory(models.Model):
+ id = models.IntegerField(primary_key=True)
+ user_history_type = models.ForeignKey('UserHistoryType', related_name='UserHistory_by_user_history_type_set', null=True)
+ creation_date = models.DateTimeField(null=True)
+ ip_address = models.CharField(max_length=40, null=True)
+ user = models.ForeignKey('User', related_name='UserHistory_by_user_set', null=True)
+ comment = models.CharField(max_length=400, null=True)
+ user_display_name = models.CharField(max_length=40, null=True)
+ moderator_user = models.ForeignKey('User', related_name='UserHistory_by_moderator_user_set', null=True)
+ reputation = models.IntegerField(null=True)
+
+class User2Badge(models.Model):
+ id = models.IntegerField(primary_key=True)
+ user = models.ForeignKey('User', related_name='User2Badge_by_user_set', null=True)
+ badge = models.ForeignKey('Badge', related_name='User2Badge_by_badge_set', null=True)
+ date = models.DateTimeField(null=True)
+ comment = models.CharField(max_length=50, null=True)
+
+class User2Vote(models.Model):
+ id = models.IntegerField(primary_key=True)
+ user = models.ForeignKey('User', related_name='User2Vote_by_user_set', null=True)
+ vote_type = models.ForeignKey('VoteType', related_name='User2Vote_by_vote_type_set', null=True)
+ target_user = models.ForeignKey('User', related_name='User2Vote_by_target_user_set', null=True)
+ creation_date = models.DateTimeField(null=True)
+ deletion_date = models.DateTimeField(null=True)
+ ip_address = models.CharField(max_length=40, null=True)
+
+class User(models.Model):
+ id = models.IntegerField(primary_key=True)
+ user_type = models.ForeignKey('UserType', related_name='User_by_user_type_set', null=True)
+ open_id = models.CharField(max_length=200, null=True)
+ reputation = models.IntegerField(null=True)
+ views = models.IntegerField(null=True)
+ creation_date = models.DateTimeField(null=True)
+ last_access_date = models.DateTimeField(null=True)
+ has_replies = models.NullBooleanField(null=True)
+ has_message = models.NullBooleanField(null=True)
+ opt_in_email = models.NullBooleanField(null=True)
+ opt_in_recruit = models.NullBooleanField(null=True)
+ last_login_date = models.DateTimeField(null=True)
+ last_email_date = models.DateTimeField(null=True)
+ last_login_ip = models.CharField(max_length=15, null=True)
+ open_id_alt = models.CharField(max_length=200, null=True)
+ email = models.CharField(max_length=100, null=True)
+ display_name = models.CharField(max_length=40, null=True)
+ display_name_cleaned = models.CharField(max_length=40, null=True)
+ website_url = models.CharField(max_length=200, null=True)
+ real_name = models.CharField(max_length=100, null=True)
+ location = models.CharField(max_length=100, null=True)
+ birthday = models.DateTimeField(null=True)
+ badge_summary = models.CharField(max_length=50, null=True)
+ about_me = models.TextField(null=True)
+ preferences_raw = models.TextField(null=True)
+ timed_penalty_date = models.DateTimeField(null=True)
+ guid = models.CharField(max_length=64, null=True)
+ phone = models.CharField(max_length=20, null=True)
+ password_id = models.IntegerField(null=True)
+
+class UserType(models.Model):
+ id = models.IntegerField(primary_key=True)
+ name = models.CharField(max_length=50, null=True)
+ description = models.CharField(max_length=300, null=True)
+
+class VoteType(models.Model):
+ id = models.IntegerField(primary_key=True)
+ name = models.CharField(max_length=50, null=True)
+ description = models.CharField(max_length=300, null=True)
+
diff --git a/forum/importers/stackexchange/parse_models.py b/forum/importers/stackexchange/parse_models.py
new file mode 100644
index 00000000..64796e57
--- /dev/null
+++ b/forum/importers/stackexchange/parse_models.py
@@ -0,0 +1,225 @@
+from xml.etree import ElementTree as et
+import sys
+import re
+import os
+if __name__ != '__main__':#hack do not import models if run as script
+ from django.db import models
+from datetime import datetime
+
+table_prefix = ''#StackExchange or something, if needed
+date_time_format = '%Y-%m-%dT%H:%M:%S' #note that fractional part of second is lost
+time_re = re.compile(r'(\.[\d]+)?$')
+loader_app_name = os.path.dirname(__file__)
+
+types = {
+ 'unsignedByte':'models.IntegerField',
+ 'FK':'models.ForeignKey',
+ 'PK':'models.IntegerField',
+ 'string':'models.CharField',
+ 'text':'models.TextField',
+ 'int':'models.IntegerField',
+ 'boolean':'models.NullBooleanField',
+ 'dateTime':'models.DateTimeField',
+ 'base64Binary':'models.TextField',
+ 'double':'models.IntegerField',
+}
+
+def camel_to_python(camel):
+ """http://stackoverflow.com/questions/1175208/
+ """
+ s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', camel)
+ return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
+
+def singular(word):
+ if word.endswith('s'):
+ return word[:-1]
+ else:
+ return word
+
+def get_table_name(name):
+ """Determine db table name
+ from the basename of the .xml file
+ """
+ out = table_prefix
+ if name.find('2') == -1:
+ out += singular(name)
+ else:
+ bits = name.split('2')
+ bits = map(singular, bits)
+ out += '2'.join(bits)
+ return out
+
+class DjangoModel(object):
+ def __init__(self, name):
+ self.name = get_table_name(name)
+ self.fields = []
+ def add_field(self,field):
+ field.table = self
+ self.fields.append(field)
+ def __str__(self):
+ out = 'class %s(models.Model):\n' % self.name
+ for f in self.fields:
+ out += ' %s\n' % str(f)
+ return out
+
+class DjangoField(object):
+ def __init__(self, name, type, restriction = None):
+ self.name = camel_to_python(name)
+ if self.name == 'class':
+ self.name = 'class_type'#work around python keyword
+ self.type = type
+ self.table = None
+ self.restriction = restriction
+ self.relation = None
+
+ def __str__(self):
+ out = '%s = %s(' % (self.name, types[self.type])
+ if self.type == 'FK':
+ out += "'%s'" % self.relation
+ out += ", related_name='%s_by_%s_set'" % (self.table.name, self.name)
+ out += ', null=True'#nullable to make life easier
+ elif self.type == 'PK':
+ out += 'primary_key=True'
+ elif self.restriction != -1:
+ if self.type == 'string':
+ out += 'max_length=%s' % self.restriction
+ out += ', null=True'
+ else:
+ raise Exception('restriction (max_length) supported only for string type')
+ else:
+ out += 'null=True'
+ out += ')'
+ return out
+
+ def get_type(self):
+ return self.type
+
+class DjangoPK(DjangoField):
+ def __init__(self):
+ self.name = 'id'
+ self.type = 'PK'
+
+class DjangoFK(DjangoField):
+ def __init__(self, source_name):
+ bits = source_name.split('Id')
+ if len(bits) == 2 and bits[1] == '':
+ name = bits[0]
+ super(DjangoFK, self).__init__(name, 'FK')
+ self.set_relation(name)
+
+ def set_relation(self, name):
+ """some relations need to be mapped
+ to actual tables
+ """
+ self.relation = table_prefix
+ if name.endswith('User'):
+ self.relation += 'User'
+ elif name.endswith('Post'):
+ self.relation += 'Post'
+ elif name in ('AcceptedAnswer','Parent'):
+ self.relation = 'self' #self-referential Post model
+ else:
+ self.relation += name
+ def get_relation(self):
+ return self.relation
+
+def get_col_type(col):
+ type = col.get('type')
+ restriction = -1
+ if type == None:
+ type_e = col.find('.//simpleType/restriction')
+ type = type_e.get('base')
+ try:
+ restriction = int(type_e.getchildren()[0].get('value'))
+ except:
+ restriction = -1
+ if restriction > 400:
+ type = 'text'
+ restriction = -1
+ return type, restriction
+
+def make_field_from_xml_tree(xml_element):
+ """used by the model parser
+ here we need to be detailed about field types
+ because this defines the database schema
+ """
+ name = xml_element.get('name')
+ if name == 'LinkedVoteId':#not used
+ return None
+ if name == 'Id':
+ field = DjangoPK()
+ elif name.endswith('Id') and name not in ('OpenId','PasswordId'):
+ field = DjangoFK(name)
+ elif name.endswith('GUID'):
+ field = DjangoField(name, 'string', 64)
+ else:
+ type, restriction = get_col_type(xml_element)
+ field = DjangoField(name, type, restriction)
+ return field
+
+def parse_field_name(input):
+ """used by the data reader
+
+ The problem is that I've scattered
+ code for determination of field name over three classes:
+ DjangoField, DjangoPK and DjangoFK
+ so the function actually cretes fake field objects
+ many time over
+ """
+ if input == 'Id':
+ return DjangoPK().name
+ elif input in ('OpenId', 'PasswordId'):
+ return DjangoField(input, 'string', 7).name#happy fake field
+ elif input.endswith('Id'):
+ return DjangoFK(input).name#real FK field
+ else:
+ return DjangoField(input, 'string', 7).name#happy fake field
+
+def parse_value(input, field_object):
+ if isinstance(field_object, models.ForeignKey):
+ try:
+ id = int(input)
+ except:
+ raise Exception('non-numeric foreign key %s' % input)
+ related_model = field_object.rel.to
+ try:
+ return related_model.objects.get(id=id)
+ except related_model.DoesNotExist:
+ obj = related_model(id=id)
+ obj.save()#save fake empty object
+ return obj
+ elif isinstance(field_object, models.IntegerField):
+ try:
+ return int(input)
+ except:
+ raise Exception('expected integer, found %s' % input)
+ elif isinstance(field_object, models.CharField):
+ return input
+ elif isinstance(field_object, models.TextField):
+ return input
+ elif isinstance(field_object, models.BooleanField):
+ try:
+ return bool(input)
+ except:
+ raise Exception('boolean value expected %s found' % input)
+ elif isinstance(field_object, models.DateTimeField):
+ input = time_re.sub('', input)
+ try:
+ return datetime.strptime(input, date_time_format)
+ except:
+ raise Exception('datetime expected "%s" found' % input)
+
+print 'from django.db import models'
+for file in sys.argv:
+ if '.xsd' in file:
+ tname = os.path.basename(file).replace('.xsd','')
+ tree = et.parse(file)
+
+ model = DjangoModel(tname)
+
+ row = tree.find('.//sequence')
+ for col in row.getchildren():
+ field = make_field_from_xml_tree(col)
+ if field:
+ model.add_field(field)
+ print model
diff --git a/forum/middleware/view_log.py b/forum/middleware/view_log.py
new file mode 100644
index 00000000..bf0b9fbb
--- /dev/null
+++ b/forum/middleware/view_log.py
@@ -0,0 +1,74 @@
+import logging
+from django.conf import settings
+from forum.views.readers import questions as questions_view
+from forum.views.commands import vote
+from django.views.static import serve
+from forum.views.writers import delete_comment, question_comments, answer_comments
+from forum.views.readers import question, question_revisions, answer_revisions
+
+#todo: the list is getting bigger and bigger - maybe there is a better way to
+#trigger reset of sarch state?
+IGNORED_VIEWS = (serve, vote, delete_comment,
+ question_comments, answer_comments,
+ question_revisions, answer_revisions)
+
+class ViewLog(object):
+ """must be modified only in this middlware
+ however, can be read anywhere else
+ """
+ def __init__(self):
+ self.views = []
+ self.depth = 3 #todo maybe move this to const.py
+ def set_current(self, view_name):
+ thi
+
+ def get_previous(self, num):
+ if num > self.depth - 1:
+ raise Exception("view log depth exceeded")
+ elif num < 0:
+ raise Exception("num must be positive");
+ elif num <= len(self.views) - 1:
+ return self.views[num]
+ else:
+ return None
+
+ def set_current(self, view_name):
+ self.views.insert(0, view_name)
+ if len(self.views) > self.depth:
+ self.views.pop()
+
+ def __str__(self):
+ return str(self.views) + ' depth=%d' % self.depth
+
+class ViewLogMiddleware(object):
+ def process_view(self, request, view_func, view_args, view_kwargs):
+ if view_func == questions_view:
+ view_str = 'questions'
+ elif view_func in IGNORED_VIEWS:
+ return
+ else:
+ view_str = view_func.__name__
+ if view_str == 'wrap':
+ return
+
+ if settings.DEBUG == True:
+ #todo: dependency!
+ from debug_toolbar.views import debug_media as debug_media_view
+ if view_func == debug_media_view:
+ return
+ else:
+ view_str = view_func.__name__
+
+ if request.user.is_authenticated():
+ user_name = request.user.username
+ else:
+ user_name = request.META['REMOTE_ADDR']
+ logging.debug('user %s, view %s' % (request.user.username, view_str))
+
+ if 'view_log' in request.session:
+ view_log = request.session['view_log']
+ else:
+ view_log = ViewLog()
+
+ view_log.set_current(view_str)
+ request.session['view_log'] = view_log
diff --git a/forum/migrations/0001_initial.py b/forum/migrations/0001_initial.py
new file mode 100644
index 00000000..e6350446
--- /dev/null
+++ b/forum/migrations/0001_initial.py
@@ -0,0 +1,780 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model 'Vote'
+ db.create_table(u'vote', (
+ ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ('voted_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='votes', to=orm['auth.User'])),
+ ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
+ ('vote', self.gf('django.db.models.fields.SmallIntegerField')()),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('forum', ['Vote'])
+
+ # Adding unique constraint on 'Vote', fields ['content_type', 'object_id', 'user']
+ db.create_unique(u'vote', ['content_type_id', 'object_id', 'user_id'])
+
+ # Adding model 'FlaggedItem'
+ db.create_table(u'flagged_item', (
+ ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ('flagged_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='flaggeditems', to=orm['auth.User'])),
+ ))
+ db.send_create_signal('forum', ['FlaggedItem'])
+
+ # Adding unique constraint on 'FlaggedItem', fields ['content_type', 'object_id', 'user']
+ db.create_unique(u'flagged_item', ['content_type_id', 'object_id', 'user_id'])
+
+ # Adding model 'Comment'
+ db.create_table(u'comment', (
+ ('comment', self.gf('django.db.models.fields.CharField')(max_length=300)),
+ ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ('added_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='comments', to=orm['auth.User'])),
+ ))
+ db.send_create_signal('forum', ['Comment'])
+
+ # Adding model 'Tag'
+ db.create_table(u'tag', (
+ ('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
+ ('deleted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('created_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='created_tags', to=orm['auth.User'])),
+ ('deleted_by', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='deleted_tags', null=True, to=orm['auth.User'])),
+ ('used_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
+ ('deleted_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('forum', ['Tag'])
+
+ # Adding model 'MarkedTag'
+ db.create_table('forum_markedtag', (
+ ('reason', self.gf('django.db.models.fields.CharField')(max_length=16)),
+ ('tag', self.gf('django.db.models.fields.related.ForeignKey')(related_name='user_selections', to=orm['forum.Tag'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='tag_selections', to=orm['auth.User'])),
+ ))
+ db.send_create_signal('forum', ['MarkedTag'])
+
+ # Adding model 'Question'
+ db.create_table(u'question', (
+ ('wiki', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('vote_up_count', self.gf('django.db.models.fields.IntegerField')(default=0)),
+ ('answer_accepted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('offensive_flag_count', self.gf('django.db.models.fields.SmallIntegerField')(default=0)),
+ ('closed_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('deleted_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('last_activity_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='last_active_in_questions', to=orm['auth.User'])),
+ ('view_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
+ ('locked_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('score', self.gf('django.db.models.fields.IntegerField')(default=0)),
+ ('author', self.gf('django.db.models.fields.related.ForeignKey')(related_name='questions', to=orm['auth.User'])),
+ ('comment_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
+ ('html', self.gf('django.db.models.fields.TextField')()),
+ ('vote_down_count', self.gf('django.db.models.fields.IntegerField')(default=0)),
+ ('closed', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('last_edited_by', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='last_edited_questions', null=True, to=orm['auth.User'])),
+ ('favourite_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
+ ('deleted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('summary', self.gf('django.db.models.fields.CharField')(max_length=180)),
+ ('answer_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
+ ('last_activity_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('closed_by', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='closed_questions', null=True, to=orm['auth.User'])),
+ ('close_reason', self.gf('django.db.models.fields.SmallIntegerField')(null=True, blank=True)),
+ ('locked', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('tagnames', self.gf('django.db.models.fields.CharField')(max_length=125)),
+ ('locked_by', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='locked_questions', null=True, to=orm['auth.User'])),
+ ('added_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('deleted_by', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='deleted_questions', null=True, to=orm['auth.User'])),
+ ('wikified_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=300)),
+ ('last_edited_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ))
+ db.send_create_signal('forum', ['Question'])
+
+ # Adding M2M table for field followed_by on 'Question'
+ db.create_table(u'question_followed_by', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('question', models.ForeignKey(orm['forum.question'], null=False)),
+ ('user', models.ForeignKey(orm['auth.user'], null=False))
+ ))
+ db.create_unique(u'question_followed_by', ['question_id', 'user_id'])
+
+ # Adding M2M table for field tags on 'Question'
+ db.create_table(u'question_tags', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('question', models.ForeignKey(orm['forum.question'], null=False)),
+ ('tag', models.ForeignKey(orm['forum.tag'], null=False))
+ ))
+ db.create_unique(u'question_tags', ['question_id', 'tag_id'])
+
+ # Adding model 'QuestionView'
+ db.create_table('forum_questionview', (
+ ('when', self.gf('django.db.models.fields.DateTimeField')()),
+ ('who', self.gf('django.db.models.fields.related.ForeignKey')(related_name='question_views', to=orm['auth.User'])),
+ ('question', self.gf('django.db.models.fields.related.ForeignKey')(related_name='viewed', to=orm['forum.Question'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('forum', ['QuestionView'])
+
+ # Adding model 'FavoriteQuestion'
+ db.create_table(u'favorite_question', (
+ ('question', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Question'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('added_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='user_favorite_questions', to=orm['auth.User'])),
+ ))
+ db.send_create_signal('forum', ['FavoriteQuestion'])
+
+ # Adding model 'QuestionRevision'
+ db.create_table(u'question_revision', (
+ ('author', self.gf('django.db.models.fields.related.ForeignKey')(related_name='questionrevisions', to=orm['auth.User'])),
+ ('tagnames', self.gf('django.db.models.fields.CharField')(max_length=125)),
+ ('text', self.gf('django.db.models.fields.TextField')()),
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=300)),
+ ('question', self.gf('django.db.models.fields.related.ForeignKey')(related_name='revisions', to=orm['forum.Question'])),
+ ('revised_at', self.gf('django.db.models.fields.DateTimeField')()),
+ ('summary', self.gf('django.db.models.fields.CharField')(max_length=300, blank=True)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('revision', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ))
+ db.send_create_signal('forum', ['QuestionRevision'])
+
+ # Adding model 'AnonymousQuestion'
+ db.create_table('forum_anonymousquestion', (
+ ('wiki', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('ip_addr', self.gf('django.db.models.fields.IPAddressField')(max_length=15)),
+ ('author', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True)),
+ ('tagnames', self.gf('django.db.models.fields.CharField')(max_length=125)),
+ ('text', self.gf('django.db.models.fields.TextField')()),
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=300)),
+ ('added_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('summary', self.gf('django.db.models.fields.CharField')(max_length=180)),
+ ('session_key', self.gf('django.db.models.fields.CharField')(max_length=40)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('forum', ['AnonymousQuestion'])
+
+ # Adding model 'Answer'
+ db.create_table(u'answer', (
+ ('wiki', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('vote_up_count', self.gf('django.db.models.fields.IntegerField')(default=0)),
+ ('offensive_flag_count', self.gf('django.db.models.fields.SmallIntegerField')(default=0)),
+ ('deleted_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('locked_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('score', self.gf('django.db.models.fields.IntegerField')(default=0)),
+ ('author', self.gf('django.db.models.fields.related.ForeignKey')(related_name='answers', to=orm['auth.User'])),
+ ('question', self.gf('django.db.models.fields.related.ForeignKey')(related_name='answers', to=orm['forum.Question'])),
+ ('comment_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
+ ('html', self.gf('django.db.models.fields.TextField')()),
+ ('vote_down_count', self.gf('django.db.models.fields.IntegerField')(default=0)),
+ ('last_edited_by', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='last_edited_answers', null=True, to=orm['auth.User'])),
+ ('accepted_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('deleted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('accepted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('locked', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('locked_by', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='locked_answers', null=True, to=orm['auth.User'])),
+ ('added_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('deleted_by', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='deleted_answers', null=True, to=orm['auth.User'])),
+ ('wikified_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('last_edited_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ))
+ db.send_create_signal('forum', ['Answer'])
+
+ # Adding model 'AnswerRevision'
+ db.create_table(u'answer_revision', (
+ ('author', self.gf('django.db.models.fields.related.ForeignKey')(related_name='answerrevisions', to=orm['auth.User'])),
+ ('text', self.gf('django.db.models.fields.TextField')()),
+ ('revised_at', self.gf('django.db.models.fields.DateTimeField')()),
+ ('summary', self.gf('django.db.models.fields.CharField')(max_length=300, blank=True)),
+ ('answer', self.gf('django.db.models.fields.related.ForeignKey')(related_name='revisions', to=orm['forum.Answer'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('revision', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ))
+ db.send_create_signal('forum', ['AnswerRevision'])
+
+ # Adding model 'AnonymousAnswer'
+ db.create_table('forum_anonymousanswer', (
+ ('wiki', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('ip_addr', self.gf('django.db.models.fields.IPAddressField')(max_length=15)),
+ ('author', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True)),
+ ('text', self.gf('django.db.models.fields.TextField')()),
+ ('question', self.gf('django.db.models.fields.related.ForeignKey')(related_name='anonymous_answers', to=orm['forum.Question'])),
+ ('added_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('summary', self.gf('django.db.models.fields.CharField')(max_length=180)),
+ ('session_key', self.gf('django.db.models.fields.CharField')(max_length=40)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('forum', ['AnonymousAnswer'])
+
+ # Adding model 'Activity'
+ db.create_table(u'activity', (
+ ('is_auditted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
+ ('active_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('activity_type', self.gf('django.db.models.fields.SmallIntegerField')()),
+ ))
+ db.send_create_signal('forum', ['Activity'])
+
+ # Adding model 'EmailFeedSetting'
+ db.create_table('forum_emailfeedsetting', (
+ ('reported_at', self.gf('django.db.models.fields.DateTimeField')(null=True)),
+ ('added_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+ ('subscriber', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ('feed_type', self.gf('django.db.models.fields.CharField')(max_length=16)),
+ ('frequency', self.gf('django.db.models.fields.CharField')(default='n', max_length=8)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('forum', ['EmailFeedSetting'])
+
+ # Adding model 'ValidationHash'
+ db.create_table('forum_validationhash', (
+ ('hash_code', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
+ ('seed', self.gf('django.db.models.fields.CharField')(max_length=12)),
+ ('expiration', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2010, 4, 25, 13, 14, 41, 581000))),
+ ('type', self.gf('django.db.models.fields.CharField')(max_length=12)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ))
+ db.send_create_signal('forum', ['ValidationHash'])
+
+ # Adding unique constraint on 'ValidationHash', fields ['user', 'type']
+ db.create_unique('forum_validationhash', ['user_id', 'type'])
+
+ # Adding model 'AuthKeyUserAssociation'
+ db.create_table('forum_authkeyuserassociation', (
+ ('added_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='auth_keys', to=orm['auth.User'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('key', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
+ ('provider', self.gf('django.db.models.fields.CharField')(max_length=64)),
+ ))
+ db.send_create_signal('forum', ['AuthKeyUserAssociation'])
+
+ # Adding model 'Badge'
+ db.create_table(u'badge', (
+ ('multiple', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('description', self.gf('django.db.models.fields.CharField')(max_length=300)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('awarded_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
+ ('type', self.gf('django.db.models.fields.SmallIntegerField')()),
+ ('slug', self.gf('django.db.models.fields.SlugField')(db_index=True, max_length=50, blank=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=50)),
+ ))
+ db.send_create_signal('forum', ['Badge'])
+
+ # Adding unique constraint on 'Badge', fields ['name', 'type']
+ db.create_unique(u'badge', ['name', 'type'])
+
+ # Adding model 'Award'
+ db.create_table(u'award', (
+ ('awarded_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('notified', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='award_user', to=orm['auth.User'])),
+ ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
+ ('badge', self.gf('django.db.models.fields.related.ForeignKey')(related_name='award_badge', to=orm['forum.Badge'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('forum', ['Award'])
+
+ # Adding model 'Repute'
+ db.create_table(u'repute', (
+ ('positive', self.gf('django.db.models.fields.SmallIntegerField')(default=0)),
+ ('question', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Question'])),
+ ('negative', self.gf('django.db.models.fields.SmallIntegerField')(default=0)),
+ ('reputation_type', self.gf('django.db.models.fields.SmallIntegerField')()),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ('reputed_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('reputation', self.gf('django.db.models.fields.IntegerField')(default=1)),
+ ))
+ db.send_create_signal('forum', ['Repute'])
+
+ # Adding model 'Book'
+ db.create_table(u'book', (
+ ('publication', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('short_name', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('author', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('cover_img', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('price', self.gf('django.db.models.fields.DecimalField')(max_digits=6, decimal_places=2)),
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('added_at', self.gf('django.db.models.fields.DateTimeField')()),
+ ('pages', self.gf('django.db.models.fields.SmallIntegerField')()),
+ ('tagnames', self.gf('django.db.models.fields.CharField')(max_length=125)),
+ ('published_at', self.gf('django.db.models.fields.DateTimeField')()),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('last_edited_at', self.gf('django.db.models.fields.DateTimeField')()),
+ ))
+ db.send_create_signal('forum', ['Book'])
+
+ # Adding M2M table for field questions on 'Book'
+ db.create_table('book_question', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('book', models.ForeignKey(orm['forum.book'], null=False)),
+ ('question', models.ForeignKey(orm['forum.question'], null=False))
+ ))
+ db.create_unique('book_question', ['book_id', 'question_id'])
+
+ # Adding model 'BookAuthorInfo'
+ db.create_table(u'book_author_info', (
+ ('added_at', self.gf('django.db.models.fields.DateTimeField')()),
+ ('book', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Book'])),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ('blog_url', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('last_edited_at', self.gf('django.db.models.fields.DateTimeField')()),
+ ))
+ db.send_create_signal('forum', ['BookAuthorInfo'])
+
+ # Adding model 'BookAuthorRss'
+ db.create_table(u'book_author_rss', (
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('url', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('added_at', self.gf('django.db.models.fields.DateTimeField')()),
+ ('book', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Book'])),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ('rss_created_at', self.gf('django.db.models.fields.DateTimeField')()),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('forum', ['BookAuthorRss'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'Vote'
+ db.delete_table(u'vote')
+
+ # Removing unique constraint on 'Vote', fields ['content_type', 'object_id', 'user']
+ db.delete_unique(u'vote', ['content_type_id', 'object_id', 'user_id'])
+
+ # Deleting model 'FlaggedItem'
+ db.delete_table(u'flagged_item')
+
+ # Removing unique constraint on 'FlaggedItem', fields ['content_type', 'object_id', 'user']
+ db.delete_unique(u'flagged_item', ['content_type_id', 'object_id', 'user_id'])
+
+ # Deleting model 'Comment'
+ db.delete_table(u'comment')
+
+ # Deleting model 'Tag'
+ db.delete_table(u'tag')
+
+ # Deleting model 'MarkedTag'
+ db.delete_table('forum_markedtag')
+
+ # Deleting model 'Question'
+ db.delete_table(u'question')
+
+ # Removing M2M table for field followed_by on 'Question'
+ db.delete_table('question_followed_by')
+
+ # Removing M2M table for field tags on 'Question'
+ db.delete_table('question_tags')
+
+ # Deleting model 'QuestionView'
+ db.delete_table('forum_questionview')
+
+ # Deleting model 'FavoriteQuestion'
+ db.delete_table(u'favorite_question')
+
+ # Deleting model 'QuestionRevision'
+ db.delete_table(u'question_revision')
+
+ # Deleting model 'AnonymousQuestion'
+ db.delete_table('forum_anonymousquestion')
+
+ # Deleting model 'Answer'
+ db.delete_table(u'answer')
+
+ # Deleting model 'AnswerRevision'
+ db.delete_table(u'answer_revision')
+
+ # Deleting model 'AnonymousAnswer'
+ db.delete_table('forum_anonymousanswer')
+
+ # Deleting model 'Activity'
+ db.delete_table(u'activity')
+
+ # Deleting model 'EmailFeedSetting'
+ db.delete_table('forum_emailfeedsetting')
+
+ # Deleting model 'ValidationHash'
+ db.delete_table('forum_validationhash')
+
+ # Removing unique constraint on 'ValidationHash', fields ['user', 'type']
+ db.delete_unique('forum_validationhash', ['user_id', 'type'])
+
+ # Deleting model 'AuthKeyUserAssociation'
+ db.delete_table('forum_authkeyuserassociation')
+
+ # Deleting model 'Badge'
+ db.delete_table(u'badge')
+
+ # Removing unique constraint on 'Badge', fields ['name', 'type']
+ db.delete_unique(u'badge', ['name', 'type'])
+
+ # Deleting model 'Award'
+ db.delete_table(u'award')
+
+ # Deleting model 'Repute'
+ db.delete_table(u'repute')
+
+ # Deleting model 'Book'
+ db.delete_table(u'book')
+
+ # Removing M2M table for field questions on 'Book'
+ db.delete_table('book_question')
+
+ # Deleting model 'BookAuthorInfo'
+ db.delete_table(u'book_author_info')
+
+ # Deleting model 'BookAuthorRss'
+ db.delete_table(u'book_author_rss')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'tag_filter_setting': ('django.db.models.fields.CharField', [], {'default': "'ignored'", 'max_length': '16'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['forum.Question']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.answer': {
+ 'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},
+ 'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_answers'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'html': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_answers'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_answers'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['forum.Question']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'forum.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Answer']"}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answerrevisions'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['auth.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['auth.User']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.book': {
+ 'Meta': {'object_name': 'Book', 'db_table': "u'book'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'cover_img': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'pages': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'price': ('django.db.models.fields.DecimalField', [], {'max_digits': '6', 'decimal_places': '2'}),
+ 'publication': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'published_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'questions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'book'", 'db_table': "'book_question'", 'to': "orm['forum.Question']"}),
+ 'short_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.bookauthorinfo': {
+ 'Meta': {'object_name': 'BookAuthorInfo', 'db_table': "u'book_author_info'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'blog_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.bookauthorrss': {
+ 'Meta': {'object_name': 'BookAuthorRss', 'db_table': "u'book_author_rss'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'rss_created_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.comment': {
+ 'Meta': {'object_name': 'Comment', 'db_table': "u'comment'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['auth.User']"})
+ },
+ 'forum.emailfeedsetting': {
+ 'Meta': {'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'forum.flaggeditem': {
+ 'Meta': {'unique_together': "(('content_type', 'object_id', 'user'),)", 'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['auth.User']"})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'forum.question': {
+ 'Meta': {'object_name': 'Question', 'db_table': "u'question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questions'", 'to': "orm['auth.User']"}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_questions'", 'to': "orm['auth.User']"}),
+ 'html': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'to': "orm['auth.User']"}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'questions'", 'to': "orm['forum.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'forum.questionrevision': {
+ 'Meta': {'object_name': 'QuestionRevision', 'db_table': "u'question_revision'"},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questionrevisions'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Question']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['forum.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'forum.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 25, 13, 14, 41, 714642)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.vote': {
+ 'Meta': {'unique_together': "(('content_type', 'object_id', 'user'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/0002_auto__add_field_answer_text__chg_field_answer_html__add_field_question.py b/forum/migrations/0002_auto__add_field_answer_text__chg_field_answer_html__add_field_question.py
new file mode 100644
index 00000000..d703c161
--- /dev/null
+++ b/forum/migrations/0002_auto__add_field_answer_text__chg_field_answer_html__add_field_question.py
@@ -0,0 +1,368 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding field 'Answer.text'
+ db.add_column(u'answer', 'text', self.gf('django.db.models.fields.TextField')(null=True), keep_default=False)
+
+ # Changing field 'Answer.html'
+ db.alter_column(u'answer', 'html', self.gf('django.db.models.fields.TextField')(null=True))
+
+ # Adding field 'Question.text'
+ db.add_column(u'question', 'text', self.gf('django.db.models.fields.TextField')(null=True), keep_default=False)
+
+ # Changing field 'Question.html'
+ db.alter_column(u'question', 'html', self.gf('django.db.models.fields.TextField')(null=True))
+
+
+ def backwards(self, orm):
+
+ # Deleting field 'Answer.text'
+ db.delete_column(u'answer', 'text')
+
+ # Changing field 'Answer.html'
+ db.alter_column(u'answer', 'html', self.gf('django.db.models.fields.TextField')())
+
+ # Deleting field 'Question.text'
+ db.delete_column(u'question', 'text')
+
+ # Changing field 'Question.html'
+ db.alter_column(u'question', 'html', self.gf('django.db.models.fields.TextField')())
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'tag_filter_setting': ('django.db.models.fields.CharField', [], {'default': "'ignored'", 'max_length': '16'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['forum.Question']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.answer': {
+ 'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},
+ 'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_answers'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_answers'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_answers'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['forum.Question']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'forum.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Answer']"}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answerrevisions'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['auth.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['auth.User']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.book': {
+ 'Meta': {'object_name': 'Book', 'db_table': "u'book'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'cover_img': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'pages': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'price': ('django.db.models.fields.DecimalField', [], {'max_digits': '6', 'decimal_places': '2'}),
+ 'publication': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'published_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'questions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'book'", 'db_table': "'book_question'", 'to': "orm['forum.Question']"}),
+ 'short_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.bookauthorinfo': {
+ 'Meta': {'object_name': 'BookAuthorInfo', 'db_table': "u'book_author_info'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'blog_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.bookauthorrss': {
+ 'Meta': {'object_name': 'BookAuthorRss', 'db_table': "u'book_author_rss'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'rss_created_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.comment': {
+ 'Meta': {'object_name': 'Comment', 'db_table': "u'comment'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['auth.User']"})
+ },
+ 'forum.emailfeedsetting': {
+ 'Meta': {'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'forum.flaggeditem': {
+ 'Meta': {'unique_together': "(('content_type', 'object_id', 'user'),)", 'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['auth.User']"})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'forum.question': {
+ 'Meta': {'object_name': 'Question', 'db_table': "u'question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questions'", 'to': "orm['auth.User']"}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_questions'", 'to': "orm['auth.User']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'to': "orm['auth.User']"}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'questions'", 'to': "orm['forum.Tag']"}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'forum.questionrevision': {
+ 'Meta': {'object_name': 'QuestionRevision', 'db_table': "u'question_revision'"},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questionrevisions'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Question']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['forum.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'forum.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 25, 16, 21, 32, 856067)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.vote': {
+ 'Meta': {'unique_together': "(('content_type', 'object_id', 'user'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/0003_copy_denorm_text_record_to_posts_for_fulltext_search.py b/forum/migrations/0003_copy_denorm_text_record_to_posts_for_fulltext_search.py
new file mode 100644
index 00000000..3e79b9d2
--- /dev/null
+++ b/forum/migrations/0003_copy_denorm_text_record_to_posts_for_fulltext_search.py
@@ -0,0 +1,354 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from forum.models import Question, Answer
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ "Write your forwards methods here."
+ for q in orm.Question.objects.all():
+ r = q.revisions.all()[0] #cannot use get_latest_revision()
+ q.text = r.text
+ q.save()
+ for a in orm.Answer.objects.all():
+ r = a.revisions.all()[0]
+ a.text = r.text
+ a.save()
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+ pass#there's no need to clean data here, just delete columns
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'tag_filter_setting': ('django.db.models.fields.CharField', [], {'default': "'ignored'", 'max_length': '16'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['forum.Question']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.answer': {
+ 'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},
+ 'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_answers'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_answers'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_answers'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['forum.Question']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'forum.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Answer']"}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answerrevisions'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['auth.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['auth.User']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.book': {
+ 'Meta': {'object_name': 'Book', 'db_table': "u'book'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'cover_img': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'pages': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'price': ('django.db.models.fields.DecimalField', [], {'max_digits': '6', 'decimal_places': '2'}),
+ 'publication': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'published_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'questions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'book'", 'db_table': "'book_question'", 'to': "orm['forum.Question']"}),
+ 'short_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.bookauthorinfo': {
+ 'Meta': {'object_name': 'BookAuthorInfo', 'db_table': "u'book_author_info'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'blog_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.bookauthorrss': {
+ 'Meta': {'object_name': 'BookAuthorRss', 'db_table': "u'book_author_rss'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'rss_created_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.comment': {
+ 'Meta': {'object_name': 'Comment', 'db_table': "u'comment'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['auth.User']"})
+ },
+ 'forum.emailfeedsetting': {
+ 'Meta': {'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'forum.flaggeditem': {
+ 'Meta': {'unique_together': "(('content_type', 'object_id', 'user'),)", 'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['auth.User']"})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'forum.question': {
+ 'Meta': {'object_name': 'Question', 'db_table': "u'question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questions'", 'to': "orm['auth.User']"}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_questions'", 'to': "orm['auth.User']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'to': "orm['auth.User']"}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'questions'", 'to': "orm['forum.Tag']"}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'forum.questionrevision': {
+ 'Meta': {'object_name': 'QuestionRevision', 'db_table': "u'question_revision'"},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questionrevisions'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Question']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['forum.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'forum.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 25, 16, 24, 24, 604164)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.vote': {
+ 'Meta': {'unique_together': "(('content_type', 'object_id', 'user'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/0004_install_full_text_indexes_for_mysql.py b/forum/migrations/0004_install_full_text_indexes_for_mysql.py
new file mode 100644
index 00000000..0c52c442
--- /dev/null
+++ b/forum/migrations/0004_install_full_text_indexes_for_mysql.py
@@ -0,0 +1,389 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from forum.models import Question, Answer
+
+Q_INDEX_NAME = 'askbot_question_full_text_index'
+A_INDEX_NAME = 'askbot_answer_full_text_index'
+Q_TABLE_NAME = Question._meta.db_table
+A_TABLE_NAME = Answer._meta.db_table
+
+def get_create_full_text_index_sql(index_name, table_name, column_list):
+ column_sql = '(%s)' % ','.join(column_list)
+ sql = 'CREATE FULLTEXT INDEX %s on %s %s' % (index_name, table_name, column_sql)
+ return sql
+
+def get_drop_index_sql(index_name, table_name):
+ return 'ALTER TABLE %s DROP INDEX %s' % (table_name, index_name)
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ """install fulltext indices for mysql
+ will work only for MyISAM engine
+ and will probably fail otherwise
+ """
+ if db.backend_name == 'mysql':
+ #todo: extract column names by introspection
+ question_index_sql = get_create_full_text_index_sql(
+ Q_INDEX_NAME,
+ Q_TABLE_NAME,
+ ('title','text','tagnames',)
+ )
+ db.execute(question_index_sql)
+
+ answer_index_sql = get_create_full_text_index_sql(
+ A_INDEX_NAME,
+ A_TABLE_NAME,
+ ('text',)
+ )
+ db.execute(answer_index_sql)
+
+ def backwards(self, orm):
+ "code for removal of full text indices in mysql"
+ if db.backend_name == 'mysql':
+ db.execute(
+ get_drop_index_sql(
+ Q_INDEX_NAME,
+ Q_TABLE_NAME,
+ )
+ )
+ db.execute(
+ get_drop_index_sql(
+ A_INDEX_NAME,
+ A_TABLE_NAME,
+ )
+ )
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'tag_filter_setting': ('django.db.models.fields.CharField', [], {'default': "'ignored'", 'max_length': '16'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['forum.Question']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.answer': {
+ 'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},
+ 'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_answers'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_answers'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_answers'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['forum.Question']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'forum.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Answer']"}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answerrevisions'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['auth.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['auth.User']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.book': {
+ 'Meta': {'object_name': 'Book', 'db_table': "u'book'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'cover_img': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'pages': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'price': ('django.db.models.fields.DecimalField', [], {'max_digits': '6', 'decimal_places': '2'}),
+ 'publication': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'published_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'questions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'book'", 'db_table': "'book_question'", 'to': "orm['forum.Question']"}),
+ 'short_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.bookauthorinfo': {
+ 'Meta': {'object_name': 'BookAuthorInfo', 'db_table': "u'book_author_info'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'blog_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.bookauthorrss': {
+ 'Meta': {'object_name': 'BookAuthorRss', 'db_table': "u'book_author_rss'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'rss_created_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.comment': {
+ 'Meta': {'object_name': 'Comment', 'db_table': "u'comment'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['auth.User']"})
+ },
+ 'forum.emailfeedsetting': {
+ 'Meta': {'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'forum.flaggeditem': {
+ 'Meta': {'unique_together': "(('content_type', 'object_id', 'user'),)", 'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['auth.User']"})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'forum.question': {
+ 'Meta': {'object_name': 'Question', 'db_table': "u'question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questions'", 'to': "orm['auth.User']"}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_questions'", 'to': "orm['auth.User']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'to': "orm['auth.User']"}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_questions'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'questions'", 'to': "orm['forum.Tag']"}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'forum.questionrevision': {
+ 'Meta': {'object_name': 'QuestionRevision', 'db_table': "u'question_revision'"},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questionrevisions'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Question']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['forum.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'forum.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 25, 19, 13, 13, 325125)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'forum.vote': {
+ 'Meta': {'unique_together': "(('content_type', 'object_id', 'user'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/__init__.py b/forum/migrations/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/forum/migrations/__init__.py
diff --git a/forum/models/__init__.py b/forum/models/__init__.py
index 2349c9e3..d0d2d4a7 100755
--- a/forum/models/__init__.py
+++ b/forum/models/__init__.py
@@ -5,6 +5,8 @@ from meta import Vote, Comment, FlaggedItem
from user import Activity, ValidationHash, EmailFeedSetting, AuthKeyUserAssociation
from repute import Badge, Award, Repute
from django.core.urlresolvers import reverse
+from forum.search.indexer import create_fulltext_indexes
+from django.db.models.signals import post_syncdb
import re
from base import *
@@ -440,6 +442,7 @@ tags_updated.connect(record_update_tags, sender=Question)
post_save.connect(record_favorite_question, sender=FavoriteQuestion)
user_updated.connect(record_user_full_updated, sender=User)
user_logged_in.connect(post_stored_anonymous_content)
+#post_syncdb.connect(create_fulltext_indexes)
Question = Question
QuestionRevision = QuestionRevision
diff --git a/forum/models/answer.py b/forum/models/answer.py
index 25a885ee..3de6cfc4 100755
--- a/forum/models/answer.py
+++ b/forum/models/answer.py
@@ -16,6 +16,7 @@ class AnswerManager(models.Manager):
author = author,
added_at = added_at,
wiki = wiki,
+ text = text,
html = sanitize_html(markdowner.convert(text)),
)
if answer.wiki:
@@ -94,6 +95,7 @@ class Answer(Content, DeletableContent):
self.last_edited_at = edited_at
self.last_edited_by = edited_by
self.html = sanitize_html(markdowner.convert(text))
+ self.text = text
#todo: bug wiki has no effect here
self.save()
@@ -136,9 +138,6 @@ class Answer(Content, DeletableContent):
else:
return None
- def get_latest_revision(self):
- return self.revisions.all()[0]
-
def get_question_title(self):
return self.question.title
diff --git a/forum/models/base.py b/forum/models/base.py
index 52fc8522..fcec47b4 100755
--- a/forum/models/base.py
+++ b/forum/models/base.py
@@ -89,30 +89,31 @@ class Content(models.Model):
"""
Base class for Question and Answer
"""
- author = models.ForeignKey(User, related_name='%(class)ss')
- added_at = models.DateTimeField(default=datetime.datetime.now)
+ author = models.ForeignKey(User, related_name='%(class)ss')
+ added_at = models.DateTimeField(default=datetime.datetime.now)
- wiki = models.BooleanField(default=False)
- wikified_at = models.DateTimeField(null=True, blank=True)
+ wiki = models.BooleanField(default=False)
+ wikified_at = models.DateTimeField(null=True, blank=True)
- locked = models.BooleanField(default=False)
- locked_by = models.ForeignKey(User, null=True, blank=True, related_name='locked_%(class)ss')
- locked_at = models.DateTimeField(null=True, blank=True)
+ locked = models.BooleanField(default=False)
+ locked_by = models.ForeignKey(User, null=True, blank=True, related_name='locked_%(class)ss')
+ locked_at = models.DateTimeField(null=True, blank=True)
- score = models.IntegerField(default=0)
- vote_up_count = models.IntegerField(default=0)
- vote_down_count = models.IntegerField(default=0)
+ score = models.IntegerField(default=0)
+ vote_up_count = models.IntegerField(default=0)
+ vote_down_count = models.IntegerField(default=0)
- comment_count = models.PositiveIntegerField(default=0)
+ comment_count = models.PositiveIntegerField(default=0)
offensive_flag_count = models.SmallIntegerField(default=0)
- last_edited_at = models.DateTimeField(null=True, blank=True)
- last_edited_by = models.ForeignKey(User, null=True, blank=True, related_name='last_edited_%(class)ss')
+ last_edited_at = models.DateTimeField(null=True, blank=True)
+ last_edited_by = models.ForeignKey(User, null=True, blank=True, related_name='last_edited_%(class)ss')
- html = models.TextField()
- comments = generic.GenericRelation(Comment)
- votes = generic.GenericRelation(Vote)
- flagged_items = generic.GenericRelation(FlaggedItem)
+ html = models.TextField(null=True)
+ text = models.TextField(null=True) #denormalized copy of latest revision
+ comments = generic.GenericRelation(Comment)
+ votes = generic.GenericRelation(Vote)
+ flagged_items = generic.GenericRelation(FlaggedItem)
class Meta:
abstract = True
@@ -141,7 +142,10 @@ class Content(models.Model):
self.comment_count = self.comment_count + 1
self.save()
- def post_get_last_update_info(self):
+ def get_latest_revision(self):
+ return self.revisions.all()[0]
+
+ def post_get_last_update_info(self):#todo: rename this subroutine
when = self.added_at
who = self.author
if self.last_edited_at and self.last_edited_at > when:
diff --git a/forum/models/question.py b/forum/models/question.py
index 9860eb24..683f7a3c 100755
--- a/forum/models/question.py
+++ b/forum/models/question.py
@@ -1,28 +1,49 @@
-from base import *
+from base import * #todo maybe remove *
from tag import Tag
+#todo: make uniform import for consts
from forum.const import CONST
+from forum import const
from forum.utils.html import sanitize_html
from markdown2 import Markdown
from django.utils.html import strip_tags
import datetime
+from django.conf import settings
+from django.utils.datastructures import SortedDict
+from forum.models.tag import MarkedTag
+from django.db.models import Q
+
markdowner = Markdown(html4tags=True)
from forum.utils.lists import LazyList
+#todo: too bad keys are duplicated see const sort methods
+QUESTION_ORDER_BY_MAP = {
+ 'latest': '-added_at',
+ 'oldest': 'added_at',
+ 'active': '-last_activity_at',
+ 'inactive': 'last_activity_at',
+ 'hottest': '-answer_count',
+ 'coldest': 'answer_count',
+ 'mostvoted': '-score',
+ 'leastvoted': 'score',
+ 'relevant': None #this is a special case
+}
+
class QuestionManager(models.Manager):
def create_new(self, title=None,author=None,added_at=None, wiki=False,tagnames=None, text=None):
html = sanitize_html(markdowner.convert(text))
summary = strip_tags(html)[:120]
question = Question(
- title = title,
- author = author,
- added_at = added_at,
+ title = title,
+ author = author,
+ added_at = added_at,
last_activity_at = added_at,
last_activity_by = author,
- wiki = wiki,
- tagnames = tagnames,
- html = html,
- summary = summary
+ wiki = wiki,
+ tagnames = tagnames,
+ html = html,
+ text = text,
+ summary = summary
)
if question.wiki:
question.last_edited_by = question.author
@@ -39,6 +60,115 @@ class QuestionManager(models.Manager):
)
return question
+ def run_advanced_search(
+ self,
+ request_user = None,
+ scope_selector = const.DEFAULT_POST_SCOPE,#unanswered/all/favorite (for logged in)
+ search_query = None,
+ tag_selector = None,
+ author_selector = None,#???question or answer author or just contributor
+ sort_method = const.DEFAULT_POST_SORT_METHOD
+ ):
+ """all parameters are guaranteed to be clean
+ however may not relate to database - in that case
+ a relvant filter will be silently dropped
+ """
+
+ qs = self.filter(deleted=False)#todo - add a possibility to see deleted questions
+
+ #return metadata
+ meta_data = {}
+ if tag_selector:
+ for tag in tag_selector:
+ qs = qs.filter(tags__name = tag)
+
+ if search_query:
+ try:
+ qs = qs.filter( Q(title__search = search_query) \
+ | Q(text__search = search_query) \
+ | Q(tagnames__search = search_query) \
+ | Q(answers__text__search = search_query)
+ )
+ except:
+ #fallback to dumb title match search
+ qs = qs.extra(
+ where=['title like %s'],
+ params=['%' + search_query + '%']
+ )
+
+ if scope_selector:
+ if scope_selector == 'unanswered':
+ if const.UNANSWERED_MEANING == 'NO_ANSWERS':
+ qs = qs.filter(answer_count=0)#todo: expand for different meanings of this
+ elif const.UNANSWERED_MEANING == 'NO_ACCEPTED_ANSWERS':
+ qs = qs.filter(answer_accepted=False)
+ elif const.UNANSWERED_MEANING == 'NO_UPVOTED_ANSWERS':
+ raise NotImplementedError()
+ else:
+ raise Exception('UNANSWERED_MEANING setting is wrong')
+ elif scope_selector == 'favorite':
+ qs = qs.filter(favorited_by = request_user)
+
+ #user contributed questions & answers
+ if author_selector:
+ try:
+ u = User.objects.get(id=int(author_selector))
+ qs = qs.filter(Q(author=u, deleted=False) | Q(answers__author=u, answers__deleted=False))
+ meta_data['author_name'] = u.username
+ except User.DoesNotExist:
+ meta_data['author_name'] = None
+
+ #get users tag filters
+ if request_user and request_user.is_authenticated():
+ uid_str = str(request_user.id)
+ #mark questions tagged with interesting tags
+ qs = qs.extra(
+ select = SortedDict([
+ (
+ 'interesting_score',
+ 'SELECT COUNT(1) FROM forum_markedtag, question_tags '
+ + 'WHERE forum_markedtag.user_id = %s '
+ + 'AND forum_markedtag.tag_id = question_tags.tag_id '
+ + 'AND forum_markedtag.reason = \'good\' '
+ + 'AND question_tags.question_id = question.id'
+ ),
+ ]),
+ select_params = (uid_str,),
+ )
+ if request_user.hide_ignored_questions:
+ #exclude ignored tags if the user wants to
+ ignored_tags = Tag.objects.filter(user_selections__reason='bad',
+ user_selections__user = request_user)
+ qs = qs.exclude(tags__in=ignored_tags)
+ else:
+ #annotate questions tagged with ignored tags
+ qs = qs.extra(
+ select = SortedDict([
+ (
+ 'ignored_score',
+ 'SELECT COUNT(1) FROM forum_markedtag, question_tags '
+ + 'WHERE forum_markedtag.user_id = %s '
+ + 'AND forum_markedtag.tag_id = question_tags.tag_id '
+ + 'AND forum_markedtag.reason = \'bad\' '
+ + 'AND question_tags.question_id = question.id'
+ )
+ ]),
+ select_params = (uid_str, )
+ )
+ # get the list of interesting and ignored tags (interesting_tag_names, ignored_tag_names) = (None, None)
+ pt = MarkedTag.objects.filter(user=request_user)
+ meta_data['interesting_tag_names'] = pt.filter(reason='good').values_list('tag__name', flat=True)
+ meta_data['ignored_tag_names'] = pt.filter(reason='bad').values_list('tag__name', flat=True)
+
+ qs = qs.select_related(depth=1)
+ #todo: fix orderby here
+ orderby = QUESTION_ORDER_BY_MAP[sort_method]
+ if orderby:
+ #relevance will be ignored here
+ qs = qs.order_by(orderby)
+ qs = qs.distinct()
+ return qs, meta_data
+
def update_tags(self, question, tagnames, user):
"""
Updates Tag associations for a question to match the given
@@ -216,6 +346,7 @@ class Question(Content, DeletableContent):
self.tagnames = tags
self.summary = question_summary
self.html = html
+ self.text = text
#wiki is an eternal trap whence there is no exit
if self.wiki == False and wiki == True:
@@ -310,9 +441,6 @@ class Question(Content, DeletableContent):
def get_revision_url(self):
return reverse('question_revisions', args=[self.id])
- def get_latest_revision(self):
- return self.revisions.all()[0]
-
def get_last_update_info(self):
when, who = self.post_get_last_update_info()
diff --git a/forum/models/tag.py b/forum/models/tag.py
index 8d26d6f4..e13baf9b 100755
--- a/forum/models/tag.py
+++ b/forum/models/tag.py
@@ -49,6 +49,8 @@ class TagManager(models.Manager):
def get_tags_by_questions(self, questions):
question_ids = []
+ if len(questions) == 0:
+ return []
for question in questions:
question_ids.append(question.id)
@@ -82,4 +84,4 @@ class MarkedTag(models.Model):
reason = models.CharField(max_length=16, choices=TAG_MARK_REASONS)
class Meta:
- app_label = 'forum' \ No newline at end of file
+ app_label = 'forum'
diff --git a/forum/search/README b/forum/search/README
new file mode 100644
index 00000000..c15dc221
--- /dev/null
+++ b/forum/search/README
@@ -0,0 +1,5 @@
+module dealing with search functions
+at this time only question and answer search
+
+that among other things contains
+available full text search implementations
diff --git a/forum/search/__init__.py b/forum/search/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/forum/search/__init__.py
diff --git a/forum/search/indexer.py b/forum/search/indexer.py
new file mode 100644
index 00000000..c7c45c59
--- /dev/null
+++ b/forum/search/indexer.py
@@ -0,0 +1,9 @@
+from django.conf import settings
+from django.db import connection
+
+def create_fulltext_indexes():
+ if settings.DATABASE_ENGINE == 'mysql':
+ cursor = connection.cursor()
+ cursor.execute('ALTER TABLE question ADD FULLTEXT (title, text, tagnames)')
+ cursor.execute('ALTER TABLE answer ADD FULLTEXT (title, text, tagnames)')
+
diff --git a/forum/search/sphinx/README b/forum/search/sphinx/README
new file mode 100644
index 00000000..8c008a23
--- /dev/null
+++ b/forum/search/sphinx/README
@@ -0,0 +1,4 @@
+This directory contains sample configuration for sphinx search
+
+Sphinx is a full text search engine for MySQL (only) with full
+word stemming in English and Russion (other languages are not supported)
diff --git a/forum/search/sphinx/sphinx.conf b/forum/search/sphinx/sphinx.conf
new file mode 100644
index 00000000..bf4bdc8b
--- /dev/null
+++ b/forum/search/sphinx/sphinx.conf
@@ -0,0 +1,127 @@
+#if you have many posts, it's best to configure another index for new posts and
+#periodically merge the diff index to the main
+#this is not important until you get to hundreds of thousands posts
+
+source src_cnprog
+{
+ # data source
+ type = mysql
+ sql_host = localhost
+ sql_user = cnprog #replace with your db username
+ sql_pass = secret #replace with your db password
+ sql_db = cnprog #replace with your db name
+ # these two are optional
+ #sql_port = 3306
+ #sql_sock = /var/lib/mysql/mysql.sock
+
+ # pre-query, executed before the main fetch query
+ sql_query_pre = SET NAMES utf8
+
+ # main document fetch query - change the table names if you are using a prefix
+ # this query creates a flat document from each question that includes only latest
+ # revisions of the question and all of it's answers
+ sql_query = SELECT q.id as id, q.title AS title, q.tagnames as tags, qr.text AS text, answers_combined.text AS answers \
+ FROM question AS q \
+ INNER JOIN \
+ ( \
+ SELECT MAX(id) as id, question_id \
+ FROM question_revision \
+ GROUP BY question_id \
+ ) \
+ AS mqr \
+ ON q.id=mqr.question_id \
+ INNER JOIN question_revision AS qr ON qr.id=mqr.id \
+ LEFT JOIN \
+ ( \
+ SELECT GROUP_CONCAT(answer_current.text SEPARATOR '. ') AS text, \
+ question_id \
+ FROM \
+ ( \
+ SELECT a.question_id as question_id, ar.text as text \
+ FROM answer AS a \
+ INNER JOIN \
+ ( \
+ SELECT MAX(id) as id, answer_id \
+ FROM answer_revision \
+ GROUP BY answer_id \
+ ) \
+ AS mar \
+ ON mar.answer_id = a.id \
+ INNER JOIN answer_revision AS ar ON ar.id=mar.id \
+ WHERE a.deleted=0 \
+ ) \
+ AS answer_current \
+ GROUP BY question_id \
+ ) \
+ AS answers_combined ON q.id=answers_combined.question_id \
+ WHERE q.deleted=0;
+
+ # optional - used by command-line search utility to display document information
+ sql_query_info = SELECT title, id FROM question WHERE id=$id
+}
+
+index cnprog {
+ # which document source to index
+ source = src_cnprog
+
+ # this is path and index file name without extension
+ # you may need to change this path or create this folder
+ path = /var/data/sphinx/cnprog_main
+
+ # docinfo (ie. per-document attribute values) storage strategy
+ docinfo = extern
+
+ # morphology
+ morphology = stem_en
+
+ # stopwords file
+ #stopwords = /var/data/sphinx/stopwords.txt
+
+ # minimum word length
+ min_word_len = 1
+
+ # uncomment next 2 lines to allow wildcard (*) searches
+ #min_infix_len = 1
+ #enable_star = 1
+
+ # charset encoding type
+ charset_type = utf-8
+}
+
+# indexer settings
+indexer
+{
+ # memory limit (default is 32M)
+ mem_limit = 64M
+}
+
+# searchd settings
+searchd
+{
+ # IP address on which search daemon will bind and accept
+ # optional, default is to listen on all addresses,
+ # ie. address = 0.0.0.0
+ address = 127.0.0.1
+
+ # port on which search daemon will listen
+ port = 3312
+
+ # searchd run info is logged here - create or change the folder
+ log = /var/log/sphinx/searchd.log
+
+ # all the search queries are logged here
+ query_log = /var/log/sphinx/query.log
+
+ # client read timeout, seconds
+ read_timeout = 5
+
+ # maximum amount of children to fork
+ max_children = 30
+
+ # a file which will contain searchd process ID
+ pid_file = /var/log/sphinx/searchd.pid
+
+ # maximum amount of matches this daemon would ever retrieve
+ # from each index and serve to client
+ max_matches = 1000
+}
diff --git a/forum/search/state_manager.py b/forum/search/state_manager.py
new file mode 100644
index 00000000..cb1908c6
--- /dev/null
+++ b/forum/search/state_manager.py
@@ -0,0 +1,152 @@
+#search state manager object
+#that lives in the session and takes care of the state
+#persistece during the search session
+from forum import const
+import logging
+
+ACTIVE_COMMANDS = (
+ 'sort', 'search', 'query',
+ 'reset_query', 'reset_author', 'reset_tags',
+ 'tags', 'scope', 'page_size', 'start_over',
+ 'page'
+)
+
+def some_in(what, where):
+ for element in what:
+ if element in where:
+ return True
+ return False
+
+class SearchState(object):
+ def __init__(self):
+ self.scope= const.DEFAULT_POST_SCOPE
+ self.query = None
+ self.tags = None
+ self.author = None
+ self.sort = const.DEFAULT_POST_SORT_METHOD
+ self.page_size = const.DEFAULT_QUESTIONS_PAGE_SIZE
+ self.page = 1
+ self.logged_in = False
+ logging.debug('new search state initialized')
+
+ def __str__(self):
+ out = 'scope=%s\n' % self.scope
+ out += 'query=%s\n' % self.query
+ if self.tags:
+ out += 'tags=%s\n' % ','.join(self.tags)
+ out += 'author=%s\n' % self.author
+ out += 'sort=%s\n' % self.sort
+ out += 'page_size=%d\n' % self.page_size
+ out += 'page=%d\n' % self.page
+ out += 'logged_in=%s\n' % str(self.logged_in)
+ return out
+
+ def set_logged_out(self):
+ if self.scope == 'favorite':
+ self.scope = None
+ self.logged_in = False
+
+ def set_logged_in(self):
+ self.logged_in = True
+
+ def reset(self):
+ #re-initialize, but keep login state
+ is_logged_in = self.logged_in
+ self.__init__()
+ self.logged_in = is_logged_in
+
+ def update_value(self, key, store):
+ if key in store:
+ old_value = getattr(self, key)
+ new_value = store[key]
+ if new_value != old_value:
+ setattr(self, key, new_value)
+ self.reset_page()
+
+ def relax_stickiness(self, input, view_log):
+ if view_log.get_previous(1) == 'questions':
+ if not some_in(ACTIVE_COMMANDS, input):
+ self.reset()
+ #todo also relax if 'all' scope was clicked twice
+
+ def update_from_user_input(self,input,raw_input = {}):
+ #todo: this function will probably not
+ #fit the case of multiple parameters entered at the same tiem
+ if 'start_over' in input:
+ self.reset()
+
+ if 'page' in input:
+ self.page = input['page']
+ #special case - on page flip no other input is accepted
+ return
+
+ if 'page_size' in input:
+ self.update_value('page_size',input)
+ self.reset_page()#todo may be smarter here - start with ~same q
+ #same as with page - return right away
+ return
+
+ if 'scope' in input:
+ if input['scope'] == 'favorite' and self.logged_in == False:
+ self.reset_scope()
+ else:
+ self.update_value('scope',input)
+
+ if 'tags' in input:
+ if self.tags:
+ old_tags = self.tags.copy()
+ self.tags = self.tags.union(input['tags'])
+ if self.tags != old_tags:
+ self.reset_page()
+ else:
+ self.tags = input['tags']
+
+ #all resets just return
+ if 'reset_tags' in input:
+ if self.tags:
+ self.tags = None
+ self.reset_page()
+ return
+
+ #todo: handle case of deleting tags one-by-one
+ if 'reset_author' in input:
+ if self.author:
+ self.author = None
+ self.reset_page()
+ return
+
+ if 'reset_query' in input:
+ self.reset_query()
+ return
+
+ self.update_value('author',input)
+
+ if 'query' in input:
+ self.update_value('query',input)
+ self.sort = 'relevant'
+ elif 'search' in raw_input:#a case of use nulling search query by hand
+ self.reset_query()
+ return
+
+
+ if 'sort' in input:
+ if input['sort'] == 'relevant' and self.query is None:
+ self.reset_sort()
+ else:
+ self.update_value('sort',input)
+
+ def reset_page(self):
+ self.page = 1
+
+ def reset_query(self):
+ if self.query:
+ self.query = None
+ self.reset_page()
+ if self.sort == 'relevant':
+ self.reset_sort()
+
+ def reset_sort(self):
+ self.sort = const.DEFAULT_POST_SORT_METHOD
+
+ def reset_scope(self):
+ self.scope = const.DEFAULT_POST_SCOPE
diff --git a/forum/skins/default/media/images/logo.gif b/forum/skins/default/media/images/logo.gif
index e4d2b957..03eb79f4 100644
--- a/forum/skins/default/media/images/logo.gif
+++ b/forum/skins/default/media/images/logo.gif
Binary files differ
diff --git a/forum/skins/default/media/style/style.css b/forum/skins/default/media/style/style.css
index 93c979ce..3f51e619 100755
--- a/forum/skins/default/media/style/style.css
+++ b/forum/skins/default/media/style/style.css
@@ -204,7 +204,6 @@ blockquote {
background-color: #F5F5F5;
}
-/*页面布局*/
#wrapper {
width: 960px;
margin: auto;
@@ -218,7 +217,7 @@ blockquote {
}
#room {
- padding: 10px 0 10px 0;
+ padding: 0 0 10px 0;
background-color: #FFF;
border-bottom: 1px solid #777;
}
@@ -251,16 +250,15 @@ blockquote {
/*#licenseLogo {position:absolute;top:10px;right:10px;}*/
-/*顶部及导航栏*/
+/* why is this called top? - this contains links like login, faq, etc */
#top {
position: absolute;
top: 0px;
- right: 0px;
+ right: 250px;
height: 20px;
text-align: right;
padding: 3px;
background-color: #ffffff;
- width: 500px;
}
/*#header {width:960px;}*/
@@ -270,13 +268,24 @@ blockquote {
margin-left: 20px;
text-decoration: underline;
font-size: 12px;
- color: #333333;
+ color: #555555;
}
#logo {
- padding: 5px 0px 0px 0px;
+ padding: 0px 0px 0px 10px;
+ height: 90px;
+ width: 70px;
+}
+
+#logoContainer {
+}
+#navTabContainer {
+ width: 600px;
+ padding-left: 10px;
+ text-align: left;
}
+/* navBar includes logo, main tabs and links like logout, about, faq */
#navBar {
float: clear;
position: relative;
@@ -285,7 +294,7 @@ blockquote {
}
#navBar .nav {
- margin: 20px 0px 0px 16px; /*letter-spacing:1px; */
+ margin: 20px 0px 0px 0px; /*letter-spacing:1px; */
}
#navBar .nav a {
@@ -300,8 +309,8 @@ blockquote {
height: 25px;
line-height: 30px;
margin-left: 10px;
- font-size: 14px;
- font-weight: 400;
+ font-size: 18px;
+ font-weight: 100;
text-decoration: none;
display: block;
float: left;
@@ -325,7 +334,7 @@ blockquote {
}
#navBar .nav a.special {
- font-size: 14px;
+ font-size: 18px;
color: #B02B2C;
font-weight: bold;
text-decoration: none;
@@ -335,35 +344,78 @@ blockquote {
text-decoration: underline;
}
+/* todo: this is probably not used any more */
#navBar .nav div.focus {
float: right;
padding-right: 0px;
}
-/*搜索栏*/
#searchBar {
- width: 958px;
- background-color: #888a85; /*#e9b96e;*/
+ display:inline-block;
+ background-color: #cccccc;/*888a85; /*#e9b96e;*/
border: 1px solid #aaaaaa;
- padding: 4px 0 0 0;
+ padding: 4px 7px 5px 5px;
}
-/* #B02B2C */
-#searchBar .content {
+#searchBar .searchInput {
+ font-size: 24px;
+ line-height: 24px;
+ height: 36px;
+ width: 598px;
+ margin: 0px;
+ padding: 5px 0 0 5px;
}
-#searchBar .searchInput {
- font-size: 13px;
- height: 18px;
- width: 400px;
+#searchBar .searchInputCancelable {
+ font-size: 24px;
+ line-height: 24px;
+ height: 36px;
+ width: 552px;
+ padding: 5px 0 0 5px;
+ margin: 0px;
}
#searchBar .searchBtn {
- font-size: 14px;
- height: 26px;
- width: 80px;
+ font-size: 20px;
+ color: #666666;
+ height: 40px;
+ line-height: 22px;
+ text-align: center;
+ margin-top:1px;
+ padding-bottom: 4px;
+}
+
+#searchBar .cancelSearchBtn {
+ font-size: 20px;
+ color: #666666;
+ height: 40px;
+ width: 40px;
+ line-height: 22px;
+ padding-bottom: 4px;
+ margin-top:1px;
+ text-align: center;
}
+#askFormBar {
+ display:inline-block;
+ background-color: #e3e3e3;/*888a85; /*#e9b96e;*/
+ border: 1px solid #aaaaaa;
+ padding: 4px 7px 5px 5px;
+}
+#askFormBar p {
+ width: 685px;
+ margin:0 0 5px 0;
+}
+#askFormBar .questionTitleInput {
+ font-size: 24px;
+ line-height: 24px;
+ height: 36px;
+ width: 680px;
+ margin: 0px;
+ padding: 5px 0 0 5px;
+}
+
+
#searchBar .options {
padding: 3px 0 3px 0;
font-size: 100%;
@@ -499,7 +551,7 @@ blockquote {
.short-summary {
position: relative;
padding: 3px 5px 5px 10px;
- border-top: 1px dotted #ccccce;
+ border-top: 1px dashed #ccccce;
overflow: hidden;
width: 700px;
float: left;
@@ -552,6 +604,10 @@ blockquote {
font-weight: 800;
}
+.evenMore a {
+ text-decoration: underline;
+}
+
.questions-count {
font-size: 32px;
font-family: sans-serif;
@@ -623,13 +679,16 @@ blockquote {
}
.boxC {
- background: #cacdc6; /*f9f7ed;*/
+ background: white /*#cacdc6; /*f9f7ed;*/
padding: 10px;
margin-bottom: 8px;
+ margin-left: 10px;
+ /*
border-top: 1px solid #eeeeec;
border-left: 1px solid #eeeeec;
border-right: 1px solid #a9aca5;
border-bottom: 1px solid #babdb6;
+ */
}
.boxC p {
@@ -846,6 +905,7 @@ a:hover.medal {
width: 100%;
clear: both;
margin-bottom: 3px;
+ margin-top: 3px;
}
.tabsA {
@@ -866,7 +926,16 @@ a:hover.medal {
height: 20px;
}
-.tabsA a.on, .tabsA a:hover, .tabsB a.on, .tabsB a:hover {
+.tabsC {
+ background-color: #FFF;
+ float: left;
+ position: relative;
+ display: block;
+ font-weight: bold;
+ height: 20px;
+}
+
+.tabsA a.on, .tabsA a:hover, .tabsB a.on, .tabsB a:hover , .tabsC a.on, tabsC a:hover {
background: #fff;
color: #a40000;
border-top: 1px solid #babdb6;
@@ -879,7 +948,7 @@ a:hover.medal {
padding: 0px 11px 0px 11px;
}
-.tabsA a {
+.tabsA a, .tabsC a{
background: #f9f7eb;
border-top: 1px solid #eeeeec;
border-left: 1px solid #eeeeec;
@@ -895,6 +964,12 @@ a:hover.medal {
text-decoration: none;
}
+.tabsA .label, .tabsC .label {
+ float: left;
+ font-weight: bold;
+ margin: 8px 4px 0 4px;
+}
+
.tabsB a {
background: #eee;
border: 1px solid #eee;
@@ -920,7 +995,6 @@ a:hover.medal {
}
.headQuestions {
- float: left;
height: 23px;
line-height: 23px;
margin: 5px 0 0 5px;
@@ -951,6 +1025,7 @@ a:hover.medal {
padding-left: 24px;
}
+/* todo: make this class applicable to all headers it is actually uses in tags.html too */
.headUsers {
float: left;
height: 23px;
@@ -1486,13 +1561,18 @@ span.form-error {
font-size: 100%;
min-height: 200px;
line-height: 18px;
+ width: 697px;
+ margin:0;
+}
+
+#id_title {
width: 100%;
}
.wmd-preview {
- margin-top: 10px;
+ margin: 10px 0 0 0;
padding: 6px;
- width: 100%;
+ width: 691px;
background-color: #F5F5F5;
min-height: 20px;
}
@@ -1680,7 +1760,6 @@ ins .post-tag {
}
.narrow .stats {
- background: transparent none repeat scroll 0 0;
float: left;
height: 48px;
margin: 0 0 0 7px;
@@ -1689,6 +1768,11 @@ ins .post-tag {
font-family: Arial;
}
+/* todo: remove this hack? */
+.user-stats-table .narrow {
+ width: 660px;
+}
+
.stats div {
font-size: 11px;
text-align: center;
@@ -2497,15 +2581,16 @@ p.signup_p {
}
.karma-diagram {
- width:550px;
- height:250px;
+ width:390px;
+ height:300px;
float:left;
+ margin-right:10px;
}
.karma-details {
float:right;
- width:385px;
- height:300px;
+ width:300px;
+ height:250px;
overflow-y:auto;
word-wrap:break-word;
}
@@ -2525,3 +2610,20 @@ p.signup_p {
color:red;
padding:5px;
}
+
+.search-result-summary {
+ font-weight: bold;
+ font-size:18px;
+ line-height:30px;
+ margin:0px 0px 0px 5px;
+ padding:0px;
+}
+.search-tips {
+ font-size:12px;
+ line-height:12px;
+ margin:0 0 5px 5px;
+ padding:0px;
+}
+.search-tips a {
+ text-decoration: underline;
+}
diff --git a/forum/skins/default/templates/about.html b/forum/skins/default/templates/about.html
index 66dcc3fd..686141b3 100644
--- a/forum/skins/default/templates/about.html
+++ b/forum/skins/default/templates/about.html
@@ -1,4 +1,4 @@
-{% extends "base_content.html" %}
+{% extends "base.html" %}
<!-- template about.html -->
{% load i18n %}
{% load extra_tags %}
diff --git a/forum/skins/default/templates/ask.html b/forum/skins/default/templates/ask.html
index 083b01d9..4278f4cb 100644
--- a/forum/skins/default/templates/ask.html
+++ b/forum/skins/default/templates/ask.html
@@ -56,6 +56,7 @@
</script>
{% endblock %}
+{% comment %}
{% block content %}
<div id="main-bar" class="headNormal">
{% trans "Ask a question" %}
@@ -124,6 +125,7 @@
</div>
</div>
{% endblock %}
+{% endcomment %}
{% block sidebar %}
{% include "question_edit_tips.html" %}
diff --git a/forum/skins/default/templates/ask_form.html b/forum/skins/default/templates/ask_form.html
new file mode 100644
index 00000000..25e9fe6c
--- /dev/null
+++ b/forum/skins/default/templates/ask_form.html
@@ -0,0 +1,66 @@
+{% load i18n %}
+{% load smart_if %}
+<div id="askform">
+ <form id="fmask" action="" method="post" >
+ <div class="form-item">
+ {% comment %}
+ <label for="id_title" ><strong>{{ form.title.label_tag }}:</strong></label>
+ {% endcomment %}
+ <div id="askFormBar">
+ {% if not request.user.is_authenticated %}
+ <p>{% trans "login to post question info" %}</p>
+ {% else %}
+ {% ifequal settings.EMAIL_VALIDATION 'on' %}
+ {% if not request.user.email_isvalid %}
+ {% blocktrans with request.user.email as email %}must have valid {{email}} to post,
+ see {{email_validation_faq_url}}
+ {% endblocktrans %}
+ {% endif %}
+ {% endifequal %}
+ {% endif %}
+ <input id="id_title" class="questionTitleInput" name="title"
+ value="{% if form.initial.title %}{{form.initial.title}}{% endif %}"/>
+ </div>
+ {{ form.title.errors }}
+ <span class="form-error"></span><br/>
+ <div class="title-desc">
+ {{ form.title.help_text }}
+ </div>
+ </div>
+
+ <div class="form-item">
+ <div id="wmd-button-bar" class="wmd-panel"></div>
+ {{ form.text }}
+
+ <div class="preview-toggle">
+ <table>
+ <tr>
+ <td>
+ <span id="pre-collapse" title="{% trans "Toggle the real time Markdown editor preview" %}">{% trans "toggle preview" %}</span>
+ </td>
+ {% if settings.WIKI_ON %}
+ <td style="text-align:right;">
+ {{ form.wiki }} <span style="font-weight:normal;cursor:help" title="{{form.wiki.help_text}}">{{ form.wiki.label_tag }} </span>
+ </td>
+ {% endif %}
+ </tr>
+
+ </table>
+ </div>
+ <div id="previewer" class="wmd-preview"></div>
+ <span class="form-error"></span>
+ </div>
+ <div class="form-item">
+ <strong>{{ form.tags.label_tag }}:</strong> {% trans "(required)" %} <span class="form-error"></span><br/>
+ {{ form.tags }} {{ form.tags.errors }}
+ </div>
+ <p class="title-desc">
+ {{ form.tags.help_text }}
+ </p>
+ {% if not request.user.is_authenticated %}
+ <input type="submit" value="{% trans "Login/signup to post your question" %}" class="submit" />
+ {% else %}
+ <input type="submit" value="{% trans "Ask your question" %}" class="submit" />
+ {% endif %}
+ </form>
+</div>
diff --git a/forum/skins/default/templates/base.html b/forum/skins/default/templates/base.html
index 1018da50..0b85e7fb 100644
--- a/forum/skins/default/templates/base.html
+++ b/forum/skins/default/templates/base.html
@@ -2,6 +2,7 @@
<!-- template base.html -->
{% load extra_filters %}
{% load extra_tags %}
+{% load smart_if %}
{% load i18n %}
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@@ -36,7 +37,19 @@
});
</script>
{% endif %}
-
+ {% if active_tab != "tags" and active_tab != "users" %}
+ <script type="text/javascript">
+ $('#nav_ask').click(
+ function(){
+ alert('hullo');
+ var starting_title = $('#keywords').attr('value');
+ alert('tittle is ' + starting_title);
+ window.location.href = $(this).attr('href') + '?'
+ + starting_title;
+ }
+ );
+ </script>
+ {% endif %}
{% block forejs %}
{% endblock %}
</head>
@@ -55,6 +68,7 @@
<div id="wrapper">
<div id="room">
<div id="CALeft">
+ {% include "input_bar.html" %}
{% block content%}
{% endblock%}
diff --git a/forum/skins/default/templates/base_content.html b/forum/skins/default/templates/base_content.html
index 1bae0afd..284007d8 100644
--- a/forum/skins/default/templates/base_content.html
+++ b/forum/skins/default/templates/base_content.html
@@ -55,6 +55,7 @@
<div id="wrapper">
<div id="room">
<div id="CAFull">
+ {% include "input_bar.html" %}
{% block content%}
{% endblock%}
diff --git a/forum/skins/default/templates/book.html b/forum/skins/default/templates/book.html
index 8574fa73..528b800d 100644
--- a/forum/skins/default/templates/book.html
+++ b/forum/skins/default/templates/book.html
@@ -122,7 +122,7 @@
</h3>
<div class="tags">
{% for tag in question.tagname_list %}
- <a href="{% url tag_questions tag|urlencode %}" title="{% "see questions tagged with" %}'{{ tag }}'{% trans "using tags" %}" rel="tag">{{ tag }}</a>
+ <a href="{% url questions %}?tags={{tag|urlencode}}" title="{% blocktrans %}see questions tagged '{{ tag }}'{% endblocktrans %}" rel="tag">{{ tag }}</a>
{% endfor %}
</div>
<div class="started">
diff --git a/forum/skins/default/templates/faq.html b/forum/skins/default/templates/faq.html
index ca963237..cc790ccc 100644
--- a/forum/skins/default/templates/faq.html
+++ b/forum/skins/default/templates/faq.html
@@ -1,4 +1,4 @@
-{% extends "base_content.html" %}
+{% extends "base.html" %}
<!-- template faq.html -->
{% load extra_tags %}
{% load humanize %}
diff --git a/forum/skins/default/templates/feedback.html b/forum/skins/default/templates/feedback.html
index 38bb48ff..af4f635f 100644
--- a/forum/skins/default/templates/feedback.html
+++ b/forum/skins/default/templates/feedback.html
@@ -1,4 +1,4 @@
-{% extends "base_content.html" %}
+{% extends "base.html" %}
<!-- template about.html -->
{% load i18n %}
{% load extra_tags %}
diff --git a/forum/skins/default/templates/header.html b/forum/skins/default/templates/header.html
index 099bfb85..0a1a3296 100644
--- a/forum/skins/default/templates/header.html
+++ b/forum/skins/default/templates/header.html
@@ -1,5 +1,6 @@
<!-- template header.html -->
{% load extra_tags %}
+{% load smart_if %}
{% load i18n %}
<div id="roof">
<div id="navBar">
@@ -13,53 +14,34 @@
<a href="{% url about %}">{% trans "about" %}</a>
<a href="{% url faq %}">{% trans "faq" %}</a>
</div>
- <table width="100%" border="0" cellspacing="0" cellpadding="0">
+ <table border="0" cellspacing="0" cellpadding="0">
<tr>
- <td width="23%">
- <div id="logo">
- <a href="{% url index %}">
- <img src="{% media "/media/images/logo.png" %}" title="{% trans "back to home page" %}" alt="{{settings.APP_TITLE}} logo"/>
- </a>
- </div>
- </td>
- <td width="77%" valign="bottom">
- <div class="nav">
- <a id="nav_questions" href="{% url questions %}" >{% trans "questions" %}</a>
- <a id="nav_tags" href="{% url tags %}">{% trans "tags" %}</a>
- <a id="nav_users" href="{% url users %}">{% trans "users" %}</a>
- {% if settings.BOOKS_ON %}
- <a id="nav_books" href="{% url books %}">{% trans "books" %}</a>
- {% endif %}
- <a id="nav_badges" href="{% url badges %}">{% trans "badges" %}</a>
- <a id="nav_unanswered" href="{% url unanswered %}">{% trans "unanswered questions" %}</a>
- <div class="focus">
- <a id="nav_ask" href="{% url ask %}" class="special">{% trans "ask a question" %}</a>
- </div>
+ <td id="logoContainer">
+ <div id="logo">
+ <a href="{% url questions %}?start_over=true"><img
+ src="{% media "/media/images/logo.gif" %}" title="{% trans "back to home page" %}" alt="{{settings.APP_TITLE}} logo"/></a>
+ </div>
+ </td>
+ <td id="navTabContainer" valign="bottom" align="left">
+ <div class="nav">
+ <a id="nav_questions" href="{% url questions %}" >{% trans "questions" %}</a>
+ <a id="nav_tags" href="{% url tags %}">{% trans "tags" %}</a>
+ <a id="nav_users" href="{% url users %}">{% trans "users" %}</a>
+ {% if settings.BOOKS_ON %}
+ <a id="nav_books" href="{% url books %}">{% trans "books" %}</a>
+ {% endif %}
+ <a id="nav_badges" href="{% url badges %}">{% trans "badges" %}</a>
+ <a id="nav_ask" href="{% url ask %}" class="special">{% trans "ask a question" %}</a>
+ {% comment %}
+ <a id="nav_unanswered" href="{% url unanswered %}">{% trans "unanswered questions" %}</a>
+ <div class="focus">
+ <a id="nav_ask" href="{% url ask %}" class="special">{% trans "ask a question" %}</a>
</div>
-
- </td>
+ {% endcomment %}
+ </div>
+ </td>
</tr>
</table>
</div>
- <div id="searchBar">
- <table width="100%" border="0" cellpadding="0" cellspacing="0" class="content">
- <tr>
- <td align="center" valign="middle">
- <form action="{% url search %}" method="get">
- <div>
- <input type="text" class="searchInput" value="{{ keywords }}" name="q" id="keywords" />
- <input type="submit" name="Submit" value="{% trans "search" %}" class="searchBtn" />
- </div>
- <div class="options">
- <input id="type-question" type="radio" value="question" name="t"
- checked="checked" /><label for="type-question">{% trans "questions" %}</label>
- <input id="type-tag" type="radio" value="tag" name="t" /><label for="type-tag">{% trans "tags" %}</label>
- <input id="type-user" type="radio" value="user" name="t" /><label for="type-user">{% trans "users" %}</label>
- </div>
- </form>
- </td>
- </tr>
- </table>
- </div>
</div>
<!-- end template header.html -->
diff --git a/forum/skins/default/templates/index.html b/forum/skins/default/templates/index.html
index 8a885dd4..f94f84fc 100644
--- a/forum/skins/default/templates/index.html
+++ b/forum/skins/default/templates/index.html
@@ -23,7 +23,7 @@
{% endblock %}
{% block content %}
<div class="tabBar">
- <div class="headQuestions">{% trans "Questions" %}</div>
+ <div class="headUsers">{% trans "Questions" %}</div>
<div class="tabsA">
<a id="latest" href="{% url questions %}?sort=latest" title="{% trans "last updated questions" %}" >{% trans "newest" %}</a>
<a id="hottest" href="{% url questions %}?sort=hottest" title="{% trans "hottest questions" %}" >{% trans "hottest" %}</a>
@@ -57,11 +57,12 @@
{% cache 60 recent_tags %}
{% for tag in tags %}
<a rel="tag"
- title="{% blocktrans with tag.name as tagname %}see questions tagged '{{tagname}}'{% endblocktrans %}" href="{% url tag_questions tag.name|urlencode %}">{{ tag.name }}</a>
+ title="{% blocktrans with tag.name as tagname %}see questions tagged '{{tagname}}'{% endblocktrans %}"
+ href="{% url questions %}?tags={{tag.name|urlencode}}">{{ tag.name }}</a>
{% endfor %}
{% endcache %}
</div>
- <div class="more"><a href="{% url tags %}">{% trans "popular tags" %} </a> </div>
+ <div class="more"><a href="{% url tags %}">{% trans "see all tags" %}</a> </div>
</div>
</div>
{% if awards %}
diff --git a/forum/skins/default/templates/index_.html b/forum/skins/default/templates/index_.html
index 5e4cf533..36531f62 100644
--- a/forum/skins/default/templates/index_.html
+++ b/forum/skins/default/templates/index_.html
@@ -22,7 +22,7 @@
{% endblock %}
{% block content %}
<div class="tabBar">
- <div class="headQuestions">{% trans "Questions" %}</div>
+ <div class="headUsers">{% trans "Questions" %}</div>
<div class="tabsA">
<a id="latest" href="{% url index %}?sort=latest" title="{% trans "last updated questions" %}" >{% trans "newest" %}</a>
<a id="hottest" href="{% url index %}?sort=hottest" title="{% trans "hottest questions" %}" >{% trans "hottest" %}</a>
@@ -60,7 +60,7 @@
<div class="tags">
{% for tag in question.tagname_list %}
- <a href="{% url tag_questions tag|urlencode %}" title="{% trans "see questions tagged" %} '{{ tag }}' {% trans "using tags" %}" rel="tag">{{ tag }}</a>
+ <a href="{% url questions %}?tags={{tag|urlencode}}" title="{% blocktrans %}see questions tagged '{{ tag }}'{% endblocktrans %}" rel="tag">{{ tag }}</a>
{% endfor %}
</div>
</div>
@@ -87,7 +87,8 @@
<div class="tags">
{% for tag in tags %}
<a rel="tag"
- title="{% blocktrans with tag.name as tagname %}see questions tagged '{{tagname}}'{% endblocktrans %}" href="{% url tag_questions tag.name|urlencode %}">{{ tag.name }}</a>
+ title="{% blocktrans with tag.name as tagname %}see questions tagged '{{tagname}}'{% endblocktrans %}"
+ href="{% url questions %}?tags={{tag.name|urlencode}}">{{ tag.name }}</a>
{% endfor %}
</div>
<div class="more"><a href="{% url tags %}">{% trans "popular tags" %} »</a> </div>
diff --git a/forum/skins/default/templates/input_bar.html b/forum/skins/default/templates/input_bar.html
new file mode 100644
index 00000000..59236350
--- /dev/null
+++ b/forum/skins/default/templates/input_bar.html
@@ -0,0 +1,45 @@
+{% load i18n %}
+{% load smart_if %}
+{% if active_tab != "ask" %}
+<div id="searchBar">
+ {% comment %}url action depends on which tab is active{% endcomment %}
+ <form
+ {% if active_tab == "tags" or active_tab == "users" %}
+ action="{% url search %}"
+ {% else %}
+ action="{% url questions %}"
+ {% endif %}
+ method="get">
+ {% comment %} class was searchInput {% endcomment %}
+ <input
+ {% if query %}
+ class="searchInputCancelable"
+ {% else %}
+ class="searchInput"
+ {% endif %}
+ type="text"
+ value="{{ query|default_if_none:"" }}"
+ name="query"
+ id="keywords"/>
+ {% if query %}{% comment %}query is only defined by questions view{% endcomment %}
+ <input type="button"
+ value="x"
+ name="reset_query"
+ {% comment %}todo - make sure it works on Enter keypress{% endcomment %}
+ onclick="window.location.href='{% url questions %}?reset_query=true'"
+ value="true"
+ class="cancelSearchBtn"/>
+ {% endif %}
+ <input type="submit" value="{% trans "search" %}" name="search" class="searchBtn" default />
+ {% if active_tab == "tags" %}
+ <input type="hidden" name="t" value="tag"/>
+ {% else %}
+ {% if active_tab == "users" %}
+ <input type="hidden" name="t" value="user"/>
+ {% endif %}
+ {% endif %}
+ </form>
+</div>
+{% else %}
+ {% include "ask_form.html" %}
+{% endif %}
diff --git a/forum/skins/default/templates/question.html b/forum/skins/default/templates/question.html
index 1c542c8b..79ff9a5b 100644
--- a/forum/skins/default/templates/question.html
+++ b/forum/skins/default/templates/question.html
@@ -128,10 +128,12 @@
{{ question.html|safe }}
</div>
<div id="question-controls" class="post-controls">
+ {% comment %}todo: here we have important case to reset search state{% endcomment %}
<div id="question-tags" class="tags">
{% for tag in question.tagname_list %}
- <a href="{% url tag_questions tag|urlencode %}" class="post-tag"
- title="{% blocktrans with tag as tagname %}see questions tagged '{{ tagname }}'{% endblocktrans %}" rel="tag">{{ tag }}</a>
+ <a href="{% url questions %}?tags={{tag|urlencode}}&start_over=true"
+ class="post-tag"
+ title="{% blocktrans %}see questions tagged '{{tag}}'{% endblocktrans %}" rel="tag">{{ tag }}</a>
{% endfor %}
</div>
{% joinitems using '<span class="action-link-separator">|</span>' %}
@@ -224,7 +226,7 @@
<hr/>
<div class="tabBar">
<a name="sort-top"></a>
- <div class="headQuestions">
+ <div class="headUsers">
{% blocktrans count answers|length as counter %}
One Answer:
{% plural %}
@@ -474,9 +476,10 @@
</p>
<p class="tags" >
{% for tag in tags %}
- <a href="{% url tag_questions tag.name|urlencode %}"
- title="{% trans "see questions tagged"%}'{{tag.name}}'{% trans "using tags" %}"
- rel="tag">{{ tag.name }}</a> <span class="tag-number">&#215;{{ tag.used_count|intcomma }}</span><br/>
+ <a href="{% url questions %}?tags={{tag.name|urlencode}}&start_over=true"
+ title="{% blocktrans with tag.name as tag_name %}see questions tagged '{{tag_name}}'{% endblocktrans %}"
+ rel="tag">{{ tag.name }}</a>
+ <span class="tag-number">&#215;{{ tag.used_count|intcomma }}</span><br/>
{% endfor %}
</p>
<p>
diff --git a/forum/skins/default/templates/question_list.html b/forum/skins/default/templates/question_list.html
index 53633691..38ac254a 100644
--- a/forum/skins/default/templates/question_list.html
+++ b/forum/skins/default/templates/question_list.html
@@ -16,7 +16,7 @@
</div>
<div class="tags">
{% for tag in question.tagname_list %}
- <a href="{% url tag_questions tag|urlencode %}" title="{% trans "see questions tagged" %} '{{ tag }}' {% trans "using tags" %}" rel="tag">{{ tag }}</a>
+ <a href="{% url questions %}?tags={{tag|urlencode}}" title="{% blocktrans %}see questions tagged '{{ tag }}'{%endblocktrans %}" rel="tag">{{ tag }}</a>
{% endfor %}
</div>
</div>
diff --git a/forum/skins/default/templates/question_summary_list_roll.html b/forum/skins/default/templates/question_summary_list_roll.html
index 57685d6d..f2432a24 100644
--- a/forum/skins/default/templates/question_summary_list_roll.html
+++ b/forum/skins/default/templates/question_summary_list_roll.html
@@ -49,7 +49,7 @@
<div class="tags">
{% for tag in question.tagname_list %}
- <a href="{% url tag_questions tag|urlencode %}" title="{% trans "see questions tagged" %}'{{ tag }}'{% trans "using tags" %}" rel="tag">{{ tag }}</a>
+ <a href="{% url questions %}?tags={{tag|urlencode}}" title="{% blocktrans %}see questions tagged '{{ tag }}'{% endblocktrans %}" rel="tag">{{ tag }}</a>
{% endfor %}
</div>
</div>
diff --git a/forum/skins/default/templates/questions.html b/forum/skins/default/templates/questions.html
index 366727d1..f864180f 100644
--- a/forum/skins/default/templates/questions.html
+++ b/forum/skins/default/templates/questions.html
@@ -10,9 +10,11 @@
<script type="text/javascript">
var tags = {{ tags_autocomplete|safe }};
$().ready(function(){
- var tab_id = "{{ tab_id }}";
- $("#"+tab_id).attr('className',"on");
- var on_tab = {% if is_unanswered %}'#nav_unanswered'{% else %}'#nav_questions'{% endif %};
+ var sort_tab_id = "{{ sort }}";
+ $("#"+sort_tab_id).attr('className',"on");
+ var scope_tab_id = "{{ scope }}";
+ $("#"+scope_tab_id).attr('className',"on");
+ var on_tab = '#nav_questions';
$(on_tab).attr('className','on');
Hilite.exact = false;
Hilite.elementid = "listA";
@@ -24,7 +26,8 @@
{% endblock %}
{% block content %}
<div class="tabBar">
- <div class="headQuestions">
+ {% comment %}
+ <div class="headUsers">
{% if searchtag %}
{% trans "Found by tags" %}
{% else %}
@@ -42,75 +45,197 @@
{% endif %}
{% endif %}
{% endif %}
+ </div><br/>
+ {% endcomment %}
+ <div class="tabsC">
+ <span class="label">{% trans "In:" %}</span>
+ <a id="all" class="off" href="?scope=all" title="{% trans "see all questions" %}">{% trans "all" %}</a>
+ <a id="unanswered" class="off" href="?scope=unanswered&sort=coldest" title="{% trans "see unanswered questions" %}">{% trans "unanswered" %}</a>
+ {% if request.user.is_authenticated %}
+ <a id="favorite" class="off" href="?scope=favorite" title="{% trans "see your favorite questions" %}">{% trans "favorite" %}</a>
+ {% endif %}
</div>
<div class="tabsA">
- <a id="latest" href="{% if is_search %}{{ search_uri }}&{% else %}?{% endif %}sort=latest" class="off" title="{% trans "most recently asked questions" %}">{% trans "newest" %}</a>
- <a id="active" href="{% if is_search %}{{ search_uri }}&{% else %}?{% endif %}sort=active" class="off" title="{% trans "most recently updated questions" %}">{% trans "active" %}</a>
- <a id="hottest" href="{% if is_search %}{{ search_uri }}&{% else %}?{% endif %}sort=hottest" class="off" title="{% trans "hottest questions" %}">{% trans "hottest" %}</a>
- <a id="mostvoted" href="{% if is_search %}{{ search_uri }}&{% else %}?{% endif %}sort=mostvoted" class="off" title="{% trans "most voted questions" %}">{% trans "most voted" %}</a>
+ <span class="label">{% trans "Sort by:" %}</span>
+ {% if sort == "oldest" %}
+ <a id="oldest"
+ href="?sort=latest"
+ class="off"
+ title="{% trans "click to see the newest questions" %}">{% trans "oldest" %}</a>
+ {% else %}
+ {% if sort == "latest" %}
+ <a id="latest"
+ href="?sort=oldest"
+ class="off"
+ title="{% trans "click to see the oldest questions" %}">{% trans "newest" %}</a>
+ {% else %}
+ <a id="latest"
+ href="?sort=latest"
+ class="off"
+ title="{% trans "click to see the newest questions" %}">{% trans "newest" %}</a>
+ {% endif %}
+ {% endif %}
+
+ {% if sort == "inactive" %}
+ <a id="inactive"
+ href="?sort=active"
+ class="off"
+ title="{% trans "click to see the most recently updated questions" %}">{% trans "inactive" %}</a>
+ {% else %}
+ {% if sort == "active" %}
+ <a id="active"
+ href="?sort=inactive"
+ class="off"
+ title="{% trans "click to see the least recently updated questions" %}">{% trans "active" %}</a>
+ {% else %}
+ <a id="active"
+ href="?sort=active"
+ class="off"
+ title="{% trans "click to see the most recently updated questions" %}">{% trans "active" %}</a>
+ {% endif %}
+ {% endif %}
+
+ {% if sort == "coldest" %}
+ <a id="coldest"
+ href="?sort=hottest"
+ class="off"
+ title="{% trans "click to see hottest questions" %}">{% trans "less answers" %}</a>
+ {% else %}
+ {% if sort == "hottest" %}
+ <a id="hottest"
+ href="?sort=coldest"
+ class="off"
+ title="{% trans "click to see coldest questions" %}">{% trans "more answers" %}</a>
+ {% else %}
+ <a id="hottest"
+ href="?sort=hottest"
+ class="off"
+ title="{% trans "click to see hottest questions" %}">{% trans "more answers" %}</a>
+ {% endif %}
+ {% endif %}
+
+ {% if sort == "leastvoted" %}
+ <a id="leastvoted"
+ href="?sort=mostvoted"
+ class="off"
+ title="{% trans "click to see most voted questions" %}">{% trans "unpopular" %}</a>
+ {% else %}
+ {% if sort == "mostvoted" %}
+ <a id="mostvoted"
+ href="?sort=leastvoted"
+ class="off"
+ title="{% trans "click to see least voted questions" %}">{% trans "popular" %}</a>
+ {% else %}
+ <a id="mostvoted"
+ href="?sort=mostvoted"
+ class="off"
+ title="{% trans "click to see most voted questions" %}">{% trans "popular" %}</a>
+ {% endif %}
+ {% endif %}
</div>
</div>
+{% if questions_count > 0 %}
+ <div style="clear:both">
+ <p class="search-result-summary">
+ {% if author_name or search_tags or query %}
+ {% blocktrans count questions_count as cnt with questions_count|intcomma as q_num %} One question found{% plural %}{{q_num}} questions found{% endblocktrans %}
+ {% else %}
+ {% blocktrans count questions_count as cnt with questions_count|intcomma as q_num %} {{q_num}} question{% plural %}{{q_num}} questions{% endblocktrans %}
+ {% endif %}
+ {% joinitems using ', ' %}
+ {% if author_name %}
+ {% blocktrans %}with {{author_name}}'s contributions{% endblocktrans %}
+ {% endif %}
+ {% separator %}
+ {% if search_tags %}
+ {% trans "tagged" %}
+ "{{ search_tags|join:"\", \"" }}"
+ {% endif %}
+ {% endjoinitems %}
+ </p>
+ {% if author_name or search_tags or query %}
+ <p class="search-tips">{% trans "Search tips:" %}
+ {% ifmany query search_tags author_name %}
+ {% joinitems using ', ' ' or ' %}
+ {% if author_name %}
+ <a href="{% url questions %}?reset_author=true">{% trans "reset author" %}</a>
+ {% endif %}
+ {% separator %}
+ {% if search_tags %}
+ <a href="{% url questions %}?reset_tags=true">{% trans "reset tags" %}</a>
+ {% endif %}
+ {% separator %}
+ {% ifmany query search_tags author_name %}
+ <a href="{% url questions %}?start_over=true">{% trans "start over" %}</a>
+ {% endifmany %}
+ {% endjoinitems %}
+ {% else %}
+ <a href="{% url questions %}?start_over=true">{% trans "start over" %}</a>
+ {% endifmany %}
+ {% trans " - to expand, or dig in by adding more tags and revising the query." %}
+ </p>
+ {% else %}
+ <p class="search-tips">{% trans "Search tip:" %} {% trans "add tags and a query to focus your search" %}</p>
+ {% endif %}
+
+ </div>
+{% endif %}
<div id="listA">
{% include "question_list.html" %}
- {% if searchtitle %}
+ {% comment %}todo: fix css here{% endcomment %}
{% if questions_count == 0 %}
- <p class="evenMore" style="padding-top:30px;text-align:center;">
- {% trans "Did not find anything?" %}
+ {% comment %}todo: add tips to widen selection{% endcomment%}
+ <p class="evenMore" style="padding-top:30px;text-align:center;">
+ {% if scope == "unanswered" %}
+ {% trans "There are no unanswered questions here" %}
+ {% endif %}
+ {% if scope == "favorite" %}
+ {% trans "No favorite questions here. " %}
+ {% trans "Please start (bookmark) some questions when you visit them" %}
+ {% endif %}
+ </p>
+ {% if query or search_tags or author_name %}
+ <p class="evenMore" style="text-align:center">
+ {% trans "You can expand your search by " %}
+ {% ifmany query search_tags author_name %}
+ {% joinitems using ', ' ' or ' %}
+ {% if author_name %}
+ <a href="{% url questions %}?reset_author=true">{% trans "resetting author" %}</a>
+ {% endif %}
+ {% separator %}
+ {% if search_tags %}
+ <a href="{% url questions %}?reset_tags=true">{% trans "resetting tags" %}</a>
+ {% endif %}
+ {% separator %}
+ {% ifmany query search_tags author_name %}
+ <a href="{% url questions %}?start_over=true">{% trans "starting over" %}</a>
+ {% endifmany %}
+ {% endjoinitems %}
+ {% else %}
+ <a href="{% url questions %}?start_over=true">{% trans "starting over" %}</a>
+ {% endifmany %}
+ </p>
+ {% endif %}
+ <p class="evenMore" style="text-align:center">
+ <a href="{% url ask %}">{% trans "Please always feel free to ask your question!" %}</a>
+ </p>
{% else %}
- <p class="evenMore" style="padding-left:9px">
- {% trans "Did not find what you were looking for?" %}
+ <p class="evenMore" style="padding-left:9px">
+ {% trans "Did not find what you were looking for?" %}
+ <a href="{% url ask %}">{% trans "Please, post your question!" %}</a>
+ </p>
{% endif %}
- <a href="{% url ask %}">{% trans "Please, post your question!" %}</a>
- </p>
- {% endif %}
</div>
{% endblock %}
-{% block tail %}
- <div class="pager">{% cnprog_paginator context %}</div>
- <div class="pagesize">{% cnprog_pagesize context %}</div>
-{% endblock %}
+ {% block tail %}
+ {% if questions_count > 10 %}{%comment%}todo: remove magic number{%endcomment%}
+ <div class="pager">{% cnprog_paginator context %}</div>
+ <div class="pagesize">{% cnprog_pagesize context %}</div>
+ {% endif %}
+ {% endblock %}
{% block sidebar %}
-<div class="boxC">
- {% if searchtag %}
- {% blocktrans count questions_count as cnt with questions_count|intcomma as q_num and searchtag as tagname %}have total {{q_num}} questions tagged {{tagname}}{% plural %}have total {{q_num}} questions tagged {{tagname}}{% endblocktrans %}
- {% else %}
- {% if searchtitle %}
- {% if settings.USE_SPHINX_SEARCH %}
- {% blocktrans count questions_count as cnt with questions_count|intcomma as q_num %} have total {{q_num}} questions containing {{searchtitle}} in full text {% plural %} have total {{q_num}} questions containing {{searchtitle}} in full text {% endblocktrans %}
- {% else %}
- {% blocktrans count questions_count as cnt with questions_count|intcomma as q_num %} have total {{q_num}} questions containing {{searchtitle}} {% plural %} have total {{q_num}} questions containing {{searchtitle}} {% endblocktrans %}
- {% endif %}
- {% else %}
- {% if is_unanswered %}
- {% blocktrans count questions as cnt with questions_count|intcomma as q_num %} have total {{q_num}} unanswered questions {% plural %} have total {{q_num}} unanswered questions {% endblocktrans %}
- {% else %}
- {% blocktrans count questions as cnt with questions_count|intcomma as q_num %} have total {{q_num}} questions {% plural %} have total {{q_num}} questions {% endblocktrans %}
- {% endif %}
- {% endif %}
- {% endif %}
- <p class="nomargin">
- {% ifequal tab_id "latest" %}
- {% trans "latest questions info" %}
- {% endifequal %}
-
- {% ifequal tab_id "active" %}
- {% trans "Questions are sorted by the <strong>time of last update</strong>." %}
- {% trans "Most recently answered ones are shown first." %}
- {% endifequal %}
-
- {% ifequal tab_id "hottest" %}
- {% trans "Questions sorted by <strong>number of responses</strong>." %}
- {% trans "Most answered questions are shown first." %}
- {% endifequal %}
-
- {% ifequal tab_id "mostvoted" %}
- {% trans "Questions are sorted by the <strong>number of votes</strong>." %}
- {% trans "Most voted questions are shown first." %}
- {% endifequal %}
- </p>
-</div>
{% if request.user.is_authenticated %}
{% include "tag_selector.html" %}
{% endif %}
@@ -118,7 +243,7 @@
<h3 class="subtitle">{% trans "Related tags" %}</h3>
<div class="tags">
{% for tag in tags %}
- <a rel="tag" title="{% blocktrans with tag.name as tag_name %}see questions tagged '{{ tag_name }}'{% endblocktrans %}" href="{% url tag_questions tag.name|urlencode %}">{{ tag.name }}</a>
+ <a rel="tag" title="{% blocktrans with tag.name as tag_name %}see questions tagged '{{ tag_name }}'{% endblocktrans %}" href="{% url questions %}?tags={{tag.name|urlencode}}">{{ tag.name }}</a>
<span class="tag-number">&#215; {{ tag.used_count|intcomma }}</span>
<br />
{% endfor %}
diff --git a/forum/skins/default/templates/tag_selector.html b/forum/skins/default/templates/tag_selector.html
index 5e3e2ad8..85b858d2 100644
--- a/forum/skins/default/templates/tag_selector.html
+++ b/forum/skins/default/templates/tag_selector.html
@@ -1,5 +1,6 @@
{% load i18n %}
{% load extra_tags %}
+{% comment %}todo - maybe disable navigation from ignored tags here when "hide" is on - with js?{%endcomment%}
<div id="tagSelector" class="boxC">
<h3 class="subtitle">{% trans "Interesting tags" %}</h3>
<div class="tags interesting marked-tags">
@@ -7,8 +8,8 @@
{% spaceless %}
<span class="deletable-tag" id="interesting-tag-{{tag_name}}">
<a rel="tag"
- title="{% blocktrans with tag as tagname %}see questions tagged '{{ tag_name }}'{% endblocktrans %}"
- href="{% url tag_questions tag_name|urlencode %}">{{tag_name}}</a>
+ title="{% blocktrans %}see questions tagged '{{ tag_name }}'{% endblocktrans %}"
+ href="{% url questions %}?tags={{tag_name|urlencode}}">{{tag_name}}</a>
<img class="delete-icon"
src="{% media "/media/images/close-small-dark.png" %}"
title="{% blocktrans %}remove '{{tag_name}}' from the list of interesting tags{% endblocktrans %}"/>
@@ -24,8 +25,8 @@
{% spaceless %}
<span class="deletable-tag" id="ignored-tag-{{tag_name}}">
<a rel="tag"
- title="{% blocktrans with tag as tagname %}see questions tagged '{{ tag_name }}'{% endblocktrans %}"
- href="{% url tag_questions tag_name|urlencode %}">{{tag_name}}</a>
+ title="{% blocktrans %}see questions tagged '{{ tag_name }}'{% endblocktrans %}"
+ href="{% url questions %}?tags={{tag_name|urlencode}}">{{tag_name}}</a>
<img class="delete-icon"
src="{% media "/media/images/close-small-dark.png" %}"
title="{% blocktrans %}remove '{{tag_name}}' from the list of ignored tags{% endblocktrans %}"/>
diff --git a/forum/skins/default/templates/tags.html b/forum/skins/default/templates/tags.html
index 50f90fb1..6627db32 100644
--- a/forum/skins/default/templates/tags.html
+++ b/forum/skins/default/templates/tags.html
@@ -1,4 +1,4 @@
-{% extends "base_content.html" %}
+{% extends "base.html" %}
<!-- tags.html -->
{% load i18n %}
{% load extra_tags %}
@@ -27,7 +27,7 @@
{% block content %}
<!-- Tabs -->
<div class="tabBar">
- <div class="headQuestions">{% trans "Tag list" %}</div>
+ <div class="headUsers">{% trans "Tag list" %}</div>
<div class="tabsA">
<a id="sort_name" href="{% url tags %}?sort=name" class="off" title="{% trans "sorted alphabetically" %}">{% trans "by name" %}</a>
<a id="sort_used" href="{% url tags %}?sort=used" class="off" title="{% trans "sorted by frequency of tag use" %}">{% trans "by popularity" %}</a>
@@ -36,7 +36,7 @@
<div id="searchtags">
<p>
{% if stag %}
- {% trans "All tags matching query" %} '<span class="darkred"><strong>{{ stag }}</strong></span>' {% trans "all tags - make this empty in english" %}:
+ {% blocktrans %}All tags matching '<span class="darkred"><strong>{{ stag }}</strong></span>'{% endblocktrans %}:
{% endif %}
{% if not tags.object_list %}
<span>{% trans "Nothing found" %}</span>
@@ -46,7 +46,8 @@
<ul class="tagsList tags">
{% for tag in tags.object_list %}
<li>
- <a href="{% url tag_questions tag|urlencode %}" title="{% trans "see questions tagged" %}'{{ tag }}'{% trans "using tags" %}" rel="tag">
+ <a href="{% url questions %}?tags={{tag|urlencode}}"
+ title="{% blocktrans %}see questions tagged '{{ tag }}'{% endblocktrans %}" rel="tag">
{{ tag }}
</a>&nbsp;
<span class="tag-number">&#215; {{ tag.used_count|intcomma }}</span>
diff --git a/forum/skins/default/templates/user.html b/forum/skins/default/templates/user.html
index 5931f31c..8fd9e267 100644
--- a/forum/skins/default/templates/user.html
+++ b/forum/skins/default/templates/user.html
@@ -1,4 +1,4 @@
-{% extends "base_content.html" %}
+{% extends "base.html" %}
<!-- user.html -->
{% load extra_tags %}
{% load extra_filters %}
diff --git a/forum/skins/default/templates/user_reputation.html b/forum/skins/default/templates/user_reputation.html
index 954fb44d..f6a33d93 100644
--- a/forum/skins/default/templates/user_reputation.html
+++ b/forum/skins/default/templates/user_reputation.html
@@ -4,6 +4,7 @@
{% load extra_filters %}
{% load humanize %}
{% load i18n %}
+{% load smart_if %}
{% block userjs %}
<script type='text/javascript' src='{% media "/media/js/excanvas.min.js" %}'></script>
<script type='text/javascript' src='{% media "/media/js/jquery.flot.min.js" %}'></script>
@@ -24,7 +25,11 @@
{% block usercontent %}
<div class="karma-summary">
<div id="diagram" class="karma-diagram"></div>
- <h3>{% trans "Change in karma per question or answer" %}</h3>
+ {% if view_user.id == user.id %}
+ <h3>{% trans "Your karma change log." %}</h3>
+ {% else %}
+ <h3>{% blocktrans with view_user.username as user_name %}{{user_name}}'s karma change log{% endblocktrans %}</h3>
+ {% endif %}
<div class="karma-details">
{% for rep in reputation %}
<p>
diff --git a/forum/skins/default/templates/user_stats.html b/forum/skins/default/templates/user_stats.html
index 1f462581..482b1228 100644
--- a/forum/skins/default/templates/user_stats.html
+++ b/forum/skins/default/templates/user_stats.html
@@ -98,7 +98,7 @@
{% for tag in user_tags%}
<a rel="tag"
title="{% blocktrans with tag.name as tag_name %}see other questions with {{view_user}}'s contributions tagged '{{ tag_name }}' {% endblocktrans %}"
- href="{% url tag_questions tag|urlencode %}?user={{view_user.username}}">{{tag.name}}</a>
+ href="{% url questions %}?tags={{tag|urlencode}}&author={{view_user.id}}&start_over=true">{{tag.name}}</a>
<span class="tag-number">&#215; {{ tag.user_tag_usage_count|intcomma }}</span><br/>
{% if forloop.counter|divisibleby:"10" %}
</td>
diff --git a/forum/skins/default/templates/users.html b/forum/skins/default/templates/users.html
index 78715e05..f3ccd6e9 100644
--- a/forum/skins/default/templates/users.html
+++ b/forum/skins/default/templates/users.html
@@ -1,4 +1,4 @@
-{% extends "base_content.html" %}
+{% extends "base.html" %}
<!-- users.html -->
{% load extra_tags %}
{% load humanize %}
diff --git a/forum/skins/default/templates/users_questions.html b/forum/skins/default/templates/users_questions.html
index be6aaf7d..99a7f90c 100644
--- a/forum/skins/default/templates/users_questions.html
+++ b/forum/skins/default/templates/users_questions.html
@@ -31,7 +31,7 @@
{% convert2tagname_list question %}
{% for tag in question.tagnames %}
<!--todo - move trans below to blocktrans -->
- <a href="{% url tag_questions tag|urlencode %}" title="{% trans "see questions tagged" %} '{{ tag }}' {% trans "using tags" %}" rel="tag">{{ tag }}</a>
+ <a href="{% url questions %}?tags={{tag|urlencode}}" title="{% blocktrans %}see questions tagged '{{ tag }}'{% endblocktrans %}" rel="tag">{{ tag }}</a>
{% endfor %}
</div>
<div class="started">
diff --git a/forum/sql_scripts/091111_upgrade_evgeny.sql b/forum/sql_scripts/091111_upgrade_evgeny.sql
new file mode 100644
index 00000000..cb76ec3c
--- /dev/null
+++ b/forum/sql_scripts/091111_upgrade_evgeny.sql
@@ -0,0 +1 @@
+ALTER TABLE `auth_user` add column is_approved tinyint(1) not NULL;
diff --git a/forum/sql_scripts/091208_upgrade_evgeny.sql b/forum/sql_scripts/091208_upgrade_evgeny.sql
new file mode 100644
index 00000000..d9c4289a
--- /dev/null
+++ b/forum/sql_scripts/091208_upgrade_evgeny.sql
@@ -0,0 +1 @@
+ALTER TABLE `auth_user` add column hide_ignored_questions tinyint(1) not NULL;
diff --git a/forum/sql_scripts/091208_upgrade_evgeny_1.sql b/forum/sql_scripts/091208_upgrade_evgeny_1.sql
new file mode 100644
index 00000000..b1b4107f
--- /dev/null
+++ b/forum/sql_scripts/091208_upgrade_evgeny_1.sql
@@ -0,0 +1 @@
+ALTER TABLE `auth_user` add column `tag_filter_setting` varchar(16) not NULL default 'ignored';
diff --git a/forum/sql_scripts/100108_upgrade_ef.sql b/forum/sql_scripts/100108_upgrade_ef.sql
new file mode 100644
index 00000000..1c9a5c1c
--- /dev/null
+++ b/forum/sql_scripts/100108_upgrade_ef.sql
@@ -0,0 +1,4 @@
+alter table auth_user add column hide_ignored_questions tinyint(1) not NULL;
+update auth_user set hide_ignored_questions=0;
+alter table auth_user add column tag_filter_setting varchar(16) not NULL;
+update auth_user set tag_filter_setting='ignored';
diff --git a/forum/sql_scripts/badges.sql b/forum/sql_scripts/badges.sql
new file mode 100644
index 00000000..5fd03d18
--- /dev/null
+++ b/forum/sql_scripts/badges.sql
@@ -0,0 +1,37 @@
+INSERT INTO badge ( id, name, type, slug, description, multiple, awarded_count) VALUES
+(1, 'Disciplined', 3, 'disciplined', 'Deleted own post with score of 3 or higher', TRUE, 0),
+(2, 'Peer Pressure', 3, 'peer-pressure', 'Deleted own post with score of -3 or lower', TRUE, 0),
+(3, 'Nice answer', 3, 'nice-answer', 'Answer voted up 10 times', TRUE, 0),
+(4, 'Nice Question', 3, 'nice-question', 'Question voted up 10 times', TRUE, 0),
+(5, 'Pundit', 3, 'pundit', 'Left 10 comments with score of 10 or more', FALSE, 0),
+(6, 'Popular Question', 3, 'popular-question', 'Asked a question with 1,000 views', TRUE, 0),
+(7, 'Citizen patrol', 3, 'citizen-patrol', 'First flagged post', FALSE, 0),
+(8, 'Cleanup', 3, 'cleanup', 'First rollback', FALSE, 0),
+(9, 'Critic', 3, 'critic', 'First down vote', FALSE, 0),
+(10, 'Editor', 3, 'editor', 'First edit', FALSE, 0),
+(11, 'Organizer', 3, 'organizer', 'First retag', FALSE, 0),
+(12, 'Scholar', 3, 'scholar', 'First accepted answer on your own question', FALSE, 0),
+(13, 'Student', 3, 'student', 'Asked first question with at least one up vote', FALSE, 0),
+(14, 'Supporter', 3, 'supporter', 'First up vote', FALSE, 0),
+(15, 'Teacher', 3, 'teacher', 'Answered first question with at least one up vote', FALSE, 0),
+(16, 'Autobiographer', 3, 'autobiographer', 'Completed all user profile fields', FALSE, 0),
+(17, 'Self-Learner', 3, 'self-learner', 'Answered your own question with at least 3 up votes', TRUE, 0),
+(18, 'Great Answer', 1, 'great-answer', 'Answer voted up 100 times', TRUE, 0),
+(19, 'Great Question', 1, 'great-question', 'Question voted up 100 times', TRUE, 0),
+(20, 'Stellar Question', 1, 'stellar-question', 'Question favorited by 100 users', TRUE, 0),
+(21, 'Famous question', 1, 'famous-question', 'Asked a question with 10,000 views', TRUE, 0),
+(22, 'Alpha', 2, 'alpha', 'Actively participated in the private alpha', FALSE, 0),
+(23, 'Good Answer', 2, 'good-answer', 'Answer voted up 25 times', TRUE, 0),
+(24, 'Good Question', 2, 'good-question', 'Question voted up 25 times', TRUE, 0),
+(25, 'Favorite Question', 2, 'favorite-question', 'Question favorited by 25 users', TRUE, 0),
+(26, 'Civic duty', 2, 'civic-duty', 'Voted 300 times', FALSE, 0),
+(27, 'Strunk & White', 2, 'strunk-and-white', 'Edited 100 entries', FALSE, 0),
+(28, 'Generalist', 2, 'generalist', 'Active in many different tags', FALSE, 0),
+(29, 'Expert', 2, 'export', 'Very active in one tag', FALSE, 0),
+(30, 'Yearling', 2, 'yearling', 'Active member for a year', FALSE, 0),
+(31, 'Notable Question', 2, 'notable-question', 'Asked a question with 2,500 views', TRUE, 0),
+(32, 'Enlightened', 2, 'enlightened', 'First answer was accepted with at least 10 up votes', FALSE, 0),
+(33, 'Beta', 2, 'beta', 'Actively participated in the private beta', FALSE, 0),
+(34, 'Guru', 2, 'guru', 'Accepted answer and voted up 40 times', TRUE, 0),
+(35, 'Necromancer', 2, 'necromancer', 'Answered a question more than 60 days later with at least 5 votes', TRUE, 0),
+(36, 'Taxonomist', 2, 'taxonomist', 'Created a tag used by 50 questions', TRUE, 0);
diff --git a/forum/sql_scripts/cnprog.xml b/forum/sql_scripts/cnprog.xml
new file mode 100644
index 00000000..95f9b362
--- /dev/null
+++ b/forum/sql_scripts/cnprog.xml
@@ -0,0 +1,1498 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Db flnm="cnprog" nm="cnprog" ver="1.3.4">
+<VerLbl></VerLbl>
+<VerNotes></VerNotes>
+<DefTblOpts></DefTblOpts>
+<DocFolder>/Users/sailing/Development/cnprog_beta2/sql_scripts</DocFolder>
+<Sch Cm="" nm="schemaA">
+<Tbl UsSo="1" nm="activity">
+<TblOpts>ENGINE=MyISAM AUTO_INCREMENT=103 DEFAULT CHARSET=latin1</TblOpts>
+<Pk ClNs="id" nm="pkactivity"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="activity_type" nu="0">
+<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="active_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="content_type_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="object_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="0" nm="is_auditted" nu="1">
+<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_activity_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="activity" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="activity_content_type_id" unq="0">
+<ClNs>content_type_id</ClNs>
+</Idx>
+<Idx clu="0" nm="activity_user_id" unq="0">
+<ClNs>user_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="answer">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkanswer"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="question_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="author_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="added_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="wiki" nu="0">
+<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="wikified_at" nu="1">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="accepted" nu="0">
+<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="deleted" nu="0">
+<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="deleted_by_id" nu="1">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="locked" nu="0">
+<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="locked_by_id" nu="1">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="locked_at" nu="1">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="score" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="comment_count" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="" nm="offensive_flag_count" nu="0">
+<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="last_edited_at" nu="1">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="last_edited_by_id" nu="1">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="html" nu="0">
+<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="vote_up_count" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="vote_down_count" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="accepted_at" nu="1">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="deleted_by_id_refs_id_192b0170" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="1"/>
+<CdTb mn="1" nm="answer" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="deleted_by_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_answer_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="answer" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="author_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_answer_question" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="question" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="answer" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="question_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="last_edited_by_id_refs_id_192b0170" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="1"/>
+<CdTb mn="1" nm="answer" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="last_edited_by_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="locked_by_id_refs_id_192b0170" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="1"/>
+<CdTb mn="1" nm="answer" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="locked_by_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="answer_author_id" unq="0">
+<ClNs>author_id</ClNs>
+</Idx>
+<Idx clu="0" nm="answer_deleted_by_id" unq="0">
+<ClNs>deleted_by_id</ClNs>
+</Idx>
+<Idx clu="0" nm="answer_last_edited_by_id" unq="0">
+<ClNs>last_edited_by_id</ClNs>
+</Idx>
+<Idx clu="0" nm="answer_locked_by_id" unq="0">
+<ClNs>locked_by_id</ClNs>
+</Idx>
+<Idx clu="0" nm="answer_question_id" unq="0">
+<ClNs>question_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="answer_revision">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci</TblOpts>
+<Pk ClNs="id" nm="pkanswer_revision"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="answer_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="revision" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="" nm="author_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="revised_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="summary" nu="0">
+<DT ds="VarChar" en="" id="12" ln="300" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="text" nu="0">
+<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_answer_revision_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="answer_revision" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="author_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="answer_revision_answer_id" unq="0">
+<ClNs>answer_id</ClNs>
+</Idx>
+<Idx clu="0" nm="answer_revision_author_id" unq="0">
+<ClNs>author_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="auth_group">
+<TblOpts>ENGINE=InnoDB DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkauth_group"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="name" nu="0">
+<DT ds="VarChar" en="" id="12" ln="80" sc="null" sg="1"/>
+</Cl>
+<Idx clu="0" nm="name" unq="1">
+<ClNs>name</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="auth_group_permissions">
+<TblOpts>ENGINE=InnoDB DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkauth_group_permissions"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="group_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="permission_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_auth_group_permissions_auth_group" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_group" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="auth_group_permissions" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="group_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_auth_group_permissions_auth_permission" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_permission" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="auth_group_permissions" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="permission_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="group_id" unq="1">
+<ClNs>group_id, permission_id</ClNs>
+</Idx>
+<Idx clu="0" nm="permission_id_refs_id_5886d21f" unq="0">
+<ClNs>permission_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="auth_message">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkauth_message"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="message" nu="0">
+<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_auth_message_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="auth_message" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="auth_message_user_id" unq="0">
+<ClNs>user_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="auth_permission">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=88 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkauth_permission"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="name" nu="0">
+<DT ds="VarChar" en="" id="12" ln="50" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="content_type_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="codename" nu="0">
+<DT ds="VarChar" en="" id="12" ln="100" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_auth_permission_django_content_type" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="django_content_type" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="auth_permission" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="content_type_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="auth_permission_content_type_id" unq="0">
+<ClNs>content_type_id</ClNs>
+</Idx>
+<Idx clu="0" nm="content_type_id" unq="1">
+<ClNs>content_type_id, codename</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="auth_user">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=104 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkauth_user"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="username" nu="0">
+<DT ds="VarChar" en="" id="12" ln="30" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="first_name" nu="0">
+<DT ds="VarChar" en="" id="12" ln="30" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="last_name" nu="0">
+<DT ds="VarChar" en="" id="12" ln="30" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="email" nu="0">
+<DT ds="VarChar" en="" id="12" ln="75" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="password" nu="0">
+<DT ds="VarChar" en="" id="12" ln="128" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="is_staff" nu="0">
+<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="is_active" nu="0">
+<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="is_superuser" nu="0">
+<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="last_login" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="date_joined" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="0" nm="gold" nu="0">
+<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="0" nm="silver" nu="0">
+<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="0" nm="bronze" nu="0">
+<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="1" nm="reputation" nu="1">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="" nm="gravatar" nu="1">
+<DT ds="VarChar" en="" id="12" ln="128" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="10" nm="questions_per_page" nu="1">
+<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="" nm="last_seen" nu="1">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="real_name" nu="1">
+<DT ds="VarChar" en="" id="12" ln="100" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="website" nu="1">
+<DT ds="VarChar" en="" id="12" ln="200" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="location" nu="1">
+<DT ds="VarChar" en="" id="12" ln="100" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="date_of_birth" nu="1">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="about" nu="1">
+<DT ds="Text" en="" id="703" ln="null" sc="null" sg="1"/>
+</Cl>
+<Idx clu="0" nm="username" unq="1">
+<ClNs>username</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="auth_user_groups">
+<TblOpts>ENGINE=InnoDB DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkauth_user_groups"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="group_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_auth_user_groups_auth_group" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_group" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="auth_user_groups" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="group_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_auth_user_groups_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="auth_user_groups" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="group_id_refs_id_f116770" unq="0">
+<ClNs>group_id</ClNs>
+</Idx>
+<Idx clu="0" nm="user_id" unq="1">
+<ClNs>user_id, group_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="auth_user_user_permissions">
+<TblOpts>ENGINE=InnoDB DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkauth_user_user_permissions"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="permission_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_auth_user_user_permissions_auth_permission" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_permission" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="auth_user_user_permissions" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="permission_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_auth_user_user_permissions_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="auth_user_user_permissions" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="permission_id_refs_id_67e79cb" unq="0">
+<ClNs>permission_id</ClNs>
+</Idx>
+<Idx clu="0" nm="user_id" unq="1">
+<ClNs>user_id, permission_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="award">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkaward"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="badge_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="awarded_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="notified" nu="0">
+<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="content_type_id" nu="1">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="object_id" nu="1">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_award_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="award" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_award_badge" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="badge" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="award" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="badge_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="award_badge_id" unq="0">
+<ClNs>badge_id</ClNs>
+</Idx>
+<Idx clu="0" nm="award_user_id" unq="0">
+<ClNs>user_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="badge">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkbadge"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="name" nu="0">
+<DT ds="VarChar" en="" id="12" ln="50" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="type" nu="0">
+<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="slug" nu="0">
+<DT ds="VarChar" en="" id="12" ln="50" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="description" nu="0">
+<DT ds="VarChar" en="" id="12" ln="300" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="multiple" nu="0">
+<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="awarded_count" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
+</Cl>
+<Idx clu="0" nm="badge_slug" unq="0">
+<ClNs>slug</ClNs>
+</Idx>
+<Idx clu="0" nm="name" unq="1">
+<ClNs>name, type</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="book">
+<TblOpts></TblOpts>
+<Pk ClNs="id" nm="pkbook"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="title" nu="0">
+<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="short_name" nu="0">
+<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="author" nu="0">
+<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="1">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="price" nu="1">
+<DT ds="Decimal" en="" id="3" ln="10" sc="2" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="pages" nu="1">
+<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="published_at" nu="0">
+<DT ds="Date" en="" id="91" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="publication" nu="0">
+<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="cover_img" nu="1">
+<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="tagnames" nu="1">
+<DT ds="VarChar" en="" id="12" ln="125" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="added_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="last_edited_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_books_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="book" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="book_short_name_Idx" unq="1">
+<ClNs>short_name</ClNs>
+</Idx>
+<Idx clu="0" nm="fk_books_auth_user" unq="0">
+<ClNs>user_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="book_author_info">
+<TblOpts></TblOpts>
+<Pk ClNs="id" nm="pkbook_author_info"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="blog_url" nu="1">
+<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="added_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="last_edited_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="book_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_book_author_info_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="book_author_info" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_book_author_info_book" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="book" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="book_author_info" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="book_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="fk_book_author_info_auth_user" unq="0">
+<ClNs>user_id</ClNs>
+</Idx>
+<Idx clu="0" nm="fk_book_author_info_book" unq="0">
+<ClNs>book_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="book_author_rss">
+<TblOpts></TblOpts>
+<Pk ClNs="id" nm="pkbook_author_rss"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="title" nu="0">
+<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="url" nu="0">
+<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="rss_created_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="added_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="book_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_book_author_rss_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="book_author_rss" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_book_author_rss_book" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="book" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="book_author_rss" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="book_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="fk_book_author_rss_auth_user" unq="0">
+<ClNs>user_id</ClNs>
+</Idx>
+<Idx clu="0" nm="fk_book_author_rss_book" unq="0">
+<ClNs>book_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="book_question">
+<TblOpts></TblOpts>
+<Pk ClNs="id" nm="pkbook_question"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="book_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="question_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_book_question_book" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="book" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="book_question" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="book_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_book_question_question" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="question" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="book_question" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="question_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="fk_book_question_book" unq="0">
+<ClNs>book_id</ClNs>
+</Idx>
+<Idx clu="0" nm="fk_book_question_question" unq="0">
+<ClNs>question_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="comment">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkcomment"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="content_type_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="object_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="comment" nu="0">
+<DT ds="VarChar" en="" id="12" ln="300" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="added_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_comment_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="comment" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_comment_django_content_type" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="django_content_type" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="comment" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="content_type_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="comment_content_type_id" unq="0">
+<ClNs>content_type_id</ClNs>
+</Idx>
+<Idx clu="0" nm="comment_user_id" unq="0">
+<ClNs>user_id</ClNs>
+</Idx>
+<Idx clu="0" nm="content_type_id" unq="0">
+<ClNs>content_type_id, object_id, user_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="django_admin_log">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkdjango_admin_log"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="action_time" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="content_type_id" nu="1">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="object_id" nu="1">
+<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="object_repr" nu="0">
+<DT ds="VarChar" en="" id="12" ln="200" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="action_flag" nu="0">
+<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="" nm="change_message" nu="0">
+<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_django_admin_log_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="django_admin_log" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_django_admin_log_django_content_type" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="django_content_type" oe="1" sch="schemaA" zr="1"/>
+<CdTb mn="1" nm="django_admin_log" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="content_type_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="django_admin_log_content_type_id" unq="0">
+<ClNs>content_type_id</ClNs>
+</Idx>
+<Idx clu="0" nm="django_admin_log_user_id" unq="0">
+<ClNs>user_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="django_authopenid_association">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkdjango_authopenid_association"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="server_url" nu="0">
+<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="handle" nu="0">
+<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="secret" nu="0">
+<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="issued" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="lifetime" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="assoc_type" nu="0">
+<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
+</Cl>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="django_authopenid_nonce">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkdjango_authopenid_nonce"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="server_url" nu="0">
+<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="timestamp" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="salt" nu="0">
+<DT ds="VarChar" en="" id="12" ln="40" sc="null" sg="1"/>
+</Cl>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="django_authopenid_userassociation">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkdjango_authopenid_userassociation"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="openid_url" nu="0">
+<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_django_authopenid_userassociation_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="django_authopenid_userassociation" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="user_id" unq="1">
+<ClNs>user_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="django_authopenid_userpasswordqueue">
+<TblOpts>ENGINE=InnoDB DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkdjango_authopenid_userpasswordqueue"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="new_password" nu="0">
+<DT ds="VarChar" en="" id="12" ln="30" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="confirm_key" nu="0">
+<DT ds="VarChar" en="" id="12" ln="40" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_django_authopenid_userpasswordqueue_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="django_authopenid_userpasswordqueue" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="user_id" unq="1">
+<ClNs>user_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="django_content_type">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkdjango_content_type"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="name" nu="0">
+<DT ds="VarChar" en="" id="12" ln="100" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="app_label" nu="0">
+<DT ds="VarChar" en="" id="12" ln="100" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="model" nu="0">
+<DT ds="VarChar" en="" id="12" ln="100" sc="null" sg="1"/>
+</Cl>
+<Idx clu="0" nm="app_label" unq="1">
+<ClNs>app_label, model</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="django_session">
+<TblOpts>ENGINE=InnoDB DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="session_key" nm="pkdjango_session"/>
+<Cl au="0" df="" nm="session_key" nu="0">
+<DT ds="VarChar" en="" id="12" ln="40" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="session_data" nu="0">
+<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="expire_date" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="django_site">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkdjango_site"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="domain" nu="0">
+<DT ds="VarChar" en="" id="12" ln="100" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="name" nu="0">
+<DT ds="VarChar" en="" id="12" ln="50" sc="null" sg="1"/>
+</Cl>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="favorite_question">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkfavorite_question"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="question_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="added_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_favorite_question_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="favorite_question" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_favorite_question_question" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="question" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="favorite_question" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="question_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="favorite_question_question_id" unq="0">
+<ClNs>question_id</ClNs>
+</Idx>
+<Idx clu="0" nm="favorite_question_user_id" unq="0">
+<ClNs>user_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="flagged_item">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkflagged_item"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="content_type_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="object_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="flagged_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_flagged_item_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="flagged_item" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_flagged_item_django_content_type" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="django_content_type" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="flagged_item" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="content_type_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="content_type_id" unq="1">
+<ClNs>content_type_id, object_id, user_id</ClNs>
+</Idx>
+<Idx clu="0" nm="flagged_item_content_type_id" unq="0">
+<ClNs>content_type_id</ClNs>
+</Idx>
+<Idx clu="0" nm="flagged_item_user_id" unq="0">
+<ClNs>user_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="question">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkquestion"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="title" nu="0">
+<DT ds="VarChar" en="" id="12" ln="300" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="author_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="added_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="wiki" nu="0">
+<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="wikified_at" nu="1">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="answer_accepted" nu="0">
+<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="closed" nu="0">
+<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="closed_by_id" nu="1">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="closed_at" nu="1">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="close_reason" nu="1">
+<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="deleted" nu="0">
+<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="deleted_at" nu="1">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="deleted_by_id" nu="1">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="locked" nu="0">
+<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="locked_by_id" nu="1">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="locked_at" nu="1">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="score" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="answer_count" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="" nm="comment_count" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="" nm="view_count" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="" nm="offensive_flag_count" nu="0">
+<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="favourite_count" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="" nm="last_edited_at" nu="1">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="last_edited_by_id" nu="1">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="last_activity_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="last_activity_by_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="tagnames" nu="0">
+<DT ds="VarChar" en="" id="12" ln="125" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="summary" nu="0">
+<DT ds="VarChar" en="" id="12" ln="180" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="html" nu="0">
+<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="vote_up_count" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="vote_down_count" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="closed_by_id_refs_id_56e9d00c" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="1"/>
+<CdTb mn="1" nm="question" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="closed_by_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="deleted_by_id_refs_id_56e9d00c" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="1"/>
+<CdTb mn="1" nm="question" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="deleted_by_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_question_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="question" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="author_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="last_activity_by_id_refs_id_56e9d00c" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="question" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="last_activity_by_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="last_edited_by_id_refs_id_56e9d00c" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="1"/>
+<CdTb mn="1" nm="question" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="last_edited_by_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="locked_by_id_refs_id_56e9d00c" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="1"/>
+<CdTb mn="1" nm="question" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="locked_by_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="question_author_id" unq="0">
+<ClNs>author_id</ClNs>
+</Idx>
+<Idx clu="0" nm="question_closed_by_id" unq="0">
+<ClNs>closed_by_id</ClNs>
+</Idx>
+<Idx clu="0" nm="question_deleted_by_id" unq="0">
+<ClNs>deleted_by_id</ClNs>
+</Idx>
+<Idx clu="0" nm="question_last_activity_by_id" unq="0">
+<ClNs>last_activity_by_id</ClNs>
+</Idx>
+<Idx clu="0" nm="question_last_edited_by_id" unq="0">
+<ClNs>last_edited_by_id</ClNs>
+</Idx>
+<Idx clu="0" nm="question_locked_by_id" unq="0">
+<ClNs>locked_by_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="question_revision">
+<TblOpts>ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1</TblOpts>
+<Pk ClNs="id" nm="pkquestion_revision"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="question_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="revision" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="" nm="title" nu="0">
+<DT ds="VarChar" en="" id="12" ln="300" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="author_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="revised_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="tagnames" nu="0">
+<DT ds="VarChar" en="" id="12" ln="125" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="summary" nu="0">
+<DT ds="VarChar" en="" id="12" ln="300" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="text" nu="0">
+<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_question_revision_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="question_revision" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="author_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_question_revision_question" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="question" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="question_revision" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="question_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="question_revision_author_id" unq="0">
+<ClNs>author_id</ClNs>
+</Idx>
+<Idx clu="0" nm="question_revision_question_id" unq="0">
+<ClNs>question_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="question_tags">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkquestion_tags"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="question_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="tag_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_question_tags_question" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="question" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="question_tags" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="question_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_question_tags_tag" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="tag" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="question_tags" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="tag_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="question_id" unq="1">
+<ClNs>question_id, tag_id</ClNs>
+</Idx>
+<Idx clu="0" nm="tag_id_refs_id_43fcb953" unq="0">
+<ClNs>tag_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="repute">
+<TblOpts>ENGINE=MyISAM AUTO_INCREMENT=17 DEFAULT CHARSET=latin1</TblOpts>
+<Pk ClNs="id" nm="pkrepute"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="positive" nu="0">
+<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="negative" nu="0">
+<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="question_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="reputed_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="reputation_type" nu="0">
+<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="reputation" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_repute_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="repute" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_repute_question" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="question" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="repute" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="question_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="repute_question_id" unq="0">
+<ClNs>question_id</ClNs>
+</Idx>
+<Idx clu="0" nm="repute_user_id" unq="0">
+<ClNs>user_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="tag">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pktag"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="name" nu="0">
+<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="created_by_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="used_count" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
+</Cl>
+<Fk deAc="3" nm="fk_tag_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="tag" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="created_by_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="name" unq="1">
+<ClNs>name</ClNs>
+</Idx>
+<Idx clu="0" nm="tag_created_by_id" unq="0">
+<ClNs>created_by_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="user_badge">
+<TblOpts>ENGINE=InnoDB DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkuser_badge"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="badge_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_user_badge_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="user_badge" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_user_badge_badge" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="badge" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="user_badge" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="badge_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="fk_user_badge_auth_user" unq="0">
+<ClNs>user_id</ClNs>
+</Idx>
+<Idx clu="0" nm="fk_user_badge_badge" unq="0">
+<ClNs>badge_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="user_favorite_questions">
+<TblOpts>ENGINE=InnoDB DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkuser_favorite_questions"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="question_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_user_favorite_questions_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="user_favorite_questions" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_user_favorite_questions_question" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="question" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="user_favorite_questions" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="question_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="fk_user_favorite_questions_auth_user" unq="0">
+<ClNs>user_id</ClNs>
+</Idx>
+<Idx clu="0" nm="fk_user_favorite_questions_question" unq="0">
+<ClNs>question_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+<Tbl UsSo="1" nm="vote">
+<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8</TblOpts>
+<Pk ClNs="id" nm="pkvote"/>
+<Cl au="1" df="" nm="id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="content_type_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="object_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
+</Cl>
+<Cl au="0" df="" nm="user_id" nu="0">
+<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="vote" nu="0">
+<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
+</Cl>
+<Cl au="0" df="" nm="voted_at" nu="0">
+<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
+</Cl>
+<Fk deAc="3" nm="fk_vote_auth_user" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="vote" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="user_id" prCl="id"/>
+</Fk>
+<Fk deAc="3" nm="fk_vote_django_content_type" prLkCl="id" upAc="3">
+<PrTb mn="0" nm="django_content_type" oe="1" sch="schemaA" zr="0"/>
+<CdTb mn="1" nm="vote" oe="1" sch="schemaA" zr="1"/>
+<ClPr cdCl="content_type_id" prCl="id"/>
+</Fk>
+<Idx clu="0" nm="content_type_id" unq="1">
+<ClNs>content_type_id, object_id, user_id</ClNs>
+</Idx>
+<Idx clu="0" nm="vote_content_type_id" unq="0">
+<ClNs>content_type_id</ClNs>
+</Idx>
+<Idx clu="0" nm="vote_user_id" unq="0">
+<ClNs>user_id</ClNs>
+</Idx>
+<SchTrHis/>
+</Tbl>
+</Sch>
+<Dgm nm="diagramA">
+<RnCf FtSz="12" lkStgy="OffsetDirect" zm="1.0">
+<VbCfg>
+<Fg ky="Auto Number" vl="0"/>
+<Fg ky="Check" vl="0"/>
+<Fg ky="Comment" vl="0"/>
+<Fg ky="Data Type" vl="1"/>
+<Fg ky="Default" vl="0"/>
+<Fg ky="ENUM Values" vl="0"/>
+<Fg ky="Length" vl="1"/>
+<Fg ky="Name" vl="1"/>
+<Fg ky="Nullable" vl="0"/>
+<Fg ky="Schema Name" vl="0"/>
+<Fg ky="Signed" vl="0"/>
+</VbCfg>
+</RnCf>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="activity" x="811" y="284"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="answer" x="413" y="472"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="answer_revision" x="1067" y="41"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="auth_group" x="593" y="703"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="auth_group_permissions" x="765" y="703"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="auth_message" x="323" y="1441"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="auth_permission" x="636" y="794"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="auth_user" x="50" y="50"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="auth_user_groups" x="403" y="703"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="auth_user_user_permissions" x="393" y="794"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="award" x="373" y="971"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="badge" x="606" y="971"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="comment" x="383" y="880"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="django_admin_log" x="363" y="1087"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="django_authopenid_association" x="1543" y="50"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="django_authopenid_nonce" x="1781" y="50"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="django_authopenid_userassociation" x="313" y="1502"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="django_authopenid_userpasswordqueue" x="303" y="1563"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="django_content_type" x="636" y="880"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="django_session" x="1088" y="222"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="django_site" x="1312" y="152"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="favorite_question" x="433" y="50"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="flagged_item" x="353" y="1198"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="question" x="423" y="121"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="question_revision" x="1380" y="241"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="question_tags" x="736" y="121"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="repute" x="1661" y="180"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="tag" x="343" y="1279"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="user_badge" x="916" y="200"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="user_favorite_questions" x="1070" y="366"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="vote" x="93" y="1341"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="book" x="962" y="1063"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="book_question" x="702" y="1160"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="book_author_info" x="931" y="1436"/>
+<TbGl bkCl="ffffffe6" sch="schemaA" tbl="book_author_rss" x="619" y="1321"/>
+<FkGl bkCl="ff000000" nm="schemaA.activity.fk_activity_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.answer.deleted_by_id_refs_id_192b0170"/>
+<FkGl bkCl="ff000000" nm="schemaA.answer.fk_answer_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.answer.fk_answer_question"/>
+<FkGl bkCl="ff000000" nm="schemaA.answer.last_edited_by_id_refs_id_192b0170"/>
+<FkGl bkCl="ff000000" nm="schemaA.answer.locked_by_id_refs_id_192b0170"/>
+<FkGl bkCl="ff000000" nm="schemaA.answer_revision.fk_answer_revision_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.auth_group_permissions.fk_auth_group_permissions_auth_group"/>
+<FkGl bkCl="ff000000" nm="schemaA.auth_group_permissions.fk_auth_group_permissions_auth_permission"/>
+<FkGl bkCl="ff000000" nm="schemaA.auth_message.fk_auth_message_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.auth_permission.fk_auth_permission_django_content_type"/>
+<FkGl bkCl="ff000000" nm="schemaA.auth_user_groups.fk_auth_user_groups_auth_group"/>
+<FkGl bkCl="ff000000" nm="schemaA.auth_user_groups.fk_auth_user_groups_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.auth_user_user_permissions.fk_auth_user_user_permissions_auth_permission"/>
+<FkGl bkCl="ff000000" nm="schemaA.auth_user_user_permissions.fk_auth_user_user_permissions_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.award.fk_award_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.award.fk_award_badge"/>
+<FkGl bkCl="ff000000" nm="schemaA.book.fk_books_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.book_author_info.fk_book_author_info_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.book_author_info.fk_book_author_info_book"/>
+<FkGl bkCl="ff000000" nm="schemaA.book_author_rss.fk_book_author_rss_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.book_author_rss.fk_book_author_rss_book"/>
+<FkGl bkCl="ff000000" nm="schemaA.book_question.fk_book_question_book"/>
+<FkGl bkCl="ff000000" nm="schemaA.book_question.fk_book_question_question"/>
+<FkGl bkCl="ff000000" nm="schemaA.comment.fk_comment_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.comment.fk_comment_django_content_type"/>
+<FkGl bkCl="ff000000" nm="schemaA.django_admin_log.fk_django_admin_log_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.django_admin_log.fk_django_admin_log_django_content_type"/>
+<FkGl bkCl="ff000000" nm="schemaA.django_authopenid_userassociation.fk_django_authopenid_userassociation_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.django_authopenid_userpasswordqueue.fk_django_authopenid_userpasswordqueue_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.favorite_question.fk_favorite_question_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.favorite_question.fk_favorite_question_question"/>
+<FkGl bkCl="ff000000" nm="schemaA.flagged_item.fk_flagged_item_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.flagged_item.fk_flagged_item_django_content_type"/>
+<FkGl bkCl="ff000000" nm="schemaA.question.closed_by_id_refs_id_56e9d00c"/>
+<FkGl bkCl="ff000000" nm="schemaA.question.deleted_by_id_refs_id_56e9d00c"/>
+<FkGl bkCl="ff000000" nm="schemaA.question.fk_question_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.question.last_activity_by_id_refs_id_56e9d00c"/>
+<FkGl bkCl="ff000000" nm="schemaA.question.last_edited_by_id_refs_id_56e9d00c"/>
+<FkGl bkCl="ff000000" nm="schemaA.question.locked_by_id_refs_id_56e9d00c"/>
+<FkGl bkCl="ff000000" nm="schemaA.question_revision.fk_question_revision_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.question_revision.fk_question_revision_question"/>
+<FkGl bkCl="ff000000" nm="schemaA.question_tags.fk_question_tags_question"/>
+<FkGl bkCl="ff000000" nm="schemaA.question_tags.fk_question_tags_tag"/>
+<FkGl bkCl="ff000000" nm="schemaA.repute.fk_repute_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.repute.fk_repute_question"/>
+<FkGl bkCl="ff000000" nm="schemaA.tag.fk_tag_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.user_badge.fk_user_badge_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.user_badge.fk_user_badge_badge"/>
+<FkGl bkCl="ff000000" nm="schemaA.user_favorite_questions.fk_user_favorite_questions_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.user_favorite_questions.fk_user_favorite_questions_question"/>
+<FkGl bkCl="ff000000" nm="schemaA.vote.fk_vote_auth_user"/>
+<FkGl bkCl="ff000000" nm="schemaA.vote.fk_vote_django_content_type"/>
+</Dgm>
+<RnmMgr NxRnmId="6">
+<RnmCh ObjCls="Table" ParCls="Schema" ParNme="schemaA" SupCls="" SupNme="">
+<Rnm id="1" nNm="book" oNm="books"/>
+</RnmCh>
+<RnmCh ObjCls="Table" ParCls="Schema" ParNme="schemaA" SupCls="" SupNme="">
+<Rnm id="2" nNm="book_question" oNm="books_questions"/>
+</RnmCh>
+<RnmCh ObjCls="Column" ParCls="Table" ParNme="book_question" SupCls="Schema" SupNme="schemaA">
+<Rnm id="3" nNm="id" oNm="books_questions_id"/>
+</RnmCh>
+<RnmCh ObjCls="Column" ParCls="Table" ParNme="book_author_rss" SupCls="Schema" SupNme="schemaA">
+<Rnm id="4" nNm="user_id" oNm="book_author_id"/>
+</RnmCh>
+<RnmCh ObjCls="Column" ParCls="Table" ParNme="book" SupCls="Schema" SupNme="schemaA">
+<Rnm id="5" nNm="short_name" oNm="shot_name"/>
+</RnmCh>
+</RnmMgr>
+<DbDocOptionMgr>
+<BasicOptionMgr>
+<Name>db.doc.option.mgr</Name>
+<BoolOpt lbl="Diagrams" nm="doc.diagrams" on="1" spl="0"/>
+<BoolOpt lbl="Foreign Keys" nm="doc.fks" on="1" spl="0"/>
+<BoolOpt lbl="Indexes" nm="doc.indexes" on="1" spl="0"/>
+<BoolOpt lbl="Overwrite CSS File" nm="doc.overwrite.css" on="1" spl="0"/>
+<BoolOpt lbl="Procedures" nm="doc.procs" on="1" spl="0"/>
+<BoolOpt lbl="Schemas" nm="doc.schemas" on="1" spl="0"/>
+<BoolOpt lbl="Sequences" nm="doc.sequences" on="1" spl="0"/>
+<BoolOpt lbl="Tables" nm="doc.tables" on="1" spl="0"/>
+<BoolOpt lbl="Triggers" nm="doc.triggers" on="1" spl="0"/>
+<BoolOpt lbl="Views" nm="doc.views" on="1" spl="0"/>
+</BasicOptionMgr>
+</DbDocOptionMgr>
+</Db>
diff --git a/forum/sql_scripts/cnprog_new_install.sql b/forum/sql_scripts/cnprog_new_install.sql
new file mode 100644
index 00000000..ac33a6ba
--- /dev/null
+++ b/forum/sql_scripts/cnprog_new_install.sql
@@ -0,0 +1,811 @@
+-- MySQL Administrator dump 1.4
+--
+-- ------------------------------------------------------
+-- Server version 5.0.67
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+
+
+--
+-- Create schema cnprog
+--
+
+CREATE DATABASE IF NOT EXISTS cnprog;
+USE cnprog;
+
+--
+-- Definition of table `cnprog`.`answer`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`answer`;
+CREATE TABLE `cnprog`.`answer` (
+ `id` int(11) NOT NULL auto_increment,
+ `question_id` int(11) NOT NULL,
+ `author_id` int(11) NOT NULL,
+ `added_at` datetime NOT NULL,
+ `wiki` tinyint(1) NOT NULL,
+ `wikified_at` datetime default NULL,
+ `accepted` tinyint(1) NOT NULL,
+ `deleted` tinyint(1) NOT NULL,
+ `deleted_by_id` int(11) default NULL,
+ `locked` tinyint(1) NOT NULL,
+ `locked_by_id` int(11) default NULL,
+ `locked_at` datetime default NULL,
+ `score` int(11) NOT NULL,
+ `vote_up_count` int(11) NOT NULL,
+ `vote_down_count` int(11) NOT NULL,
+ `comment_count` int(10) unsigned NOT NULL,
+ `offensive_flag_count` smallint(6) NOT NULL,
+ `last_edited_at` datetime default NULL,
+ `last_edited_by_id` int(11) default NULL,
+ `html` longtext NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `answer_question_id` (`question_id`),
+ KEY `answer_author_id` (`author_id`),
+ KEY `answer_deleted_by_id` (`deleted_by_id`),
+ KEY `answer_locked_by_id` (`locked_by_id`),
+ KEY `answer_last_edited_by_id` (`last_edited_by_id`),
+ CONSTRAINT `author_id_refs_id_192b0170` FOREIGN KEY (`author_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `deleted_by_id_refs_id_192b0170` FOREIGN KEY (`deleted_by_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `last_edited_by_id_refs_id_192b0170` FOREIGN KEY (`last_edited_by_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `locked_by_id_refs_id_192b0170` FOREIGN KEY (`locked_by_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `question_id_refs_id_7d6550c9` FOREIGN KEY (`question_id`) REFERENCES `question` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;
+
+--
+-- Definition of table `cnprog`.`auth_group`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`auth_group`;
+CREATE TABLE `cnprog`.`auth_group` (
+ `id` int(11) NOT NULL auto_increment,
+ `name` varchar(80) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name` (`name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`auth_group`
+--
+
+--
+-- Definition of table `cnprog`.`auth_group_permissions`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`auth_group_permissions`;
+CREATE TABLE `cnprog`.`auth_group_permissions` (
+ `id` int(11) NOT NULL auto_increment,
+ `group_id` int(11) NOT NULL,
+ `permission_id` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `group_id` (`group_id`,`permission_id`),
+ KEY `permission_id_refs_id_5886d21f` (`permission_id`),
+ CONSTRAINT `group_id_refs_id_3cea63fe` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`),
+ CONSTRAINT `permission_id_refs_id_5886d21f` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`auth_group_permissions`
+--
+
+--
+-- Definition of table `cnprog`.`auth_message`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`auth_message`;
+CREATE TABLE `cnprog`.`auth_message` (
+ `id` int(11) NOT NULL auto_increment,
+ `user_id` int(11) NOT NULL,
+ `message` longtext NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `auth_message_user_id` (`user_id`),
+ CONSTRAINT `user_id_refs_id_650f49a6` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`auth_message`
+--
+
+--
+-- Definition of table `cnprog`.`auth_permission`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`auth_permission`;
+CREATE TABLE `cnprog`.`auth_permission` (
+ `id` int(11) NOT NULL auto_increment,
+ `name` varchar(50) NOT NULL,
+ `content_type_id` int(11) NOT NULL,
+ `codename` varchar(100) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `content_type_id` (`content_type_id`,`codename`),
+ KEY `auth_permission_content_type_id` (`content_type_id`),
+ CONSTRAINT `content_type_id_refs_id_728de91f` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=76 DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`auth_permission`
+--
+INSERT INTO `cnprog`.`auth_permission` VALUES (1,'Can add permission',1,'add_permission'),
+ (2,'Can change permission',1,'change_permission'),
+ (3,'Can delete permission',1,'delete_permission'),
+ (4,'Can add group',2,'add_group'),
+ (5,'Can change group',2,'change_group'),
+ (6,'Can delete group',2,'delete_group'),
+ (7,'Can add user',3,'add_user'),
+ (8,'Can change user',3,'change_user'),
+ (9,'Can delete user',3,'delete_user'),
+ (10,'Can add message',4,'add_message'),
+ (11,'Can change message',4,'change_message'),
+ (12,'Can delete message',4,'delete_message'),
+ (13,'Can add content type',5,'add_contenttype'),
+ (14,'Can change content type',5,'change_contenttype'),
+ (15,'Can delete content type',5,'delete_contenttype'),
+ (16,'Can add session',6,'add_session'),
+ (17,'Can change session',6,'change_session'),
+ (18,'Can delete session',6,'delete_session'),
+ (19,'Can add site',7,'add_site'),
+ (20,'Can change site',7,'change_site'),
+ (21,'Can delete site',7,'delete_site'),
+ (25,'Can add answer',9,'add_answer'),
+ (26,'Can change answer',9,'change_answer'),
+ (27,'Can delete answer',9,'delete_answer'),
+ (28,'Can add comment',10,'add_comment'),
+ (29,'Can change comment',10,'change_comment'),
+ (30,'Can delete comment',10,'delete_comment'),
+ (31,'Can add tag',11,'add_tag'),
+ (32,'Can change tag',11,'change_tag'),
+ (33,'Can delete tag',11,'delete_tag'),
+ (37,'Can add nonce',13,'add_nonce'),
+ (38,'Can change nonce',13,'change_nonce'),
+ (39,'Can delete nonce',13,'delete_nonce'),
+ (40,'Can add association',14,'add_association'),
+ (41,'Can change association',14,'change_association'),
+ (42,'Can delete association',14,'delete_association'),
+ (43,'Can add nonce',15,'add_nonce'),
+ (44,'Can change nonce',15,'change_nonce'),
+ (45,'Can delete nonce',15,'delete_nonce'),
+ (46,'Can add association',16,'add_association'),
+ (47,'Can change association',16,'change_association'),
+ (48,'Can delete association',16,'delete_association'),
+ (49,'Can add user association',17,'add_userassociation'),
+ (50,'Can change user association',17,'change_userassociation'),
+ (51,'Can delete user association',17,'delete_userassociation'),
+ (52,'Can add user password queue',18,'add_userpasswordqueue'),
+ (53,'Can change user password queue',18,'change_userpasswordqueue'),
+ (54,'Can delete user password queue',18,'delete_userpasswordqueue'),
+ (55,'Can add log entry',19,'add_logentry'),
+ (56,'Can change log entry',19,'change_logentry'),
+ (57,'Can delete log entry',19,'delete_logentry'),
+ (58,'Can add question',20,'add_question'),
+ (59,'Can change question',20,'change_question'),
+ (60,'Can delete question',20,'delete_question'),
+ (61,'Can add vote',21,'add_vote'),
+ (62,'Can change vote',21,'change_vote'),
+ (63,'Can delete vote',21,'delete_vote'),
+ (64,'Can add flagged item',22,'add_flaggeditem'),
+ (65,'Can change flagged item',22,'change_flaggeditem'),
+ (66,'Can delete flagged item',22,'delete_flaggeditem'),
+ (67,'Can add favorite question',23,'add_favoritequestion'),
+ (68,'Can change favorite question',23,'change_favoritequestion'),
+ (69,'Can delete favorite question',23,'delete_favoritequestion'),
+ (70,'Can add badge',24,'add_badge'),
+ (71,'Can change badge',24,'change_badge'),
+ (72,'Can delete badge',24,'delete_badge'),
+ (73,'Can add award',25,'add_award'),
+ (74,'Can change award',25,'change_award'),
+ (75,'Can delete award',25,'delete_award');
+
+--
+-- Definition of table `cnprog`.`auth_user`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`auth_user`;
+CREATE TABLE `cnprog`.`auth_user` (
+ `id` int(11) NOT NULL auto_increment,
+ `username` varchar(30) NOT NULL,
+ `first_name` varchar(30) NOT NULL,
+ `last_name` varchar(30) NOT NULL,
+ `email` varchar(75) NOT NULL,
+ `password` varchar(128) NOT NULL,
+ `is_staff` tinyint(1) NOT NULL,
+ `is_active` tinyint(1) NOT NULL,
+ `is_superuser` tinyint(1) NOT NULL,
+ `last_login` datetime NOT NULL,
+ `date_joined` datetime NOT NULL,
+ `gold` smallint(6) NOT NULL default '0',
+ `silver` smallint(5) unsigned NOT NULL default '0',
+ `bronze` smallint(5) unsigned NOT NULL default '0',
+ `reputation` int(10) unsigned default '1',
+ `gravatar` varchar(128) default NULL,
+ `questions_per_page` smallint(5) unsigned default '10',
+ `last_seen` datetime default NULL,
+ `real_name` varchar(100) default NULL,
+ `website` varchar(200) default NULL,
+ `location` varchar(100) default NULL,
+ `date_of_birth` datetime default NULL,
+ `about` text,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `username` (`username`)
+) ENGINE=InnoDB AUTO_INCREMENT=104 DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`auth_user`
+--
+INSERT INTO `cnprog`.`auth_user` VALUES (2,'chagel','','','chagel@gmail.com','sha1$6a2fb$0d2ffe90bcba542fc962f57967a88e507799cc74',1,1,1,'2008-12-16 15:35:17','2008-12-11 20:12:53',0,0,0,1,'8c1efc4f4618aa68b18c88f2bcaa5564',10,NULL,NULL,NULL,NULL,NULL,NULL),
+ (3,'mike','','','ichagel@yahoo.com','sha1$f7ef5$1015ae6b2c8a2774a028419d3c57e13145b83284',0,1,0,'2008-12-15 12:56:23','2008-12-15 12:56:23',0,0,0,1,NULL,10,NULL,NULL,NULL,NULL,NULL,NULL),
+ (4,'sailingcai','','','sailingcai@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-23 06:14:45','2008-12-20 15:19:21',1,2,3,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','',NULL,''),
+ (5,'sailingcai1','','','1@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21',NULL,NULL,NULL,NULL,NULL),
+ (6,'sailing2','','','2@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (7,'sailing3','','','3@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (8,'sailing4','','','4@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (9,'sailing5','','','5@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (10,'sailing6','','','6@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (11,'sailing7','','','7@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (12,'sailing8','','','8@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (13,'sailing9','','','9@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (14,'sailing10','','','10@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (15,'sailing11','','','11@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (16,'sailing12','','','12@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (17,'sailing13','','','13@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (18,'sailing14','','','14@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (19,'sailing15','','','15@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (20,'sailing16','','','16@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (21,'sailing17','','','17@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (22,'sailing18','','','18@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (23,'sailing19','','','19@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (24,'sailing20','','','20@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (25,'sailing21','','','21@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (26,'sailing22','','','22@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (27,'sailing23','','','23@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (28,'sailing24','','','24@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (29,'sailing25','','','25@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (30,'sailing26','','','26@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (31,'sailing27','','','27@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (32,'sailing28','','','28@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (33,'sailing29','','','29@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (34,'sailing30','','','30@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (35,'sailing31','','','31@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (36,'sailing32','','','32@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (37,'sailing33','','','33@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (38,'sailing34','','','34@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (39,'sailing35','','','35@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (40,'sailing36','','','36@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (41,'sailing37','','','37@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (42,'sailing38','','','38@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (43,'sailing39','','','39@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (44,'sailing40','','','40@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (45,'sailing41','','','41@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (46,'sailing42','','','42@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (47,'sailing43','','','43@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (48,'sailing44','','','44@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (49,'sailing45','','','45@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (50,'sailing46','','','46@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (51,'sailing47','','','47@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (52,'sailing48','','','48@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (53,'sailing49','','','49@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (54,'sailing50','','','50@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (55,'sailing51','','','51@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (56,'sailing52','','','52@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (57,'sailing53','','','53@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (58,'sailing54','','','54@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (59,'sailing55','','','55@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (60,'sailing56','','','56@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (61,'sailing57','','','57@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (62,'sailing58','','','58@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (63,'sailing59','','','59@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (64,'sailing60','','','60@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (65,'sailing61','','','61@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (66,'sailing62','','','62@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (67,'sailing63','','','63@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (68,'sailing64','','','64@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (69,'sailing65','','','65@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (70,'sailing66','','','66@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (71,'sailing67','','','67@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (72,'sailing68','','','68@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (73,'sailing69','','','69@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (74,'sailing70','','','70@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (75,'sailing71','','','71@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (76,'sailing72','','','72@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (77,'sailing73','','','73@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (78,'sailing74','','','74@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (79,'sailing75','','','75@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (80,'sailing76','','','76@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (81,'sailing77','','','77@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (82,'sailing78','','','78@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (83,'sailing79','','','79@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (84,'sailing80','','','80@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (85,'sailing81','','','81@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (86,'sailing82','','','82@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (87,'sailing83','','','83@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (88,'sailing84','','','84@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (89,'sailing85','','','85@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (90,'sailing86','','','86@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (91,'sailing87','','','87@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (92,'sailing88','','','88@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (93,'sailing89','','','89@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (94,'sailing90','','','90@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (95,'sailing91','','','91@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (96,'sailing92','','','92@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (97,'sailing93','','','93@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (98,'sailing94','','','94@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (99,'sailing95','','','95@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (100,'sailing96','','','96@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (101,'sailing97','','','97@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (102,'sailing98','','','98@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
+ (103,'sailing99','','','99@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00','');
+
+--
+-- Definition of table `cnprog`.`auth_user_groups`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`auth_user_groups`;
+CREATE TABLE `cnprog`.`auth_user_groups` (
+ `id` int(11) NOT NULL auto_increment,
+ `user_id` int(11) NOT NULL,
+ `group_id` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `user_id` (`user_id`,`group_id`),
+ KEY `group_id_refs_id_f116770` (`group_id`),
+ CONSTRAINT `group_id_refs_id_f116770` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`),
+ CONSTRAINT `user_id_refs_id_7ceef80f` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`auth_user_groups`
+--
+
+--
+-- Definition of table `cnprog`.`auth_user_user_permissions`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`auth_user_user_permissions`;
+CREATE TABLE `cnprog`.`auth_user_user_permissions` (
+ `id` int(11) NOT NULL auto_increment,
+ `user_id` int(11) NOT NULL,
+ `permission_id` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `user_id` (`user_id`,`permission_id`),
+ KEY `permission_id_refs_id_67e79cb` (`permission_id`),
+ CONSTRAINT `permission_id_refs_id_67e79cb` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`),
+ CONSTRAINT `user_id_refs_id_dfbab7d` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`auth_user_user_permissions`
+--
+
+--
+-- Definition of table `cnprog`.`award`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`award`;
+CREATE TABLE `cnprog`.`award` (
+ `id` int(11) NOT NULL auto_increment,
+ `user_id` int(11) NOT NULL,
+ `badge_id` int(11) NOT NULL,
+ `awarded_at` datetime NOT NULL,
+ `notified` tinyint(1) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `award_user_id` (`user_id`),
+ KEY `award_badge_id` (`badge_id`),
+ CONSTRAINT `badge_id_refs_id_651af0e1` FOREIGN KEY (`badge_id`) REFERENCES `badge` (`id`),
+ CONSTRAINT `user_id_refs_id_2d83e9b6` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`award`
+--
+
+--
+-- Definition of table `cnprog`.`badge`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`badge`;
+CREATE TABLE `cnprog`.`badge` (
+ `id` int(11) NOT NULL auto_increment,
+ `name` varchar(50) NOT NULL,
+ `type` smallint(6) NOT NULL,
+ `slug` varchar(50) NOT NULL,
+ `description` varchar(300) NOT NULL,
+ `multiple` tinyint(1) NOT NULL,
+ `awarded_count` int(10) unsigned NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name` (`name`,`type`),
+ KEY `badge_slug` (`slug`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`badge`
+--
+
+--
+-- Definition of table `cnprog`.`comment`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`comment`;
+CREATE TABLE `cnprog`.`comment` (
+ `id` int(11) NOT NULL auto_increment,
+ `content_type_id` int(11) NOT NULL,
+ `object_id` int(10) unsigned NOT NULL,
+ `user_id` int(11) NOT NULL,
+ `comment` varchar(300) NOT NULL,
+ `added_at` datetime NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `content_type_id` (`content_type_id`,`object_id`,`user_id`),
+ KEY `comment_content_type_id` (`content_type_id`),
+ KEY `comment_user_id` (`user_id`),
+ CONSTRAINT `content_type_id_refs_id_13a5866c` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
+ CONSTRAINT `user_id_refs_id_6be725e8` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`comment`
+--
+
+--
+-- Definition of table `cnprog`.`django_admin_log`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`django_admin_log`;
+CREATE TABLE `cnprog`.`django_admin_log` (
+ `id` int(11) NOT NULL auto_increment,
+ `action_time` datetime NOT NULL,
+ `user_id` int(11) NOT NULL,
+ `content_type_id` int(11) default NULL,
+ `object_id` longtext,
+ `object_repr` varchar(200) NOT NULL,
+ `action_flag` smallint(5) unsigned NOT NULL,
+ `change_message` longtext NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `django_admin_log_user_id` (`user_id`),
+ KEY `django_admin_log_content_type_id` (`content_type_id`),
+ CONSTRAINT `content_type_id_refs_id_288599e6` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
+ CONSTRAINT `user_id_refs_id_c8665aa` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`django_admin_log`
+--
+INSERT INTO `cnprog`.`django_admin_log` VALUES (1,'2008-12-18 23:41:41',2,7,'1','cnprog.com',2,'已修改 domain 和 name 。');
+
+--
+-- Definition of table `cnprog`.`django_authopenid_association`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`django_authopenid_association`;
+CREATE TABLE `cnprog`.`django_authopenid_association` (
+ `id` int(11) NOT NULL auto_increment,
+ `server_url` longtext NOT NULL,
+ `handle` varchar(255) NOT NULL,
+ `secret` longtext NOT NULL,
+ `issued` int(11) NOT NULL,
+ `lifetime` int(11) NOT NULL,
+ `assoc_type` longtext NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`django_authopenid_association`
+--
+INSERT INTO `cnprog`.`django_authopenid_association` VALUES (2,'https://www.google.com/accounts/o8/ud','AOQobUfcCH4sgjsBGGscrzxIa5UM4clofAB6nixx8Qq_NWco4ynn_Kc4','u5cva43abzdwF8CJOFZfkzfk7x8=\n',1229022261,1229022261,'HMAC-SHA1'),
+ (3,'https://api.screenname.aol.com/auth/openidServer','diAyLjAgayAwIGJhT2VvYkdDZ21RSHJ4QldzQnhTdjIxV3BVbz0%3D-j5HRXRB1VbPyg48jGKE1Q70dfv76lGHEPwd9071%2FJ7f6SSw5YhakrwWpsVXtr34T6iHwPDdo6RU%3D','EmQL3+5oR6mFKIaeBNy6hXyUJ/w=\n',1229282202,1229282202,'HMAC-SHA1'),
+ (4,'https://open.login.yahooapis.com/openid/op/auth','JcBeY.uWXu2YjzbuCQiqFzAb0MIc7ATeKiPO4eAp3vluPMqZp_NCxepvMLGrJjxxDKTaNnr06wepMos8ap6SQYZiTi51tZ05lMWnpZAiOA1hsq_WMlEL7G9YE66GEA9A','QXiuN6B7E8nP5QhyHI3IB26t4SA=\n',1229282256,1229282256,'HMAC-SHA1'),
+ (5,'http://openid.claimid.com/server','{HMAC-SHA1}{494575fd}{uLEbxQ==}','GvPbkgMHh0QVPH7mStCGuWb2AKY=\n',1229288957,1229288957,'HMAC-SHA1'),
+ (6,'http://www.blogger.com/openid-server.g','oida-1229424484019-158830626','8gaU4aKnIFCLKIkHdxZQp7ZGNck=\n',1229424478,1229424478,'HMAC-SHA1');
+
+--
+-- Definition of table `cnprog`.`django_authopenid_nonce`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`django_authopenid_nonce`;
+CREATE TABLE `cnprog`.`django_authopenid_nonce` (
+ `id` int(11) NOT NULL auto_increment,
+ `server_url` varchar(255) NOT NULL,
+ `timestamp` int(11) NOT NULL,
+ `salt` varchar(40) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;
+
+--
+-- Definition of table `cnprog`.`django_authopenid_userassociation`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`django_authopenid_userassociation`;
+CREATE TABLE `cnprog`.`django_authopenid_userassociation` (
+ `id` int(11) NOT NULL auto_increment,
+ `openid_url` varchar(255) NOT NULL,
+ `user_id` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `user_id` (`user_id`),
+ CONSTRAINT `user_id_refs_id_163d208d` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`django_authopenid_userassociation`
+--
+INSERT INTO `cnprog`.`django_authopenid_userassociation` VALUES (2,'https://www.google.com/accounts/o8/id?id=AItOawl7CVVHl4DWtteqj4dd_A23zKRwPZgOOjw',2),
+ (3,'https://me.yahoo.com/a/f8f2zXF91okYL4iN2Zh4P542a5s-#f4af2',3),
+ (4,'https://me.yahoo.com/sailingcai#6fa4e',4);
+
+--
+-- Definition of table `cnprog`.`django_authopenid_userpasswordqueue`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`django_authopenid_userpasswordqueue`;
+CREATE TABLE `cnprog`.`django_authopenid_userpasswordqueue` (
+ `id` int(11) NOT NULL auto_increment,
+ `user_id` int(11) NOT NULL,
+ `new_password` varchar(30) NOT NULL,
+ `confirm_key` varchar(40) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `user_id` (`user_id`),
+ CONSTRAINT `user_id_refs_id_76bcaaa4` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`django_authopenid_userpasswordqueue`
+--
+
+--
+-- Definition of table `cnprog`.`django_content_type`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`django_content_type`;
+CREATE TABLE `cnprog`.`django_content_type` (
+ `id` int(11) NOT NULL auto_increment,
+ `name` varchar(100) NOT NULL,
+ `app_label` varchar(100) NOT NULL,
+ `model` varchar(100) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `app_label` (`app_label`,`model`)
+) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`django_content_type`
+--
+INSERT INTO `cnprog`.`django_content_type` VALUES (1,'permission','auth','permission'),
+ (2,'group','auth','group'),
+ (3,'user','auth','user'),
+ (4,'message','auth','message'),
+ (5,'content type','contenttypes','contenttype'),
+ (6,'session','sessions','session'),
+ (7,'site','sites','site'),
+ (9,'answer','forum','answer'),
+ (10,'comment','forum','comment'),
+ (11,'tag','forum','tag'),
+ (13,'nonce','django_openidconsumer','nonce'),
+ (14,'association','django_openidconsumer','association'),
+ (15,'nonce','django_authopenid','nonce'),
+ (16,'association','django_authopenid','association'),
+ (17,'user association','django_authopenid','userassociation'),
+ (18,'user password queue','django_authopenid','userpasswordqueue'),
+ (19,'log entry','admin','logentry'),
+ (20,'question','forum','question'),
+ (21,'vote','forum','vote'),
+ (22,'flagged item','forum','flaggeditem'),
+ (23,'favorite question','forum','favoritequestion'),
+ (24,'badge','forum','badge'),
+ (25,'award','forum','award');
+
+--
+-- Definition of table `cnprog`.`django_session`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`django_session`;
+CREATE TABLE `cnprog`.`django_session` (
+ `session_key` varchar(40) NOT NULL,
+ `session_data` longtext NOT NULL,
+ `expire_date` datetime NOT NULL,
+ PRIMARY KEY (`session_key`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Definition of table `cnprog`.`django_site`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`django_site`;
+CREATE TABLE `cnprog`.`django_site` (
+ `id` int(11) NOT NULL auto_increment,
+ `domain` varchar(100) NOT NULL,
+ `name` varchar(50) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`django_site`
+--
+INSERT INTO `cnprog`.`django_site` VALUES (1,'cnprog.com','CNProg.com');
+
+--
+-- Definition of table `cnprog`.`favorite_question`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`favorite_question`;
+CREATE TABLE `cnprog`.`favorite_question` (
+ `id` int(11) NOT NULL auto_increment,
+ `question_id` int(11) NOT NULL,
+ `user_id` int(11) NOT NULL,
+ `added_at` datetime NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `favorite_question_question_id` (`question_id`),
+ KEY `favorite_question_user_id` (`user_id`),
+ CONSTRAINT `question_id_refs_id_1ebe1cc3` FOREIGN KEY (`question_id`) REFERENCES `question` (`id`),
+ CONSTRAINT `user_id_refs_id_52853822` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`favorite_question`
+--
+
+--
+-- Definition of table `cnprog`.`flagged_item`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`flagged_item`;
+CREATE TABLE `cnprog`.`flagged_item` (
+ `id` int(11) NOT NULL auto_increment,
+ `content_type_id` int(11) NOT NULL,
+ `object_id` int(10) unsigned NOT NULL,
+ `user_id` int(11) NOT NULL,
+ `flagged_at` datetime NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `content_type_id` (`content_type_id`,`object_id`,`user_id`),
+ KEY `flagged_item_content_type_id` (`content_type_id`),
+ KEY `flagged_item_user_id` (`user_id`),
+ CONSTRAINT `content_type_id_refs_id_76e44d74` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
+ CONSTRAINT `user_id_refs_id_35e3c608` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`flagged_item`
+--
+
+--
+-- Definition of table `cnprog`.`question`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`question`;
+CREATE TABLE `cnprog`.`question` (
+ `id` int(11) NOT NULL auto_increment,
+ `title` varchar(300) NOT NULL,
+ `author_id` int(11) NOT NULL,
+ `added_at` datetime NOT NULL,
+ `wiki` tinyint(1) NOT NULL,
+ `wikified_at` datetime default NULL,
+ `answer_accepted` tinyint(1) NOT NULL,
+ `closed` tinyint(1) NOT NULL,
+ `closed_by_id` int(11) default NULL,
+ `closed_at` datetime default NULL,
+ `close_reason` smallint(6) default NULL,
+ `deleted` tinyint(1) NOT NULL,
+ `deleted_at` datetime default NULL,
+ `deleted_by_id` int(11) default NULL,
+ `locked` tinyint(1) NOT NULL,
+ `locked_by_id` int(11) default NULL,
+ `locked_at` datetime default NULL,
+ `vote_up_count` int(11) NOT NULL,
+ `vote_down_count` int(11) NOT NULL,
+ `score` int(11) NOT NULL,
+ `answer_count` int(10) unsigned NOT NULL,
+ `comment_count` int(10) unsigned NOT NULL,
+ `view_count` int(10) unsigned NOT NULL,
+ `offensive_flag_count` smallint(6) NOT NULL,
+ `favourite_count` int(10) unsigned NOT NULL,
+ `last_edited_at` datetime default NULL,
+ `last_edited_by_id` int(11) default NULL,
+ `last_activity_at` datetime NOT NULL,
+ `last_activity_by_id` int(11) NOT NULL,
+ `tagnames` varchar(125) NOT NULL,
+ `summary` varchar(180) NOT NULL,
+ `html` longtext NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `question_author_id` (`author_id`),
+ KEY `question_closed_by_id` (`closed_by_id`),
+ KEY `question_deleted_by_id` (`deleted_by_id`),
+ KEY `question_locked_by_id` (`locked_by_id`),
+ KEY `question_last_edited_by_id` (`last_edited_by_id`),
+ KEY `question_last_activity_by_id` (`last_activity_by_id`),
+ CONSTRAINT `author_id_refs_id_56e9d00c` FOREIGN KEY (`author_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `closed_by_id_refs_id_56e9d00c` FOREIGN KEY (`closed_by_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `deleted_by_id_refs_id_56e9d00c` FOREIGN KEY (`deleted_by_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `last_activity_by_id_refs_id_56e9d00c` FOREIGN KEY (`last_activity_by_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `last_edited_by_id_refs_id_56e9d00c` FOREIGN KEY (`last_edited_by_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `locked_by_id_refs_id_56e9d00c` FOREIGN KEY (`locked_by_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
+
+--
+-- Definition of table `cnprog`.`question_tags`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`question_tags`;
+CREATE TABLE `cnprog`.`question_tags` (
+ `id` int(11) NOT NULL auto_increment,
+ `question_id` int(11) NOT NULL,
+ `tag_id` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `question_id` (`question_id`,`tag_id`),
+ KEY `tag_id_refs_id_43fcb953` (`tag_id`),
+ CONSTRAINT `question_id_refs_id_266147c6` FOREIGN KEY (`question_id`) REFERENCES `question` (`id`),
+ CONSTRAINT `tag_id_refs_id_43fcb953` FOREIGN KEY (`tag_id`) REFERENCES `tag` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8;
+
+--
+-- Definition of table `cnprog`.`tag`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`tag`;
+CREATE TABLE `cnprog`.`tag` (
+ `id` int(11) NOT NULL auto_increment,
+ `name` varchar(255) NOT NULL,
+ `created_by_id` int(11) NOT NULL,
+ `used_count` int(10) unsigned NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name` (`name`),
+ KEY `tag_created_by_id` (`created_by_id`),
+ CONSTRAINT `created_by_id_refs_id_47205d6d` FOREIGN KEY (`created_by_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
+
+--
+-- Definition of table `cnprog`.`user_badge`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`user_badge`;
+CREATE TABLE `cnprog`.`user_badge` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `user_id` int(10) unsigned NOT NULL,
+ `badge_id` int(10) unsigned NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Definition of table `cnprog`.`user_favorite_questions`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`user_favorite_questions`;
+CREATE TABLE `cnprog`.`user_favorite_questions` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `user_id` int(10) unsigned NOT NULL,
+ `question_id` int(10) unsigned NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`user_favorite_questions`
+--
+
+DROP TABLE IF EXISTS `cnprog`.`vote`;
+CREATE TABLE `cnprog`.`vote` (
+ `id` int(11) NOT NULL auto_increment,
+ `content_type_id` int(11) NOT NULL,
+ `object_id` int(10) unsigned NOT NULL,
+ `user_id` int(11) NOT NULL,
+ `vote` smallint(6) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `content_type_id` (`content_type_id`,`object_id`,`user_id`),
+ KEY `vote_content_type_id` (`content_type_id`),
+ KEY `vote_user_id` (`user_id`),
+ CONSTRAINT `content_type_id_refs_id_50124414` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
+ CONSTRAINT `user_id_refs_id_760a4df0` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `cnprog`.`vote`
+--
+
+
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
diff --git a/forum/sql_scripts/cnprog_new_install_2009_02_28.sql b/forum/sql_scripts/cnprog_new_install_2009_02_28.sql
new file mode 100644
index 00000000..80b9fced
--- /dev/null
+++ b/forum/sql_scripts/cnprog_new_install_2009_02_28.sql
@@ -0,0 +1,456 @@
+SET FOREIGN_KEY_CHECKS = 0;
+
+CREATE TABLE `activity` (
+ `id` int(11) NOT NULL auto_increment,
+ `user_id` int(11) NOT NULL,
+ `activity_type` smallint(6) NOT NULL,
+ `active_at` datetime NOT NULL,
+ `content_type_id` int(11) NOT NULL,
+ `object_id` int(10) unsigned NOT NULL,
+ `is_auditted` tinyint(1) default '0',
+ PRIMARY KEY (`id`),
+ KEY `activity_user_id` (`user_id`),
+ KEY `activity_content_type_id` (`content_type_id`)
+) ENGINE=MyISAM AUTO_INCREMENT=103 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `answer` (
+ `id` int(11) NOT NULL auto_increment,
+ `question_id` int(11) NOT NULL,
+ `author_id` int(11) NOT NULL,
+ `added_at` datetime NOT NULL,
+ `wiki` tinyint(1) NOT NULL,
+ `wikified_at` datetime default NULL,
+ `accepted` tinyint(1) NOT NULL,
+ `deleted` tinyint(1) NOT NULL,
+ `deleted_by_id` int(11) default NULL,
+ `locked` tinyint(1) NOT NULL,
+ `locked_by_id` int(11) default NULL,
+ `locked_at` datetime default NULL,
+ `score` int(11) NOT NULL,
+ `comment_count` int(10) unsigned NOT NULL,
+ `offensive_flag_count` smallint(6) NOT NULL,
+ `last_edited_at` datetime default NULL,
+ `last_edited_by_id` int(11) default NULL,
+ `html` longtext NOT NULL,
+ `vote_up_count` int(11) NOT NULL,
+ `vote_down_count` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `answer_question_id` (`question_id`),
+ KEY `answer_author_id` (`author_id`),
+ KEY `answer_deleted_by_id` (`deleted_by_id`),
+ KEY `answer_locked_by_id` (`locked_by_id`),
+ KEY `answer_last_edited_by_id` (`last_edited_by_id`),
+ CONSTRAINT `author_id_refs_id_192b0170` FOREIGN KEY (`author_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `deleted_by_id_refs_id_192b0170` FOREIGN KEY (`deleted_by_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `last_edited_by_id_refs_id_192b0170` FOREIGN KEY (`last_edited_by_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `locked_by_id_refs_id_192b0170` FOREIGN KEY (`locked_by_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `question_id_refs_id_7d6550c9` FOREIGN KEY (`question_id`) REFERENCES `question` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `answer_revision` (
+ `id` int(11) NOT NULL auto_increment,
+ `answer_id` int(11) NOT NULL,
+ `revision` int(10) unsigned NOT NULL,
+ `author_id` int(11) NOT NULL,
+ `revised_at` datetime NOT NULL,
+ `summary` varchar(300) collate utf8_unicode_ci NOT NULL,
+ `text` longtext collate utf8_unicode_ci NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `answer_revision_answer_id` (`answer_id`),
+ KEY `answer_revision_author_id` (`author_id`)
+) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `auth_group` (
+ `id` int(11) NOT NULL auto_increment,
+ `name` varchar(80) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name` (`name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `auth_group_permissions` (
+ `id` int(11) NOT NULL auto_increment,
+ `group_id` int(11) NOT NULL,
+ `permission_id` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `group_id` (`group_id`,`permission_id`),
+ KEY `permission_id_refs_id_5886d21f` (`permission_id`),
+ CONSTRAINT `group_id_refs_id_3cea63fe` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`),
+ CONSTRAINT `permission_id_refs_id_5886d21f` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `auth_message` (
+ `id` int(11) NOT NULL auto_increment,
+ `user_id` int(11) NOT NULL,
+ `message` longtext NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `auth_message_user_id` (`user_id`),
+ CONSTRAINT `user_id_refs_id_650f49a6` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `auth_permission` (
+ `id` int(11) NOT NULL auto_increment,
+ `name` varchar(50) NOT NULL,
+ `content_type_id` int(11) NOT NULL,
+ `codename` varchar(100) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `content_type_id` (`content_type_id`,`codename`),
+ KEY `auth_permission_content_type_id` (`content_type_id`),
+ CONSTRAINT `content_type_id_refs_id_728de91f` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=88 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `auth_user` (
+ `id` int(11) NOT NULL auto_increment,
+ `username` varchar(30) NOT NULL,
+ `first_name` varchar(30) NOT NULL,
+ `last_name` varchar(30) NOT NULL,
+ `email` varchar(75) NOT NULL,
+ `password` varchar(128) NOT NULL,
+ `is_staff` tinyint(1) NOT NULL,
+ `is_active` tinyint(1) NOT NULL,
+ `is_superuser` tinyint(1) NOT NULL,
+ `last_login` datetime NOT NULL,
+ `date_joined` datetime NOT NULL,
+ `gold` smallint(6) NOT NULL default '0',
+ `silver` smallint(5) unsigned NOT NULL default '0',
+ `bronze` smallint(5) unsigned NOT NULL default '0',
+ `reputation` int(10) unsigned default '1',
+ `gravatar` varchar(128) default NULL,
+ `questions_per_page` smallint(5) unsigned default '10',
+ `last_seen` datetime default NULL,
+ `real_name` varchar(100) default NULL,
+ `website` varchar(200) default NULL,
+ `location` varchar(100) default NULL,
+ `date_of_birth` datetime default NULL,
+ `about` text,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `username` (`username`)
+) ENGINE=InnoDB AUTO_INCREMENT=104 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `auth_user_groups` (
+ `id` int(11) NOT NULL auto_increment,
+ `user_id` int(11) NOT NULL,
+ `group_id` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `user_id` (`user_id`,`group_id`),
+ KEY `group_id_refs_id_f116770` (`group_id`),
+ CONSTRAINT `group_id_refs_id_f116770` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`),
+ CONSTRAINT `user_id_refs_id_7ceef80f` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `auth_user_user_permissions` (
+ `id` int(11) NOT NULL auto_increment,
+ `user_id` int(11) NOT NULL,
+ `permission_id` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `user_id` (`user_id`,`permission_id`),
+ KEY `permission_id_refs_id_67e79cb` (`permission_id`),
+ CONSTRAINT `permission_id_refs_id_67e79cb` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`),
+ CONSTRAINT `user_id_refs_id_dfbab7d` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `award` (
+ `id` int(11) NOT NULL auto_increment,
+ `user_id` int(11) NOT NULL,
+ `badge_id` int(11) NOT NULL,
+ `awarded_at` datetime NOT NULL,
+ `notified` tinyint(1) NOT NULL,
+ `content_type_id` int(11) default NULL,
+ `object_id` int(10) default NULL,
+ PRIMARY KEY (`id`),
+ KEY `award_user_id` (`user_id`),
+ KEY `award_badge_id` (`badge_id`),
+ CONSTRAINT `badge_id_refs_id_651af0e1` FOREIGN KEY (`badge_id`) REFERENCES `badge` (`id`),
+ CONSTRAINT `user_id_refs_id_2d83e9b6` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `badge` (
+ `id` int(11) NOT NULL auto_increment,
+ `name` varchar(50) NOT NULL,
+ `type` smallint(6) NOT NULL,
+ `slug` varchar(50) NOT NULL,
+ `description` varchar(300) NOT NULL,
+ `multiple` tinyint(1) NOT NULL,
+ `awarded_count` int(10) unsigned NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name` (`name`,`type`),
+ KEY `badge_slug` (`slug`)
+) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `comment` (
+ `id` int(11) NOT NULL auto_increment,
+ `content_type_id` int(11) NOT NULL,
+ `object_id` int(10) unsigned NOT NULL,
+ `user_id` int(11) NOT NULL,
+ `comment` varchar(300) NOT NULL,
+ `added_at` datetime NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `comment_content_type_id` (`content_type_id`),
+ KEY `comment_user_id` (`user_id`),
+ KEY `content_type_id` (`content_type_id`,`object_id`,`user_id`),
+ CONSTRAINT `content_type_id_refs_id_13a5866c` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
+ CONSTRAINT `user_id_refs_id_6be725e8` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `django_admin_log` (
+ `id` int(11) NOT NULL auto_increment,
+ `action_time` datetime NOT NULL,
+ `user_id` int(11) NOT NULL,
+ `content_type_id` int(11) default NULL,
+ `object_id` longtext,
+ `object_repr` varchar(200) NOT NULL,
+ `action_flag` smallint(5) unsigned NOT NULL,
+ `change_message` longtext NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `django_admin_log_user_id` (`user_id`),
+ KEY `django_admin_log_content_type_id` (`content_type_id`),
+ CONSTRAINT `content_type_id_refs_id_288599e6` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
+ CONSTRAINT `user_id_refs_id_c8665aa` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `django_authopenid_association` (
+ `id` int(11) NOT NULL auto_increment,
+ `server_url` longtext NOT NULL,
+ `handle` varchar(255) NOT NULL,
+ `secret` longtext NOT NULL,
+ `issued` int(11) NOT NULL,
+ `lifetime` int(11) NOT NULL,
+ `assoc_type` longtext NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `django_authopenid_nonce` (
+ `id` int(11) NOT NULL auto_increment,
+ `server_url` varchar(255) NOT NULL,
+ `timestamp` int(11) NOT NULL,
+ `salt` varchar(40) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `django_authopenid_userassociation` (
+ `id` int(11) NOT NULL auto_increment,
+ `openid_url` varchar(255) NOT NULL,
+ `user_id` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `user_id` (`user_id`),
+ CONSTRAINT `user_id_refs_id_163d208d` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `django_authopenid_userpasswordqueue` (
+ `id` int(11) NOT NULL auto_increment,
+ `user_id` int(11) NOT NULL,
+ `new_password` varchar(30) NOT NULL,
+ `confirm_key` varchar(40) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `user_id` (`user_id`),
+ CONSTRAINT `user_id_refs_id_76bcaaa4` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `django_content_type` (
+ `id` int(11) NOT NULL auto_increment,
+ `name` varchar(100) NOT NULL,
+ `app_label` varchar(100) NOT NULL,
+ `model` varchar(100) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `app_label` (`app_label`,`model`)
+) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `django_session` (
+ `session_key` varchar(40) NOT NULL,
+ `session_data` longtext NOT NULL,
+ `expire_date` datetime NOT NULL,
+ PRIMARY KEY (`session_key`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `django_site` (
+ `id` int(11) NOT NULL auto_increment,
+ `domain` varchar(100) NOT NULL,
+ `name` varchar(50) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `favorite_question` (
+ `id` int(11) NOT NULL auto_increment,
+ `question_id` int(11) NOT NULL,
+ `user_id` int(11) NOT NULL,
+ `added_at` datetime NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `favorite_question_question_id` (`question_id`),
+ KEY `favorite_question_user_id` (`user_id`),
+ CONSTRAINT `question_id_refs_id_1ebe1cc3` FOREIGN KEY (`question_id`) REFERENCES `question` (`id`),
+ CONSTRAINT `user_id_refs_id_52853822` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `flagged_item` (
+ `id` int(11) NOT NULL auto_increment,
+ `content_type_id` int(11) NOT NULL,
+ `object_id` int(10) unsigned NOT NULL,
+ `user_id` int(11) NOT NULL,
+ `flagged_at` datetime NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `content_type_id` (`content_type_id`,`object_id`,`user_id`),
+ KEY `flagged_item_content_type_id` (`content_type_id`),
+ KEY `flagged_item_user_id` (`user_id`),
+ CONSTRAINT `content_type_id_refs_id_76e44d74` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
+ CONSTRAINT `user_id_refs_id_35e3c608` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `question` (
+ `id` int(11) NOT NULL auto_increment,
+ `title` varchar(300) NOT NULL,
+ `author_id` int(11) NOT NULL,
+ `added_at` datetime NOT NULL,
+ `wiki` tinyint(1) NOT NULL,
+ `wikified_at` datetime default NULL,
+ `answer_accepted` tinyint(1) NOT NULL,
+ `closed` tinyint(1) NOT NULL,
+ `closed_by_id` int(11) default NULL,
+ `closed_at` datetime default NULL,
+ `close_reason` smallint(6) default NULL,
+ `deleted` tinyint(1) NOT NULL,
+ `deleted_at` datetime default NULL,
+ `deleted_by_id` int(11) default NULL,
+ `locked` tinyint(1) NOT NULL,
+ `locked_by_id` int(11) default NULL,
+ `locked_at` datetime default NULL,
+ `score` int(11) NOT NULL,
+ `answer_count` int(10) unsigned NOT NULL,
+ `comment_count` int(10) unsigned NOT NULL,
+ `view_count` int(10) unsigned NOT NULL,
+ `offensive_flag_count` smallint(6) NOT NULL,
+ `favourite_count` int(10) unsigned NOT NULL,
+ `last_edited_at` datetime default NULL,
+ `last_edited_by_id` int(11) default NULL,
+ `last_activity_at` datetime NOT NULL,
+ `last_activity_by_id` int(11) NOT NULL,
+ `tagnames` varchar(125) NOT NULL,
+ `summary` varchar(180) NOT NULL,
+ `html` longtext NOT NULL,
+ `vote_up_count` int(11) NOT NULL,
+ `vote_down_count` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `question_author_id` (`author_id`),
+ KEY `question_closed_by_id` (`closed_by_id`),
+ KEY `question_deleted_by_id` (`deleted_by_id`),
+ KEY `question_locked_by_id` (`locked_by_id`),
+ KEY `question_last_edited_by_id` (`last_edited_by_id`),
+ KEY `question_last_activity_by_id` (`last_activity_by_id`),
+ CONSTRAINT `author_id_refs_id_56e9d00c` FOREIGN KEY (`author_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `closed_by_id_refs_id_56e9d00c` FOREIGN KEY (`closed_by_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `deleted_by_id_refs_id_56e9d00c` FOREIGN KEY (`deleted_by_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `last_activity_by_id_refs_id_56e9d00c` FOREIGN KEY (`last_activity_by_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `last_edited_by_id_refs_id_56e9d00c` FOREIGN KEY (`last_edited_by_id`) REFERENCES `auth_user` (`id`),
+ CONSTRAINT `locked_by_id_refs_id_56e9d00c` FOREIGN KEY (`locked_by_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `question_revision` (
+ `id` int(11) NOT NULL auto_increment,
+ `question_id` int(11) NOT NULL,
+ `revision` int(10) unsigned NOT NULL,
+ `title` varchar(300) NOT NULL,
+ `author_id` int(11) NOT NULL,
+ `revised_at` datetime NOT NULL,
+ `tagnames` varchar(125) NOT NULL,
+ `summary` varchar(300) NOT NULL,
+ `text` longtext NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `question_revision_question_id` (`question_id`),
+ KEY `question_revision_author_id` (`author_id`)
+) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
+
+
+CREATE TABLE `question_tags` (
+ `id` int(11) NOT NULL auto_increment,
+ `question_id` int(11) NOT NULL,
+ `tag_id` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `question_id` (`question_id`,`tag_id`),
+ KEY `tag_id_refs_id_43fcb953` (`tag_id`),
+ CONSTRAINT `question_id_refs_id_266147c6` FOREIGN KEY (`question_id`) REFERENCES `question` (`id`),
+ CONSTRAINT `tag_id_refs_id_43fcb953` FOREIGN KEY (`tag_id`) REFERENCES `tag` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `repute` (
+ `id` int(11) NOT NULL auto_increment,
+ `user_id` int(11) NOT NULL,
+ `positive` smallint(6) NOT NULL,
+ `negative` smallint(6) NOT NULL,
+ `question_id` int(11) NOT NULL,
+ `reputed_at` datetime NOT NULL,
+ `reputation_type` smallint(6) NOT NULL,
+ `reputation` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `repute_user_id` (`user_id`),
+ KEY `repute_question_id` (`question_id`)
+) ENGINE=MyISAM AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `tag` (
+ `id` int(11) NOT NULL auto_increment,
+ `name` varchar(255) NOT NULL,
+ `created_by_id` int(11) NOT NULL,
+ `used_count` int(10) unsigned NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name` (`name`),
+ KEY `tag_created_by_id` (`created_by_id`),
+ CONSTRAINT `created_by_id_refs_id_47205d6d` FOREIGN KEY (`created_by_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `user_badge` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `user_id` int(10) unsigned NOT NULL,
+ `badge_id` int(10) unsigned NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `user_favorite_questions` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `user_id` int(10) unsigned NOT NULL,
+ `question_id` int(10) unsigned NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE `vote` (
+ `id` int(11) NOT NULL auto_increment,
+ `content_type_id` int(11) NOT NULL,
+ `object_id` int(10) unsigned NOT NULL,
+ `user_id` int(11) NOT NULL,
+ `vote` smallint(6) NOT NULL,
+ `voted_at` datetime NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `content_type_id` (`content_type_id`,`object_id`,`user_id`),
+ KEY `vote_content_type_id` (`content_type_id`),
+ KEY `vote_user_id` (`user_id`),
+ CONSTRAINT `content_type_id_refs_id_50124414` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
+ CONSTRAINT `user_id_refs_id_760a4df0` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
+
+
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/forum/sql_scripts/cnprog_new_install_2009_03_31.sql b/forum/sql_scripts/cnprog_new_install_2009_03_31.sql
new file mode 100644
index 00000000..c2c69f36
--- /dev/null
+++ b/forum/sql_scripts/cnprog_new_install_2009_03_31.sql
@@ -0,0 +1,891 @@
+USE cnprog;
+
+
+/************ Update: Tables ***************/
+
+/******************** Add Table: activity ************************/
+
+/* Build Table Structure */
+CREATE TABLE activity
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ activity_type SMALLINT NOT NULL,
+ active_at DATETIME NOT NULL,
+ content_type_id INTEGER NOT NULL,
+ object_id INTEGER UNSIGNED NOT NULL,
+ is_auditted TINYINT NULL DEFAULT 0
+) ENGINE=MyISAM AUTO_INCREMENT=103 DEFAULT CHARSET=latin1;
+
+/* Table Items: activity */
+
+/* Add Indexes for: activity */
+CREATE INDEX activity_content_type_id ON activity (content_type_id);
+CREATE INDEX activity_user_id ON activity (user_id);
+
+/******************** Add Table: answer ************************/
+
+/* Build Table Structure */
+CREATE TABLE answer
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ question_id INTEGER NOT NULL,
+ author_id INTEGER NOT NULL,
+ added_at DATETIME NOT NULL,
+ wiki TINYINT NOT NULL,
+ wikified_at DATETIME NULL,
+ accepted TINYINT NOT NULL,
+ deleted TINYINT NOT NULL,
+ deleted_by_id INTEGER NULL,
+ locked TINYINT NOT NULL,
+ locked_by_id INTEGER NULL,
+ locked_at DATETIME NULL,
+ score INTEGER NOT NULL,
+ comment_count INTEGER UNSIGNED NOT NULL,
+ offensive_flag_count SMALLINT NOT NULL,
+ last_edited_at DATETIME NULL,
+ last_edited_by_id INTEGER NULL,
+ html LONGTEXT NOT NULL,
+ vote_up_count INTEGER NOT NULL,
+ vote_down_count INTEGER NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
+
+/* Table Items: answer */
+
+/* Add Indexes for: answer */
+CREATE INDEX answer_author_id ON answer (author_id);
+CREATE INDEX answer_deleted_by_id ON answer (deleted_by_id);
+CREATE INDEX answer_last_edited_by_id ON answer (last_edited_by_id);
+CREATE INDEX answer_locked_by_id ON answer (locked_by_id);
+CREATE INDEX answer_question_id ON answer (question_id);
+
+/******************** Add Table: answer_revision ************************/
+
+/* Build Table Structure */
+CREATE TABLE answer_revision
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ answer_id INTEGER NOT NULL,
+ revision INTEGER UNSIGNED NOT NULL,
+ author_id INTEGER NOT NULL,
+ revised_at DATETIME NOT NULL,
+ summary TEXT NOT NULL,
+ `text` LONGTEXT NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+/* Table Items: answer_revision */
+
+/* Add Indexes for: answer_revision */
+CREATE INDEX answer_revision_answer_id ON answer_revision (answer_id);
+CREATE INDEX answer_revision_author_id ON answer_revision (author_id);
+
+/******************** Add Table: auth_group ************************/
+
+/* Build Table Structure */
+CREATE TABLE auth_group
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(80) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+/* Table Items: auth_group */
+
+/* Add Indexes for: auth_group */
+CREATE UNIQUE INDEX name ON auth_group (name);
+
+/******************** Add Table: auth_group_permissions ************************/
+
+/* Build Table Structure */
+CREATE TABLE auth_group_permissions
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ group_id INTEGER NOT NULL,
+ permission_id INTEGER NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+/* Table Items: auth_group_permissions */
+
+/* Add Indexes for: auth_group_permissions */
+CREATE UNIQUE INDEX group_id ON auth_group_permissions (group_id, permission_id);
+CREATE INDEX permission_id_refs_id_5886d21f ON auth_group_permissions (permission_id);
+
+/******************** Add Table: auth_message ************************/
+
+/* Build Table Structure */
+CREATE TABLE auth_message
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ message LONGTEXT NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;
+
+/* Table Items: auth_message */
+
+/* Add Indexes for: auth_message */
+CREATE INDEX auth_message_user_id ON auth_message (user_id);
+
+/******************** Add Table: auth_permission ************************/
+
+/* Build Table Structure */
+CREATE TABLE auth_permission
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(50) NOT NULL,
+ content_type_id INTEGER NOT NULL,
+ codename VARCHAR(100) NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=88 DEFAULT CHARSET=utf8;
+
+/* Table Items: auth_permission */
+
+/* Add Indexes for: auth_permission */
+CREATE INDEX auth_permission_content_type_id ON auth_permission (content_type_id);
+CREATE UNIQUE INDEX content_type_id ON auth_permission (content_type_id, codename);
+
+/******************** Add Table: auth_user ************************/
+
+/* Build Table Structure */
+CREATE TABLE auth_user
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ username VARCHAR(30) NOT NULL,
+ first_name VARCHAR(30) NOT NULL,
+ last_name VARCHAR(30) NOT NULL,
+ email VARCHAR(75) NOT NULL,
+ password VARCHAR(128) NOT NULL,
+ is_staff TINYINT NOT NULL,
+ is_active TINYINT NOT NULL,
+ is_superuser TINYINT NOT NULL,
+ last_login DATETIME NOT NULL,
+ date_joined DATETIME NOT NULL,
+ gold SMALLINT NOT NULL DEFAULT 0,
+ silver SMALLINT UNSIGNED NOT NULL DEFAULT 0,
+ bronze SMALLINT UNSIGNED NOT NULL DEFAULT 0,
+ reputation INTEGER UNSIGNED NULL DEFAULT 1,
+ gravatar VARCHAR(128) NULL,
+ questions_per_page SMALLINT UNSIGNED NULL DEFAULT 10,
+ last_seen DATETIME NULL,
+ real_name VARCHAR(100) NULL,
+ website VARCHAR(200) NULL,
+ location VARCHAR(100) NULL,
+ date_of_birth DATETIME NULL,
+ about TEXT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=104 DEFAULT CHARSET=utf8;
+
+/* Table Items: auth_user */
+
+/* Add Indexes for: auth_user */
+CREATE UNIQUE INDEX username ON auth_user (username);
+
+/******************** Add Table: auth_user_groups ************************/
+
+/* Build Table Structure */
+CREATE TABLE auth_user_groups
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ group_id INTEGER NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+/* Table Items: auth_user_groups */
+
+/* Add Indexes for: auth_user_groups */
+CREATE INDEX group_id_refs_id_f116770 ON auth_user_groups (group_id);
+CREATE UNIQUE INDEX user_id ON auth_user_groups (user_id, group_id);
+
+/******************** Add Table: auth_user_user_permissions ************************/
+
+/* Build Table Structure */
+CREATE TABLE auth_user_user_permissions
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ permission_id INTEGER NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+/* Table Items: auth_user_user_permissions */
+
+/* Add Indexes for: auth_user_user_permissions */
+CREATE INDEX permission_id_refs_id_67e79cb ON auth_user_user_permissions (permission_id);
+CREATE UNIQUE INDEX user_id ON auth_user_user_permissions (user_id, permission_id);
+
+/******************** Add Table: award ************************/
+
+/* Build Table Structure */
+CREATE TABLE award
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ badge_id INTEGER NOT NULL,
+ awarded_at DATETIME NOT NULL,
+ notified TINYINT NOT NULL,
+ content_type_id INTEGER NULL,
+ object_id INTEGER NULL
+) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;
+
+/* Table Items: award */
+
+/* Add Indexes for: award */
+CREATE INDEX award_badge_id ON award (badge_id);
+CREATE INDEX award_user_id ON award (user_id);
+
+/******************** Add Table: badge ************************/
+
+/* Build Table Structure */
+CREATE TABLE badge
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(50) NOT NULL,
+ `type` SMALLINT NOT NULL,
+ slug VARCHAR(50) NOT NULL,
+ description TEXT NOT NULL,
+ multiple TINYINT NOT NULL,
+ awarded_count INTEGER UNSIGNED NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
+
+/* Table Items: badge */
+
+/* Add Indexes for: badge */
+CREATE INDEX badge_slug ON badge (slug);
+CREATE UNIQUE INDEX name ON badge (name, `type`);
+
+/******************** Add Table: book ************************/
+
+/* Build Table Structure */
+CREATE TABLE book
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ title VARCHAR(255) NOT NULL,
+ short_name VARCHAR(255) NOT NULL,
+ author VARCHAR(255) NOT NULL,
+ user_id INTEGER NULL,
+ price DECIMAL(10, 2) NULL,
+ pages SMALLINT NULL,
+ published_at DATE NOT NULL,
+ publication VARCHAR(255) NOT NULL,
+ cover_img VARCHAR(255) NULL,
+ tagnames VARCHAR(125) NULL,
+ added_at DATETIME NOT NULL,
+ last_edited_at DATETIME NOT NULL
+) TYPE=InnoDB;
+
+/* Table Items: book */
+
+/* Add Indexes for: book */
+CREATE UNIQUE INDEX book_short_name_Idx ON book (short_name);
+CREATE INDEX fk_books_auth_user ON book (user_id);
+
+/******************** Add Table: book_author_info ************************/
+
+/* Build Table Structure */
+CREATE TABLE book_author_info
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ blog_url VARCHAR(255) NULL,
+ user_id INTEGER NOT NULL,
+ added_at DATETIME NOT NULL,
+ last_edited_at DATETIME NOT NULL
+) TYPE=InnoDB;
+
+/* Table Items: book_author_info */
+
+/* Add Indexes for: book_author_info */
+CREATE INDEX fk_book_author_info_auth_user ON book_author_info (user_id);
+
+/******************** Add Table: book_author_rss ************************/
+
+/* Build Table Structure */
+CREATE TABLE book_author_rss
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ title VARCHAR(255) NOT NULL,
+ url VARCHAR(255) NOT NULL,
+ rss_created_at DATETIME NOT NULL,
+ user_id INTEGER NOT NULL,
+ added_at DATETIME NOT NULL
+) TYPE=InnoDB;
+
+/* Table Items: book_author_rss */
+
+/* Add Indexes for: book_author_rss */
+CREATE INDEX fk_book_author_rss_auth_user ON book_author_rss (user_id);
+
+/******************** Add Table: book_question ************************/
+
+/* Build Table Structure */
+CREATE TABLE book_question
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ book_id INTEGER NOT NULL,
+ question_id INTEGER NOT NULL
+) TYPE=InnoDB;
+
+/* Table Items: book_question */
+
+/* Add Indexes for: book_question */
+CREATE INDEX fk_book_question_book ON book_question (book_id);
+CREATE INDEX fk_book_question_question ON book_question (question_id);
+
+/******************** Add Table: `comment` ************************/
+
+/* Build Table Structure */
+CREATE TABLE `comment`
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ content_type_id INTEGER NOT NULL,
+ object_id INTEGER UNSIGNED NOT NULL,
+ user_id INTEGER NOT NULL,
+ `comment` TEXT NOT NULL,
+ added_at DATETIME NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
+
+/* Table Items: `comment` */
+
+/* Add Indexes for: comment */
+CREATE INDEX comment_content_type_id ON `comment` (content_type_id);
+CREATE INDEX comment_user_id ON `comment` (user_id);
+CREATE INDEX content_type_id ON `comment` (content_type_id, object_id, user_id);
+
+/******************** Add Table: django_admin_log ************************/
+
+/* Build Table Structure */
+CREATE TABLE django_admin_log
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ action_time DATETIME NOT NULL,
+ user_id INTEGER NOT NULL,
+ content_type_id INTEGER NULL,
+ object_id LONGTEXT NULL,
+ object_repr VARCHAR(200) NOT NULL,
+ action_flag SMALLINT UNSIGNED NOT NULL,
+ change_message LONGTEXT NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
+
+/* Table Items: django_admin_log */
+
+/* Add Indexes for: django_admin_log */
+CREATE INDEX django_admin_log_content_type_id ON django_admin_log (content_type_id);
+CREATE INDEX django_admin_log_user_id ON django_admin_log (user_id);
+
+/******************** Add Table: django_authopenid_association ************************/
+
+/* Build Table Structure */
+CREATE TABLE django_authopenid_association
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ server_url LONGTEXT NOT NULL,
+ handle VARCHAR(255) NOT NULL,
+ secret LONGTEXT NOT NULL,
+ issued INTEGER NOT NULL,
+ lifetime INTEGER NOT NULL,
+ assoc_type LONGTEXT NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
+
+/******************** Add Table: django_authopenid_nonce ************************/
+
+/* Build Table Structure */
+CREATE TABLE django_authopenid_nonce
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ server_url VARCHAR(255) NOT NULL,
+ `timestamp` INTEGER NOT NULL,
+ salt VARCHAR(40) NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8;
+
+/******************** Add Table: django_authopenid_userassociation ************************/
+
+/* Build Table Structure */
+CREATE TABLE django_authopenid_userassociation
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ openid_url VARCHAR(255) NOT NULL,
+ user_id INTEGER NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
+
+/* Table Items: django_authopenid_userassociation */
+
+/* Add Indexes for: django_authopenid_userassociation */
+CREATE UNIQUE INDEX user_id ON django_authopenid_userassociation (user_id);
+
+/******************** Add Table: django_authopenid_userpasswordqueue ************************/
+
+/* Build Table Structure */
+CREATE TABLE django_authopenid_userpasswordqueue
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ new_password VARCHAR(30) NOT NULL,
+ confirm_key VARCHAR(40) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+/* Table Items: django_authopenid_userpasswordqueue */
+
+/* Add Indexes for: django_authopenid_userpasswordqueue */
+CREATE UNIQUE INDEX user_id ON django_authopenid_userpasswordqueue (user_id);
+
+/******************** Add Table: django_content_type ************************/
+
+/* Build Table Structure */
+CREATE TABLE django_content_type
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(100) NOT NULL,
+ app_label VARCHAR(100) NOT NULL,
+ model VARCHAR(100) NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;
+
+/* Table Items: django_content_type */
+
+/* Add Indexes for: django_content_type */
+CREATE UNIQUE INDEX app_label ON django_content_type (app_label, model);
+
+/******************** Add Table: django_session ************************/
+
+/* Build Table Structure */
+CREATE TABLE django_session
+(
+ session_key VARCHAR(40) NOT NULL,
+ session_data LONGTEXT NOT NULL,
+ expire_date DATETIME NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+/* Table Items: django_session */
+ALTER TABLE django_session ADD CONSTRAINT pkdjango_session
+ PRIMARY KEY (session_key);
+
+/******************** Add Table: django_site ************************/
+
+/* Build Table Structure */
+CREATE TABLE django_site
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ domain VARCHAR(100) NOT NULL,
+ name VARCHAR(50) NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
+
+/******************** Add Table: favorite_question ************************/
+
+/* Build Table Structure */
+CREATE TABLE favorite_question
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ question_id INTEGER NOT NULL,
+ user_id INTEGER NOT NULL,
+ added_at DATETIME NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
+
+/* Table Items: favorite_question */
+
+/* Add Indexes for: favorite_question */
+CREATE INDEX favorite_question_question_id ON favorite_question (question_id);
+CREATE INDEX favorite_question_user_id ON favorite_question (user_id);
+
+/******************** Add Table: flagged_item ************************/
+
+/* Build Table Structure */
+CREATE TABLE flagged_item
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ content_type_id INTEGER NOT NULL,
+ object_id INTEGER UNSIGNED NOT NULL,
+ user_id INTEGER NOT NULL,
+ flagged_at DATETIME NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
+
+/* Table Items: flagged_item */
+
+/* Add Indexes for: flagged_item */
+CREATE UNIQUE INDEX content_type_id ON flagged_item (content_type_id, object_id, user_id);
+CREATE INDEX flagged_item_content_type_id ON flagged_item (content_type_id);
+CREATE INDEX flagged_item_user_id ON flagged_item (user_id);
+
+/******************** Add Table: question ************************/
+
+/* Build Table Structure */
+CREATE TABLE question
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ title TEXT NOT NULL,
+ author_id INTEGER NOT NULL,
+ added_at DATETIME NOT NULL,
+ wiki TINYINT NOT NULL,
+ wikified_at DATETIME NULL,
+ answer_accepted TINYINT NOT NULL,
+ closed TINYINT NOT NULL,
+ closed_by_id INTEGER NULL,
+ closed_at DATETIME NULL,
+ close_reason SMALLINT NULL,
+ deleted TINYINT NOT NULL,
+ deleted_at DATETIME NULL,
+ deleted_by_id INTEGER NULL,
+ locked TINYINT NOT NULL,
+ locked_by_id INTEGER NULL,
+ locked_at DATETIME NULL,
+ score INTEGER NOT NULL,
+ answer_count INTEGER UNSIGNED NOT NULL,
+ comment_count INTEGER UNSIGNED NOT NULL,
+ view_count INTEGER UNSIGNED NOT NULL,
+ offensive_flag_count SMALLINT NOT NULL,
+ favourite_count INTEGER UNSIGNED NOT NULL,
+ last_edited_at DATETIME NULL,
+ last_edited_by_id INTEGER NULL,
+ last_activity_at DATETIME NOT NULL,
+ last_activity_by_id INTEGER NOT NULL,
+ tagnames VARCHAR(125) NOT NULL,
+ summary VARCHAR(180) NOT NULL,
+ html LONGTEXT NOT NULL,
+ vote_up_count INTEGER NOT NULL,
+ vote_down_count INTEGER NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;
+
+/* Table Items: question */
+
+/* Add Indexes for: question */
+CREATE INDEX question_author_id ON question (author_id);
+CREATE INDEX question_closed_by_id ON question (closed_by_id);
+CREATE INDEX question_deleted_by_id ON question (deleted_by_id);
+CREATE INDEX question_last_activity_by_id ON question (last_activity_by_id);
+CREATE INDEX question_last_edited_by_id ON question (last_edited_by_id);
+CREATE INDEX question_locked_by_id ON question (locked_by_id);
+
+/******************** Add Table: question_revision ************************/
+
+/* Build Table Structure */
+CREATE TABLE question_revision
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ question_id INTEGER NOT NULL,
+ revision INTEGER UNSIGNED NOT NULL,
+ title TEXT NOT NULL,
+ author_id INTEGER NOT NULL,
+ revised_at DATETIME NOT NULL,
+ tagnames VARCHAR(125) NOT NULL,
+ summary TEXT NOT NULL,
+ `text` LONGTEXT NOT NULL
+) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
+
+/* Table Items: question_revision */
+
+/* Add Indexes for: question_revision */
+CREATE INDEX question_revision_author_id ON question_revision (author_id);
+CREATE INDEX question_revision_question_id ON question_revision (question_id);
+
+/******************** Add Table: question_tags ************************/
+
+/* Build Table Structure */
+CREATE TABLE question_tags
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ question_id INTEGER NOT NULL,
+ tag_id INTEGER NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;
+
+/* Table Items: question_tags */
+
+/* Add Indexes for: question_tags */
+CREATE UNIQUE INDEX question_id ON question_tags (question_id, tag_id);
+CREATE INDEX tag_id_refs_id_43fcb953 ON question_tags (tag_id);
+
+/******************** Add Table: repute ************************/
+
+/* Build Table Structure */
+CREATE TABLE repute
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ positive SMALLINT NOT NULL,
+ negative SMALLINT NOT NULL,
+ question_id INTEGER NOT NULL,
+ reputed_at DATETIME NOT NULL,
+ reputation_type SMALLINT NOT NULL,
+ reputation INTEGER NOT NULL
+) ENGINE=MyISAM AUTO_INCREMENT=17 DEFAULT CHARSET=latin1;
+
+/* Table Items: repute */
+
+/* Add Indexes for: repute */
+CREATE INDEX repute_question_id ON repute (question_id);
+CREATE INDEX repute_user_id ON repute (user_id);
+
+/******************** Add Table: tag ************************/
+
+/* Build Table Structure */
+CREATE TABLE tag
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ created_by_id INTEGER NOT NULL,
+ used_count INTEGER UNSIGNED NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;
+
+/* Table Items: tag */
+
+/* Add Indexes for: tag */
+CREATE UNIQUE INDEX name ON tag (name);
+CREATE INDEX tag_created_by_id ON tag (created_by_id);
+
+/******************** Add Table: user_badge ************************/
+
+/* Build Table Structure */
+CREATE TABLE user_badge
+(
+ id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ badge_id INTEGER NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+/* Table Items: user_badge */
+
+/* Add Indexes for: user_badge */
+CREATE INDEX fk_user_badge_auth_user ON user_badge (user_id);
+CREATE INDEX fk_user_badge_badge ON user_badge (badge_id);
+
+/******************** Add Table: user_favorite_questions ************************/
+
+/* Build Table Structure */
+CREATE TABLE user_favorite_questions
+(
+ id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ question_id INTEGER NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+/* Table Items: user_favorite_questions */
+
+/* Add Indexes for: user_favorite_questions */
+CREATE INDEX fk_user_favorite_questions_auth_user ON user_favorite_questions (user_id);
+CREATE INDEX fk_user_favorite_questions_question ON user_favorite_questions (question_id);
+
+/******************** Add Table: vote ************************/
+
+/* Build Table Structure */
+CREATE TABLE vote
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ content_type_id INTEGER NOT NULL,
+ object_id INTEGER UNSIGNED NOT NULL,
+ user_id INTEGER NOT NULL,
+ vote SMALLINT NOT NULL,
+ voted_at DATETIME NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
+
+/* Table Items: vote */
+
+/* Add Indexes for: vote */
+CREATE UNIQUE INDEX content_type_id ON vote (content_type_id, object_id, user_id);
+CREATE INDEX vote_content_type_id ON vote (content_type_id);
+CREATE INDEX vote_user_id ON vote (user_id);
+
+
+/************ Add Foreign Keys to Database ***************/
+/*-----------------------------------------------------------
+Warning: Versions of MySQL prior to 4.1.2 require indexes on all columns involved in a foreign key. The following indexes may be required:
+fk_auth_group_permissions_auth_group may require an index on table: auth_group_permissions, column: group_id
+fk_auth_user_groups_auth_user may require an index on table: auth_user_groups, column: user_id
+fk_auth_user_user_permissions_auth_user may require an index on table: auth_user_user_permissions, column: user_id
+fk_question_tags_question may require an index on table: question_tags, column: question_id
+-----------------------------------------------------------
+*/
+
+/************ Foreign Key: fk_activity_auth_user ***************/
+ALTER TABLE activity ADD CONSTRAINT fk_activity_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: deleted_by_id_refs_id_192b0170 ***************/
+ALTER TABLE answer ADD CONSTRAINT deleted_by_id_refs_id_192b0170
+ FOREIGN KEY (deleted_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_answer_auth_user ***************/
+ALTER TABLE answer ADD CONSTRAINT fk_answer_auth_user
+ FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_answer_question ***************/
+ALTER TABLE answer ADD CONSTRAINT fk_answer_question
+ FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: last_edited_by_id_refs_id_192b0170 ***************/
+ALTER TABLE answer ADD CONSTRAINT last_edited_by_id_refs_id_192b0170
+ FOREIGN KEY (last_edited_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: locked_by_id_refs_id_192b0170 ***************/
+ALTER TABLE answer ADD CONSTRAINT locked_by_id_refs_id_192b0170
+ FOREIGN KEY (locked_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_answer_revision_auth_user ***************/
+ALTER TABLE answer_revision ADD CONSTRAINT fk_answer_revision_auth_user
+ FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_auth_group_permissions_auth_group ***************/
+ALTER TABLE auth_group_permissions ADD CONSTRAINT fk_auth_group_permissions_auth_group
+ FOREIGN KEY (group_id) REFERENCES auth_group (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_auth_group_permissions_auth_permission ***************/
+ALTER TABLE auth_group_permissions ADD CONSTRAINT fk_auth_group_permissions_auth_permission
+ FOREIGN KEY (permission_id) REFERENCES auth_permission (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_auth_message_auth_user ***************/
+ALTER TABLE auth_message ADD CONSTRAINT fk_auth_message_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_auth_permission_django_content_type ***************/
+ALTER TABLE auth_permission ADD CONSTRAINT fk_auth_permission_django_content_type
+ FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_auth_user_groups_auth_group ***************/
+ALTER TABLE auth_user_groups ADD CONSTRAINT fk_auth_user_groups_auth_group
+ FOREIGN KEY (group_id) REFERENCES auth_group (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_auth_user_groups_auth_user ***************/
+ALTER TABLE auth_user_groups ADD CONSTRAINT fk_auth_user_groups_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_auth_user_user_permissions_auth_permission ***************/
+ALTER TABLE auth_user_user_permissions ADD CONSTRAINT fk_auth_user_user_permissions_auth_permission
+ FOREIGN KEY (permission_id) REFERENCES auth_permission (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_auth_user_user_permissions_auth_user ***************/
+ALTER TABLE auth_user_user_permissions ADD CONSTRAINT fk_auth_user_user_permissions_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_award_auth_user ***************/
+ALTER TABLE award ADD CONSTRAINT fk_award_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_award_badge ***************/
+ALTER TABLE award ADD CONSTRAINT fk_award_badge
+ FOREIGN KEY (badge_id) REFERENCES badge (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_books_auth_user ***************/
+ALTER TABLE book ADD CONSTRAINT fk_books_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_book_author_info_auth_user ***************/
+ALTER TABLE book_author_info ADD CONSTRAINT fk_book_author_info_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_book_author_rss_auth_user ***************/
+ALTER TABLE book_author_rss ADD CONSTRAINT fk_book_author_rss_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_book_question_book ***************/
+ALTER TABLE book_question ADD CONSTRAINT fk_book_question_book
+ FOREIGN KEY (book_id) REFERENCES book (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_book_question_question ***************/
+ALTER TABLE book_question ADD CONSTRAINT fk_book_question_question
+ FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_comment_auth_user ***************/
+ALTER TABLE `comment` ADD CONSTRAINT fk_comment_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_comment_django_content_type ***************/
+ALTER TABLE `comment` ADD CONSTRAINT fk_comment_django_content_type
+ FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_django_admin_log_auth_user ***************/
+ALTER TABLE django_admin_log ADD CONSTRAINT fk_django_admin_log_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_django_admin_log_django_content_type ***************/
+ALTER TABLE django_admin_log ADD CONSTRAINT fk_django_admin_log_django_content_type
+ FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_django_authopenid_userassociation_auth_user ***************/
+ALTER TABLE django_authopenid_userassociation ADD CONSTRAINT fk_django_authopenid_userassociation_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_django_authopenid_userpasswordqueue_auth_user ***************/
+ALTER TABLE django_authopenid_userpasswordqueue ADD CONSTRAINT fk_django_authopenid_userpasswordqueue_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_favorite_question_auth_user ***************/
+ALTER TABLE favorite_question ADD CONSTRAINT fk_favorite_question_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_favorite_question_question ***************/
+ALTER TABLE favorite_question ADD CONSTRAINT fk_favorite_question_question
+ FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_flagged_item_auth_user ***************/
+ALTER TABLE flagged_item ADD CONSTRAINT fk_flagged_item_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_flagged_item_django_content_type ***************/
+ALTER TABLE flagged_item ADD CONSTRAINT fk_flagged_item_django_content_type
+ FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: closed_by_id_refs_id_56e9d00c ***************/
+ALTER TABLE question ADD CONSTRAINT closed_by_id_refs_id_56e9d00c
+ FOREIGN KEY (closed_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: deleted_by_id_refs_id_56e9d00c ***************/
+ALTER TABLE question ADD CONSTRAINT deleted_by_id_refs_id_56e9d00c
+ FOREIGN KEY (deleted_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_question_auth_user ***************/
+ALTER TABLE question ADD CONSTRAINT fk_question_auth_user
+ FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: last_activity_by_id_refs_id_56e9d00c ***************/
+ALTER TABLE question ADD CONSTRAINT last_activity_by_id_refs_id_56e9d00c
+ FOREIGN KEY (last_activity_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: last_edited_by_id_refs_id_56e9d00c ***************/
+ALTER TABLE question ADD CONSTRAINT last_edited_by_id_refs_id_56e9d00c
+ FOREIGN KEY (last_edited_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: locked_by_id_refs_id_56e9d00c ***************/
+ALTER TABLE question ADD CONSTRAINT locked_by_id_refs_id_56e9d00c
+ FOREIGN KEY (locked_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_question_revision_auth_user ***************/
+ALTER TABLE question_revision ADD CONSTRAINT fk_question_revision_auth_user
+ FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_question_revision_question ***************/
+ALTER TABLE question_revision ADD CONSTRAINT fk_question_revision_question
+ FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_question_tags_question ***************/
+ALTER TABLE question_tags ADD CONSTRAINT fk_question_tags_question
+ FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_question_tags_tag ***************/
+ALTER TABLE question_tags ADD CONSTRAINT fk_question_tags_tag
+ FOREIGN KEY (tag_id) REFERENCES tag (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_repute_auth_user ***************/
+ALTER TABLE repute ADD CONSTRAINT fk_repute_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_repute_question ***************/
+ALTER TABLE repute ADD CONSTRAINT fk_repute_question
+ FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_tag_auth_user ***************/
+ALTER TABLE tag ADD CONSTRAINT fk_tag_auth_user
+ FOREIGN KEY (created_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_user_badge_auth_user ***************/
+ALTER TABLE user_badge ADD CONSTRAINT fk_user_badge_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_user_badge_badge ***************/
+ALTER TABLE user_badge ADD CONSTRAINT fk_user_badge_badge
+ FOREIGN KEY (badge_id) REFERENCES badge (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_user_favorite_questions_auth_user ***************/
+ALTER TABLE user_favorite_questions ADD CONSTRAINT fk_user_favorite_questions_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_user_favorite_questions_question ***************/
+ALTER TABLE user_favorite_questions ADD CONSTRAINT fk_user_favorite_questions_question
+ FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_vote_auth_user ***************/
+ALTER TABLE vote ADD CONSTRAINT fk_vote_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_vote_django_content_type ***************/
+ALTER TABLE vote ADD CONSTRAINT fk_vote_django_content_type
+ FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION; \ No newline at end of file
diff --git a/forum/sql_scripts/cnprog_new_install_2009_04_07.sql b/forum/sql_scripts/cnprog_new_install_2009_04_07.sql
new file mode 100644
index 00000000..ff9016fa
--- /dev/null
+++ b/forum/sql_scripts/cnprog_new_install_2009_04_07.sql
@@ -0,0 +1,24 @@
+USE cnprog;
+
+
+/************ Add Foreign Keys to Database ***************/
+
+/************ Foreign Key: fk_activity_auth_user ***************/
+ALTER TABLE activity ADD CONSTRAINT fk_activity_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_question_revision_auth_user ***************/
+ALTER TABLE question_revision ADD CONSTRAINT fk_question_revision_auth_user
+ FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_question_revision_question ***************/
+ALTER TABLE question_revision ADD CONSTRAINT fk_question_revision_question
+ FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_repute_auth_user ***************/
+ALTER TABLE repute ADD CONSTRAINT fk_repute_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_repute_question ***************/
+ALTER TABLE repute ADD CONSTRAINT fk_repute_question
+ FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION; \ No newline at end of file
diff --git a/forum/sql_scripts/cnprog_new_install_2009_04_09.sql b/forum/sql_scripts/cnprog_new_install_2009_04_09.sql
new file mode 100644
index 00000000..f4424852
--- /dev/null
+++ b/forum/sql_scripts/cnprog_new_install_2009_04_09.sql
@@ -0,0 +1,904 @@
+USE cnprog;
+
+
+/************ Update: Tables ***************/
+
+/******************** Add Table: activity ************************/
+
+/* Build Table Structure */
+CREATE TABLE activity
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ activity_type SMALLINT NOT NULL,
+ active_at DATETIME NOT NULL,
+ content_type_id INTEGER NOT NULL,
+ object_id INTEGER UNSIGNED NOT NULL,
+ is_auditted TINYINT NULL DEFAULT 0
+) ENGINE=MyISAM AUTO_INCREMENT=103 DEFAULT CHARSET=latin1;
+
+/* Table Items: activity */
+
+/* Add Indexes for: activity */
+CREATE INDEX activity_content_type_id ON activity (content_type_id);
+CREATE INDEX activity_user_id ON activity (user_id);
+
+/******************** Add Table: answer ************************/
+
+/* Build Table Structure */
+CREATE TABLE answer
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ question_id INTEGER NOT NULL,
+ author_id INTEGER NOT NULL,
+ added_at DATETIME NOT NULL,
+ wiki TINYINT NOT NULL,
+ wikified_at DATETIME NULL,
+ accepted TINYINT NOT NULL,
+ deleted TINYINT NOT NULL,
+ deleted_by_id INTEGER NULL,
+ locked TINYINT NOT NULL,
+ locked_by_id INTEGER NULL,
+ locked_at DATETIME NULL,
+ score INTEGER NOT NULL,
+ comment_count INTEGER UNSIGNED NOT NULL,
+ offensive_flag_count SMALLINT NOT NULL,
+ last_edited_at DATETIME NULL,
+ last_edited_by_id INTEGER NULL,
+ html LONGTEXT NOT NULL,
+ vote_up_count INTEGER NOT NULL,
+ vote_down_count INTEGER NOT NULL,
+ accepted_at DATETIME NULL
+) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
+
+/* Table Items: answer */
+
+/* Add Indexes for: answer */
+CREATE INDEX answer_author_id ON answer (author_id);
+CREATE INDEX answer_deleted_by_id ON answer (deleted_by_id);
+CREATE INDEX answer_last_edited_by_id ON answer (last_edited_by_id);
+CREATE INDEX answer_locked_by_id ON answer (locked_by_id);
+CREATE INDEX answer_question_id ON answer (question_id);
+
+/******************** Add Table: answer_revision ************************/
+
+/* Build Table Structure */
+CREATE TABLE answer_revision
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ answer_id INTEGER NOT NULL,
+ revision INTEGER UNSIGNED NOT NULL,
+ author_id INTEGER NOT NULL,
+ revised_at DATETIME NOT NULL,
+ summary TEXT NOT NULL,
+ `text` LONGTEXT NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+/* Table Items: answer_revision */
+
+/* Add Indexes for: answer_revision */
+CREATE INDEX answer_revision_answer_id ON answer_revision (answer_id);
+CREATE INDEX answer_revision_author_id ON answer_revision (author_id);
+
+/******************** Add Table: auth_group ************************/
+
+/* Build Table Structure */
+CREATE TABLE auth_group
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(80) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+/* Table Items: auth_group */
+
+/* Add Indexes for: auth_group */
+CREATE UNIQUE INDEX name ON auth_group (name);
+
+/******************** Add Table: auth_group_permissions ************************/
+
+/* Build Table Structure */
+CREATE TABLE auth_group_permissions
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ group_id INTEGER NOT NULL,
+ permission_id INTEGER NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+/* Table Items: auth_group_permissions */
+
+/* Add Indexes for: auth_group_permissions */
+CREATE UNIQUE INDEX group_id ON auth_group_permissions (group_id, permission_id);
+CREATE INDEX permission_id_refs_id_5886d21f ON auth_group_permissions (permission_id);
+
+/******************** Add Table: auth_message ************************/
+
+/* Build Table Structure */
+CREATE TABLE auth_message
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ message LONGTEXT NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;
+
+/* Table Items: auth_message */
+
+/* Add Indexes for: auth_message */
+CREATE INDEX auth_message_user_id ON auth_message (user_id);
+
+/******************** Add Table: auth_permission ************************/
+
+/* Build Table Structure */
+CREATE TABLE auth_permission
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(50) NOT NULL,
+ content_type_id INTEGER NOT NULL,
+ codename VARCHAR(100) NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=88 DEFAULT CHARSET=utf8;
+
+/* Table Items: auth_permission */
+
+/* Add Indexes for: auth_permission */
+CREATE INDEX auth_permission_content_type_id ON auth_permission (content_type_id);
+CREATE UNIQUE INDEX content_type_id ON auth_permission (content_type_id, codename);
+
+/******************** Add Table: auth_user ************************/
+
+/* Build Table Structure */
+CREATE TABLE auth_user
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ username VARCHAR(30) NOT NULL,
+ first_name VARCHAR(30) NOT NULL,
+ last_name VARCHAR(30) NOT NULL,
+ email VARCHAR(75) NOT NULL,
+ password VARCHAR(128) NOT NULL,
+ is_staff TINYINT NOT NULL,
+ is_active TINYINT NOT NULL,
+ is_superuser TINYINT NOT NULL,
+ last_login DATETIME NOT NULL,
+ date_joined DATETIME NOT NULL,
+ gold SMALLINT NOT NULL DEFAULT 0,
+ silver SMALLINT UNSIGNED NOT NULL DEFAULT 0,
+ bronze SMALLINT UNSIGNED NOT NULL DEFAULT 0,
+ reputation INTEGER UNSIGNED NULL DEFAULT 1,
+ gravatar VARCHAR(128) NULL,
+ questions_per_page SMALLINT UNSIGNED NULL DEFAULT 10,
+ last_seen DATETIME NULL,
+ real_name VARCHAR(100) NULL,
+ website VARCHAR(200) NULL,
+ location VARCHAR(100) NULL,
+ date_of_birth DATETIME NULL,
+ about TEXT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=104 DEFAULT CHARSET=utf8;
+
+/* Table Items: auth_user */
+
+/* Add Indexes for: auth_user */
+CREATE UNIQUE INDEX username ON auth_user (username);
+
+/******************** Add Table: auth_user_groups ************************/
+
+/* Build Table Structure */
+CREATE TABLE auth_user_groups
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ group_id INTEGER NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+/* Table Items: auth_user_groups */
+
+/* Add Indexes for: auth_user_groups */
+CREATE INDEX group_id_refs_id_f116770 ON auth_user_groups (group_id);
+CREATE UNIQUE INDEX user_id ON auth_user_groups (user_id, group_id);
+
+/******************** Add Table: auth_user_user_permissions ************************/
+
+/* Build Table Structure */
+CREATE TABLE auth_user_user_permissions
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ permission_id INTEGER NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+/* Table Items: auth_user_user_permissions */
+
+/* Add Indexes for: auth_user_user_permissions */
+CREATE INDEX permission_id_refs_id_67e79cb ON auth_user_user_permissions (permission_id);
+CREATE UNIQUE INDEX user_id ON auth_user_user_permissions (user_id, permission_id);
+
+/******************** Add Table: award ************************/
+
+/* Build Table Structure */
+CREATE TABLE award
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ badge_id INTEGER NOT NULL,
+ awarded_at DATETIME NOT NULL,
+ notified TINYINT NOT NULL,
+ content_type_id INTEGER NULL,
+ object_id INTEGER NULL
+) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;
+
+/* Table Items: award */
+
+/* Add Indexes for: award */
+CREATE INDEX award_badge_id ON award (badge_id);
+CREATE INDEX award_user_id ON award (user_id);
+
+/******************** Add Table: badge ************************/
+
+/* Build Table Structure */
+CREATE TABLE badge
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(50) NOT NULL,
+ `type` SMALLINT NOT NULL,
+ slug VARCHAR(50) NOT NULL,
+ description TEXT NOT NULL,
+ multiple TINYINT NOT NULL,
+ awarded_count INTEGER UNSIGNED NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
+
+/* Table Items: badge */
+
+/* Add Indexes for: badge */
+CREATE INDEX badge_slug ON badge (slug);
+CREATE UNIQUE INDEX name ON badge (name, `type`);
+
+/******************** Add Table: book ************************/
+
+/* Build Table Structure */
+CREATE TABLE book
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ title VARCHAR(255) NOT NULL,
+ short_name VARCHAR(255) NOT NULL,
+ author VARCHAR(255) NOT NULL,
+ user_id INTEGER NULL,
+ price DECIMAL(10, 2) NULL,
+ pages SMALLINT NULL,
+ published_at DATE NOT NULL,
+ publication VARCHAR(255) NOT NULL,
+ cover_img VARCHAR(255) NULL,
+ tagnames VARCHAR(125) NULL,
+ added_at DATETIME NOT NULL,
+ last_edited_at DATETIME NOT NULL
+) TYPE=InnoDB;
+
+/* Table Items: book */
+
+/* Add Indexes for: book */
+CREATE UNIQUE INDEX book_short_name_Idx ON book (short_name);
+CREATE INDEX fk_books_auth_user ON book (user_id);
+
+/******************** Add Table: book_author_info ************************/
+
+/* Build Table Structure */
+CREATE TABLE book_author_info
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ blog_url VARCHAR(255) NULL,
+ user_id INTEGER NOT NULL,
+ added_at DATETIME NOT NULL,
+ last_edited_at DATETIME NOT NULL,
+ book_id INTEGER NOT NULL
+) TYPE=InnoDB;
+
+/* Table Items: book_author_info */
+
+/* Add Indexes for: book_author_info */
+CREATE INDEX fk_book_author_info_auth_user ON book_author_info (user_id);
+CREATE INDEX fk_book_author_info_book ON book_author_info (book_id);
+
+/******************** Add Table: book_author_rss ************************/
+
+/* Build Table Structure */
+CREATE TABLE book_author_rss
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ title VARCHAR(255) NOT NULL,
+ url VARCHAR(255) NOT NULL,
+ rss_created_at DATETIME NOT NULL,
+ user_id INTEGER NOT NULL,
+ added_at DATETIME NOT NULL,
+ book_id INTEGER NOT NULL
+) TYPE=InnoDB;
+
+/* Table Items: book_author_rss */
+
+/* Add Indexes for: book_author_rss */
+CREATE INDEX fk_book_author_rss_auth_user ON book_author_rss (user_id);
+CREATE INDEX fk_book_author_rss_book ON book_author_rss (book_id);
+
+/******************** Add Table: book_question ************************/
+
+/* Build Table Structure */
+CREATE TABLE book_question
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ book_id INTEGER NOT NULL,
+ question_id INTEGER NOT NULL
+) TYPE=InnoDB;
+
+/* Table Items: book_question */
+
+/* Add Indexes for: book_question */
+CREATE INDEX fk_book_question_book ON book_question (book_id);
+CREATE INDEX fk_book_question_question ON book_question (question_id);
+
+/******************** Add Table: `comment` ************************/
+
+/* Build Table Structure */
+CREATE TABLE `comment`
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ content_type_id INTEGER NOT NULL,
+ object_id INTEGER UNSIGNED NOT NULL,
+ user_id INTEGER NOT NULL,
+ `comment` TEXT NOT NULL,
+ added_at DATETIME NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
+
+/* Table Items: `comment` */
+
+/* Add Indexes for: comment */
+CREATE INDEX comment_content_type_id ON `comment` (content_type_id);
+CREATE INDEX comment_user_id ON `comment` (user_id);
+CREATE INDEX content_type_id ON `comment` (content_type_id, object_id, user_id);
+
+/******************** Add Table: django_admin_log ************************/
+
+/* Build Table Structure */
+CREATE TABLE django_admin_log
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ action_time DATETIME NOT NULL,
+ user_id INTEGER NOT NULL,
+ content_type_id INTEGER NULL,
+ object_id LONGTEXT NULL,
+ object_repr VARCHAR(200) NOT NULL,
+ action_flag SMALLINT UNSIGNED NOT NULL,
+ change_message LONGTEXT NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
+
+/* Table Items: django_admin_log */
+
+/* Add Indexes for: django_admin_log */
+CREATE INDEX django_admin_log_content_type_id ON django_admin_log (content_type_id);
+CREATE INDEX django_admin_log_user_id ON django_admin_log (user_id);
+
+/******************** Add Table: django_authopenid_association ************************/
+
+/* Build Table Structure */
+CREATE TABLE django_authopenid_association
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ server_url LONGTEXT NOT NULL,
+ handle VARCHAR(255) NOT NULL,
+ secret LONGTEXT NOT NULL,
+ issued INTEGER NOT NULL,
+ lifetime INTEGER NOT NULL,
+ assoc_type LONGTEXT NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
+
+/******************** Add Table: django_authopenid_nonce ************************/
+
+/* Build Table Structure */
+CREATE TABLE django_authopenid_nonce
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ server_url VARCHAR(255) NOT NULL,
+ `timestamp` INTEGER NOT NULL,
+ salt VARCHAR(40) NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8;
+
+/******************** Add Table: django_authopenid_userassociation ************************/
+
+/* Build Table Structure */
+CREATE TABLE django_authopenid_userassociation
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ openid_url VARCHAR(255) NOT NULL,
+ user_id INTEGER NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
+
+/* Table Items: django_authopenid_userassociation */
+
+/* Add Indexes for: django_authopenid_userassociation */
+CREATE UNIQUE INDEX user_id ON django_authopenid_userassociation (user_id);
+
+/******************** Add Table: django_authopenid_userpasswordqueue ************************/
+
+/* Build Table Structure */
+CREATE TABLE django_authopenid_userpasswordqueue
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ new_password VARCHAR(30) NOT NULL,
+ confirm_key VARCHAR(40) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+/* Table Items: django_authopenid_userpasswordqueue */
+
+/* Add Indexes for: django_authopenid_userpasswordqueue */
+CREATE UNIQUE INDEX user_id ON django_authopenid_userpasswordqueue (user_id);
+
+/******************** Add Table: django_content_type ************************/
+
+/* Build Table Structure */
+CREATE TABLE django_content_type
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(100) NOT NULL,
+ app_label VARCHAR(100) NOT NULL,
+ model VARCHAR(100) NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;
+
+/* Table Items: django_content_type */
+
+/* Add Indexes for: django_content_type */
+CREATE UNIQUE INDEX app_label ON django_content_type (app_label, model);
+
+/******************** Add Table: django_session ************************/
+
+/* Build Table Structure */
+CREATE TABLE django_session
+(
+ session_key VARCHAR(40) NOT NULL,
+ session_data LONGTEXT NOT NULL,
+ expire_date DATETIME NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+/* Table Items: django_session */
+ALTER TABLE django_session ADD CONSTRAINT pkdjango_session
+ PRIMARY KEY (session_key);
+
+/******************** Add Table: django_site ************************/
+
+/* Build Table Structure */
+CREATE TABLE django_site
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ domain VARCHAR(100) NOT NULL,
+ name VARCHAR(50) NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
+
+/******************** Add Table: favorite_question ************************/
+
+/* Build Table Structure */
+CREATE TABLE favorite_question
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ question_id INTEGER NOT NULL,
+ user_id INTEGER NOT NULL,
+ added_at DATETIME NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
+
+/* Table Items: favorite_question */
+
+/* Add Indexes for: favorite_question */
+CREATE INDEX favorite_question_question_id ON favorite_question (question_id);
+CREATE INDEX favorite_question_user_id ON favorite_question (user_id);
+
+/******************** Add Table: flagged_item ************************/
+
+/* Build Table Structure */
+CREATE TABLE flagged_item
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ content_type_id INTEGER NOT NULL,
+ object_id INTEGER UNSIGNED NOT NULL,
+ user_id INTEGER NOT NULL,
+ flagged_at DATETIME NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
+
+/* Table Items: flagged_item */
+
+/* Add Indexes for: flagged_item */
+CREATE UNIQUE INDEX content_type_id ON flagged_item (content_type_id, object_id, user_id);
+CREATE INDEX flagged_item_content_type_id ON flagged_item (content_type_id);
+CREATE INDEX flagged_item_user_id ON flagged_item (user_id);
+
+/******************** Add Table: question ************************/
+
+/* Build Table Structure */
+CREATE TABLE question
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ title TEXT NOT NULL,
+ author_id INTEGER NOT NULL,
+ added_at DATETIME NOT NULL,
+ wiki TINYINT NOT NULL,
+ wikified_at DATETIME NULL,
+ answer_accepted TINYINT NOT NULL,
+ closed TINYINT NOT NULL,
+ closed_by_id INTEGER NULL,
+ closed_at DATETIME NULL,
+ close_reason SMALLINT NULL,
+ deleted TINYINT NOT NULL,
+ deleted_at DATETIME NULL,
+ deleted_by_id INTEGER NULL,
+ locked TINYINT NOT NULL,
+ locked_by_id INTEGER NULL,
+ locked_at DATETIME NULL,
+ score INTEGER NOT NULL,
+ answer_count INTEGER UNSIGNED NOT NULL,
+ comment_count INTEGER UNSIGNED NOT NULL,
+ view_count INTEGER UNSIGNED NOT NULL,
+ offensive_flag_count SMALLINT NOT NULL,
+ favourite_count INTEGER UNSIGNED NOT NULL,
+ last_edited_at DATETIME NULL,
+ last_edited_by_id INTEGER NULL,
+ last_activity_at DATETIME NOT NULL,
+ last_activity_by_id INTEGER NOT NULL,
+ tagnames VARCHAR(125) NOT NULL,
+ summary VARCHAR(180) NOT NULL,
+ html LONGTEXT NOT NULL,
+ vote_up_count INTEGER NOT NULL,
+ vote_down_count INTEGER NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;
+
+/* Table Items: question */
+
+/* Add Indexes for: question */
+CREATE INDEX question_author_id ON question (author_id);
+CREATE INDEX question_closed_by_id ON question (closed_by_id);
+CREATE INDEX question_deleted_by_id ON question (deleted_by_id);
+CREATE INDEX question_last_activity_by_id ON question (last_activity_by_id);
+CREATE INDEX question_last_edited_by_id ON question (last_edited_by_id);
+CREATE INDEX question_locked_by_id ON question (locked_by_id);
+
+/******************** Add Table: question_revision ************************/
+
+/* Build Table Structure */
+CREATE TABLE question_revision
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ question_id INTEGER NOT NULL,
+ revision INTEGER UNSIGNED NOT NULL,
+ title TEXT NOT NULL,
+ author_id INTEGER NOT NULL,
+ revised_at DATETIME NOT NULL,
+ tagnames VARCHAR(125) NOT NULL,
+ summary TEXT NOT NULL,
+ `text` LONGTEXT NOT NULL
+) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
+
+/* Table Items: question_revision */
+
+/* Add Indexes for: question_revision */
+CREATE INDEX question_revision_author_id ON question_revision (author_id);
+CREATE INDEX question_revision_question_id ON question_revision (question_id);
+
+/******************** Add Table: question_tags ************************/
+
+/* Build Table Structure */
+CREATE TABLE question_tags
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ question_id INTEGER NOT NULL,
+ tag_id INTEGER NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;
+
+/* Table Items: question_tags */
+
+/* Add Indexes for: question_tags */
+CREATE UNIQUE INDEX question_id ON question_tags (question_id, tag_id);
+CREATE INDEX tag_id_refs_id_43fcb953 ON question_tags (tag_id);
+
+/******************** Add Table: repute ************************/
+
+/* Build Table Structure */
+CREATE TABLE repute
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ positive SMALLINT NOT NULL,
+ negative SMALLINT NOT NULL,
+ question_id INTEGER NOT NULL,
+ reputed_at DATETIME NOT NULL,
+ reputation_type SMALLINT NOT NULL,
+ reputation INTEGER NOT NULL
+) ENGINE=MyISAM AUTO_INCREMENT=17 DEFAULT CHARSET=latin1;
+
+/* Table Items: repute */
+
+/* Add Indexes for: repute */
+CREATE INDEX repute_question_id ON repute (question_id);
+CREATE INDEX repute_user_id ON repute (user_id);
+
+/******************** Add Table: tag ************************/
+
+/* Build Table Structure */
+CREATE TABLE tag
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ created_by_id INTEGER NOT NULL,
+ used_count INTEGER UNSIGNED NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;
+
+/* Table Items: tag */
+
+/* Add Indexes for: tag */
+CREATE UNIQUE INDEX name ON tag (name);
+CREATE INDEX tag_created_by_id ON tag (created_by_id);
+
+/******************** Add Table: user_badge ************************/
+
+/* Build Table Structure */
+CREATE TABLE user_badge
+(
+ id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ badge_id INTEGER NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+/* Table Items: user_badge */
+
+/* Add Indexes for: user_badge */
+CREATE INDEX fk_user_badge_auth_user ON user_badge (user_id);
+CREATE INDEX fk_user_badge_badge ON user_badge (badge_id);
+
+/******************** Add Table: user_favorite_questions ************************/
+
+/* Build Table Structure */
+CREATE TABLE user_favorite_questions
+(
+ id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ question_id INTEGER NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+/* Table Items: user_favorite_questions */
+
+/* Add Indexes for: user_favorite_questions */
+CREATE INDEX fk_user_favorite_questions_auth_user ON user_favorite_questions (user_id);
+CREATE INDEX fk_user_favorite_questions_question ON user_favorite_questions (question_id);
+
+/******************** Add Table: vote ************************/
+
+/* Build Table Structure */
+CREATE TABLE vote
+(
+ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ content_type_id INTEGER NOT NULL,
+ object_id INTEGER UNSIGNED NOT NULL,
+ user_id INTEGER NOT NULL,
+ vote SMALLINT NOT NULL,
+ voted_at DATETIME NOT NULL
+) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
+
+/* Table Items: vote */
+
+/* Add Indexes for: vote */
+CREATE UNIQUE INDEX content_type_id ON vote (content_type_id, object_id, user_id);
+CREATE INDEX vote_content_type_id ON vote (content_type_id);
+CREATE INDEX vote_user_id ON vote (user_id);
+
+
+/************ Add Foreign Keys to Database ***************/
+/*-----------------------------------------------------------
+Warning: Versions of MySQL prior to 4.1.2 require indexes on all columns involved in a foreign key. The following indexes may be required:
+fk_auth_group_permissions_auth_group may require an index on table: auth_group_permissions, column: group_id
+fk_auth_user_groups_auth_user may require an index on table: auth_user_groups, column: user_id
+fk_auth_user_user_permissions_auth_user may require an index on table: auth_user_user_permissions, column: user_id
+fk_question_tags_question may require an index on table: question_tags, column: question_id
+-----------------------------------------------------------
+*/
+
+/************ Foreign Key: fk_activity_auth_user ***************/
+ALTER TABLE activity ADD CONSTRAINT fk_activity_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: deleted_by_id_refs_id_192b0170 ***************/
+ALTER TABLE answer ADD CONSTRAINT deleted_by_id_refs_id_192b0170
+ FOREIGN KEY (deleted_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_answer_auth_user ***************/
+ALTER TABLE answer ADD CONSTRAINT fk_answer_auth_user
+ FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_answer_question ***************/
+ALTER TABLE answer ADD CONSTRAINT fk_answer_question
+ FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: last_edited_by_id_refs_id_192b0170 ***************/
+ALTER TABLE answer ADD CONSTRAINT last_edited_by_id_refs_id_192b0170
+ FOREIGN KEY (last_edited_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: locked_by_id_refs_id_192b0170 ***************/
+ALTER TABLE answer ADD CONSTRAINT locked_by_id_refs_id_192b0170
+ FOREIGN KEY (locked_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_answer_revision_auth_user ***************/
+ALTER TABLE answer_revision ADD CONSTRAINT fk_answer_revision_auth_user
+ FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_auth_group_permissions_auth_group ***************/
+ALTER TABLE auth_group_permissions ADD CONSTRAINT fk_auth_group_permissions_auth_group
+ FOREIGN KEY (group_id) REFERENCES auth_group (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_auth_group_permissions_auth_permission ***************/
+ALTER TABLE auth_group_permissions ADD CONSTRAINT fk_auth_group_permissions_auth_permission
+ FOREIGN KEY (permission_id) REFERENCES auth_permission (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_auth_message_auth_user ***************/
+ALTER TABLE auth_message ADD CONSTRAINT fk_auth_message_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_auth_permission_django_content_type ***************/
+ALTER TABLE auth_permission ADD CONSTRAINT fk_auth_permission_django_content_type
+ FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_auth_user_groups_auth_group ***************/
+ALTER TABLE auth_user_groups ADD CONSTRAINT fk_auth_user_groups_auth_group
+ FOREIGN KEY (group_id) REFERENCES auth_group (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_auth_user_groups_auth_user ***************/
+ALTER TABLE auth_user_groups ADD CONSTRAINT fk_auth_user_groups_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_auth_user_user_permissions_auth_permission ***************/
+ALTER TABLE auth_user_user_permissions ADD CONSTRAINT fk_auth_user_user_permissions_auth_permission
+ FOREIGN KEY (permission_id) REFERENCES auth_permission (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_auth_user_user_permissions_auth_user ***************/
+ALTER TABLE auth_user_user_permissions ADD CONSTRAINT fk_auth_user_user_permissions_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_award_auth_user ***************/
+ALTER TABLE award ADD CONSTRAINT fk_award_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_award_badge ***************/
+ALTER TABLE award ADD CONSTRAINT fk_award_badge
+ FOREIGN KEY (badge_id) REFERENCES badge (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_books_auth_user ***************/
+ALTER TABLE book ADD CONSTRAINT fk_books_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_book_author_info_auth_user ***************/
+ALTER TABLE book_author_info ADD CONSTRAINT fk_book_author_info_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_book_author_info_book ***************/
+ALTER TABLE book_author_info ADD CONSTRAINT fk_book_author_info_book
+ FOREIGN KEY (book_id) REFERENCES book (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_book_author_rss_auth_user ***************/
+ALTER TABLE book_author_rss ADD CONSTRAINT fk_book_author_rss_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_book_author_rss_book ***************/
+ALTER TABLE book_author_rss ADD CONSTRAINT fk_book_author_rss_book
+ FOREIGN KEY (book_id) REFERENCES book (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_book_question_book ***************/
+ALTER TABLE book_question ADD CONSTRAINT fk_book_question_book
+ FOREIGN KEY (book_id) REFERENCES book (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_book_question_question ***************/
+ALTER TABLE book_question ADD CONSTRAINT fk_book_question_question
+ FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_comment_auth_user ***************/
+ALTER TABLE `comment` ADD CONSTRAINT fk_comment_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_comment_django_content_type ***************/
+ALTER TABLE `comment` ADD CONSTRAINT fk_comment_django_content_type
+ FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_django_admin_log_auth_user ***************/
+ALTER TABLE django_admin_log ADD CONSTRAINT fk_django_admin_log_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_django_admin_log_django_content_type ***************/
+ALTER TABLE django_admin_log ADD CONSTRAINT fk_django_admin_log_django_content_type
+ FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_django_authopenid_userassociation_auth_user ***************/
+ALTER TABLE django_authopenid_userassociation ADD CONSTRAINT fk_django_authopenid_userassociation_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_django_authopenid_userpasswordqueue_auth_user ***************/
+ALTER TABLE django_authopenid_userpasswordqueue ADD CONSTRAINT fk_django_authopenid_userpasswordqueue_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_favorite_question_auth_user ***************/
+ALTER TABLE favorite_question ADD CONSTRAINT fk_favorite_question_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_favorite_question_question ***************/
+ALTER TABLE favorite_question ADD CONSTRAINT fk_favorite_question_question
+ FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_flagged_item_auth_user ***************/
+ALTER TABLE flagged_item ADD CONSTRAINT fk_flagged_item_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_flagged_item_django_content_type ***************/
+ALTER TABLE flagged_item ADD CONSTRAINT fk_flagged_item_django_content_type
+ FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: closed_by_id_refs_id_56e9d00c ***************/
+ALTER TABLE question ADD CONSTRAINT closed_by_id_refs_id_56e9d00c
+ FOREIGN KEY (closed_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: deleted_by_id_refs_id_56e9d00c ***************/
+ALTER TABLE question ADD CONSTRAINT deleted_by_id_refs_id_56e9d00c
+ FOREIGN KEY (deleted_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_question_auth_user ***************/
+ALTER TABLE question ADD CONSTRAINT fk_question_auth_user
+ FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: last_activity_by_id_refs_id_56e9d00c ***************/
+ALTER TABLE question ADD CONSTRAINT last_activity_by_id_refs_id_56e9d00c
+ FOREIGN KEY (last_activity_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: last_edited_by_id_refs_id_56e9d00c ***************/
+ALTER TABLE question ADD CONSTRAINT last_edited_by_id_refs_id_56e9d00c
+ FOREIGN KEY (last_edited_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: locked_by_id_refs_id_56e9d00c ***************/
+ALTER TABLE question ADD CONSTRAINT locked_by_id_refs_id_56e9d00c
+ FOREIGN KEY (locked_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_question_revision_auth_user ***************/
+ALTER TABLE question_revision ADD CONSTRAINT fk_question_revision_auth_user
+ FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_question_revision_question ***************/
+ALTER TABLE question_revision ADD CONSTRAINT fk_question_revision_question
+ FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_question_tags_question ***************/
+ALTER TABLE question_tags ADD CONSTRAINT fk_question_tags_question
+ FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_question_tags_tag ***************/
+ALTER TABLE question_tags ADD CONSTRAINT fk_question_tags_tag
+ FOREIGN KEY (tag_id) REFERENCES tag (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_repute_auth_user ***************/
+ALTER TABLE repute ADD CONSTRAINT fk_repute_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_repute_question ***************/
+ALTER TABLE repute ADD CONSTRAINT fk_repute_question
+ FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_tag_auth_user ***************/
+ALTER TABLE tag ADD CONSTRAINT fk_tag_auth_user
+ FOREIGN KEY (created_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_user_badge_auth_user ***************/
+ALTER TABLE user_badge ADD CONSTRAINT fk_user_badge_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_user_badge_badge ***************/
+ALTER TABLE user_badge ADD CONSTRAINT fk_user_badge_badge
+ FOREIGN KEY (badge_id) REFERENCES badge (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_user_favorite_questions_auth_user ***************/
+ALTER TABLE user_favorite_questions ADD CONSTRAINT fk_user_favorite_questions_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_user_favorite_questions_question ***************/
+ALTER TABLE user_favorite_questions ADD CONSTRAINT fk_user_favorite_questions_question
+ FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_vote_auth_user ***************/
+ALTER TABLE vote ADD CONSTRAINT fk_vote_auth_user
+ FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
+
+/************ Foreign Key: fk_vote_django_content_type ***************/
+ALTER TABLE vote ADD CONSTRAINT fk_vote_django_content_type
+ FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION; \ No newline at end of file
diff --git a/forum/sql_scripts/drop-all-tables.sh b/forum/sql_scripts/drop-all-tables.sh
new file mode 100644
index 00000000..1e55cb1f
--- /dev/null
+++ b/forum/sql_scripts/drop-all-tables.sh
@@ -0,0 +1,4 @@
+mysql_username=''
+mysql_database=''
+mysqldump -u $mysql_username -p --add-drop-table --no-data $mysql_database | grep ^DROP
+#| mysql -u[USERNAME] -p[PASSWORD] [DATABASE]
diff --git a/forum/sql_scripts/drop-auth.sql b/forum/sql_scripts/drop-auth.sql
new file mode 100644
index 00000000..bc17dce3
--- /dev/null
+++ b/forum/sql_scripts/drop-auth.sql
@@ -0,0 +1,8 @@
+drop table auth_group;
+drop table auth_group_permissions;
+drop table auth_message;
+drop table auth_permission;
+drop table auth_user;
+drop table auth_user_groups;
+drop table auth_user_user_permissions;
+
diff --git a/forum/sql_scripts/pg_fts_install.sql b/forum/sql_scripts/pg_fts_install.sql
new file mode 100644
index 00000000..d0655134
--- /dev/null
+++ b/forum/sql_scripts/pg_fts_install.sql
@@ -0,0 +1,38 @@
+ALTER TABLE question ADD COLUMN tsv tsvector;
+
+CREATE OR REPLACE FUNCTION public.create_plpgsql_language ()
+ RETURNS TEXT
+ AS $$
+ CREATE LANGUAGE plpgsql;
+ SELECT 'language plpgsql created'::TEXT;
+ $$
+LANGUAGE 'sql';
+
+SELECT CASE WHEN
+ (SELECT true::BOOLEAN
+ FROM pg_language
+ WHERE lanname='plpgsql')
+ THEN
+ (SELECT 'language already installed'::TEXT)
+ ELSE
+ (SELECT public.create_plpgsql_language())
+ END;
+
+DROP FUNCTION public.create_plpgsql_language ();
+
+CREATE OR REPLACE FUNCTION set_question_tsv() RETURNS TRIGGER AS $$
+begin
+ new.tsv :=
+ setweight(to_tsvector('english', coalesce(new.tagnames,'')), 'A') ||
+ setweight(to_tsvector('english', coalesce(new.title,'')), 'B') ||
+ setweight(to_tsvector('english', coalesce(new.summary,'')), 'C');
+ RETURN new;
+end
+$$ LANGUAGE plpgsql;
+
+CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE
+ON question FOR EACH ROW EXECUTE PROCEDURE set_question_tsv();
+
+CREATE INDEX blog_entry_tsv ON blog_entry USING gin(body_tsv);
+
+UPDATE question SET title = title;
diff --git a/forum/sql_scripts/update_2009_01_13_001.sql b/forum/sql_scripts/update_2009_01_13_001.sql
new file mode 100644
index 00000000..165d1125
--- /dev/null
+++ b/forum/sql_scripts/update_2009_01_13_001.sql
@@ -0,0 +1,62 @@
+-- phpMyAdmin SQL Dump
+-- version 3.0.0-beta
+-- http://www.phpmyadmin.net
+--
+-- Host: localhost
+-- Generation Time: Jan 12, 2009 at 08:55 PM
+-- Server version: 5.0.67
+-- PHP Version: 5.2.6
+
+SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+
+--
+-- Database: `twogeekt_lanai`
+--
+
+--
+-- Dumping data for table `badge`
+--
+
+INSERT INTO `badge` (`id`, `name`, `type`, `slug`, `description`, `multiple`, `awarded_count`) VALUES
+(1, '炼狱法师', 3, '炼狱法师', '删除自己有3个以上赞成票的帖子', 1, 0),
+(2, '压力白领', 3, '压力白领', '删除自己有3个以上反对票的帖子', 1, 0),
+(3, '优秀回答', 3, '优秀回答', '回答好评10次以上', 1, 0),
+(4, '优秀问题', 3, '优秀问题', '问题好评10次以上', 1, 0),
+(5, '评论家', 3, '评论家', '评论10次以上', 1, 0),
+(6, '流行问题', 3, '流行问题', '问题的浏览量超过1000人次', 1, 0),
+(7, '巡逻兵', 3, '巡逻兵', '第一次标记垃圾帖子', 1, 0),
+(8, '清洁工', 3, '清洁工', '第一次撤销投票', 1, 0),
+(9, '批评家', 3, '批评家', '第一次反对票', 1, 0),
+(10, '小编', 3, '小编', '第一次编辑更新', 1, 0),
+(11, '村长', 3, '村长', '第一次重新标签', 1, 0),
+(12, '学者', 3, '学者', '第一次标记答案', 1, 0),
+(13, '学生', 3, '学生', '第一次提问并且有一次以上赞成票', 1, 0),
+(14, '支持者', 3, '支持者', '第一次赞成票', 1, 0),
+(15, '教师', 3, '教师', '第一次回答问题并且得到一个以上赞成票', 1, 0),
+(16, '自传作者', 3, '自传作者', '完整填写用户资料所有选项', 1, 0),
+(17, '自学成才', 3, '自学成才', '回答自己的问题并且有3个以上赞成票', 1, 0),
+(18, '最有价值回答', 1, '最有价值回答', '回答超过100次赞成票', 1, 0),
+(19, '最有价值问题', 1, '最有价值问题', '问题超过100次赞成票', 1, 0),
+(20, '万人迷', 1, '万人迷', '问题被100人以上收藏', 1, 0),
+(21, '著名问题', 1, '著名问题', '问题的浏览量超过10000人次', 1, 0),
+(22, 'alpha用户', 2, 'alpha用户', '内测期间的活跃用户', 1, 0),
+(23, '极好回答', 2, '极好回答', '回答超过25次赞成票', 1, 0),
+(24, '极好问题', 2, '极好问题', '问题超过25次赞成票', 1, 0),
+(25, '受欢迎问题', 2, '受欢迎问题', '问题被25人以上收藏', 1, 0),
+(26, '优秀市民', 2, '优秀市民', '投票300次以上', 1, 0),
+(27, '编辑主任', 2, '编辑主任', '编辑了100个帖子', 1, 0),
+(28, '通才', 2, '通才', '在多个标签领域活跃', 1, 0),
+(29, '专家', 2, '专家', '在一个标签领域活跃出众', 1, 0),
+(30, '老鸟', 2, '老鸟', '活跃超过一年的用户', 1, 0),
+(31, '最受关注问题', 2, '最受关注问题', '问题的浏览量超过2500人次', 1, 0),
+(32, '学问家', 2, '学问家', '第一次回答被投赞成票10次以上', 1, 0),
+(33, 'beta用户', 2, 'beta用户', 'beta期间活跃参与', 1, 0),
+(34, '导师', 2, '导师', '被指定为最佳答案并且赞成票40以上', 1, 0),
+(35, '巫师', 2, '巫师', '在提问60天之后回答并且赞成票5次以上', 1, 0),
+(36, '分类专家', 2, '分类专家', '创建的标签被50个以上问题使用', 1, 0);
diff --git a/forum/sql_scripts/update_2009_01_13_002.sql b/forum/sql_scripts/update_2009_01_13_002.sql
new file mode 100644
index 00000000..c223cb8c
--- /dev/null
+++ b/forum/sql_scripts/update_2009_01_13_002.sql
@@ -0,0 +1 @@
+ALTER TABLE activity ADD COLUMN is_auditted tinyint(1) DEFAULT 0 \ No newline at end of file
diff --git a/forum/sql_scripts/update_2009_01_18_001.sql b/forum/sql_scripts/update_2009_01_18_001.sql
new file mode 100644
index 00000000..6f29fa32
--- /dev/null
+++ b/forum/sql_scripts/update_2009_01_18_001.sql
@@ -0,0 +1,62 @@
+-- phpMyAdmin SQL Dump
+-- version 3.0.0-beta
+-- http://www.phpmyadmin.net
+--
+-- Host: localhost
+-- Generation Time: Jan 12, 2009 at 08:55 PM
+-- Server version: 5.0.67
+-- PHP Version: 5.2.6
+
+SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+
+--
+-- Database: `twogeekt_lanai`
+--
+
+--
+-- Dumping data for table `badge`
+--
+
+INSERT INTO `badge` (`id`, `name`, `type`, `slug`, `description`, `multiple`, `awarded_count`) VALUES
+(1, '炼狱法师', 3, '炼狱法师', '删除自己有3个以上赞成票的帖子', 1, 0),
+(2, '压力白领', 3, '压力白领', '删除自己有3个以上反对票的帖子', 1, 0),
+(3, '优秀回答', 3, '优秀回答', '回答好评10次以上', 1, 0),
+(4, '优秀问题', 3, '优秀问题', '问题好评10次以上', 1, 0),
+(5, '评论家', 3, '评论家', '评论10次以上', 0, 0),
+(6, '流行问题', 3, '流行问题', '问题的浏览量超过1000人次', 1, 0),
+(7, '巡逻兵', 3, '巡逻兵', '第一次标记垃圾帖子', 0, 0),
+(8, '清洁工', 3, '清洁工', '第一次撤销投票', 0, 0),
+(9, '批评家', 3, '批评家', '第一次反对票', 0, 0),
+(10, '小编', 3, '小编', '第一次编辑更新', 0, 0),
+(11, '村长', 3, '村长', '第一次重新标签', 0, 0),
+(12, '学者', 3, '学者', '第一次标记答案', 0, 0),
+(13, '学生', 3, '学生', '第一次提问并且有一次以上赞成票', 0, 0),
+(14, '支持者', 3, '支持者', '第一次赞成票', 0, 0),
+(15, '教师', 3, '教师', '第一次回答问题并且得到一个以上赞成票', 0, 0),
+(16, '自传作者', 3, '自传作者', '完整填写用户资料所有选项', 0, 0),
+(17, '自学成才', 3, '自学成才', '回答自己的问题并且有3个以上赞成票', 1, 0),
+(18, '最有价值回答', 1, '最有价值回答', '回答超过100次赞成票', 1, 0),
+(19, '最有价值问题', 1, '最有价值问题', '问题超过100次赞成票', 1, 0),
+(20, '万人迷', 1, '万人迷', '问题被100人以上收藏', 1, 0),
+(21, '著名问题', 1, '著名问题', '问题的浏览量超过10000人次', 1, 0),
+(22, 'alpha用户', 2, 'alpha用户', '内测期间的活跃用户', 0, 0),
+(23, '极好回答', 2, '极好回答', '回答超过25次赞成票', 1, 0),
+(24, '极好问题', 2, '极好问题', '问题超过25次赞成票', 1, 0),
+(25, '受欢迎问题', 2, '受欢迎问题', '问题被25人以上收藏', 1, 0),
+(26, '优秀市民', 2, '优秀市民', '投票300次以上', 0, 0),
+(27, '编辑主任', 2, '编辑主任', '编辑了100个帖子', 0, 0),
+(28, '通才', 2, '通才', '在多个标签领域活跃', 0, 0),
+(29, '专家', 2, '专家', '在一个标签领域活跃出众', 0, 0),
+(30, '老鸟', 2, '老鸟', '活跃超过一年的用户', 0, 0),
+(31, '最受关注问题', 2, '最受关注问题', '问题的浏览量超过2500人次', 1, 0),
+(32, '学问家', 2, '学问家', '第一次回答被投赞成票10次以上', 0, 0),
+(33, 'beta用户', 2, 'beta用户', 'beta期间活跃参与', 0, 0),
+(34, '导师', 2, '导师', '被指定为最佳答案并且赞成票40以上', 1, 0),
+(35, '巫师', 2, '巫师', '在提问60天之后回答并且赞成票5次以上', 1, 0),
+(36, '分类专家', 2, '分类专家', '创建的标签被50个以上问题使用', 1, 0);
diff --git a/forum/sql_scripts/update_2009_01_24.sql b/forum/sql_scripts/update_2009_01_24.sql
new file mode 100644
index 00000000..45b83935
--- /dev/null
+++ b/forum/sql_scripts/update_2009_01_24.sql
@@ -0,0 +1,2 @@
+ALTER TABLE award ADD COLUMN `content_type_id` int(11);
+ALTER TABLE award ADD COLUMN `object_id` int(10); \ No newline at end of file
diff --git a/forum/sql_scripts/update_2009_01_25_001.sql b/forum/sql_scripts/update_2009_01_25_001.sql
new file mode 100644
index 00000000..16c3487b
--- /dev/null
+++ b/forum/sql_scripts/update_2009_01_25_001.sql
@@ -0,0 +1,2 @@
+ALTER TABLE `award` ADD `content_type_id` INT NULL
+ALTER TABLE `award` ADD `object_id` INT NULL
diff --git a/forum/sql_scripts/update_2009_02_26_001.sql b/forum/sql_scripts/update_2009_02_26_001.sql
new file mode 100644
index 00000000..a6af5931
--- /dev/null
+++ b/forum/sql_scripts/update_2009_02_26_001.sql
@@ -0,0 +1,19 @@
+ALTER TABLE answer ADD COLUMN `accepted_at` datetime default null;
+
+/* Update accepted_at column with answer added datetime for existing data */
+UPDATE answer
+SET accepted_at = added_at
+WHERE accepted = 1 AND accepted_at IS NULL;
+
+/* workround for c# url problem on bluehost server */
+UPDATE tag
+SET name = 'csharp'
+WHERE name = 'c#'
+
+UPDATE question
+SET tagnames = replace(tagnames, 'c#', 'csharp')
+WHERE tagnames like '%c#%'
+
+UPDATE question_revision
+SET tagnames = replace(tagnames, 'c#', 'csharp')
+WHERE tagnames like '%c#%'
diff --git a/forum/sql_scripts/update_2009_04_10_001.sql b/forum/sql_scripts/update_2009_04_10_001.sql
new file mode 100644
index 00000000..8148632a
--- /dev/null
+++ b/forum/sql_scripts/update_2009_04_10_001.sql
@@ -0,0 +1,3 @@
+ALTER TABLE Tag ADD COLUMN deleted_at datetime default null;
+ALTER TABLE Tag ADD COLUMN deleted_by_id INTEGER NULL;
+ALTER TABLE Tag ADD COLUMN deleted TINYINT NOT NULL;
diff --git a/forum/sql_scripts/update_2009_07_05_EF.sql b/forum/sql_scripts/update_2009_07_05_EF.sql
new file mode 100644
index 00000000..43c7c2f0
--- /dev/null
+++ b/forum/sql_scripts/update_2009_07_05_EF.sql
@@ -0,0 +1,3 @@
+ALTER TABLE auth_user ADD COLUMN email_isvalid TINYINT(1) NOT NULL;
+UPDATE auth_user SET email_isvalid=1;
+ALTER TABLE auth_user ADD COLUMN email_key varchar(32);
diff --git a/forum/sql_scripts/update_2009_12_24_001.sql b/forum/sql_scripts/update_2009_12_24_001.sql
new file mode 100644
index 00000000..3d082c2f
--- /dev/null
+++ b/forum/sql_scripts/update_2009_12_24_001.sql
@@ -0,0 +1,5 @@
+alter table question add column `vote_up_count` int(11) NOT NULL;
+alter table question add column `vote_down_count` int(11) NOT NULL;
+
+alter table answer add column `vote_up_count` int(11) NOT NULL;
+alter table answer add column `vote_down_count` int(11) NOT NULL; \ No newline at end of file
diff --git a/forum/sql_scripts/update_2009_12_27_001.sql b/forum/sql_scripts/update_2009_12_27_001.sql
new file mode 100644
index 00000000..e2da7d4d
--- /dev/null
+++ b/forum/sql_scripts/update_2009_12_27_001.sql
@@ -0,0 +1,3 @@
+ALTER TABLE comment DROP INDEX content_type_id;
+
+ALTER TABLE comment ADD INDEX `content_type_id` (`content_type_id`,`object_id`,`user_id`); \ No newline at end of file
diff --git a/forum/sql_scripts/update_2009_12_27_002.sql b/forum/sql_scripts/update_2009_12_27_002.sql
new file mode 100644
index 00000000..a36470bf
--- /dev/null
+++ b/forum/sql_scripts/update_2009_12_27_002.sql
@@ -0,0 +1 @@
+ALTER TABLE `vote` ADD `voted_at` DATETIME NOT NULL \ No newline at end of file
diff --git a/forum/sql_scripts/update_2010_01_23.sql b/forum/sql_scripts/update_2010_01_23.sql
new file mode 100755
index 00000000..621207be
--- /dev/null
+++ b/forum/sql_scripts/update_2010_01_23.sql
@@ -0,0 +1,9 @@
+CREATE TABLE `fbconnect_fbassociation` (
+ `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
+ `user_id` integer NOT NULL,
+ `fbuid` varchar(12) NOT NULL UNIQUE
+)
+;
+ALTER TABLE `fbconnect_fbassociation` ADD CONSTRAINT `user_id_refs_id_3534873d`
+FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`);
+CREATE INDEX `fbconnect_fbassociation_user_id` ON `fbconnect_fbassociation` (`user_id`);
diff --git a/forum/sql_scripts/update_2010_02_22.sql b/forum/sql_scripts/update_2010_02_22.sql
new file mode 100644
index 00000000..2778885a
--- /dev/null
+++ b/forum/sql_scripts/update_2010_02_22.sql
@@ -0,0 +1 @@
+alter table answer add column deleted_at datetime;
diff --git a/forum/templatetags/extra_tags.py b/forum/templatetags/extra_tags.py
index 382d19f0..83aeb4c7 100755
--- a/forum/templatetags/extra_tags.py
+++ b/forum/templatetags/extra_tags.py
@@ -304,8 +304,12 @@ class ItemSeparatorNode(template.Node):
return self.content
class JoinItemListNode(template.Node):
- def __init__(self,separator=ItemSeparatorNode("''"), items=()):
+ def __init__(self,separator=ItemSeparatorNode("''"), last_separator=None, items=()):
self.separator = separator
+ if last_separator:
+ self.last_separator = last_separator
+ else:
+ self.last_separator = separator
self.items = items
def render(self,context):
out = []
@@ -314,16 +318,34 @@ class JoinItemListNode(template.Node):
bit = item.render(context)
if not empty_re.search(bit):
out.append(bit)
- return self.separator.render(context).join(out)
+ if len(out) == 1:
+ return out[0]
+ if len(out) > 1:
+ last = out.pop()
+ all_but_last = self.separator.render(context).join(out)
+ return self.last_separator.render(context).join((all_but_last,last))
+ else:
+ assert(len(out)==0)
+ return ''
@register.tag(name="joinitems")
def joinitems(parser,token):
try:
- tagname,junk,sep_token = token.split_contents()
- except ValueError:
- raise template.TemplateSyntaxError("joinitems tag requires 'using \"separator html\"' parameters")
+ tagname, junk, sep_token = token.split_contents()
+ last_sep_token = None
+ except:
+ try:
+ tagname, junk, sep_token, last_sep_token = token.split_contents()
+ except:
+ raise template.TemplateSyntaxError('incorrect usage of joinitems tag first param '
+ 'must be \'using\' second - separator and '
+ 'optional third - last item separator')
if junk == 'using':
sep_node = ItemSeparatorNode(sep_token)
+ if last_sep_token:
+ last_sep_node = ItemSeparatorNode(last_sep_token)
+ else:
+ last_sep_node = None
else:
raise template.TemplateSyntaxError("joinitems tag requires 'using \"separator html\"' parameters")
nodelist = []
@@ -333,7 +355,7 @@ def joinitems(parser,token):
if next.contents == 'endjoinitems':
break
- return JoinItemListNode(separator=sep_node,items=nodelist)
+ return JoinItemListNode(separator=sep_node,last_separator=last_sep_node,items=nodelist)
class BlockMediaUrlNode(template.Node):
def __init__(self,nodelist):
@@ -436,3 +458,46 @@ def question_counter_widget(question):
#returns a dictionary with keys like 'votes_bg', etc
return locals()
+class IsManyNode(template.Node):
+ def __init__(self, test_items, true_nodelist, false_nodelist):
+ self.true_nodelist = true_nodelist
+ self.false_nodelist = false_nodelist
+ self.test_items = test_items
+ def render(self, context):
+ maybe = False
+ for item in self.test_items:
+ is_good = item.resolve(context)
+ if maybe == True and is_good:
+ return self.true_nodelist.render(context)
+ if is_good:
+ maybe = True
+ return self.false_nodelist.render(context)
+
+@register.tag(name='ifmany')
+def ifmany(parser,token):
+ """usage {% ifmany item1 item2 item3 ... itemN %} stuff {% endifmany %}
+ returns content included into the tag if more than one
+ item evaluates to Tru'ish value - that's the idea
+ {% else %} is not supported yet
+ """
+
+ bits = list(token.split_contents())
+ start_tag = bits.pop(0)
+
+ test_items = []
+ for bit in bits:
+ item = parser.compile_filter(bit)
+ test_items.append(item)
+
+ end_tag = 'end' + start_tag
+ else_tag = 'else'
+ true_nodelist = parser.parse((end_tag,else_tag,))
+ token = parser.next_token()
+ if token.contents == else_tag:
+ false_nodelist = parser.parse((end_tag,))
+ token = parser.next_token()
+ else:
+ false_nodelist = template.NodeList()
+
+
+ return IsManyNode(test_items, true_nodelist, false_nodelist)
diff --git a/forum/utils/decorators.py b/forum/utils/decorators.py
index e4e7acb3..440e8312 100755
--- a/forum/utils/decorators.py
+++ b/forum/utils/decorators.py
@@ -22,4 +22,3 @@ def ajax_method(view_func):
json = simplejson.dumps(retval)
return HttpResponse(json,mimetype='application/json')
return wrap
-
diff --git a/forum/views/readers.py b/forum/views/readers.py
index 3f0bef0f..89a9550b 100644
--- a/forum/views/readers.py
+++ b/forum/views/readers.py
@@ -13,7 +13,6 @@ from django.db.models import Q
from django.utils.translation import ugettext as _
from django.template.defaultfilters import slugify
from django.core.urlresolvers import reverse
-from django.utils.datastructures import SortedDict
from django.views.decorators.cache import cache_page
from forum.utils.html import sanitize_html
@@ -24,8 +23,10 @@ from forum.forms import *
from forum.models import *
from forum.auth import *
from forum.const import *
+from forum import const
from forum import auth
from forum.utils.forms import get_next_url
+from forum.search.state_manager import SearchState
# used in index page
#refactor - move these numbers somewhere?
@@ -35,7 +36,6 @@ INDEX_TAGS_SIZE = 25
# used in tags list
DEFAULT_PAGE_SIZE = 60
# used in questions
-QUESTIONS_PAGE_SIZE = 30
# used in answers
ANSWERS_PAGE_SIZE = 10
@@ -54,24 +54,6 @@ def _get_tags_cache_json():#service routine used by views requiring tag list in
tags = simplejson.dumps(tags_list)
return tags
-def _get_and_remember_questions_sort_method(request, view_dic, default):#service routine used by q listing views and question view
- """manages persistence of post sort order
- it is assumed that when user wants newest question -
- then he/she wants newest answers as well, etc.
- how far should this assumption actually go - may be a good question
- """
- if default not in view_dic:
- raise Exception('default value must be in view_dic')
-
- q_sort_method = request.REQUEST.get('sort', None)
- if q_sort_method == None:
- q_sort_method = request.session.get('questions_sort_method', default)
-
- if q_sort_method not in view_dic:
- q_sort_method = default
- request.session['questions_sort_method'] = q_sort_method
- return q_sort_method, view_dic[q_sort_method]
-
#refactor? - we have these
#views that generate a listing of questions in one way or another:
#index, unanswered, questions, search, tag
@@ -81,280 +63,122 @@ def _get_and_remember_questions_sort_method(request, view_dic, default):#service
def index(request):#generates front page - shows listing of questions sorted in various ways
"""index view mapped to the root url of the Q&A site
"""
- view_dic = {
- "latest":"-last_activity_at",
- "hottest":"-answer_count",
- "mostvoted":"-score",
- }
- view_id, orderby = _get_and_remember_questions_sort_method(request, view_dic, 'latest')
-
- pagesize = request.session.get("pagesize",QUESTIONS_PAGE_SIZE)
- try:
- page = int(request.GET.get('page', '1'))
- except ValueError:
- page = 1
-
- qs = Question.objects.exclude(deleted=True).order_by(orderby)
-
- objects_list = Paginator(qs, pagesize)
- questions = objects_list.page(page)
-
- # RISK - inner join queries
- #questions = questions.select_related()
- tags = Tag.objects.get_valid_tags(INDEX_TAGS_SIZE)
-
- awards = Award.objects.get_recent_awards()
-
- (interesting_tag_names, ignored_tag_names) = (None, None)
- if request.user.is_authenticated():
- pt = MarkedTag.objects.filter(user=request.user)
- interesting_tag_names = pt.filter(reason='good').values_list('tag__name', flat=True)
- ignored_tag_names = pt.filter(reason='bad').values_list('tag__name', flat=True)
-
- tags_autocomplete = _get_tags_cache_json()
-
- return render_to_response('index.html', {
- 'interesting_tag_names': interesting_tag_names,
- 'tags_autocomplete': tags_autocomplete,
- 'ignored_tag_names': ignored_tag_names,
- "questions" : questions,
- "tab_id" : view_id,
- "tags" : tags,
- "awards" : awards[:INDEX_AWARD_SIZE],
- "context" : {
- 'is_paginated' : True,
- 'pages': objects_list.num_pages,
- 'page': page,
- 'has_previous': questions.has_previous(),
- 'has_next': questions.has_next(),
- 'previous': questions.previous_page_number(),
- 'next': questions.next_page_number(),
- 'base_url' : request.path + '?sort=%s&' % view_id,
- 'pagesize' : pagesize
- }}, context_instance=RequestContext(request))
+ return HttpResponseRedirect(reverse('questions'))
+#todo: eliminate this from urls
def unanswered(request):#generates listing of unanswered questions
return questions(request, unanswered=True)
-def questions(request, tagname=None, unanswered=False):#a view generating listing of questions, used by 'unanswered' too
+def questions(request):#a view generating listing of questions, used by 'unanswered' too
"""
List of Questions, Tagged questions, and Unanswered questions.
"""
- # template file
- # "questions.html" or maybe index.html in the future
- template_file = "questions.html"
- # Set flag to False by default. If it is equal to True, then need to be saved.
- pagesize_changed = False
- # get pagesize from session, if failed then get default value
- pagesize = request.session.get("pagesize",QUESTIONS_PAGE_SIZE)
- try:
- page = int(request.GET.get('page', '1'))
- except ValueError:
- page = 1
- view_dic = {"latest":"-added_at", "active":"-last_activity_at", "hottest":"-answer_count", "mostvoted":"-score" }
- view_id, orderby = _get_and_remember_questions_sort_method(request,view_dic,'latest')
-
- # check if request is from tagged questions
- qs = Question.objects.exclude(deleted=True)
+ #don't allow to post to this view
+ if request.method == 'POST':
+ raise Http404
- if tagname is not None:
- qs = qs.filter(tags__name = unquote(tagname))
+ #todo: redo SearchState to accept input from
+ #view_log, session and request parameters
+ search_state = request.session.get('search_state', SearchState())
- if unanswered:
- qs = qs.exclude(answer_accepted=True)
+ view_log = request.session['view_log']
- author_name = None
- #user contributed questions & answers
- if 'user' in request.GET:
- try:
- author_name = request.GET['user']
- u = User.objects.get(username=author_name)
- qs = qs.filter(Q(author=u) | Q(answers__author=u))
- except User.DoesNotExist:
- author_name = None
+ if view_log.get_previous(1) != 'questions':
+ if view_log.get_previous(2) != 'questions':
+ #print 'user stepped too far, resetting search state'
+ search_state.reset()
if request.user.is_authenticated():
- uid_str = str(request.user.id)
- qs = qs.extra(
- select = SortedDict([
- (
- 'interesting_score',
- 'SELECT COUNT(1) FROM forum_markedtag, question_tags '
- + 'WHERE forum_markedtag.user_id = %s '
- + 'AND forum_markedtag.tag_id = question_tags.tag_id '
- + 'AND forum_markedtag.reason = \'good\' '
- + 'AND question_tags.question_id = question.id'
- ),
- ]),
- select_params = (uid_str,),
- )
- if request.user.hide_ignored_questions:
- ignored_tags = Tag.objects.filter(user_selections__reason='bad',
- user_selections__user = request.user)
- qs = qs.exclude(tags__in=ignored_tags)
- else:
- qs = qs.extra(
- select = SortedDict([
- (
- 'ignored_score',
- 'SELECT COUNT(1) FROM forum_markedtag, question_tags '
- + 'WHERE forum_markedtag.user_id = %s '
- + 'AND forum_markedtag.tag_id = question_tags.tag_id '
- + 'AND forum_markedtag.reason = \'bad\' '
- + 'AND question_tags.question_id = question.id'
- )
- ]),
- select_params = (uid_str, )
- )
-
- qs = qs.select_related(depth=1).order_by(orderby)
-
- objects_list = Paginator(qs, pagesize)
- questions = objects_list.page(page)
-
- # Get related tags from this page objects
- if questions.object_list.count() > 0:
- related_tags = Tag.objects.get_tags_by_questions(questions.object_list)
- else:
- related_tags = None
- tags_autocomplete = _get_tags_cache_json()
+ search_state.set_logged_in()
+
+ form = AdvancedSearchForm(request.GET)
+ #todo: form is used only for validation...
+ if form.is_valid():
+ search_state.update_from_user_input(
+ form.cleaned_data,
+ request.GET,
+ )
+ #todo: better put these in separately then analyze
+ #what neesd to be done, otherwise there are two routines
+ #that take request.GET I don't like this use of parameters
+ #another weakness is that order of routine calls matters here
+ search_state.relax_stickiness( request.GET, view_log )
+
+ request.session['search_state'] = search_state
+ request.session.modified = True
+
+ #force reset for debugging
+ #search_state.reset()
+ #request.session.modified = True
+
+ #have this call implemented for sphinx, mysql and pgsql
+ (qs, meta_data) = Question.objects.run_advanced_search(
+ request_user = request.user,
+ scope_selector = search_state.scope,#unanswered/all/favorite (for logged in)
+ search_query = search_state.query,
+ tag_selector = search_state.tags,
+ author_selector = search_state.author,
+ sort_method = search_state.sort
+ )
+
+ objects_list = Paginator(qs, search_state.page_size)
+ questions = objects_list.page(search_state.page)
+
+ #todo maybe do this search on query the set instead
+ related_tags = Tag.objects.get_tags_by_questions(questions.object_list)
- # get the list of interesting and ignored tags
- (interesting_tag_names, ignored_tag_names) = (None, None)
- if request.user.is_authenticated():
- pt = MarkedTag.objects.filter(user=request.user)
- interesting_tag_names = pt.filter(reason='good').values_list('tag__name', flat=True)
- ignored_tag_names = pt.filter(reason='bad').values_list('tag__name', flat=True)
+ tags_autocomplete = _get_tags_cache_json()
- return render_to_response(template_file, {
- "questions" : questions,
- "author_name" : author_name,
- "tab_id" : view_id,
- "questions_count" : objects_list.count,
- "tags" : related_tags,
- "tags_autocomplete" : tags_autocomplete,
- "searchtag" : tagname,
- "is_unanswered" : unanswered,
- "interesting_tag_names": interesting_tag_names,
- 'ignored_tag_names': ignored_tag_names,
- "context" : {
+ #todo!!!!
+ #contributors = #User.objects.get_related_to_questions
+
+ #todo: organize variables by type
+ return render_to_response('questions.html', {
+ 'questions' : questions,
+ 'author_name' : meta_data.get('author_name',None),
+ 'tab_id' : search_state.sort,
+ 'questions_count' : objects_list.count,
+ 'tags' : related_tags,
+ 'query': search_state.query,
+ 'search_tags' : search_state.tags,
+ 'tags_autocomplete' : tags_autocomplete,
+ 'is_unanswered' : False,#remove this from template
+ 'interesting_tag_names': meta_data.get('interesting_tag_names',None),
+ 'ignored_tag_names': meta_data.get('ignored_tag_names',None),
+ 'sort': search_state.sort,
+ 'scope': search_state.scope,
+ 'context' : {
'is_paginated' : True,
'pages': objects_list.num_pages,
- 'page': page,
+ 'page': search_state.page,
'has_previous': questions.has_previous(),
'has_next': questions.has_next(),
'previous': questions.previous_page_number(),
'next': questions.next_page_number(),
- 'base_url' : request.path + '?sort=%s&' % view_id,
- 'pagesize' : pagesize
+ 'base_url' : request.path + '?sort=%s&' % search_state.sort,#todo in T sort=>sort_method
+ 'pagesize' : search_state.page_size,#todo in T pagesize -> page_size
}}, context_instance=RequestContext(request))
def search(request): #generates listing of questions matching a search query - including tags and just words
- """generates listing of questions matching a search query
- supports full text search in mysql db using sphinx and internally in postgresql
- falls back on simple partial string matching approach if
- full text search function is not available
+ """redirects to people and tag search pages
+ todo: eliminate this altogether and instead make
+ search "tab" sensitive automatically - the radio-buttons
+ are useless under the search bar
"""
if request.method == "GET":
- keywords = request.GET.get("q")
- search_type = request.GET.get("t")
+ search_type = request.GET.get('t')
+ query = request.GET.get('query')
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
- if keywords is None:
- return HttpResponseRedirect(reverse(index))
if search_type == 'tag':
- return HttpResponseRedirect(reverse('tags') + '?q=%s&page=%s' % (keywords.strip(), page))
- elif search_type == "user":
- return HttpResponseRedirect(reverse('users') + '?q=%s&page=%s' % (keywords.strip(), page))
- elif search_type == "question":
-
- template_file = "questions.html"
- # Set flag to False by default. If it is equal to True, then need to be saved.
- pagesize_changed = False
- # get pagesize from session, if failed then get default value
- user_page_size = request.session.get("pagesize", QUESTIONS_PAGE_SIZE)
- # set pagesize equal to logon user specified value in database
- if request.user.is_authenticated() and request.user.questions_per_page > 0:
- user_page_size = request.user.questions_per_page
-
- try:
- page = int(request.GET.get('page', '1'))
- # get new pagesize from UI selection
- pagesize = int(request.GET.get('pagesize', user_page_size))
- if pagesize <> user_page_size:
- pagesize_changed = True
-
- except ValueError:
- page = 1
- pagesize = user_page_size
-
- # save this pagesize to user database
- if pagesize_changed:
- request.session["pagesize"] = pagesize
- if request.user.is_authenticated():
- user = request.user
- user.questions_per_page = pagesize
- user.save()
-
- view_id = request.GET.get('sort', None)
- view_dic = {"latest":"-added_at", "active":"-last_activity_at", "hottest":"-answer_count", "mostvoted":"-score" }
- try:
- orderby = view_dic[view_id]
- except KeyError:
- view_id = "latest"
- orderby = "-added_at"
-
- def question_search(keywords, orderby):
- objects = Question.objects.filter(deleted=False).extra(where=['title like %s'], params=['%' + keywords + '%']).order_by(orderby)
- # RISK - inner join queries
- return objects.select_related();
-
- from forum.modules import get_handler
-
- question_search = get_handler('question_search', question_search)
-
- objects = question_search(keywords, orderby)
-
- objects_list = Paginator(objects, pagesize)
- questions = objects_list.page(page)
-
- # Get related tags from this page objects
- related_tags = []
- for question in questions.object_list:
- tags = list(question.tags.all())
- for tag in tags:
- if tag not in related_tags:
- related_tags.append(tag)
-
- #if is_search is true in the context, prepend this string to soting tabs urls
- search_uri = "?q=%s&page=%d&t=question" % ("+".join(keywords.split()), page)
-
- return render_to_response(template_file, {
- "questions" : questions,
- "tab_id" : view_id,
- "questions_count" : objects_list.count,
- "tags" : related_tags,
- "searchtag" : None,
- "searchtitle" : keywords,
- "keywords" : keywords,
- "is_unanswered" : False,
- "is_search": True,
- "search_uri": search_uri,
- "context" : {
- 'is_paginated' : True,
- 'pages': objects_list.num_pages,
- 'page': page,
- 'has_previous': questions.has_previous(),
- 'has_next': questions.has_next(),
- 'previous': questions.previous_page_number(),
- 'next': questions.next_page_number(),
- 'base_url' : request.path + '?t=question&q=%s&sort=%s&' % (keywords, view_id),
- 'pagesize' : pagesize
- }}, context_instance=RequestContext(request))
-
+ return HttpResponseRedirect(reverse('tags') + '?q=%s&page=%s' % (query.strip(), page))
+ elif search_type == 'user':
+ return HttpResponseRedirect(reverse('users') + '?q=%s&page=%s' % (query.strip(), page))
+ else:
+ raise Http404
else:
raise Http404
@@ -386,6 +210,7 @@ def tags(request):#view showing a listing of available tags - plain list
tags = objects_list.page(objects_list.num_pages)
return render_to_response('tags.html', {
+ "active_tab": "tags",
"tags" : tags,
"stag" : stag,
"tab_id" : sortby,
diff --git a/forum/views/users.py b/forum/views/users.py
index 705bbbb0..113c46e6 100755
--- a/forum/views/users.py
+++ b/forum/views/users.py
@@ -17,6 +17,7 @@ from forum import auth
import calendar
from django.contrib.contenttypes.models import ContentType
from forum.models import user_updated
+from forum.const import USERS_PAGE_SIZE
from django.conf import settings
question_type = ContentType.objects.get_for_model(Question)
@@ -32,8 +33,6 @@ question_revision_type_id = question_revision_type.id
answer_revision_type_id = answer_revision_type.id
repute_type_id = repute_type.id
-USERS_PAGE_SIZE = 35# refactor - move to some constants file
-
def users(request):
is_paginated = True
sortby = request.GET.get('sort', 'reputation')
@@ -65,11 +64,12 @@ def users(request):
users = objects_list.page(objects_list.num_pages)
return render_to_response('users.html', {
- "users" : users,
- "suser" : suser,
- "keywords" : suser,
- "tab_id" : sortby,
- "context" : {
+ 'active_tab': 'users',
+ 'users' : users,
+ 'suser' : suser,
+ 'keywords' : suser,
+ 'tab_id' : sortby,
+ 'context' : {
'is_paginated' : is_paginated,
'pages': objects_list.num_pages,
'page': page,
@@ -124,6 +124,7 @@ def edit_user(request, id):
if settings.EDITABLE_SCREEN_NAME:
user.username = sanitize_html(form.cleaned_data['username'])
+
user.real_name = sanitize_html(form.cleaned_data['realname'])
user.website = sanitize_html(form.cleaned_data['website'])
user.location = sanitize_html(form.cleaned_data['city'])
diff --git a/forum/views/writers.py b/forum/views/writers.py
index b9b1aad5..57c8e043 100755
--- a/forum/views/writers.py
+++ b/forum/views/writers.py
@@ -132,9 +132,18 @@ def ask(request):#view used to ask a new question
return HttpResponseRedirect(reverse('user_signin_new_question'))
else:
form = AskForm()
+ if 'title' in request.GET:
+ raw_title = request.GET['title']
+ form.initial['title'] = strip_tags(strip_entities(raw_title))
+ else:
+ search_state = request.session.get('search_state',None)
+ if search_state:
+ query = search_state.query
+ form.initial['title'] = query
tags = _get_tags_cache_json()
return render_to_response('ask.html', {
+ 'active_tab': 'ask',
'form' : form,
'tags' : tags,
'email_validation_faq_url':reverse('faq') + '#validate',
@@ -318,7 +327,6 @@ def __generate_comments_json(obj, type, user):#non-view generates json data for
data = simplejson.dumps(json_comments)
return HttpResponse(data, mimetype="application/json")
-
def question_comments(request, id):#ajax handler for loading comments to question
question = get_object_or_404(Question, id=id)
user = request.user