summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x.gitignore16
-rw-r--r--MANIFEST.in11
-rw-r--r--README9
-rwxr-xr-xaskbot.iml10
-rw-r--r--askbot/LICENSE (renamed from forum/LICENSE)0
-rw-r--r--askbot/__init__.py14
-rw-r--r--[-rwxr-xr-x]askbot/admin.py (renamed from forum/admin.py)32
-rw-r--r--[-rwxr-xr-x]askbot/auth.py (renamed from forum/auth.py)334
-rw-r--r--askbot/bin/dos2unix.sh (renamed from dos2unix.sh)0
-rwxr-xr-xaskbot/bin/rmpyc (renamed from rmpyc)0
-rw-r--r--askbot/conf/README5
-rw-r--r--askbot/conf/__init__.py16
-rw-r--r--askbot/conf/email.py69
-rw-r--r--askbot/conf/external_keys.py93
-rw-r--r--askbot/conf/flatpages.py37
-rw-r--r--askbot/conf/forum_data_rules.py62
-rw-r--r--askbot/conf/minimum_reputation.py148
-rw-r--r--askbot/conf/reputation_changes.py149
-rw-r--r--askbot/conf/settings_wrapper.py77
-rw-r--r--askbot/conf/site_settings.py94
-rw-r--r--askbot/conf/skin_counter_settings.py251
-rw-r--r--askbot/conf/skin_general_settings.py38
-rw-r--r--askbot/conf/user_settings.py30
-rw-r--r--askbot/conf/vote_rules.py69
-rw-r--r--[-rwxr-xr-x]askbot/const/__init__.py (renamed from forum/const.py)107
-rw-r--r--askbot/const/message_keys.py19
-rw-r--r--askbot/context.py34
-rw-r--r--askbot/cron/README (renamed from forum/cron/README)0
-rw-r--r--askbot/cron/askbot_cron_job18
-rw-r--r--askbot/deployment/__init__.py101
-rw-r--r--askbot/deployment/dialogs.py20
-rw-r--r--askbot/deployment/messages.py91
-rw-r--r--askbot/deployment/path_utils.py146
-rw-r--r--askbot/deps/README2
-rw-r--r--askbot/deps/__init__.py (renamed from __init__.py)0
-rw-r--r--askbot/deps/django_authopenid/README5
-rw-r--r--askbot/deps/django_authopenid/__init__.py (renamed from django_authopenid/__init__.py)0
-rw-r--r--askbot/deps/django_authopenid/admin.py (renamed from django_authopenid/admin.py)2
-rw-r--r--askbot/deps/django_authopenid/forms.py (renamed from django_authopenid/forms.py)11
-rw-r--r--askbot/deps/django_authopenid/middleware.py (renamed from django_authopenid/middleware.py)2
-rw-r--r--askbot/deps/django_authopenid/mimeparse.py (renamed from django_authopenid/mimeparse.py)0
-rw-r--r--askbot/deps/django_authopenid/models.py (renamed from django_authopenid/models.py)0
-rw-r--r--[-rwxr-xr-x]askbot/deps/django_authopenid/urls.py (renamed from django_authopenid/urls.py)6
-rw-r--r--askbot/deps/django_authopenid/util.py (renamed from django_authopenid/util.py)2
-rw-r--r--[-rwxr-xr-x]askbot/deps/django_authopenid/views.py (renamed from django_authopenid/views.py)46
-rw-r--r--askbot/deps/grapefruit.py (renamed from forum_modules/grapefruit.py)0
-rw-r--r--askbot/deps/livesettings/README4
-rw-r--r--askbot/deps/livesettings/__init__.py16
-rw-r--r--askbot/deps/livesettings/forms.py38
-rw-r--r--askbot/deps/livesettings/functions.py247
-rw-r--r--askbot/deps/livesettings/locale/de/LC_MESSAGES/django.mobin0 -> 706 bytes
-rw-r--r--askbot/deps/livesettings/locale/de/LC_MESSAGES/django.po101
-rw-r--r--askbot/deps/livesettings/locale/en/LC_MESSAGES/django.mobin0 -> 367 bytes
-rw-r--r--askbot/deps/livesettings/locale/en/LC_MESSAGES/django.po100
-rw-r--r--[-rwxr-xr-x]askbot/deps/livesettings/locale/es/LC_MESSAGES/django.po (renamed from fbconnect/__init__.py)0
-rw-r--r--askbot/deps/livesettings/locale/fr/LC_MESSAGES/django.mobin0 -> 1621 bytes
-rw-r--r--askbot/deps/livesettings/locale/fr/LC_MESSAGES/django.po113
-rw-r--r--askbot/deps/livesettings/locale/he/LC_MESSAGES/django.mobin0 -> 1655 bytes
-rw-r--r--askbot/deps/livesettings/locale/he/LC_MESSAGES/django.po98
-rw-r--r--askbot/deps/livesettings/locale/it/LC_MESSAGES/django.mobin0 -> 1582 bytes
-rw-r--r--askbot/deps/livesettings/locale/it/LC_MESSAGES/django.po106
-rw-r--r--askbot/deps/livesettings/locale/ko/LC_MESSAGES/django.mobin0 -> 1128 bytes
-rw-r--r--askbot/deps/livesettings/locale/ko/LC_MESSAGES/django.po100
-rw-r--r--askbot/deps/livesettings/locale/pl/LC_MESSAGES/django.mobin0 -> 1470 bytes
-rw-r--r--askbot/deps/livesettings/locale/pl/LC_MESSAGES/django.po97
-rw-r--r--askbot/deps/livesettings/locale/pt_BR/LC_MESSAGES/django.mobin0 -> 1208 bytes
-rw-r--r--askbot/deps/livesettings/locale/pt_BR/LC_MESSAGES/django.po100
-rw-r--r--askbot/deps/livesettings/locale/ru/LC_MESSAGES/django.mobin0 -> 1178 bytes
-rw-r--r--askbot/deps/livesettings/locale/ru/LC_MESSAGES/django.po85
-rw-r--r--askbot/deps/livesettings/locale/sv/LC_MESSAGES/django.mobin0 -> 1481 bytes
-rw-r--r--askbot/deps/livesettings/locale/sv/LC_MESSAGES/django.po92
-rw-r--r--askbot/deps/livesettings/locale/tr/LC_MESSAGES/django.mobin0 -> 1242 bytes
-rw-r--r--askbot/deps/livesettings/locale/tr/LC_MESSAGES/django.po102
-rw-r--r--askbot/deps/livesettings/models.py170
-rw-r--r--askbot/deps/livesettings/overrides.py55
-rw-r--r--askbot/deps/livesettings/signals.py3
-rw-r--r--askbot/deps/livesettings/templates/livesettings/_admin_site_views.html15
-rw-r--r--askbot/deps/livesettings/templates/livesettings/group_settings.html81
-rw-r--r--askbot/deps/livesettings/templates/livesettings/site_settings.html101
-rw-r--r--askbot/deps/livesettings/templates/livesettings/text.txt1
-rw-r--r--askbot/deps/livesettings/templatetags/__init__.py (renamed from forum/importers/__init__.py)0
-rw-r--r--askbot/deps/livesettings/templatetags/config_tags.py91
-rw-r--r--askbot/deps/livesettings/tests.py545
-rw-r--r--askbot/deps/livesettings/urls.py7
-rw-r--r--askbot/deps/livesettings/utils.py87
-rw-r--r--askbot/deps/livesettings/values.py628
-rw-r--r--askbot/deps/livesettings/views.py93
-rw-r--r--askbot/deps/recaptcha_django/.svn/all-wcprops17
-rw-r--r--askbot/deps/recaptcha_django/.svn/entries52
-rw-r--r--askbot/deps/recaptcha_django/.svn/format1
-rw-r--r--askbot/deps/recaptcha_django/.svn/text-base/__init__.py.svn-base76
-rw-r--r--askbot/deps/recaptcha_django/.svn/text-base/middleware.py.svn-base12
-rw-r--r--askbot/deps/recaptcha_django/__init__.py80
-rw-r--r--askbot/deps/recaptcha_django/docs/.svn/all-wcprops11
-rw-r--r--askbot/deps/recaptcha_django/docs/.svn/entries40
-rw-r--r--askbot/deps/recaptcha_django/docs/.svn/format1
-rw-r--r--askbot/deps/recaptcha_django/docs/.svn/text-base/overview.txt.svn-base1
-rw-r--r--askbot/deps/recaptcha_django/docs/overview.txt1
-rw-r--r--askbot/deps/recaptcha_django/middleware.py12
-rw-r--r--askbot/doc/HOW_TO_DEBUG (renamed from forum/documentation/HOW_TO_DEBUG)0
-rw-r--r--askbot/doc/INSTALL (renamed from forum/documentation/INSTALL)111
-rw-r--r--askbot/doc/INSTALL.pip (renamed from forum/documentation/INSTALL.pip)0
-rw-r--r--askbot/doc/INSTALL.webfaction (renamed from forum/documentation/INSTALL.webfaction)0
-rw-r--r--askbot/doc/ROADMAP.rst (renamed from forum/documentation/ROADMAP.rst)0
-rw-r--r--askbot/doc/TODO.rst (renamed from forum/documentation/TODO.rst)0
-rw-r--r--askbot/doc/UPGRADE (renamed from forum/documentation/UPGRADE)0
-rw-r--r--askbot/doc/WISH_LIST (renamed from forum/documentation/WISH_LIST)0
-rw-r--r--askbot/doc/askbot-requirements.txt (renamed from forum/documentation/askbot-requirements.txt)0
-rw-r--r--askbot/doc/scratch (renamed from forum/documentation/scratch)5
-rw-r--r--askbot/feed.py63
-rw-r--r--[-rwxr-xr-x]askbot/forms.py (renamed from forum/forms.py)134
-rw-r--r--askbot/importers/__init__.py (renamed from forum/importers/stackexchange/__init__.py)0
-rw-r--r--askbot/importers/stackexchange/ANOMALIES (renamed from forum/importers/stackexchange/ANOMALIES)0
-rw-r--r--askbot/importers/stackexchange/README (renamed from forum/importers/stackexchange/README)0
-rw-r--r--askbot/importers/stackexchange/__init__.py (renamed from forum/importers/stackexchange/management/__init__.py)0
-rw-r--r--askbot/importers/stackexchange/management/__init__.py (renamed from forum/importers/stackexchange/management/commands/__init__.py)0
-rw-r--r--[-rwxr-xr-x]askbot/importers/stackexchange/management/commands/__init__.py (renamed from forum/management/commands/__init__.py)0
-rw-r--r--askbot/importers/stackexchange/management/commands/load_stackexchange.py (renamed from forum/importers/stackexchange/management/commands/load_stackexchange.py)25
-rw-r--r--askbot/importers/stackexchange/models.py (renamed from forum/importers/stackexchange/models.py)0
-rw-r--r--askbot/importers/stackexchange/parse_models.py (renamed from forum/importers/stackexchange/parse_models.py)0
-rw-r--r--askbot/locale/de/LC_MESSAGES/django.mo (renamed from locale/de/LC_MESSAGES/django.mo)bin80778 -> 80778 bytes
-rw-r--r--askbot/locale/de/LC_MESSAGES/django.po (renamed from locale/de/LC_MESSAGES/django.po)0
-rw-r--r--askbot/locale/en/LC_MESSAGES/django.mobin0 -> 24140 bytes
-rw-r--r--askbot/locale/en/LC_MESSAGES/django.po (renamed from locale/en/LC_MESSAGES/django.po)1970
-rw-r--r--askbot/locale/es/LC_MESSAGES/django.mo (renamed from locale/es/LC_MESSAGES/django.mo)bin43243 -> 43243 bytes
-rw-r--r--askbot/locale/es/LC_MESSAGES/django.po (renamed from locale/es/LC_MESSAGES/django.po)0
-rw-r--r--askbot/locale/ru/LC_MESSAGES/django.mo (renamed from locale/ru/LC_MESSAGES/django.mo)bin93578 -> 93578 bytes
-rw-r--r--askbot/locale/ru/LC_MESSAGES/django.po (renamed from locale/ru/LC_MESSAGES/django.po)256
-rw-r--r--askbot/locale/sr/LC_MESSAGES/django.mo (renamed from locale/sr/LC_MESSAGES/django.mo)bin56072 -> 56072 bytes
-rw-r--r--askbot/locale/sr/LC_MESSAGES/django.po (renamed from locale/sr/LC_MESSAGES/django.po)0
-rw-r--r--askbot/locale/tr/LC_MESSAGES/django.mo (renamed from locale/tr/LC_MESSAGES/django.mo)bin52874 -> 52874 bytes
-rw-r--r--askbot/locale/tr/LC_MESSAGES/django.po (renamed from locale/tr/LC_MESSAGES/django.po)0
-rw-r--r--askbot/locale/vi/LC_MESSAGES/django.mo (renamed from locale/vi/LC_MESSAGES/django.mo)bin25588 -> 25588 bytes
-rw-r--r--askbot/locale/vi/LC_MESSAGES/django.po (renamed from locale/vi/LC_MESSAGES/django.po)0
-rw-r--r--askbot/locale/zh-cn/LC_MESSAGES/django.mo (renamed from locale/zh-cn/LC_MESSAGES/django.mo)bin24271 -> 24271 bytes
-rw-r--r--askbot/locale/zh-cn/LC_MESSAGES/django.po (renamed from locale/zh-cn/LC_MESSAGES/django.po)0
-rw-r--r--[-rwxr-xr-x]askbot/management/__init__.py (renamed from forum/middleware/__init__.py)0
-rw-r--r--askbot/management/commands/__init__.py (renamed from forum/migrations/__init__.py)0
-rw-r--r--askbot/management/commands/add_admin.py (renamed from forum/management/commands/add_admin.py)0
-rw-r--r--[-rwxr-xr-x]askbot/management/commands/base_command.py (renamed from forum/management/commands/base_command.py)18
-rw-r--r--[-rwxr-xr-x]askbot/management/commands/clean_award_badges.py (renamed from forum/management/commands/clean_award_badges.py)18
-rw-r--r--[-rwxr-xr-x]askbot/management/commands/message_to_everyone.py (renamed from forum/management/commands/message_to_everyone.py)0
-rw-r--r--[-rwxr-xr-x]askbot/management/commands/multi_award_badges.py (renamed from forum/management/commands/multi_award_badges.py)87
-rw-r--r--[-rwxr-xr-x]askbot/management/commands/once_award_badges.py (renamed from forum/management/commands/once_award_badges.py)99
-rw-r--r--[-rwxr-xr-x]askbot/management/commands/pg_base_command.py (renamed from forum/management/commands/pg_base_command.py)4
-rw-r--r--[-rwxr-xr-x]askbot/management/commands/pg_clean_award_badges.py (renamed from forum/management/commands/pg_clean_award_badges.py)2
-rw-r--r--[-rwxr-xr-x]askbot/management/commands/pg_multi_award_badges.py (renamed from forum/management/commands/pg_multi_award_badges.py)4
-rw-r--r--[-rwxr-xr-x]askbot/management/commands/pg_once_award_badges.py (renamed from forum/management/commands/pg_once_award_badges.py)4
-rw-r--r--askbot/management/commands/remove_admin.py (renamed from forum/management/commands/remove_admin.py)0
-rw-r--r--[-rwxr-xr-x]askbot/management/commands/sample_command.py (renamed from forum/management/commands/sample_command.py)2
-rw-r--r--askbot/management/commands/send_email_alerts.py477
-rw-r--r--[-rwxr-xr-x]askbot/management/commands/subscribe_everyone.py (renamed from forum/management/commands/subscribe_everyone.py)19
-rw-r--r--askbot/middleware/__init__.py (renamed from forum/search/__init__.py)0
-rw-r--r--[-rwxr-xr-x]askbot/middleware/anon_user.py (renamed from forum/middleware/anon_user.py)27
-rw-r--r--[-rwxr-xr-x]askbot/middleware/cancel.py (renamed from forum/middleware/cancel.py)2
-rw-r--r--[-rwxr-xr-x]askbot/middleware/pagesize.py (renamed from forum/middleware/pagesize.py)18
-rw-r--r--askbot/middleware/spaceless.py15
-rw-r--r--askbot/middleware/view_log.py (renamed from forum/middleware/view_log.py)10
-rw-r--r--askbot/migrations/0001_initial.py1550
-rw-r--r--askbot/migrations/0002_auto__add_field_answer_text__chg_field_answer_html__add_field_question.py700
-rw-r--r--askbot/migrations/0003_copy_denorm_text_record_to_posts_for_fulltext_search.py687
-rw-r--r--askbot/migrations/0004_install_full_text_indexes_for_mysql.py720
-rw-r--r--askbot/migrations/0005_install_badges.py751
-rw-r--r--askbot/migrations/0006_add_subscription_setting_for_comments_and_mentions.py719
-rw-r--r--askbot/migrations/0007_install_mentions_model.py708
-rw-r--r--askbot/migrations/0008_add_html_field_to_comments.py708
-rw-r--r--askbot/migrations/0009_calculate_html_field_for_comments.py854
-rw-r--r--askbot/migrations/0010_add_receiving_user_to_activity_model.py (renamed from forum/migrations/0002_auto__add_field_answer_text__chg_field_answer_html__add_field_question.py)48
-rw-r--r--askbot/migrations/0011_merge_mentions_into_activity.py724
-rw-r--r--askbot/migrations/0012_delete_some_unused_models.py755
-rw-r--r--askbot/migrations/0013_add_response_count__to_user.py (renamed from forum/migrations/0003_copy_denorm_text_record_to_posts_for_fulltext_search.py)104
-rw-r--r--askbot/migrations/0014_rename_schema_from_forum_to_askbot.py611
-rw-r--r--askbot/migrations/0015_rename_forum_contenttypes_to_askbot.py (renamed from forum/migrations/0004_install_full_text_indexes_for_mysql.py)281
-rw-r--r--[-rwxr-xr-x]askbot/migrations/__init__.py (renamed from forum/templatetags/__init__.py)0
-rw-r--r--askbot/models/__init__.py696
-rw-r--r--[-rwxr-xr-x]askbot/models/answer.py (renamed from forum/models/answer.py)89
-rw-r--r--askbot/models/base.py211
-rw-r--r--askbot/models/content.py245
-rw-r--r--askbot/models/meta.py211
-rw-r--r--[-rwxr-xr-x]askbot/models/question.py (renamed from forum/models/question.py)221
-rw-r--r--[-rwxr-xr-x]askbot/models/repute.py (renamed from forum/models/repute.py)21
-rw-r--r--askbot/models/signals.py23
-rw-r--r--[-rwxr-xr-x]askbot/models/tag.py (renamed from forum/models/tag.py)9
-rw-r--r--askbot/models/user.py340
-rw-r--r--askbot/search/README (renamed from forum/search/README)0
-rw-r--r--[-rwxr-xr-x]askbot/search/__init__.py (renamed from forum/utils/__init__.py)0
-rw-r--r--askbot/search/indexer.py (renamed from forum/search/indexer.py)0
-rw-r--r--askbot/search/sphinx/README (renamed from forum/search/sphinx/README)0
-rw-r--r--askbot/search/sphinx/sphinx.conf (renamed from forum/search/sphinx/sphinx.conf)0
-rw-r--r--askbot/search/state_manager.py (renamed from forum/search/state_manager.py)55
-rw-r--r--[-rwxr-xr-x]askbot/setup_templates/__init__.py (renamed from forum_modules/__init__.py)0
-rw-r--r--askbot/setup_templates/django.wsgi (renamed from django.wsgi)0
-rw-r--r--askbot/setup_templates/log/README (renamed from log/README)0
-rw-r--r--askbot/setup_templates/manage.py (renamed from manage.py)0
-rw-r--r--askbot/setup_templates/settings.py194
-rwxr-xr-xaskbot/setup_templates/upfiles/README (renamed from forum/upfiles/README)0
-rw-r--r--askbot/setup_templates/urls.py (renamed from urls.py)10
-rw-r--r--[-rwxr-xr-x]askbot/sitemap.py (renamed from forum/sitemap.py)2
-rwxr-xr-xaskbot/skins/README (renamed from forum/skins/README)0
-rw-r--r--[-rwxr-xr-x]askbot/skins/__init__.py (renamed from forum_modules/robotstxt/__init__.py)0
-rwxr-xr-xaskbot/skins/common/media/README (renamed from forum/skins/common/media/README)0
-rwxr-xr-xaskbot/skins/default/media/images/blue-up-arrow-h18px.png (renamed from forum/skins/default/media/images/blue-up-arrow-h18px.png)bin593 -> 593 bytes
-rwxr-xr-xaskbot/skins/default/media/images/box-arrow.gif (renamed from forum/skins/default/media/images/box-arrow.gif)bin69 -> 69 bytes
-rwxr-xr-xaskbot/skins/default/media/images/bullet_green.gif (renamed from forum/skins/default/media/images/bullet_green.gif)bin64 -> 64 bytes
-rwxr-xr-xaskbot/skins/default/media/images/cc-88x31.png (renamed from forum/skins/default/media/images/cc-88x31.png)bin5460 -> 5460 bytes
-rwxr-xr-xaskbot/skins/default/media/images/cc-wiki.png (renamed from forum/skins/default/media/images/cc-wiki.png)bin2333 -> 2333 bytes
-rwxr-xr-xaskbot/skins/default/media/images/close-small-dark.png (renamed from forum/skins/default/media/images/close-small-dark.png)bin226 -> 226 bytes
-rwxr-xr-xaskbot/skins/default/media/images/close-small-hover.png (renamed from forum/skins/default/media/images/close-small-hover.png)bin337 -> 337 bytes
-rwxr-xr-xaskbot/skins/default/media/images/close-small.png (renamed from forum/skins/default/media/images/close-small.png)bin293 -> 293 bytes
-rwxr-xr-xaskbot/skins/default/media/images/dash.gif (renamed from forum/skins/default/media/images/dash.gif)bin44 -> 44 bytes
-rwxr-xr-xaskbot/skins/default/media/images/djangomade124x25_grey.gif (renamed from forum/skins/default/media/images/djangomade124x25_grey.gif)bin2035 -> 2035 bytes
-rwxr-xr-xaskbot/skins/default/media/images/dot-g.gif (renamed from forum/skins/default/media/images/dot-g.gif)bin61 -> 61 bytes
-rwxr-xr-xaskbot/skins/default/media/images/dot-list.gif (renamed from forum/skins/default/media/images/dot-list.gif)bin56 -> 56 bytes
-rwxr-xr-xaskbot/skins/default/media/images/edit.png (renamed from forum/skins/default/media/images/edit.png)bin758 -> 758 bytes
-rwxr-xr-xaskbot/skins/default/media/images/expander-arrow-hide.gif (renamed from forum/skins/default/media/images/expander-arrow-hide.gif)bin126 -> 126 bytes
-rwxr-xr-xaskbot/skins/default/media/images/expander-arrow-show.gif (renamed from forum/skins/default/media/images/expander-arrow-show.gif)bin135 -> 135 bytes
-rw-r--r--askbot/skins/default/media/images/favicon.gif (renamed from forum/skins/default/media/images/favicon.gif)bin898 -> 898 bytes
-rwxr-xr-xaskbot/skins/default/media/images/feed-icon-small.png (renamed from forum/skins/default/media/images/feed-icon-small.png)bin689 -> 689 bytes
-rwxr-xr-xaskbot/skins/default/media/images/gray-up-arrow-h18px.png (renamed from forum/skins/default/media/images/gray-up-arrow-h18px.png)bin383 -> 383 bytes
-rwxr-xr-xaskbot/skins/default/media/images/grippie.png (renamed from forum/skins/default/media/images/grippie.png)bin162 -> 162 bytes
-rwxr-xr-xaskbot/skins/default/media/images/indicator.gif (renamed from forum/skins/default/media/images/indicator.gif)bin2545 -> 2545 bytes
-rw-r--r--askbot/skins/default/media/images/logo.gif (renamed from forum/skins/default/media/images/logo.gif)bin2272 -> 2272 bytes
-rw-r--r--askbot/skins/default/media/images/logo.png (renamed from forum/skins/default/media/images/logo.png)bin5841 -> 5841 bytes
-rwxr-xr-xaskbot/skins/default/media/images/logo1.png (renamed from forum/skins/default/media/images/logo1.png)bin2752 -> 2752 bytes
-rwxr-xr-xaskbot/skins/default/media/images/logo2.png (renamed from forum/skins/default/media/images/logo2.png)bin2124 -> 2124 bytes
-rw-r--r--askbot/skins/default/media/images/mail-envelope-empty.pngbin0 -> 547 bytes
-rw-r--r--askbot/skins/default/media/images/mail-envelope-full.pngbin0 -> 482 bytes
-rwxr-xr-xaskbot/skins/default/media/images/medala.gif (renamed from forum/skins/default/media/images/medala.gif)bin801 -> 801 bytes
-rwxr-xr-xaskbot/skins/default/media/images/medala_on.gif (renamed from forum/skins/default/media/images/medala_on.gif)bin957 -> 957 bytes
-rwxr-xr-xaskbot/skins/default/media/images/new.gif (renamed from forum/skins/default/media/images/new.gif)bin635 -> 635 bytes
-rwxr-xr-xaskbot/skins/default/media/images/nophoto.png (renamed from forum/skins/default/media/images/nophoto.png)bin696 -> 696 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid.gif (renamed from forum/skins/default/media/images/openid.gif)bin910 -> 910 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid/aol.gif (renamed from forum/skins/default/media/images/openid/aol.gif)bin2205 -> 2205 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid/blogger.ico (renamed from forum/skins/default/media/images/openid/blogger.ico)bin3638 -> 3638 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid/claimid.ico (renamed from forum/skins/default/media/images/openid/claimid.ico)bin3638 -> 3638 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid/facebook.gif (renamed from forum/skins/default/media/images/openid/facebook.gif)bin2075 -> 2075 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid/flickr.ico (renamed from forum/skins/default/media/images/openid/flickr.ico)bin1150 -> 1150 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid/google.gif (renamed from forum/skins/default/media/images/openid/google.gif)bin1596 -> 1596 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid/livejournal.ico (renamed from forum/skins/default/media/images/openid/livejournal.ico)bin5222 -> 5222 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid/myopenid.ico (renamed from forum/skins/default/media/images/openid/myopenid.ico)bin2862 -> 2862 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid/openid-inputicon.gif (renamed from forum/skins/default/media/images/openid/openid-inputicon.gif)bin237 -> 237 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid/openid.gif (renamed from forum/skins/default/media/images/openid/openid.gif)bin740 -> 740 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid/technorati.ico (renamed from forum/skins/default/media/images/openid/technorati.ico)bin2294 -> 2294 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid/twitter.png (renamed from forum/skins/default/media/images/openid/twitter.png)bin3130 -> 3130 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid/verisign.ico (renamed from forum/skins/default/media/images/openid/verisign.ico)bin4710 -> 4710 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid/vidoop.ico (renamed from forum/skins/default/media/images/openid/vidoop.ico)bin1406 -> 1406 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid/wordpress.ico (renamed from forum/skins/default/media/images/openid/wordpress.ico)bin1150 -> 1150 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid/yahoo.gif (renamed from forum/skins/default/media/images/openid/yahoo.gif)bin1510 -> 1510 bytes
-rwxr-xr-xaskbot/skins/default/media/images/quest-bg.gif (renamed from forum/skins/default/media/images/quest-bg.gif)bin294 -> 294 bytes
-rwxr-xr-xaskbot/skins/default/media/images/vote-accepted-on.png (renamed from forum/skins/default/media/images/vote-accepted-on.png)bin1124 -> 1124 bytes
-rwxr-xr-xaskbot/skins/default/media/images/vote-accepted.png (renamed from forum/skins/default/media/images/vote-accepted.png)bin1058 -> 1058 bytes
-rwxr-xr-xaskbot/skins/default/media/images/vote-arrow-down-on.png (renamed from forum/skins/default/media/images/vote-arrow-down-on.png)bin905 -> 905 bytes
-rwxr-xr-xaskbot/skins/default/media/images/vote-arrow-down.png (renamed from forum/skins/default/media/images/vote-arrow-down.png)bin876 -> 876 bytes
-rwxr-xr-xaskbot/skins/default/media/images/vote-arrow-up-on.png (renamed from forum/skins/default/media/images/vote-arrow-up-on.png)bin906 -> 906 bytes
-rwxr-xr-xaskbot/skins/default/media/images/vote-arrow-up.png (renamed from forum/skins/default/media/images/vote-arrow-up.png)bin843 -> 843 bytes
-rwxr-xr-xaskbot/skins/default/media/images/vote-favorite-off.png (renamed from forum/skins/default/media/images/vote-favorite-off.png)bin930 -> 930 bytes
-rwxr-xr-xaskbot/skins/default/media/images/vote-favorite-on.png (renamed from forum/skins/default/media/images/vote-favorite-on.png)bin1023 -> 1023 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/aol.gif (renamed from forum/skins/default/media/jquery-openid/images/aol.gif)bin2205 -> 2205 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/blogger-1.png (renamed from forum/skins/default/media/jquery-openid/images/blogger-1.png)bin432 -> 432 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/blogger.ico (renamed from forum/skins/default/media/jquery-openid/images/blogger.ico)bin3638 -> 3638 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/claimid-0.png (renamed from forum/skins/default/media/jquery-openid/images/claimid-0.png)bin629 -> 629 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/claimid.ico (renamed from forum/skins/default/media/jquery-openid/images/claimid.ico)bin3638 -> 3638 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/facebook.gif (renamed from forum/skins/default/media/jquery-openid/images/facebook.gif)bin2075 -> 2075 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/flickr.ico (renamed from forum/skins/default/media/jquery-openid/images/flickr.ico)bin1150 -> 1150 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/flickr.png (renamed from forum/skins/default/media/jquery-openid/images/flickr.png)bin426 -> 426 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/google.gif (renamed from forum/skins/default/media/jquery-openid/images/google.gif)bin1596 -> 1596 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/livejournal-1.png (renamed from forum/skins/default/media/jquery-openid/images/livejournal-1.png)bin713 -> 713 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/livejournal.ico (renamed from forum/skins/default/media/jquery-openid/images/livejournal.ico)bin5222 -> 5222 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/myopenid-2.png (renamed from forum/skins/default/media/jquery-openid/images/myopenid-2.png)bin511 -> 511 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/myopenid.ico (renamed from forum/skins/default/media/jquery-openid/images/myopenid.ico)bin2862 -> 2862 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/openid-inputicon.gif (renamed from forum/skins/default/media/jquery-openid/images/openid-inputicon.gif)bin237 -> 237 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/openid.gif (renamed from forum/skins/default/media/jquery-openid/images/openid.gif)bin740 -> 740 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/openidico.png (renamed from forum/skins/default/media/jquery-openid/images/openidico.png)bin654 -> 654 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/openidico16.png (renamed from forum/skins/default/media/jquery-openid/images/openidico16.png)bin554 -> 554 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/technorati-1.png (renamed from forum/skins/default/media/jquery-openid/images/technorati-1.png)bin606 -> 606 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/technorati.ico (renamed from forum/skins/default/media/jquery-openid/images/technorati.ico)bin2294 -> 2294 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/verisign-2.png (renamed from forum/skins/default/media/jquery-openid/images/verisign-2.png)bin859 -> 859 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/verisign.ico (renamed from forum/skins/default/media/jquery-openid/images/verisign.ico)bin4710 -> 4710 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/vidoop.ico (renamed from forum/skins/default/media/jquery-openid/images/vidoop.ico)bin1406 -> 1406 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/vidoop.png (renamed from forum/skins/default/media/jquery-openid/images/vidoop.png)bin499 -> 499 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/wordpress.ico (renamed from forum/skins/default/media/jquery-openid/images/wordpress.ico)bin1150 -> 1150 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/wordpress.png (renamed from forum/skins/default/media/jquery-openid/images/wordpress.png)bin566 -> 566 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/images/yahoo.gif (renamed from forum/skins/default/media/jquery-openid/images/yahoo.gif)bin1682 -> 1682 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/jquery.openid.js (renamed from forum/skins/default/media/jquery-openid/jquery.openid.js)0
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/openid.css (renamed from forum/skins/default/media/jquery-openid/openid.css)0
-rw-r--r--askbot/skins/default/media/js/com.cnprog.admin.js (renamed from forum/skins/default/media/js/com.cnprog.admin.js)0
-rw-r--r--askbot/skins/default/media/js/com.cnprog.editor.js (renamed from forum/skins/default/media/js/com.cnprog.editor.js)0
-rw-r--r--askbot/skins/default/media/js/com.cnprog.i18n.js (renamed from forum/skins/default/media/js/com.cnprog.i18n.js)0
-rwxr-xr-xaskbot/skins/default/media/js/com.cnprog.post.js (renamed from forum/skins/default/media/js/com.cnprog.post.js)0
-rw-r--r--askbot/skins/default/media/js/com.cnprog.tag_selector.js (renamed from forum/skins/default/media/js/com.cnprog.tag_selector.js)0
-rw-r--r--askbot/skins/default/media/js/com.cnprog.utils.js (renamed from forum/skins/default/media/js/com.cnprog.utils.js)0
-rwxr-xr-xaskbot/skins/default/media/js/compress.bat (renamed from forum/skins/default/media/js/compress.bat)0
-rw-r--r--askbot/skins/default/media/js/excanvas.min.js (renamed from forum/skins/default/media/js/excanvas.min.js)0
-rwxr-xr-xaskbot/skins/default/media/js/flot-build.bat (renamed from forum/skins/default/media/js/flot-build.bat)0
-rw-r--r--askbot/skins/default/media/js/jquery-1.2.6.js (renamed from forum/skins/default/media/js/jquery-1.2.6.js)0
-rw-r--r--askbot/skins/default/media/js/jquery-1.2.6.min.js (renamed from forum/skins/default/media/js/jquery-1.2.6.min.js)0
-rw-r--r--askbot/skins/default/media/js/jquery.ajaxfileupload.js (renamed from forum/skins/default/media/js/jquery.ajaxfileupload.js)0
-rw-r--r--askbot/skins/default/media/js/jquery.flot.js (renamed from forum/skins/default/media/js/jquery.flot.js)0
-rw-r--r--askbot/skins/default/media/js/jquery.flot.min.js (renamed from forum/skins/default/media/js/jquery.flot.min.js)0
-rw-r--r--askbot/skins/default/media/js/jquery.form.js (renamed from forum/skins/default/media/js/jquery.form.js)0
-rw-r--r--askbot/skins/default/media/js/jquery.i18n.js (renamed from forum/skins/default/media/js/jquery.i18n.js)0
-rw-r--r--askbot/skins/default/media/js/jquery.openid.js (renamed from forum/skins/default/media/js/jquery.openid.js)0
-rw-r--r--askbot/skins/default/media/js/jquery.validate.pack.js (renamed from forum/skins/default/media/js/jquery.validate.pack.js)0
-rw-r--r--askbot/skins/default/media/js/org.askbot.output-words.html (renamed from forum/skins/default/media/js/org.askbot.output-words.html)0
-rw-r--r--askbot/skins/default/media/js/org.askbot.output-words.js (renamed from forum/skins/default/media/js/org.askbot.output-words.js)0
-rw-r--r--askbot/skins/default/media/js/se_hilite.js (renamed from forum/skins/default/media/js/se_hilite.js)0
-rw-r--r--askbot/skins/default/media/js/se_hilite_src.js (renamed from forum/skins/default/media/js/se_hilite_src.js)0
-rwxr-xr-xaskbot/skins/default/media/js/wmd/images/wmd-buttons.png (renamed from forum/skins/default/media/js/wmd/images/wmd-buttons.png)bin7465 -> 7465 bytes
-rwxr-xr-xaskbot/skins/default/media/js/wmd/showdown-min.js (renamed from forum/skins/default/media/js/wmd/showdown-min.js)0
-rwxr-xr-xaskbot/skins/default/media/js/wmd/showdown.js (renamed from forum/skins/default/media/js/wmd/showdown.js)0
-rwxr-xr-xaskbot/skins/default/media/js/wmd/wmd-min.js (renamed from forum/skins/default/media/js/wmd/wmd-min.js)0
-rwxr-xr-xaskbot/skins/default/media/js/wmd/wmd-test.html (renamed from forum/skins/default/media/js/wmd/wmd-test.html)0
-rwxr-xr-xaskbot/skins/default/media/js/wmd/wmd.css (renamed from forum/skins/default/media/js/wmd/wmd.css)0
-rwxr-xr-xaskbot/skins/default/media/js/wmd/wmd.js (renamed from forum/skins/default/media/js/wmd/wmd.js)0
-rwxr-xr-xaskbot/skins/default/media/js/yuicompressor-2.4.2.jar (renamed from forum/skins/default/media/js/yuicompressor-2.4.2.jar)bin851219 -> 851219 bytes
-rwxr-xr-xaskbot/skins/default/media/style/auth.css (renamed from forum/skins/default/media/style/auth.css)0
-rwxr-xr-xaskbot/skins/default/media/style/default.css (renamed from forum/skins/default/media/style/default.css)0
-rwxr-xr-xaskbot/skins/default/media/style/jquery.autocomplete.css (renamed from forum/skins/default/media/style/jquery.autocomplete.css)0
-rwxr-xr-xaskbot/skins/default/media/style/openid.css (renamed from forum/skins/default/media/style/openid.css)0
-rwxr-xr-xaskbot/skins/default/media/style/prettify.css (renamed from forum/skins/default/media/style/prettify.css)0
-rwxr-xr-xaskbot/skins/default/media/style/style.css (renamed from forum/skins/default/media/style/style.css)54
-rw-r--r--askbot/skins/default/templates/404.html (renamed from forum/skins/default/templates/404.html)0
-rw-r--r--askbot/skins/default/templates/500.html (renamed from forum/skins/default/templates/500.html)0
-rw-r--r--askbot/skins/default/templates/about.html18
-rw-r--r--askbot/skins/default/templates/account_settings.html (renamed from forum/skins/default/templates/account_settings.html)0
-rw-r--r--askbot/skins/default/templates/answer_edit.html (renamed from forum/skins/default/templates/answer_edit.html)0
-rw-r--r--askbot/skins/default/templates/answer_edit_tips.html (renamed from forum/skins/default/templates/answer_edit_tips.html)0
-rw-r--r--askbot/skins/default/templates/ask.html (renamed from forum/skins/default/templates/ask.html)4
-rw-r--r--askbot/skins/default/templates/ask_form.html (renamed from forum/skins/default/templates/ask_form.html)4
-rw-r--r--askbot/skins/default/templates/authopenid/changeemail.html (renamed from forum/skins/default/templates/authopenid/changeemail.html)0
-rw-r--r--askbot/skins/default/templates/authopenid/changeopenid.html (renamed from forum/skins/default/templates/authopenid/changeopenid.html)0
-rw-r--r--askbot/skins/default/templates/authopenid/changepw.html (renamed from forum/skins/default/templates/authopenid/changepw.html)0
-rw-r--r--askbot/skins/default/templates/authopenid/complete.html (renamed from forum/skins/default/templates/authopenid/complete.html)0
-rw-r--r--askbot/skins/default/templates/authopenid/confirm_email.txt (renamed from forum/skins/default/templates/authopenid/confirm_email.txt)0
-rw-r--r--askbot/skins/default/templates/authopenid/delete.html (renamed from forum/skins/default/templates/authopenid/delete.html)0
-rw-r--r--askbot/skins/default/templates/authopenid/email_validation.txt (renamed from forum/skins/default/templates/authopenid/email_validation.txt)0
-rw-r--r--askbot/skins/default/templates/authopenid/external_legacy_login_info.html (renamed from forum/skins/default/templates/authopenid/external_legacy_login_info.html)0
-rw-r--r--askbot/skins/default/templates/authopenid/failure.html (renamed from forum/skins/default/templates/authopenid/failure.html)0
-rw-r--r--askbot/skins/default/templates/authopenid/sendpw.html (renamed from forum/skins/default/templates/authopenid/sendpw.html)0
-rw-r--r--askbot/skins/default/templates/authopenid/sendpw_email.txt (renamed from forum/skins/default/templates/authopenid/sendpw_email.txt)0
-rw-r--r--askbot/skins/default/templates/authopenid/settings.html (renamed from forum/skins/default/templates/authopenid/settings.html)0
-rwxr-xr-xaskbot/skins/default/templates/authopenid/signin.html (renamed from forum/skins/default/templates/authopenid/signin.html)0
-rw-r--r--askbot/skins/default/templates/authopenid/signup.html (renamed from forum/skins/default/templates/authopenid/signup.html)0
-rw-r--r--askbot/skins/default/templates/authopenid/yadis.xrdf (renamed from forum/skins/default/templates/authopenid/yadis.xrdf)0
-rw-r--r--askbot/skins/default/templates/badge.html (renamed from forum/skins/default/templates/badge.html)0
-rw-r--r--askbot/skins/default/templates/badges.html (renamed from forum/skins/default/templates/badges.html)0
-rw-r--r--askbot/skins/default/templates/base.html (renamed from forum/skins/default/templates/base.html)6
-rw-r--r--askbot/skins/default/templates/base_content.html (renamed from forum/skins/default/templates/base_content.html)6
-rw-r--r--askbot/skins/default/templates/book.html (renamed from forum/skins/default/templates/book.html)0
-rw-r--r--askbot/skins/default/templates/close.html (renamed from forum/skins/default/templates/close.html)0
-rw-r--r--askbot/skins/default/templates/edit_user_email_feeds_form.html (renamed from forum/skins/default/templates/edit_user_email_feeds_form.html)0
-rw-r--r--askbot/skins/default/templates/email_base.html (renamed from forum/skins/default/templates/email_base.html)0
-rw-r--r--askbot/skins/default/templates/faq.html (renamed from forum/skins/default/templates/faq.html)36
-rwxr-xr-xaskbot/skins/default/templates/fbconnect/xd_receiver.html (renamed from forum/skins/default/templates/fbconnect/xd_receiver.html)2
-rw-r--r--askbot/skins/default/templates/feedback.html (renamed from forum/skins/default/templates/feedback.html)0
-rw-r--r--askbot/skins/default/templates/feedback_email.txt (renamed from forum/skins/default/templates/feedback_email.txt)0
-rwxr-xr-xaskbot/skins/default/templates/feeds/rss_description.html (renamed from forum/skins/default/templates/feeds/rss_description.html)0
-rwxr-xr-xaskbot/skins/default/templates/feeds/rss_title.html (renamed from forum/skins/default/templates/feeds/rss_title.html)0
-rw-r--r--askbot/skins/default/templates/footer.html (renamed from forum/skins/default/templates/footer.html)2
-rw-r--r--askbot/skins/default/templates/header.html53
-rw-r--r--askbot/skins/default/templates/input_bar.html (renamed from forum/skins/default/templates/input_bar.html)2
-rw-r--r--askbot/skins/default/templates/instant_notification.html46
-rw-r--r--askbot/skins/default/templates/logout.html (renamed from forum/skins/default/templates/logout.html)0
-rw-r--r--askbot/skins/default/templates/notarobot.html (renamed from forum/skins/default/templates/notarobot.html)0
-rw-r--r--askbot/skins/default/templates/pagesize.html (renamed from forum/skins/default/templates/pagesize.html)0
-rw-r--r--askbot/skins/default/templates/paginator.html (renamed from forum/skins/default/templates/paginator.html)0
-rw-r--r--askbot/skins/default/templates/post_contributor_info.html (renamed from forum/skins/default/templates/post_contributor_info.html)0
-rw-r--r--askbot/skins/default/templates/privacy.html17
-rw-r--r--askbot/skins/default/templates/question.html (renamed from forum/skins/default/templates/question.html)10
-rw-r--r--askbot/skins/default/templates/question_counter_widget.html (renamed from forum/skins/default/templates/question_counter_widget.html)0
-rw-r--r--askbot/skins/default/templates/question_edit.html (renamed from forum/skins/default/templates/question_edit.html)0
-rw-r--r--askbot/skins/default/templates/question_edit_tips.html (renamed from forum/skins/default/templates/question_edit_tips.html)0
-rw-r--r--askbot/skins/default/templates/question_list.html (renamed from forum/skins/default/templates/question_list.html)2
-rw-r--r--askbot/skins/default/templates/question_retag.html (renamed from forum/skins/default/templates/question_retag.html)0
-rw-r--r--askbot/skins/default/templates/question_summary_list_roll.html (renamed from forum/skins/default/templates/question_summary_list_roll.html)0
-rw-r--r--askbot/skins/default/templates/questions.html (renamed from forum/skins/default/templates/questions.html)8
-rw-r--r--askbot/skins/default/templates/reopen.html (renamed from forum/skins/default/templates/reopen.html)0
-rw-r--r--askbot/skins/default/templates/revisions_answer.html (renamed from forum/skins/default/templates/revisions_answer.html)2
-rw-r--r--askbot/skins/default/templates/revisions_question.html (renamed from forum/skins/default/templates/revisions_question.html)2
-rw-r--r--askbot/skins/default/templates/tag_selector.html (renamed from forum/skins/default/templates/tag_selector.html)0
-rw-r--r--askbot/skins/default/templates/tags.html (renamed from forum/skins/default/templates/tags.html)0
-rw-r--r--askbot/skins/default/templates/user.html (renamed from forum/skins/default/templates/user.html)9
-rw-r--r--askbot/skins/default/templates/user_edit.html (renamed from forum/skins/default/templates/user_edit.html)0
-rw-r--r--askbot/skins/default/templates/user_email_subscriptions.html (renamed from forum/skins/default/templates/user_email_subscriptions.html)0
-rw-r--r--askbot/skins/default/templates/user_favorites.html (renamed from forum/skins/default/templates/user_favorites.html)0
-rw-r--r--askbot/skins/default/templates/user_footer.html (renamed from forum/skins/default/templates/user_footer.html)0
-rw-r--r--askbot/skins/default/templates/user_info.html (renamed from forum/skins/default/templates/user_info.html)3
-rw-r--r--askbot/skins/default/templates/user_recent.html (renamed from forum/skins/default/templates/user_recent.html)0
-rw-r--r--askbot/skins/default/templates/user_reputation.html (renamed from forum/skins/default/templates/user_reputation.html)0
-rw-r--r--askbot/skins/default/templates/user_responses.html41
-rw-r--r--askbot/skins/default/templates/user_stats.html (renamed from forum/skins/default/templates/user_stats.html)2
-rw-r--r--askbot/skins/default/templates/user_tabs.html (renamed from forum/skins/default/templates/user_tabs.html)0
-rw-r--r--askbot/skins/default/templates/user_votes.html (renamed from forum/skins/default/templates/user_votes.html)0
-rw-r--r--askbot/skins/default/templates/users.html (renamed from forum/skins/default/templates/users.html)0
-rw-r--r--askbot/skins/default/templates/users_questions.html (renamed from forum/skins/default/templates/users_questions.html)0
-rw-r--r--[-rwxr-xr-x]askbot/skins/loaders.py (renamed from forum/skins/__init__.py)29
-rw-r--r--askbot/skins/utils.py29
-rw-r--r--askbot/sql_scripts/091111_upgrade_evgeny.sql (renamed from forum/sql_scripts/091111_upgrade_evgeny.sql)0
-rw-r--r--askbot/sql_scripts/091208_upgrade_evgeny.sql (renamed from forum/sql_scripts/091208_upgrade_evgeny.sql)0
-rw-r--r--askbot/sql_scripts/091208_upgrade_evgeny_1.sql (renamed from forum/sql_scripts/091208_upgrade_evgeny_1.sql)0
-rw-r--r--askbot/sql_scripts/100108_upgrade_ef.sql (renamed from forum/sql_scripts/100108_upgrade_ef.sql)0
-rw-r--r--askbot/sql_scripts/badges.sql (renamed from forum/sql_scripts/badges.sql)0
-rw-r--r--askbot/sql_scripts/cnprog.xml (renamed from forum/sql_scripts/cnprog.xml)0
-rw-r--r--askbot/sql_scripts/cnprog_new_install.sql (renamed from forum/sql_scripts/cnprog_new_install.sql)0
-rw-r--r--askbot/sql_scripts/cnprog_new_install_2009_02_28.sql (renamed from forum/sql_scripts/cnprog_new_install_2009_02_28.sql)0
-rw-r--r--askbot/sql_scripts/cnprog_new_install_2009_03_31.sql (renamed from forum/sql_scripts/cnprog_new_install_2009_03_31.sql)0
-rw-r--r--askbot/sql_scripts/cnprog_new_install_2009_04_07.sql (renamed from forum/sql_scripts/cnprog_new_install_2009_04_07.sql)0
-rw-r--r--askbot/sql_scripts/cnprog_new_install_2009_04_09.sql (renamed from forum/sql_scripts/cnprog_new_install_2009_04_09.sql)0
-rw-r--r--askbot/sql_scripts/drop-all-tables.sh (renamed from forum/sql_scripts/drop-all-tables.sh)0
-rw-r--r--askbot/sql_scripts/drop-auth.sql (renamed from forum/sql_scripts/drop-auth.sql)0
-rw-r--r--askbot/sql_scripts/pg_fts_install.sql (renamed from forum/sql_scripts/pg_fts_install.sql)0
-rw-r--r--askbot/sql_scripts/update_2009_01_13_001.sql (renamed from forum/sql_scripts/update_2009_01_13_001.sql)0
-rw-r--r--askbot/sql_scripts/update_2009_01_13_002.sql (renamed from forum/sql_scripts/update_2009_01_13_002.sql)0
-rw-r--r--askbot/sql_scripts/update_2009_01_18_001.sql (renamed from forum/sql_scripts/update_2009_01_18_001.sql)0
-rw-r--r--askbot/sql_scripts/update_2009_01_24.sql (renamed from forum/sql_scripts/update_2009_01_24.sql)0
-rw-r--r--askbot/sql_scripts/update_2009_01_25_001.sql (renamed from forum/sql_scripts/update_2009_01_25_001.sql)0
-rw-r--r--askbot/sql_scripts/update_2009_02_26_001.sql (renamed from forum/sql_scripts/update_2009_02_26_001.sql)0
-rw-r--r--askbot/sql_scripts/update_2009_04_10_001.sql (renamed from forum/sql_scripts/update_2009_04_10_001.sql)0
-rw-r--r--askbot/sql_scripts/update_2009_07_05_EF.sql (renamed from forum/sql_scripts/update_2009_07_05_EF.sql)0
-rw-r--r--askbot/sql_scripts/update_2009_12_24_001.sql (renamed from forum/sql_scripts/update_2009_12_24_001.sql)0
-rw-r--r--askbot/sql_scripts/update_2009_12_27_001.sql (renamed from forum/sql_scripts/update_2009_12_27_001.sql)0
-rw-r--r--askbot/sql_scripts/update_2009_12_27_002.sql (renamed from forum/sql_scripts/update_2009_12_27_002.sql)0
-rw-r--r--askbot/sql_scripts/update_2010_02_22.sql (renamed from forum/sql_scripts/update_2010_02_22.sql)0
-rw-r--r--askbot/templatetags/__init__.py (renamed from forum_modules/sphinxfulltext/__init__.py)0
-rw-r--r--[-rwxr-xr-x]askbot/templatetags/extra_filters.py (renamed from forum/templatetags/extra_filters.py)8
-rw-r--r--[-rwxr-xr-x]askbot/templatetags/extra_tags.py (renamed from forum/templatetags/extra_tags.py)262
-rw-r--r--[-rwxr-xr-x]askbot/templatetags/smart_if.py (renamed from forum/templatetags/smart_if.py)0
-rw-r--r--askbot/tests.py870
-rw-r--r--askbot/upfiles/README3
-rw-r--r--askbot/urls.py204
-rw-r--r--[-rwxr-xr-x]askbot/user_messages/__init__.py (renamed from forum/user_messages/__init__.py)0
-rw-r--r--[-rwxr-xr-x]askbot/user_messages/context_processors.py (renamed from forum/user_messages/context_processors.py)3
-rw-r--r--askbot/utils/__init__.py (renamed from forum_modules/pgfulltext/DISABLED)0
-rw-r--r--[-rwxr-xr-x]askbot/utils/cache.py (renamed from forum/utils/cache.py)2
-rw-r--r--askbot/utils/colors.py (renamed from forum/utils/colors.py)8
-rw-r--r--[-rwxr-xr-x]askbot/utils/decorators.py (renamed from forum/utils/decorators.py)0
-rw-r--r--[-rwxr-xr-x]askbot/utils/diff.py (renamed from forum/utils/diff.py)0
-rw-r--r--[-rwxr-xr-x]askbot/utils/email.py (renamed from forum/utils/email.py)2
-rw-r--r--[-rwxr-xr-x]askbot/utils/forms.py (renamed from forum/utils/forms.py)17
-rw-r--r--askbot/utils/functions.py45
-rw-r--r--[-rwxr-xr-x]askbot/utils/html.py (renamed from forum/utils/html.py)0
-rw-r--r--[-rwxr-xr-x]askbot/utils/lists.py (renamed from forum/utils/lists.py)0
-rw-r--r--askbot/utils/markup.py112
-rw-r--r--[-rwxr-xr-x]askbot/utils/time.py (renamed from forum/utils/time.py)0
-rwxr-xr-xaskbot/views/README (renamed from forum/views/README)0
-rw-r--r--askbot/views/__init__.py8
-rw-r--r--[-rwxr-xr-x]askbot/views/commands.py (renamed from forum/views/commands.py)33
-rw-r--r--[-rwxr-xr-x]askbot/views/meta.py (renamed from forum/views/meta.py)8
-rw-r--r--askbot/views/readers.py (renamed from forum/views/readers.py)145
-rw-r--r--[-rwxr-xr-x]askbot/views/users.py (renamed from forum/views/users.py)589
-rw-r--r--[-rwxr-xr-x]askbot/views/writers.py (renamed from forum/views/writers.py)91
-rwxr-xr-xcache/README.TXT1
-rw-r--r--ez_setup.py284
-rwxr-xr-xfbconnect/fb.py96
-rwxr-xr-xfbconnect/forms.py8
-rwxr-xr-xfbconnect/models.py6
-rwxr-xr-xfbconnect/pjson.py313
-rwxr-xr-xfbconnect/tests.py23
-rwxr-xr-xfbconnect/urls.py19
-rwxr-xr-xfbconnect/views.py112
-rwxr-xr-xforum/__init__.py1
-rwxr-xr-xforum/badges/__init__.py10
-rwxr-xr-xforum/badges/base.py11
-rw-r--r--forum/context.py47
-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
-rwxr-xr-xforum/feed.py43
-rwxr-xr-xforum/management/__init__.py3
-rwxr-xr-xforum/management/commands/send_email_alerts.py320
-rw-r--r--forum/migrations/0001_initial.py780
-rw-r--r--forum/migrations/0005_install_badges.py417
-rwxr-xr-xforum/models/__init__.py507
-rwxr-xr-xforum/models/base.py160
-rwxr-xr-xforum/models/meta.py93
-rwxr-xr-xforum/models/user.py134
-rwxr-xr-xforum/modules.py78
-rwxr-xr-xforum/settings.py51
-rw-r--r--forum/skins/common/media/js/closure/README.rst9
-rw-r--r--forum/skins/common/media/js/closure/setup-closure.sh12
-rw-r--r--forum/skins/default/templates/about.html36
-rw-r--r--forum/skins/default/templates/header.html47
-rw-r--r--forum/skins/default/templates/privacy.html42
-rw-r--r--forum/skins/default/templates/user_responses.html23
-rwxr-xr-xforum/sql_scripts/update_2010_01_23.sql9
-rwxr-xr-xforum/urls.py104
-rw-r--r--forum/utils/functions.py5
-rwxr-xr-xforum/utils/odict.py1399
-rwxr-xr-xforum/views/__init__.py5
-rw-r--r--forum_modules/authentication/README3
-rwxr-xr-xforum_modules/authentication/auth.py144
-rwxr-xr-xforum_modules/books/__init__.py3
-rwxr-xr-xforum_modules/books/models.py63
-rwxr-xr-xforum_modules/books/urls.py10
-rwxr-xr-xforum_modules/books/views.py142
-rw-r--r--forum_modules/pgfulltext/__init__.py9
-rw-r--r--forum_modules/pgfulltext/handlers.py11
-rw-r--r--forum_modules/pgfulltext/management.py30
-rw-r--r--forum_modules/pgfulltext/pg_fts_install.sql38
-rwxr-xr-xforum_modules/robotstxt/DISABLED0
-rwxr-xr-xforum_modules/robotstxt/templates/robots.txt2
-rwxr-xr-xforum_modules/robotstxt/urls.py6
-rw-r--r--forum_modules/sphinxfulltext/DISABLED0
-rw-r--r--forum_modules/sphinxfulltext/dependencies.py2
-rw-r--r--forum_modules/sphinxfulltext/handlers.py4
-rw-r--r--forum_modules/sphinxfulltext/models.py11
-rw-r--r--forum_modules/sphinxfulltext/settings.py5
-rw-r--r--locale/en/LC_MESSAGES/django.mobin25222 -> 0 bytes
-rwxr-xr-xlog/README.TXT1
-rwxr-xr-xrun1
-rw-r--r--settings.py96
-rwxr-xr-xsettings_local.py.dist126
-rw-r--r--setup.py77
516 files changed, 22211 insertions, 8005 deletions
diff --git a/.gitignore b/.gitignore
index b5938208..795e011d 100755
--- a/.gitignore
+++ b/.gitignore
@@ -2,9 +2,11 @@
*.swp
*.log
cache/??
+run
*.wsgi
nbproject
settings_local.py
+settings.py
.idea
*.iml
env
@@ -12,6 +14,16 @@ nbproject
pip-log.txt
*.zip
tmp/*
+/tmp/
+/__init__.py
+/manage.py
+/urls.py
+/log
load
-forum/skins/default/media/js/flot
-forum/skins/common/media/js/closure/google-closure
+askbot/skins/default/media/js/flot
+askbot/skins/common/media/js/closure/google-closure
+askbot/fixtures
+*.egg
+dist
+*.egg-info
+build
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 00000000..2cbc3a7c
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,11 @@
+include ez_setup.py
+recursive-include askbot *
+recursive-exclude askbot *.pyc
+recursive-exclude .git
+prune dist
+prune tmp
+prune build
+exclude settings.py
+exclude manage.py
+exclude __init__.py
+exclude urls.py
diff --git a/README b/README
index 56da61c5..1d9862dc 100644
--- a/README
+++ b/README
@@ -1,9 +1,10 @@
-This is Askbot project - open source Q&A system
+This is Askbot project - open source Q&A system, like StackOverflow, Yahoo Answers and some others
-Demo site is http://askbot.org/meta
+Demo site is http://askbot.org
-All documentation is in the directory forum/documentation
+All documentation is in the directory askbot/doc
askbot-devel repository is open to anyone who wants to help develop Askbot - just drop us a note
-Askbot is based on code of CNPROG, originally created by Mike Chen and Sailing Cai and some code written for OSQA
+Askbot is based on code of CNPROG, originally created by Mike Chen
+and Sailing Cai and some code written for OSQA
diff --git a/askbot.iml b/askbot.iml
deleted file mode 100755
index 4e760f0a..00000000
--- a/askbot.iml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module type="PYTHON_MODULE" version="4">
- <component name="NewModuleRootManager" inherit-compiler-output="true">
- <exclude-output />
- <content url="file://$MODULE_DIR$" />
- <orderEntry type="jdk" jdkName="Python 2.6.4" jdkType="Python SDK" />
- <orderEntry type="sourceFolder" forTests="false" />
- </component>
-</module>
-
diff --git a/forum/LICENSE b/askbot/LICENSE
index 803781c5..803781c5 100644
--- a/forum/LICENSE
+++ b/askbot/LICENSE
diff --git a/askbot/__init__.py b/askbot/__init__.py
new file mode 100644
index 00000000..90c491d8
--- /dev/null
+++ b/askbot/__init__.py
@@ -0,0 +1,14 @@
+"""aksbot askbot module
+"""
+__all__ = [
+ 'admin',
+ 'auth',
+ 'const',
+ 'feed',
+ 'forms',
+ 'managers',
+ 'models',
+ 'sitemap',
+ 'urls',
+ 'views'
+]
diff --git a/forum/admin.py b/askbot/admin.py
index 3afa2241..1ecfa3aa 100755..100644
--- a/forum/admin.py
+++ b/askbot/admin.py
@@ -1,7 +1,9 @@
+"""
+linking of askbot modules to admin interface
+"""
# -*- coding: utf-8 -*-
-
from django.contrib import admin
-from models import *
+from askbot import models
class AnonymousQuestionAdmin(admin.ModelAdmin):
"""AnonymousQuestion admin class"""
@@ -54,19 +56,19 @@ class ActivityAdmin(admin.ModelAdmin):
#class BookAuthorRssAdmin(admin.ModelAdmin):
# """ admin class"""
-admin.site.register(Question, QuestionAdmin)
-admin.site.register(Tag, TagAdmin)
-admin.site.register(Answer, Answerdmin)
-admin.site.register(Comment, CommentAdmin)
-admin.site.register(Vote, VoteAdmin)
-admin.site.register(FlaggedItem, FlaggedItemAdmin)
-admin.site.register(FavoriteQuestion, FavoriteQuestionAdmin)
-admin.site.register(QuestionRevision, QuestionRevisionAdmin)
-admin.site.register(AnswerRevision, AnswerRevisionAdmin)
-admin.site.register(Badge, BadgeAdmin)
-admin.site.register(Award, AwardAdmin)
-admin.site.register(Repute, ReputeAdmin)
-admin.site.register(Activity, ActivityAdmin)
+admin.site.register(models.Question, QuestionAdmin)
+admin.site.register(models.Tag, TagAdmin)
+admin.site.register(models.Answer, Answerdmin)
+admin.site.register(models.Comment, CommentAdmin)
+admin.site.register(models.Vote, VoteAdmin)
+admin.site.register(models.FlaggedItem, FlaggedItemAdmin)
+admin.site.register(models.FavoriteQuestion, FavoriteQuestionAdmin)
+admin.site.register(models.QuestionRevision, QuestionRevisionAdmin)
+admin.site.register(models.AnswerRevision, AnswerRevisionAdmin)
+admin.site.register(models.Badge, BadgeAdmin)
+admin.site.register(models.Award, AwardAdmin)
+admin.site.register(models.Repute, ReputeAdmin)
+admin.site.register(models.Activity, ActivityAdmin)
#admin.site.register(Book, BookAdmin)
#admin.site.register(BookAuthorInfo, BookAuthorInfoAdmin)
#admin.site.register(BookAuthorRss, BookAuthorRssAdmin)
diff --git a/forum/auth.py b/askbot/auth.py
index 5d6e71c4..55a1633f 100755..100644
--- a/forum/auth.py
+++ b/askbot/auth.py
@@ -7,56 +7,13 @@ and superuser status.
import datetime
from django.utils.translation import ugettext as _
from django.db import transaction
-from models import Repute
-from models import Question
-from models import Answer
-from models import mark_offensive, delete_post_or_answer
-from const import TYPE_REPUTATION
+from askbot.models import Repute
+from askbot.models import Question
+from askbot.models import Answer
+from askbot.models import signals
import logging
-VOTE_UP = 15
-FLAG_OFFENSIVE = 15
-POST_IMAGES = 15
-LEAVE_COMMENTS = 50
-UPLOAD_FILES = 60
-VOTE_DOWN = 100
-CLOSE_OWN_QUESTIONS = 250
-RETAG_OTHER_QUESTIONS = 500
-REOPEN_OWN_QUESTIONS = 500
-EDIT_COMMUNITY_WIKI_POSTS = 750
-EDIT_OTHER_POSTS = 2000
-DELETE_COMMENTS = 2000
-VIEW_OFFENSIVE_FLAGS = 2000
-DISABLE_URL_NOFOLLOW = 2000
-CLOSE_OTHER_QUESTIONS = 3000
-LOCK_POSTS = 4000
-
-VOTE_RULES = {
- 'scope_votes_per_user_per_day' : 30, # how many votes of one user has everyday
- 'scope_flags_per_user_per_day' : 5, # how many times user can flag posts everyday
- 'scope_warn_votes_left' : 10, # start when to warn user how many votes left
- 'scope_deny_unvote_days' : 1, # if 1 days passed, user can't cancel votes.
- 'scope_flags_invisible_main_page' : 3, # post doesn't show on main page if has more than 3 offensive flags
- 'scope_flags_delete_post' : 5, # post will be deleted if it has more than 5 offensive flags
-}
-
-REPUTATION_RULES = {
- 'initial_score' : 1,
- 'scope_per_day_by_upvotes' : 200,
- 'gain_by_upvoted' : 10,
- 'gain_by_answer_accepted' : 15,
- 'gain_by_accepting_answer' : 2,
- 'gain_by_downvote_canceled' : 2,
- 'gain_by_canceling_downvote' : 1,
- 'lose_by_canceling_accepted_answer' : -2,
- 'lose_by_accepted_answer_cancled' : -15,
- 'lose_by_downvoted' : -2,
- 'lose_by_flagged' : -2,
- 'lose_by_downvoting' : -1,
- 'lose_by_flagged_lastrevision_3_times': -30,
- 'lose_by_flagged_lastrevision_5_times': -100,
- 'lose_by_upvote_canceled' : -10,
-}
+from askbot.conf import settings as askbot_settings
def can_moderate_users(user):
return user.is_superuser
@@ -64,97 +21,117 @@ def can_moderate_users(user):
def can_vote_up(user):
"""Determines if a User can vote Questions and Answers up."""
return user.is_authenticated() and (
- user.reputation >= VOTE_UP or
+ user.reputation >= askbot_settings.MIN_REP_TO_VOTE_UP or
user.is_superuser)
def can_flag_offensive(user):
"""Determines if a User can flag Questions and Answers as offensive."""
return user.is_authenticated() and (
- user.reputation >= FLAG_OFFENSIVE or
+ user.reputation >= askbot_settings.MIN_REP_TO_FLAG_OFFENSIVE or
user.is_superuser)
-def can_add_comments(user,subject):
+def can_add_comments(user, subject):
"""Determines if a User can add comments to Questions and Answers."""
if user.is_authenticated():
if user.id == subject.author.id:
return True
- if user.reputation >= LEAVE_COMMENTS:
+ if user.reputation >= askbot_settings.MIN_REP_TO_LEAVE_COMMENTS:
return True
if user.is_superuser:
return True
- if isinstance(subject,Answer) and subject.question.author.id == user.id:
- return True
+ if isinstance(subject, Answer):
+ if subject.question.author.id == user.id:
+ return True
return False
def can_vote_down(user):
"""Determines if a User can vote Questions and Answers down."""
- return user.is_authenticated() and (
- user.reputation >= VOTE_DOWN or
- user.is_superuser)
+ if user.is_authenticated():
+ if user.reputation >= askbot_settings.MIN_REP_TO_VOTE_DOWN:
+ return True
+ if user.is_superuser:
+ return True
+ return False
def can_retag_questions(user):
"""Determines if a User can retag Questions."""
- return user.is_authenticated() and (
- RETAG_OTHER_QUESTIONS <= user.reputation < EDIT_OTHER_POSTS or
- user.is_superuser)
+ if user.is_authenticated():
+ if user.reputation >= askbot_settings.MIN_REP_TO_RETAG_OTHERS_QUESTIONS:
+ if user.reputation < askbot_settings.MIN_REP_TO_EDIT_OTHERS_POSTS:
+ return True
+ if user.is_superuser:
+ return True
+ return False
def can_edit_post(user, post):
"""Determines if a User can edit the given Question or Answer."""
- return user.is_authenticated() and (
- user.id == post.author_id or
- (post.wiki and user.reputation >= EDIT_COMMUNITY_WIKI_POSTS) or
- user.reputation >= EDIT_OTHER_POSTS or
- user.is_superuser)
+ if user.is_authenticated():
+ if user.id == post.author_id:
+ return True
+ if post.wiki:
+ if user.reputation >= askbot_settings.MIN_REP_TO_EDIT_WIKI:
+ return True
+ if user.reputation >= askbot_settings.MIN_REP_TO_EDIT_OTHERS_POSTS:
+ return True
+ if user.is_superuser:
+ return True
+ return False
def can_delete_comment(user, comment):
"""Determines if a User can delete the given Comment."""
return user.is_authenticated() and (
user.id == comment.user_id or
- user.reputation >= DELETE_COMMENTS or
+ user.reputation >= askbot_settings.MIN_REP_TO_DELETE_OTHERS_COMMENTS or
user.is_superuser)
def can_view_offensive_flags(user):
"""Determines if a User can view offensive flag counts."""
return user.is_authenticated() and (
- user.reputation >= VIEW_OFFENSIVE_FLAGS or
+ user.reputation >= askbot_settings.MIN_REP_TO_VIEW_OFFENSIVE_FLAGS or
user.is_superuser)
def can_close_question(user, question):
"""Determines if a User can close the given Question."""
return user.is_authenticated() and (
(user.id == question.author_id and
- user.reputation >= CLOSE_OWN_QUESTIONS) or
- user.reputation >= CLOSE_OTHER_QUESTIONS or
+ user.reputation >= askbot_settings.MIN_REP_TO_CLOSE_OWN_QUESTIONS) or
+ user.reputation >= askbot_settings.MIN_REP_TO_CLOSE_OTHERS_QUESTIONS or
user.is_superuser)
def can_lock_posts(user):
"""Determines if a User can lock Questions or Answers."""
return user.is_authenticated() and (
- user.reputation >= LOCK_POSTS or
+ user.reputation >= askbot_settings.MIN_REP_TO_LOCK_POSTS or
user.is_superuser)
def can_follow_url(user):
"""Determines if the URL link can be followed by Google search engine."""
- return user.reputation >= DISABLE_URL_NOFOLLOW
+ return user.reputation >= askbot_settings.MIN_REP_TO_DISABLE_URL_NOFOLLOW
def can_accept_answer(user, question, answer):
- return (user.is_authenticated() and
- question.author != answer.author and
- question.author == user) or user.is_superuser
+ if user.is_superuser:
+ return True
+ if user.is_authenticated():
+ if question.author != answer.author and question.author == user:
+ return True
+ return False
# now only support to reopen own question except superuser
def can_reopen_question(user, question):
- return (user.is_authenticated() and
- user.id == question.author_id and
- user.reputation >= REOPEN_OWN_QUESTIONS) or user.is_superuser
+ if user.is_superuser:
+ return True
+ if user.is_authenticated() and user.id == question.author_id:
+ if user.reputation >= askbot_settings.MIN_REP_TO_REOPEN_OWN_QUESTIONS:
+ return True
+ return False
def can_delete_post(user, post):
if user.is_superuser:
return True
elif user.is_authenticated() and user == post.author:
- if isinstance(post,Answer):
+ if isinstance(post, Answer):
return True
- elif isinstance(post,Question):
+ elif isinstance(post, Question):
answers = post.answers.all()
for answer in answers:
if user != answer.author and answer.deleted == False:
@@ -182,8 +159,12 @@ def can_view_user_edit(request_user, target_user):
return (request_user.is_authenticated() and request_user == target_user)
def can_upload_files(request_user):
- return (request_user.is_authenticated() and request_user.reputation >= UPLOAD_FILES) or \
- request_user.is_superuser
+ if request_user.is_superuser:
+ return True
+ if request_user.is_authenticated():
+ if request_user.reputation >= askbot_settings.MIN_REP_TO_UPLOAD_FILES:
+ return True
+ return False
###########################################
## actions and reputation changes event
@@ -204,53 +185,71 @@ def onFlaggedItem(item, post, user, timestamp=None):
post.offensive_flag_count = post.offensive_flag_count + 1
post.save()
- post.author.reputation = calculate_reputation(post.author.reputation,
- int(REPUTATION_RULES['lose_by_flagged']))
+ post.author.reputation = calculate_reputation(
+ post.author.reputation,
+ askbot_settings.REP_LOSS_FOR_RECEIVING_DOWNVOTE
+ )
post.author.save()
question = post
if isinstance(post, Answer):
question = post.question
- reputation = Repute(user=post.author,
- negative=int(REPUTATION_RULES['lose_by_flagged']),
- question=question, reputed_at=timestamp,
- reputation_type=-4,
- reputation=post.author.reputation)
+ reputation = Repute(
+ user=post.author,
+ negative=askbot_settings.REP_LOSS_FOR_RECEIVING_DOWNVOTE,
+ question=question, reputed_at=timestamp,
+ reputation_type=-4,
+ reputation=post.author.reputation
+ )
reputation.save()
#todo: These should be updated to work on same revisions.
- if post.offensive_flag_count == VOTE_RULES['scope_flags_invisible_main_page'] :
- post.author.reputation = calculate_reputation(post.author.reputation,
- int(REPUTATION_RULES['lose_by_flagged_lastrevision_3_times']))
+ if post.offensive_flag_count == askbot_settings.MIN_FLAGS_TO_HIDE_POST:
+ post.author.reputation = \
+ calculate_reputation(
+ post.author.reputation,
+ askbot_settings.REP_LOSS_FOR_RECEIVING_THREE_FLAGS_PER_REVISION
+ )
+
post.author.save()
- reputation = Repute(user=post.author,
- negative=int(REPUTATION_RULES['lose_by_flagged_lastrevision_3_times']),
- question=question,
- reputed_at=timestamp,
- reputation_type=-6,
- reputation=post.author.reputation)
+ reputation = Repute(
+ user=post.author,
+ negative=\
+ askbot_settings.REP_LOSS_FOR_RECEIVING_THREE_FLAGS_PER_REVISION,
+ question=question,
+ reputed_at=timestamp,
+ reputation_type=-6,
+ reputation=post.author.reputation
+ )
reputation.save()
- elif post.offensive_flag_count == VOTE_RULES['scope_flags_delete_post']:
- post.author.reputation = calculate_reputation(post.author.reputation,
- int(REPUTATION_RULES['lose_by_flagged_lastrevision_5_times']))
+ elif post.offensive_flag_count == askbot_settings.MIN_FLAGS_TO_DELETE_POST:
+ post.author.reputation = \
+ calculate_reputation(
+ post.author.reputation,
+ askbot_settings.REP_LOSS_FOR_RECEIVING_FIVE_FLAGS_PER_REVISION
+ )
+
post.author.save()
- reputation = Repute(user=post.author,
- negative=int(REPUTATION_RULES['lose_by_flagged_lastrevision_5_times']),
- question=question,
- reputed_at=timestamp,
- reputation_type=-7,
- reputation=post.author.reputation)
+ reputation = Repute(
+ user=post.author,
+ negative=\
+ askbot_settings.REP_LOSS_FOR_RECEIVING_FIVE_FLAGS_PER_REVISION,
+ question=question,
+ reputed_at=timestamp,
+ reputation_type=-7,
+ reputation=post.author.reputation
+ )
reputation.save()
post.deleted = True
#post.deleted_at = timestamp
#post.deleted_by = Admin
post.save()
- mark_offensive.send(
+ signals.mark_offensive.send(
sender=post.__class__,
instance=post,
mark_by=user
@@ -267,11 +266,13 @@ def onAnswerAccept(answer, user, timestamp=None):
answer.save()
answer.question.save()
- answer.author.reputation = calculate_reputation(answer.author.reputation,
- int(REPUTATION_RULES['gain_by_answer_accepted']))
+ answer.author.reputation = calculate_reputation(
+ answer.author.reputation,
+ askbot_settings.REP_GAIN_FOR_RECEIVING_ANSWER_ACCEPTANCE
+ )
answer.author.save()
reputation = Repute(user=answer.author,
- positive=int(REPUTATION_RULES['gain_by_answer_accepted']),
+ positive=askbot_settings.REP_GAIN_FOR_RECEIVING_ANSWER_ACCEPTANCE,
question=answer.question,
reputed_at=timestamp,
reputation_type=2,
@@ -279,10 +280,10 @@ def onAnswerAccept(answer, user, timestamp=None):
reputation.save()
user.reputation = calculate_reputation(user.reputation,
- int(REPUTATION_RULES['gain_by_accepting_answer']))
+ askbot_settings.REP_GAIN_FOR_ACCEPTING_ANSWER)
user.save()
reputation = Repute(user=user,
- positive=int(REPUTATION_RULES['gain_by_accepting_answer']),
+ positive=askbot_settings.REP_GAIN_FOR_ACCEPTING_ANSWER,
question=answer.question,
reputed_at=timestamp,
reputation_type=3,
@@ -299,22 +300,27 @@ def onAnswerAcceptCanceled(answer, user, timestamp=None):
answer.save()
answer.question.save()
- answer.author.reputation = calculate_reputation(answer.author.reputation,
- int(REPUTATION_RULES['lose_by_accepted_answer_cancled']))
+ answer.author.reputation = calculate_reputation(
+ answer.author.reputation,
+ askbot_settings.REP_LOSS_FOR_RECEIVING_CANCELATION_OF_ANSWER_ACCEPTANCE
+ )
answer.author.save()
- reputation = Repute(user=answer.author,
- negative=int(REPUTATION_RULES['lose_by_accepted_answer_cancled']),
- question=answer.question,
- reputed_at=timestamp,
- reputation_type=-2,
- reputation=answer.author.reputation)
+ reputation = Repute(
+ user=answer.author,
+ negative=\
+ askbot_settings.REP_LOSS_FOR_RECEIVING_CANCELATION_OF_ANSWER_ACCEPTANCE,
+ question=answer.question,
+ reputed_at=timestamp,
+ reputation_type=-2,
+ reputation=answer.author.reputation
+ )
reputation.save()
user.reputation = calculate_reputation(user.reputation,
- int(REPUTATION_RULES['lose_by_canceling_accepted_answer']))
+ askbot_settings.REP_LOSS_FOR_CANCELING_ANSWER_ACCEPTANCE)
user.save()
reputation = Repute(user=user,
- negative=int(REPUTATION_RULES['lose_by_canceling_accepted_answer']),
+ negative=askbot_settings.REP_LOSS_FOR_CANCELING_ANSWER_ACCEPTANCE,
question=answer.question,
reputed_at=timestamp,
reputation_type=-1,
@@ -334,9 +340,9 @@ def onUpVoted(vote, post, user, timestamp=None):
if not post.wiki:
author = post.author
todays_rep_gain = Repute.objects.get_reputation_by_upvoted_today(author)
- if todays_rep_gain < int(REPUTATION_RULES['scope_per_day_by_upvotes']):
+ if todays_rep_gain < askbot_settings.MAX_REP_GAIN_PER_USER_PER_DAY:
author.reputation = calculate_reputation(author.reputation,
- int(REPUTATION_RULES['gain_by_upvoted']))
+ askbot_settings.REP_GAIN_FOR_RECEIVING_UPVOTE)
author.save()
question = post
@@ -344,7 +350,7 @@ def onUpVoted(vote, post, user, timestamp=None):
question = post.question
reputation = Repute(user=author,
- positive=int(REPUTATION_RULES['gain_by_upvoted']),
+ positive=askbot_settings.REP_GAIN_FOR_RECEIVING_UPVOTE,
question=question,
reputed_at=timestamp,
reputation_type=1,
@@ -365,20 +371,25 @@ def onUpVotedCanceled(vote, post, user, timestamp=None):
if not post.wiki:
author = post.author
- author.reputation = calculate_reputation(author.reputation,
- int(REPUTATION_RULES['lose_by_upvote_canceled']))
+ author.reputation = \
+ calculate_reputation(
+ author.reputation,
+ askbot_settings.REP_LOSS_FOR_RECEIVING_UPVOTE_CANCELATION
+ )
author.save()
question = post
if isinstance(post, Answer):
question = post.question
- reputation = Repute(user=author,
- negative=int(REPUTATION_RULES['lose_by_upvote_canceled']),
- question=question,
- reputed_at=timestamp,
- reputation_type=-8,
- reputation=author.reputation)
+ reputation = Repute(
+ user=author,
+ negative=askbot_settings.REP_LOSS_FOR_RECEIVING_UPVOTE_CANCELATION,
+ question=question,
+ reputed_at=timestamp,
+ reputation_type=-8,
+ reputation=author.reputation
+ )
reputation.save()
@transaction.commit_on_success
@@ -393,8 +404,10 @@ def onDownVoted(vote, post, user, timestamp=None):
if not post.wiki:
author = post.author
- author.reputation = calculate_reputation(author.reputation,
- int(REPUTATION_RULES['lose_by_downvoted']))
+ author.reputation = calculate_reputation(
+ author.reputation,
+ askbot_settings.REP_LOSS_FOR_DOWNVOTING
+ )
author.save()
question = post
@@ -402,19 +415,21 @@ def onDownVoted(vote, post, user, timestamp=None):
question = post.question
reputation = Repute(user=author,
- negative=int(REPUTATION_RULES['lose_by_downvoted']),
+ negative=askbot_settings.REP_LOSS_FOR_DOWNVOTING,
question=question,
reputed_at=timestamp,
reputation_type=-3,
reputation=author.reputation)
reputation.save()
- user.reputation = calculate_reputation(user.reputation,
- int(REPUTATION_RULES['lose_by_downvoting']))
+ user.reputation = calculate_reputation(
+ user.reputation,
+ askbot_settings.REP_LOSS_FOR_RECEIVING_DOWNVOTE
+ )
user.save()
reputation = Repute(user=user,
- negative=int(REPUTATION_RULES['lose_by_downvoting']),
+ negative=askbot_settings.REP_LOSS_FOR_RECEIVING_DOWNVOTE,
question=question,
reputed_at=timestamp,
reputation_type=-5,
@@ -435,8 +450,10 @@ def onDownVotedCanceled(vote, post, user, timestamp=None):
if not post.wiki:
author = post.author
- author.reputation = calculate_reputation(author.reputation,
- int(REPUTATION_RULES['gain_by_downvote_canceled']))
+ author.reputation = calculate_reputation(
+ author.reputation,
+ askbot_settings.REP_GAIN_FOR_RECEIVING_DOWNVOTE_CANCELATION
+ )
author.save()
question = post
@@ -444,19 +461,21 @@ def onDownVotedCanceled(vote, post, user, timestamp=None):
question = post.question
reputation = Repute(user=author,
- positive=int(REPUTATION_RULES['gain_by_downvote_canceled']),
- question=question,
- reputed_at=timestamp,
- reputation_type=4,
- reputation=author.reputation)
+ positive=\
+ askbot_settings.REP_GAIN_FOR_RECEIVING_DOWNVOTE_CANCELATION,
+ question=question,
+ reputed_at=timestamp,
+ reputation_type=4,
+ reputation=author.reputation
+ )
reputation.save()
user.reputation = calculate_reputation(user.reputation,
- int(REPUTATION_RULES['gain_by_canceling_downvote']))
+ askbot_settings.REP_GAIN_FOR_CANCELING_DOWNVOTE)
user.save()
reputation = Repute(user=user,
- positive=int(REPUTATION_RULES['gain_by_canceling_downvote']),
+ positive=askbot_settings.REP_GAIN_FOR_CANCELING_DOWNVOTE,
question=question,
reputed_at=timestamp,
reputation_type=5,
@@ -470,10 +489,13 @@ def onDeleteCanceled(post, user, timestamp=None):
post.deleted_at = None
post.save()
logging.debug('now restoring something')
- if isinstance(post,Answer):
- logging.debug('updated answer count on undelete, have %d' % post.question.answer_count)
+ if isinstance(post, Answer):
+ logging.debug(
+ 'updated answer count on undelete, have %d' \
+ % post.question.answer_count
+ )
Question.objects.update_answer_count(post.question)
- elif isinstance(post,Question):
+ elif isinstance(post, Question):
for tag in list(post.tags.all()):
if tag.used_count == 1 and tag.deleted:
tag.deleted = False
@@ -502,12 +524,16 @@ def onDeleted(post, user, timestamp=None):
answers = post.answers.all()
if user == post.author:
if len(answers) > 0:
- msg = _('Your question and all of it\'s answers have been deleted')
+ msg = _(
+ 'Your question and all of it\'s answers have been deleted'
+ )
else:
msg = _('Your question has been deleted')
else:
if len(answers) > 0:
- msg = _('The question and all of it\'s answers have been deleted')
+ msg = _(
+ 'The question and all of it\'s answers have been deleted'
+ )
else:
msg = _('The question has been deleted')
user.message_set.create(message=msg)
@@ -517,7 +543,7 @@ def onDeleted(post, user, timestamp=None):
elif isinstance(post, Answer):
Question.objects.update_answer_count(post.question)
logging.debug('updated answer count to %d' % post.question.answer_count)
- delete_post_or_answer.send(
+ signals.delete_post_or_answer.send(
sender=post.__class__,
instance=post,
delete_by=user
diff --git a/dos2unix.sh b/askbot/bin/dos2unix.sh
index 2864426a..2864426a 100644
--- a/dos2unix.sh
+++ b/askbot/bin/dos2unix.sh
diff --git a/rmpyc b/askbot/bin/rmpyc
index 014575f6..014575f6 100755
--- a/rmpyc
+++ b/askbot/bin/rmpyc
diff --git a/askbot/conf/README b/askbot/conf/README
new file mode 100644
index 00000000..4dd62329
--- /dev/null
+++ b/askbot/conf/README
@@ -0,0 +1,5 @@
+this directory contains
+forum site configurations for livesettings
+
+they need to be imported in models so made this a part of
+models module
diff --git a/askbot/conf/__init__.py b/askbot/conf/__init__.py
new file mode 100644
index 00000000..de52c601
--- /dev/null
+++ b/askbot/conf/__init__.py
@@ -0,0 +1,16 @@
+#import these to compile code and install values
+import askbot.conf.minimum_reputation
+import askbot.conf.vote_rules
+import askbot.conf.reputation_changes
+import askbot.conf.email
+import askbot.conf.forum_data_rules
+import askbot.conf.flatpages
+import askbot.conf.site_settings
+import askbot.conf.external_keys
+import askbot.conf.skin_counter_settings
+import askbot.conf.skin_general_settings
+import askbot.conf.user_settings
+
+#import main settings object
+from askbot.conf.settings_wrapper import settings
+
diff --git a/askbot/conf/email.py b/askbot/conf/email.py
new file mode 100644
index 00000000..dd3e5bdc
--- /dev/null
+++ b/askbot/conf/email.py
@@ -0,0 +1,69 @@
+"""
+Email related settings
+"""
+from askbot.conf.settings_wrapper import settings
+from askbot.deps.livesettings import ConfigurationGroup, IntegerValue, BooleanValue
+from askbot.deps.livesettings import StringValue
+from django.utils.translation import ugettext as _
+from askbot import const
+
+EMAIL = ConfigurationGroup(
+ 'EMAIL',
+ _('Email and email alert settings'),
+ )
+
+settings.register(
+ IntegerValue(
+ EMAIL,
+ 'MAX_ALERTS_PER_EMAIL',
+ default=7,
+ description=_('Maximum number of news entries in an email alert')
+ )
+)
+
+settings.register(
+ StringValue(
+ EMAIL,
+ 'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE',
+ default='w',
+ choices=const.NOTIFICATION_DELIVERY_SCHEDULE_CHOICES,
+ description=_('Default news notification frequency'),
+ help_text=_(
+ 'This option currently defines default frequency '
+ 'of emailed updates in the following five categories: '
+ 'questions asked by user, answered by user, individually '
+ 'selected, entire forum (per person tag filter applies) '
+ 'and posts mentioning the user and comment responses'
+ )
+ )
+)
+
+settings.register(
+ BooleanValue(
+ EMAIL,
+ 'EMAIL_VALIDATION',
+ default=False,
+ hidden=True,
+ description=_('Require email verification before allowing to post'),
+ help_text=_('Active email verification is done by sending a verification key in email')
+ )
+)
+
+settings.register(
+ BooleanValue(
+ EMAIL,
+ 'EMAIL_UNIQUE',
+ default=True,
+ description=_('Allow only one account per email address')
+ )
+)
+
+settings.register(
+ StringValue(
+ EMAIL,
+ 'ANONYMOUS_USER_EMAIL',
+ default='anonymous@askbot.org',
+ description=_('Fake email for anonymous user'),
+ help_text=_('Use this setting to control gravatar for email-less user')
+ )
+)
diff --git a/askbot/conf/external_keys.py b/askbot/conf/external_keys.py
new file mode 100644
index 00000000..667a997f
--- /dev/null
+++ b/askbot/conf/external_keys.py
@@ -0,0 +1,93 @@
+"""
+External service key settings
+"""
+from askbot.conf.settings_wrapper import settings
+from askbot.deps.livesettings import ConfigurationGroup, StringValue
+from django.utils.translation import ugettext as _
+from django.conf import settings as django_settings
+
+EXTERNAL_KEYS = ConfigurationGroup(
+ 'EXTERNAL_KEYS',
+ _('Keys to connect the site with external services like Facebook, etc.')
+ )
+
+settings.register(
+ StringValue(
+ EXTERNAL_KEYS,
+ 'GOOGLE_SITEMAP_CODE',
+ description=_('Google site verification key'),
+ help_text=_(
+ 'This key helps google index your site '
+ 'please obtain is at '
+ '<a href="%(google_webmasters_tools_url)s">'
+ 'google webmasters tools site</a>'
+ ) % {'google_webmasters_tools_url':
+ 'https://www.google.com/webmasters/tools/home?hl=' \
+ + django_settings.LANGUAGE_CODE}
+ )
+)
+
+settings.register(
+ StringValue(
+ EXTERNAL_KEYS,
+ 'GOOGLE_ANALYTICS_KEY',
+ description=_('Google Analytics key'),
+ help_text=_(
+ 'Obtain is at <a href="%(ga_site)s">'
+ 'Google Analytics</a> site, if you '
+ 'wish to use Google Analytics to monitor '
+ 'your site'
+ ) % {'ga_site':'http://www.google.com/intl/%s/analytics/' \
+ % django_settings.LANGUAGE_CODE }
+ )
+)
+
+settings.register(
+ StringValue(
+ EXTERNAL_KEYS,
+ 'RECAPTCHA_PRIVATE_KEY',
+ description=_('Recaptcha private key') + ' - does not work yet',
+ hidden=True,
+ help_text=_(
+ 'Recaptcha is a tool that helps distinguish '
+ 'real people from annoying spam robots. '
+ 'Please get this and a public key at '
+ 'the <a href="http://recaptcha.net">recaptcha.net</a>'
+ )
+ )
+)
+
+settings.register(
+ StringValue(
+ EXTERNAL_KEYS,
+ 'RECAPTCHA_PUBLIC_KEY',
+ hidden=True,
+ description=_('Recaptcha public key') + ' - does not work yet'
+ )
+)
+
+settings.register(
+ StringValue(
+ EXTERNAL_KEYS,
+ 'FB_API_KEY',
+ description=_('Facebook public API key') + ' - does not work yet',
+ hidden=True,
+ help_text=_(
+ 'Facebook API key and Facebook secret '
+ 'allow to use Facebook Connect login method '
+ 'at your site. Please obtain these keys '
+ 'at <a href="http://www.facebook.com/developers/createapp.php">'
+ 'facebook create app</a> site'
+ )
+ )
+
+)
+
+settings.register(
+ StringValue(
+ EXTERNAL_KEYS,
+ 'FB_SECRET',
+ hidden=True,
+ description=_('Facebook secret key') + ' - does not work yet'
+ )
+)
diff --git a/askbot/conf/flatpages.py b/askbot/conf/flatpages.py
new file mode 100644
index 00000000..27e3e35d
--- /dev/null
+++ b/askbot/conf/flatpages.py
@@ -0,0 +1,37 @@
+"""
+Q&A forum flatpages (about, etc.)
+"""
+from askbot.conf.settings_wrapper import settings
+from askbot.deps.livesettings import ConfigurationGroup, LongStringValue
+from django.utils.translation import ugettext as _
+
+FLATPAGES = ConfigurationGroup(
+ 'FLATPAGES',
+ _('Flatpages - about, privacy policy, etc.')
+ )
+
+settings.register(
+ LongStringValue(
+ FLATPAGES,
+ 'FORUM_ABOUT',
+ description=_('Text of the Q&A forum About page (html format)'),
+ help_text=\
+ _(
+ 'Save, then <a href="http://validator.w3.org/">'
+ 'use HTML validator</a> on the "about" page to check your input.'
+ )
+ )
+)
+
+settings.register(
+ LongStringValue(
+ FLATPAGES,
+ 'FORUM_PRIVACY',
+ description=_('Text of the Q&A forum Privacy Policy (html format)'),
+ help_text=\
+ _(
+ 'Save, then <a href="http://validator.w3.org/">'
+ 'use HTML validator</a> on the "privacy" page to check your input.'
+ )
+ )
+)
diff --git a/askbot/conf/forum_data_rules.py b/askbot/conf/forum_data_rules.py
new file mode 100644
index 00000000..58fedf5a
--- /dev/null
+++ b/askbot/conf/forum_data_rules.py
@@ -0,0 +1,62 @@
+"""
+Settings for askbot data display and entry
+"""
+from askbot.conf.settings_wrapper import settings
+from askbot.deps.livesettings import ConfigurationGroup, BooleanValue, IntegerValue
+from askbot.deps.livesettings import StringValue
+from django.utils.translation import ugettext as _
+from askbot import const
+
+FORUM_DATA_RULES = ConfigurationGroup(
+ 'FORUM_DATA_RULES',
+ _('Settings for askbot data entry and display')
+ )
+
+settings.register(
+ BooleanValue(
+ FORUM_DATA_RULES,
+ 'WIKI_ON',
+ default=True,
+ description=_('Check to enable community wiki feature')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ FORUM_DATA_RULES,
+ 'MAX_TAG_LENGTH',
+ default=20,
+ description=_('Maximum length of tag (number of characters)')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ FORUM_DATA_RULES,
+ 'MAX_TAGS_PER_POST',
+ default=5,
+ description=_('Maximum number of tags per question')
+ )
+)
+
+#todo: looks like there is a bug in askbot.deps.livesettings
+#that does not allow Integer values with defaults and choices
+settings.register(
+ StringValue(
+ FORUM_DATA_RULES,
+ 'DEFAULT_QUESTIONS_PAGE_SIZE',
+ choices=const.PAGE_SIZE_CHOICES,
+ default='30',
+ description=_('Number of questions to list by default')
+ )
+)
+
+settings.register(
+ StringValue(
+ FORUM_DATA_RULES,
+ 'UNANSWERED_QUESTION_MEANING',
+ choices=const.UNANSWERED_QUESTION_MEANING_CHOICES,
+ default='NO_ACCEPTED_ANSWERS',
+ description=_('What should "unanswered question" mean?')
+ )
+)
diff --git a/askbot/conf/minimum_reputation.py b/askbot/conf/minimum_reputation.py
new file mode 100644
index 00000000..d7044911
--- /dev/null
+++ b/askbot/conf/minimum_reputation.py
@@ -0,0 +1,148 @@
+"""
+Settings for minimum reputation required for
+a variety of actions on the askbot askbot
+"""
+from askbot.conf.settings_wrapper import settings
+from askbot.deps.livesettings import ConfigurationGroup, IntegerValue
+from django.utils.translation import ugettext as _
+
+MIN_REP = ConfigurationGroup(
+ 'MIN_REP',
+ _('Minimum reputation required to perform actions'),
+ ordering=0
+ )
+
+settings.register(
+ IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_VOTE_UP',
+ default=15,
+ description=_('Upvote')
+ )
+ )
+
+settings.register(
+ IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_VOTE_DOWN',
+ default=100,
+ description=_('Downvote')
+ )
+ )
+
+settings.register(
+ IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_FLAG_OFFENSIVE',
+ default=15,
+ description=_('Flag offensive')
+ )
+ )
+
+settings.register(
+ IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_LEAVE_COMMENTS',
+ default=50,
+ description=_('Leave comments')
+ )
+ )
+
+settings.register(
+ IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_DELETE_OTHERS_COMMENTS',
+ default=2000,
+ description=_('Delete comments posted by others')
+ )
+ )
+
+settings.register(
+ IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_UPLOAD_FILES',
+ default=60,
+ description=_('Upload files')
+ )
+ )
+
+settings.register(
+ IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_CLOSE_OWN_QUESTIONS',
+ default=250,
+ description=_('Close own questions'),
+ )
+ )
+
+settings.register(
+ IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_RETAG_OTHERS_QUESTIONS',
+ default=500,
+ description=_('Retag questions posted by other people')
+ )
+ )
+
+settings.register(
+ IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_REOPEN_OWN_QUESTIONS',
+ default=500,
+ description=_('Reopen own questions')
+ )
+ )
+
+settings.register(
+ IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_EDIT_WIKI',
+ default=750,
+ description=_('Edit community wiki posts')
+ )
+ )
+
+settings.register(
+ IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_EDIT_OTHERS_POSTS',
+ default=2000,
+ description=_('Edit posts authored by other people')
+ )
+ )
+
+settings.register(
+ IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_VIEW_OFFENSIVE_FLAGS',
+ default=2000,
+ description=_('View offensive flags')
+ )
+ )
+
+settings.register(
+ IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_DISABLE_URL_NOFOLLOW',
+ default=2000,
+ description=_('Disable nofollow directive on links')
+ )
+ )
+
+settings.register(
+ IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_CLOSE_OTHERS_QUESTIONS',
+ default=2000,
+ description=_('Close questions asked by others')
+ )
+ )
+
+settings.register(
+ IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_LOCK_POSTS',
+ default=4000,
+ description=_('Lock posts')
+ )
+ )
diff --git a/askbot/conf/reputation_changes.py b/askbot/conf/reputation_changes.py
new file mode 100644
index 00000000..46214d57
--- /dev/null
+++ b/askbot/conf/reputation_changes.py
@@ -0,0 +1,149 @@
+"""
+Settings for reputation changes that apply to
+user in response to various actions by the same
+users or others
+"""
+from askbot.conf.settings_wrapper import settings
+from askbot.deps.livesettings import ConfigurationGroup, IntegerValue
+from django.utils.translation import ugettext as _
+
+REP_CHANGES = ConfigurationGroup(
+ 'REP_CHANGES',
+ _('Reputaion loss and gain rules'),
+ ordering=2
+ )
+
+settings.register(
+ IntegerValue(
+ REP_CHANGES,
+ 'MAX_REP_GAIN_PER_USER_PER_DAY',
+ default=200,
+ description=_('Maximum daily reputation gain per user')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ REP_CHANGES,
+ 'REP_GAIN_FOR_RECEIVING_UPVOTE',
+ default=10,
+ description=_('Gain for receiving an upvote')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ REP_CHANGES,
+ 'REP_GAIN_FOR_RECEIVING_ANSWER_ACCEPTANCE',
+ default=15,
+ description=_('Gain for the author of accepted answer')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ REP_CHANGES,
+ 'REP_GAIN_FOR_ACCEPTING_ANSWER',
+ default=2,
+ description=_('Gain for accepting best answer')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ REP_CHANGES,
+ 'REP_GAIN_FOR_RECEIVING_DOWNVOTE_CANCELATION',
+ default=2,
+ description=_('Gain for post owner on canceled downvote')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ REP_CHANGES,
+ 'REP_GAIN_FOR_CANCELING_DOWNVOTE',
+ default=1,
+ description=_('Gain for voter on canceling downvote')
+ )
+)
+#'gain_by_canceling_downvote',
+
+settings.register(
+ IntegerValue(
+ REP_CHANGES,
+ 'REP_LOSS_FOR_CANCELING_ANSWER_ACCEPTANCE',
+ default=-2,
+ description=_('Loss for voter for canceling of answer acceptance')
+ )
+)
+#'lose_by_canceling_accepted_answer',
+
+settings.register(
+ IntegerValue(
+ REP_CHANGES,
+ 'REP_LOSS_FOR_RECEIVING_CANCELATION_OF_ANSWER_ACCEPTANCE',
+ default=-5,
+ description=_('Loss for author whose answer was "un-accepted"')
+ )
+)
+#'lose_by_accepted_answer_cancled',
+
+settings.register(
+ IntegerValue(
+ REP_CHANGES,
+ 'REP_LOSS_FOR_DOWNVOTING',
+ default=-2,
+ description=_('Loss for giving a downvote')
+ )
+)
+#'lose_by_downvoted',
+
+settings.register(
+ IntegerValue(
+ REP_CHANGES,
+ 'REP_LOSS_FOR_RECEIVING_FLAG',
+ default=-2,
+ description=_('Loss for owner of post that was flagged offensive')
+ )
+)
+#'lose_by_flagged',
+
+settings.register(
+ IntegerValue(
+ REP_CHANGES,
+ 'REP_LOSS_FOR_RECEIVING_DOWNVOTE',
+ default=-1,
+ description=_('Loss for owner of post that was downvoted')
+ )
+)
+#'lose_by_downvoting',
+
+settings.register(
+ IntegerValue(
+ REP_CHANGES,
+ 'REP_LOSS_FOR_RECEIVING_THREE_FLAGS_PER_REVISION',
+ default=-30,
+ description=_('Loss for owner of post that was flagged 3 times per same revision')
+ )
+)
+#'lose_by_flagged_lastrevision_3_times',
+
+settings.register(
+ IntegerValue(
+ REP_CHANGES,
+ 'REP_LOSS_FOR_RECEIVING_FIVE_FLAGS_PER_REVISION',
+ default=-100,
+ description=_('Loss for owner of post that was flagged 5 times per same revision')
+ )
+)
+#'lose_by_flagged_lastrevision_5_times',
+
+settings.register(
+ IntegerValue(
+ REP_CHANGES,
+ 'REP_LOSS_FOR_RECEIVING_UPVOTE_CANCELATION',
+ default=-10,
+ description=_('Loss for post owner when upvote is canceled')
+ )
+)
+#'lose_by_upvote_canceled',
diff --git a/askbot/conf/settings_wrapper.py b/askbot/conf/settings_wrapper.py
new file mode 100644
index 00000000..2dbf9b74
--- /dev/null
+++ b/askbot/conf/settings_wrapper.py
@@ -0,0 +1,77 @@
+"""
+Definition of a Singleton wrapper class for askbot.deps.livesettings
+with interface similar to django.conf.settings
+that is each setting has unique key and is accessible
+via dotted lookup.
+
+for example to lookup value of setting BLAH you would do
+
+from askbot.conf import settings as askbot_settings
+
+askbot_settings.BLAH
+
+NOTE that at the moment there is distinction between settings
+(django settings) and askbot_settings (forum.deps.livesettings)
+
+the value will be taken from askbot.deps.livesettings database or cache
+note that during compilation phase database is not accessible
+for the most part, so actual values are reliably available only
+at run time
+
+askbot.deps.livesettings is a module developed for satchmo project
+"""
+from askbot.deps.livesettings import SortedDotDict, config_register
+
+class ConfigSettings(object):
+ """A very simple Singleton wrapper for settings
+ a limitation is that all settings names using this class
+ must be distinct, even though they might belong
+ to different settings groups
+ """
+ __instance = None
+
+ def __init__(self):
+ """assigns SortedDotDict to self.__instance if not set"""
+ if ConfigSettings.__instance == None:
+ ConfigSettings.__instance = SortedDotDict()
+ self.__dict__['_ConfigSettings__instance'] = ConfigSettings.__instance
+ self.__ordering_index = {}
+
+ def __getattr__(self, key):
+ """value lookup returns the actual value of setting
+ not the object - this way only very minimal modifications
+ will be required in code to convert an app
+ depending on django.conf.settings to askbot.deps.livesettings
+ """
+ return getattr(self.__instance, key).value
+
+ def register(self, value):
+ """registers the setting
+ value must be a subclass of askbot.deps.livesettings.Value
+ """
+ key = value.key
+ group_key = value.group.key
+
+ ordering = self.__ordering_index.get(group_key, None)
+ if ordering:
+ ordering += 1
+ value.ordering = ordering
+ else:
+ ordering = 1
+ value.ordering = ordering
+ self.__ordering_index[group_key] = ordering
+
+ if key in self.__instance:
+ raise Exception('setting %s is already registered' % key)
+ else:
+ self.__instance[key] = config_register(value)
+
+ def as_dict(self):
+ out = dict()
+ for key in self.__instance.keys():
+ #todo: this is odd that I could not use self.__instance.items() mapping here
+ out[key] = self.__instance[key].value
+ return out
+
+#settings instance to be used elsewhere in the project
+settings = ConfigSettings()
diff --git a/askbot/conf/site_settings.py b/askbot/conf/site_settings.py
new file mode 100644
index 00000000..5b0213e4
--- /dev/null
+++ b/askbot/conf/site_settings.py
@@ -0,0 +1,94 @@
+"""
+Q&A website settings - title, desctiption, basic urls
+keywords
+"""
+from askbot.conf.settings_wrapper import settings
+from askbot.deps.livesettings import ConfigurationGroup, StringValue
+from django.utils.translation import ugettext as _
+from django.utils.html import escape
+from askbot import const
+
+QA_SITE_SETTINGS = ConfigurationGroup(
+ 'QA_SITE_SETTINGS',
+ _('Q&A forum website parameters and urls')
+ )
+
+settings.register(
+ StringValue(
+ QA_SITE_SETTINGS,
+ 'APP_TITLE',
+ default=u'ASKBOT: Open Source Q&A Forum',
+ description=_('Site title for the Q&A forum')
+ )
+)
+
+settings.register(
+ StringValue(
+ QA_SITE_SETTINGS,
+ 'APP_KEYWORDS',
+ default=u'ASKBOT,CNPROG,forum,community',
+ description=_('Comma separated list of Q&A site keywords')
+ )
+)
+
+settings.register(
+ StringValue(
+ QA_SITE_SETTINGS,
+ 'APP_COPYRIGHT',
+ default='Copyright ASKBOT, 2010. Some rights reserved under creative commons license.',
+ description=_('Copyright message to show in the footer')
+ )
+)
+
+settings.register(
+ StringValue(
+ QA_SITE_SETTINGS,
+ 'APP_DESCRIPTION',
+ default='Open source question and answer forum written in Python and Django',
+ description=_('Site description for the search engines')
+ )
+)
+
+settings.register(
+ StringValue(
+ QA_SITE_SETTINGS,
+ 'APP_SHORT_NAME',
+ default=_('Askbot'),
+ hidden=True,
+ description=_('Short name for your Q&A forum')
+ )
+)
+
+settings.register(
+ StringValue(
+ QA_SITE_SETTINGS,
+ 'APP_URL',
+ default='http://askbot.org',
+ description=_('Base URL for your Q&A forum, must start with http or https'),
+ )
+)
+
+settings.register(
+ StringValue(
+ QA_SITE_SETTINGS,
+ 'GREETING_URL',
+ default='/' + _('faq/'),#cannot reverse url here, unfortunately, must be absolute also
+ hidden=True,
+ description=_('Link shown in the greeting message shown to the anonymous user'),
+ help_text=_('If you change this url from the default - '
+ 'then you will also probably want to adjust translation of '
+ 'the following string: ') + '"'
+ + escape(const.GREETING_FOR_ANONYMOUS_USER + '"'
+ ' You can find this string in your locale django.po file'
+ )
+ )
+)
+
+settings.register(
+ StringValue(
+ QA_SITE_SETTINGS,
+ 'FEEDBACK_SITE_URL',
+ description=_('Feedback site URL'),
+ help_text=_('If left empty, a simple internal feedback form will be used instead')
+ )
+)
diff --git a/askbot/conf/skin_counter_settings.py b/askbot/conf/skin_counter_settings.py
new file mode 100644
index 00000000..d7037693
--- /dev/null
+++ b/askbot/conf/skin_counter_settings.py
@@ -0,0 +1,251 @@
+"""
+Skin settings to color view, vote and answer counters
+"""
+from askbot.conf.settings_wrapper import settings
+from askbot.deps.livesettings import ConfigurationGroup, IntegerValue, StringValue
+from django.utils.translation import ugettext as _
+from askbot.deps.grapefruit import Color
+
+SKIN_COUNTER_SETTINGS = ConfigurationGroup(
+ 'SKIN_COUNTER_SETTINGS',
+ _('Skin: view, vote and answer counters')
+ )
+
+settings.register(
+ IntegerValue(
+ SKIN_COUNTER_SETTINGS,
+ 'VOTE_COUNTER_EXPECTED_MAXIMUM',
+ default=3,
+ description=_('Vote counter value to give "full color"')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_VOTE_COUNTER_EMPTY_BG',
+ default='white',
+ description=_('Background color for votes = 0'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_VOTE_COUNTER_EMPTY_FG',
+ default='gray',
+ description=_('Foreground color for votes = 0'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_VOTE_COUNTER_MIN_BG',
+ default='white',
+ description=_('Background color for votes = 1'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_VOTE_COUNTER_MIN_FG',
+ default='black',
+ description=_('Foreground color for votes = 1'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_VOTE_COUNTER_MAX_BG',
+ default='#a9d0f5',
+ description=_('Background color for votes = MAX'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_VOTE_COUNTER_MAX_FG',
+ default=Color.NewFromHtml(
+ settings.COLORS_VOTE_COUNTER_MAX_BG
+ ).DarkerColor(0.7).html,
+ description=_('Foreground color for votes = MAX'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ SKIN_COUNTER_SETTINGS,
+ 'VIEW_COUNTER_EXPECTED_MAXIMUM',
+ default=100,
+ description=_('View counter value to give "full color"')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_VIEW_COUNTER_EMPTY_BG',
+ default='gray',
+ description=_('Background color for views = 0'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_VIEW_COUNTER_EMPTY_FG',
+ default='white',
+ description=_('Foreground color for views = 0'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_VIEW_COUNTER_MIN_BG',
+ default='#D0F5A9',
+ description=_('Background color for views = 1'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_VIEW_COUNTER_MIN_FG',
+ default=Color.NewFromHtml(
+ settings.COLORS_VIEW_COUNTER_MIN_BG
+ ).DarkerColor(0.6).html,
+ description=_('Foreground color for views = 1'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_VIEW_COUNTER_MAX_BG',
+ default='#FF8000',
+ description=_('Background color for views = MAX'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_VIEW_COUNTER_MAX_FG',
+ default=Color.NewFromHtml(
+ settings.COLORS_VIEW_COUNTER_MAX_BG
+ ).DarkerColor(0.7).html,
+ description=_('Foreground color for views = MAX'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ SKIN_COUNTER_SETTINGS,
+ 'ANSWER_COUNTER_EXPECTED_MAXIMUM',
+ default=4,
+ description=_('Answer counter value to give "full color"')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_ANSWER_COUNTER_EMPTY_BG',
+ default=Color.NewFromHtml('#a40000').Blend(
+ Color.NewFromHtml('white'),0.8
+ ).html,
+ description=_('Background color for answers = 0'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_ANSWER_COUNTER_EMPTY_FG',
+ default='yellow',
+ description=_('Foreground color for answers = 0'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_ANSWER_COUNTER_MIN_BG',
+ default='#AEB404',
+ description=_('Background color for answers = 1'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_ANSWER_COUNTER_MIN_FG',
+ default='white',
+ description=_('Foreground color for answers = 1'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_ANSWER_COUNTER_MAX_BG',
+ default=Color.NewFromHtml('#61380B').Blend(
+ Color.NewFromHtml('white'),0.75
+ ).html,
+ description=_('Background color for answers = MAX'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_ANSWER_COUNTER_MAX_FG',
+ default='#ffff00',
+ description=_('Foreground color for answers = MAX'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_ANSWER_COUNTER_ACCEPTED_BG',
+ default=Color.NewFromHtml('darkgreen').Blend(
+ Color.NewFromHtml('white'),0.8
+ ).html,
+ description=_('Background color for accepted'),
+ help_text=_('HTML color name of hex value')
+ )
+)
+
+settings.register(
+ StringValue(
+ SKIN_COUNTER_SETTINGS,
+ 'COLORS_ANSWER_COUNTER_ACCEPTED_FG',
+ default='#D0F5A9',
+ description=_('Foreground color for accepted answer'),
+ help_text=_('HTML color name of hex value')
+ )
+)
diff --git a/askbot/conf/skin_general_settings.py b/askbot/conf/skin_general_settings.py
new file mode 100644
index 00000000..b96f3424
--- /dev/null
+++ b/askbot/conf/skin_general_settings.py
@@ -0,0 +1,38 @@
+"""
+General skin settings
+"""
+from askbot.conf.settings_wrapper import settings
+from askbot.deps.livesettings import ConfigurationGroup, StringValue, IntegerValue
+from django.utils.translation import ugettext as _
+from askbot.skins.utils import get_skin_choices
+
+GENERAL_SKIN_SETTINGS = ConfigurationGroup(
+ 'GENERAL_SKIN_SETTINGS',
+ _('Skin: general settings'),
+ )
+
+settings.register(
+ StringValue(
+ GENERAL_SKIN_SETTINGS,
+ 'ASKBOT_DEFAULT_SKIN',
+ default='default',
+ choices=get_skin_choices(),
+ description=_('Select skin'),
+ )
+)
+
+settings.register(
+ IntegerValue(
+ GENERAL_SKIN_SETTINGS,
+ 'MEDIA_RESOURCE_REVISION',
+ default=1,
+ description=_('Skin media revision number'),
+ help_text=_(
+ 'Increment this number when you change '
+ 'image in skin media or stylesheet. '
+ 'This helps avoid showing your users '
+ 'outdated images from their browser cache.'
+ )
+ )
+)
+
diff --git a/askbot/conf/user_settings.py b/askbot/conf/user_settings.py
new file mode 100644
index 00000000..9add71b1
--- /dev/null
+++ b/askbot/conf/user_settings.py
@@ -0,0 +1,30 @@
+"""
+User policy settings
+"""
+from askbot.conf.settings_wrapper import settings
+from askbot.deps.livesettings import ConfigurationGroup, BooleanValue, IntegerValue
+from django.utils.translation import ugettext as _
+
+USER_SETTINGS = ConfigurationGroup(
+ 'USER_SETTINGS',
+ _('User policy settings')
+ )
+
+settings.register(
+ BooleanValue(
+ USER_SETTINGS,
+ 'EDITABLE_SCREEN_NAME',
+ default=True,
+ description=_('Allow editing user screen name')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ USER_SETTINGS,
+ 'MIN_USERNAME_LENGTH',
+ hidden=True,
+ default=1,
+ description=_('Minimum allowed length for screen name')
+ )
+)
diff --git a/askbot/conf/vote_rules.py b/askbot/conf/vote_rules.py
new file mode 100644
index 00000000..a8b7d5f5
--- /dev/null
+++ b/askbot/conf/vote_rules.py
@@ -0,0 +1,69 @@
+"""
+Forum configuration settings detailing rules on votes
+and offensive flags.
+
+For example number of times a person can vote each day, etc.
+"""
+from askbot.conf.settings_wrapper import settings
+from askbot.deps.livesettings import ConfigurationGroup, IntegerValue
+from django.utils.translation import ugettext as _
+
+VOTE_RULES = ConfigurationGroup(
+ 'VOTE_RULES',
+ _('Limits applicable to votes and moderation flags'),
+ ordering=1,
+ )
+
+settings.register(
+ IntegerValue(
+ VOTE_RULES,
+ 'MAX_VOTES_PER_USER_PER_DAY',
+ default=30,
+ description=_('Number of votes a user can cast per day')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ VOTE_RULES,
+ 'MAX_FLAGS_PER_USER_PER_DAY',
+ default=5,
+ description=_('Maximum number of flags per user per day')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ VOTE_RULES,
+ 'VOTES_LEFT_WARNING_THRESHOLD',
+ default=5,
+ description=_('Threshold for warning about remaining daily votes')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ VOTE_RULES,
+ 'MAX_DAYS_TO_CANCEL_VOTE',
+ default=1,
+ description=_('Number of days to allow canceling votes')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ VOTE_RULES,
+ 'MIN_FLAGS_TO_HIDE_POST',
+ default=3,
+ description=_('Number of flags required to automatically hide posts')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ VOTE_RULES,
+ 'MIN_FLAGS_TO_DELETE_POST',
+ default=5,
+ description=_('Number of flags required to automatically delete posts')
+ )
+)
diff --git a/forum/const.py b/askbot/const/__init__.py
index d546e0c5..3395cca7 100755..100644
--- a/forum/const.py
+++ b/askbot/const/__init__.py
@@ -1,5 +1,6 @@
# encoding:utf-8
from django.utils.translation import ugettext as _
+import re
"""
All constants could be used in other modules
For reasons that models, views can't have unicode text in this project, all unicode text go here.
@@ -54,12 +55,21 @@ POST_SCOPE_LIST = (
('favorite', _('favorite')),
)
DEFAULT_POST_SCOPE = 'all'
-DEFAULT_QUESTIONS_PAGE_SIZE = 30
-PAGE_SIZE_CHOICES = (('10','10',),('30','30',),('50','50',),)
+PAGE_SIZE_CHOICES = (('10', '10',), ('30', '30',), ('50', '50',),)
+#todo: remove this duplication
+QUESTIONS_PER_PAGE_USER_CHOICES = (
+ (10, u'10'),
+ (30, u'30'),
+ (50, u'50'),
+)
-UNANSWERED_MEANING_LIST = ('NO_ANSWERS','NO_UPVOTED_ANSWERS','NO_ACCEPTED_ANSWERS')
-UNANSWERED_MEANING = 'NO_ACCEPTED_ANSWERS'
-assert(UNANSWERED_MEANING in UNANSWERED_MEANING_LIST)
+UNANSWERED_QUESTION_MEANING_CHOICES = (
+ ('NO_ANSWERS', _('Question has no answers')),
+ ('NO_ACCEPTED_ANSWERS', _('Question has no accepted answers')),
+)
+#todo: implement this
+# ('NO_UPVOTED_ANSWERS',),
+#)
#todo:
#this probably needs to be language-specific
@@ -69,8 +79,6 @@ assert(UNANSWERED_MEANING in UNANSWERED_MEANING_LIST)
#to do full string match
TAG_REGEX = r'^[\w\+\.\-]+$'
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
@@ -89,13 +97,15 @@ TYPE_ACTIVITY_MARK_OFFENSIVE=14
TYPE_ACTIVITY_UPDATE_TAGS=15
TYPE_ACTIVITY_FAVORITE=16
TYPE_ACTIVITY_USER_FULL_UPDATED = 17
-TYPE_ACTIVITY_QUESTION_EMAIL_UPDATE_SENT = 18
+TYPE_ACTIVITY_EMAIL_UPDATE_SENT = 18
+TYPE_ACTIVITY_MENTION = 19
#TYPE_ACTIVITY_EDIT_QUESTION=17
#TYPE_ACTIVITY_EDIT_ANSWER=18
+#todo: rename this to TYPE_ACTIVITY_CHOICES
TYPE_ACTIVITY = (
- (TYPE_ACTIVITY_ASK_QUESTION, _('question')),
- (TYPE_ACTIVITY_ANSWER, _('answer')),
+ (TYPE_ACTIVITY_ASK_QUESTION, _('asked a question')),
+ (TYPE_ACTIVITY_ANSWER, _('answered a question')),
(TYPE_ACTIVITY_COMMENT_QUESTION, _('commented question')),
(TYPE_ACTIVITY_COMMENT_ANSWER, _('commented answer')),
(TYPE_ACTIVITY_UPDATE_QUESTION, _('edited question')),
@@ -111,7 +121,55 @@ TYPE_ACTIVITY = (
(TYPE_ACTIVITY_UPDATE_TAGS, _('updated tags')),
(TYPE_ACTIVITY_FAVORITE, _('selected favorite')),
(TYPE_ACTIVITY_USER_FULL_UPDATED, _('completed user profile')),
- (TYPE_ACTIVITY_QUESTION_EMAIL_UPDATE_SENT, _('email update sent to user')),
+ (TYPE_ACTIVITY_EMAIL_UPDATE_SENT, _('email update sent to user')),
+ (TYPE_ACTIVITY_MENTION, _('mentioned in the post')),
+)
+
+
+#MENTION activity is added implicitly, unfortunately
+RESPONSE_ACTIVITY_TYPES_FOR_INSTANT_NOTIFICATIONS = (
+ TYPE_ACTIVITY_COMMENT_QUESTION,
+ TYPE_ACTIVITY_COMMENT_ANSWER,
+ TYPE_ACTIVITY_UPDATE_ANSWER,
+ TYPE_ACTIVITY_UPDATE_QUESTION,
+ TYPE_ACTIVITY_ANSWER,
+ TYPE_ACTIVITY_ASK_QUESTION,
+)
+
+
+#the same as for instant notifications for now
+#MENTION activity is added implicitly, unfortunately
+RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY = (
+ TYPE_ACTIVITY_ANSWER,
+ TYPE_ACTIVITY_ASK_QUESTION,
+ TYPE_ACTIVITY_COMMENT_QUESTION,
+ TYPE_ACTIVITY_COMMENT_ANSWER,
+ TYPE_ACTIVITY_UPDATE_ANSWER,
+ TYPE_ACTIVITY_UPDATE_QUESTION,
+# TYPE_ACTIVITY_PRIZE,
+# TYPE_ACTIVITY_MARK_ANSWER,
+# TYPE_ACTIVITY_VOTE_UP,
+# TYPE_ACTIVITY_VOTE_DOWN,
+# TYPE_ACTIVITY_CANCEL_VOTE,
+# TYPE_ACTIVITY_DELETE_QUESTION,
+# TYPE_ACTIVITY_DELETE_ANSWER,
+# TYPE_ACTIVITY_MARK_OFFENSIVE,
+# TYPE_ACTIVITY_FAVORITE,
+)
+
+
+RESPONSE_ACTIVITY_TYPE_MAP_FOR_TEMPLATES = {
+ TYPE_ACTIVITY_COMMENT_QUESTION: 'question_comment',
+ TYPE_ACTIVITY_COMMENT_ANSWER: 'answer_comment',
+ TYPE_ACTIVITY_UPDATE_ANSWER: 'answer_update',
+ TYPE_ACTIVITY_UPDATE_QUESTION: 'question_update',
+ TYPE_ACTIVITY_ANSWER: 'new_answer',
+ TYPE_ACTIVITY_ASK_QUESTION: 'new_question',
+ }
+
+assert(
+ set(RESPONSE_ACTIVITY_TYPES_FOR_INSTANT_NOTIFICATIONS) \
+ == set(RESPONSE_ACTIVITY_TYPE_MAP_FOR_TEMPLATES.keys())
)
TYPE_RESPONSE = {
@@ -121,7 +179,7 @@ TYPE_RESPONSE = {
'ANSWER_ACCEPTED' : _('answer_accepted'),
}
-CONST = {
+POST_STATUS = {
'closed' : _('[closed]'),
'deleted' : _('[deleted]'),
'default_version' : _('initial version'),
@@ -129,6 +187,25 @@ 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
+TAG_EMAIL_FILTER_CHOICES = (
+ ('ignored', _('exclude ignored tags')),
+ ('interesting',_('allow only selected tags'))
+)
+
+NOTIFICATION_DELIVERY_SCHEDULE_CHOICES= (
+ ('i',_('instantly')),
+ ('d',_('daily')),
+ ('w',_('weekly')),
+ ('n',_('no email')),
+ )
+
+USERS_PAGE_SIZE = 28#todo: move it to settings?
+USERNAME_REGEX_STRING = r'^[\w ]+$'
+
+#chars that can go before or after @mention
+TWITTER_STYLE_MENTION_TERMINATION_CHARS = '\n ;,.!?<>'
+
+COMMENT_HARD_MAX_LENGTH = 2048
+
+#an exception import * because that file has only strings
+from askbot.const.message_keys import *
diff --git a/askbot/const/message_keys.py b/askbot/const/message_keys.py
new file mode 100644
index 00000000..f7f8e8e3
--- /dev/null
+++ b/askbot/const/message_keys.py
@@ -0,0 +1,19 @@
+"""
+This file must hold keys for translatable messages
+that are used as variables
+it is important that a dummy _() function is used here
+this way message key will be pulled into django.po
+and can still be used as a variable in python files
+"""
+_ = lambda v:v
+
+#NOTE: all strings must be explicitly put into this dictionary,
+#because you don't want to import _ from here with import *
+__all__ = ['GREETING_FOR_ANONYMOUS_USER', ]
+
+#this variable is shown in settings, because
+#the url within is configurable, the default is reverse('faq')
+#if user changes url they will have to be able to fix the
+#message translation too
+GREETING_FOR_ANONYMOUS_USER = \
+ _('First time here? Check out the <a href="%s">FAQ</a>!')
diff --git a/askbot/context.py b/askbot/context.py
new file mode 100644
index 00000000..3d246dd2
--- /dev/null
+++ b/askbot/context.py
@@ -0,0 +1,34 @@
+from django.conf import settings
+from askbot.conf import settings as askbot_settings
+def application_settings(context):
+ my_settings = askbot_settings.as_dict()
+ my_settings['LANGUAGE_CODE'] = settings.LANGUAGE_CODE
+ my_settings['FORUM_SCRIPT_ALIAS'] = settings.FORUM_SCRIPT_ALIAS
+ #print '\n'.join(sorted(my_settings.keys()))
+ return {'settings':my_settings}
+
+def auth_processor(request):
+ """
+ Returns context variables required by apps that use Django's authentication
+ system.
+
+ If there is no 'user' attribute in the request, uses AnonymousUser (from
+ django.contrib.auth).
+ """
+ if hasattr(request, 'user'):
+ user = request.user
+ if user.is_authenticated():
+ messages = user.message_set.all()
+ else:
+ messages = None
+ else:
+ from django.contrib.auth.models import AnonymousUser
+ user = AnonymousUser()
+ messages = None
+
+ from django.core.context_processors import PermWrapper
+ return {
+ 'user': user,
+ 'messages': messages,
+ 'perms': PermWrapper(user),
+ }
diff --git a/forum/cron/README b/askbot/cron/README
index d5573150..d5573150 100644
--- a/forum/cron/README
+++ b/askbot/cron/README
diff --git a/askbot/cron/askbot_cron_job b/askbot/cron/askbot_cron_job
new file mode 100644
index 00000000..71910f27
--- /dev/null
+++ b/askbot/cron/askbot_cron_job
@@ -0,0 +1,18 @@
+#!/bin/sh
+# this is a cron job for askbot that includes all
+# commands that need to be run periodically
+# please find introduction to cron here:
+# http://www.unixgeeks.org/security/newbie/unix/cron-1.html
+#
+# if you prefer, you can split this file into several
+
+PROJECT_PARENT_DIR=/path/to/dir_containing_askbot_site
+PROJECT_DIR_NAME=askbot_site
+
+export PYTHONPATH=$PROJECT_PARENT_DIR:$PYTHONPATH
+PROJECT_ROOT=$PYTHONPATH/$PROJECT_NAME
+
+#these are actual commands that are to be run
+python $PROJECT_ROOT/manage.py send_email_alerts
+python $PROJECT_ROOT/manage.py once_award_badges
+python $PROJECT_ROOT/manage.py multi_award_badges
diff --git a/askbot/deployment/__init__.py b/askbot/deployment/__init__.py
new file mode 100644
index 00000000..9f4ebaf9
--- /dev/null
+++ b/askbot/deployment/__init__.py
@@ -0,0 +1,101 @@
+"""
+module for deploying askbot
+"""
+import os.path
+from askbot.deployment import messages
+from askbot.deployment import dialogs
+from askbot.deployment import path_utils
+
+def startforum():
+ """basic deployment procedure
+ asks user several questions, then either creates
+ new deployment (in the case of new installation)
+ or gives hints on how to add askbot to an existing
+ Django project
+ """
+ #ask
+ print messages.DEPLOY_PREAMBLE
+
+ directory = None #directory where to put stuff
+ create_new = False #create new django project or not
+ where_to_deploy_msg = messages.WHERE_TO_DEPLOY
+ while directory is None:
+
+ directory = raw_input(where_to_deploy_msg + ' ')
+
+ where_to_deploy_msg = messages.WHERE_TO_DEPLOY_QUIT
+
+ directory = os.path.normpath(directory)
+ directory = os.path.abspath(directory)
+
+ if os.path.isfile(directory):
+ print messages.CANT_INSTALL_INTO_FILE % {'path':directory}
+ directory = None
+ continue
+
+ if path_utils.can_create_path(directory):
+ if os.path.exists(directory):
+ if path_utils.path_is_clean_for_django(directory):
+ if path_utils.has_existing_django_project(directory):
+ message = messages.SHOULD_ADD_APP_HERE % \
+ {
+ 'path': directory
+ }
+ should_add_app = dialogs.multiple_choice_input(
+ message,
+ options = ['yes','no']
+ )
+ if should_add_app == 'yes':
+ assert(create_new == False)
+ if path_utils.dir_name_acceptable(directory):
+ break
+ else:
+ print messages.format_msg_bad_dir_name(directory)
+ directory = None
+ continue
+ else:
+ directory = None
+ continue
+ else:
+ assert(directory != None)
+ if path_utils.dir_name_acceptable(directory):
+ create_new = True
+ break
+ else:
+ print messages.format_msg_bad_dir_name(directory)
+ directory = None
+ continue
+ else:
+ print messages.format_msg_dir_unclean_django(directory)
+ directory = None
+ continue
+ else:
+ message = messages.format_msg_create(directory)
+ should_create_new = dialogs.multiple_choice_input(
+ message,
+ options = ['yes','no']
+ )
+ if should_create_new == 'yes':
+ if path_utils.dir_name_acceptable(directory):
+ create_new = True
+ break
+ else:
+ print messages.format_msg_bad_dir_name(directory)
+ directory = None
+ continue
+ else:
+ directory = None
+ continue
+ else:
+ print messages.format_msg_dir_not_writable(directory)
+ directory = None
+ continue
+
+ help_file = os.path.join(directory, 'askbot', 'doc', 'INSTALL')
+ if create_new:
+ path_utils.create_path(directory)
+ path_utils.deploy_into(directory, new_project = True)
+ print messages.HOW_TO_DEPLOY_NEW % {'help_file': help_file}
+ else:
+ path_utils.deploy_into(directory, new_project = False)
+ print messages.HOW_TO_ADD_ASKBOT_TO_DJANGO % {'help_file': help_file}
diff --git a/askbot/deployment/dialogs.py b/askbot/deployment/dialogs.py
new file mode 100644
index 00000000..40f0d2ee
--- /dev/null
+++ b/askbot/deployment/dialogs.py
@@ -0,0 +1,20 @@
+"""functions that directly handle user input
+"""
+from askbot.deployment import messages
+import time
+
+def multiple_choice_input(prompt_phrase, options = None):
+ """prints a prompt, accepts keyboard input
+ and makes sure that user response is one of given
+ in the options argument, which is required
+ and must be a list
+ """
+ assert(isinstance(options, list))
+ while 1:
+ response = raw_input('\n%s (type %s): ' % (prompt_phrase, '/'.join(options)))
+ if response in options:
+ return response
+ else:
+ opt_string = ','.join(options)
+ print messages.INVALID_INPUT % {'opt_string': opt_string}
+ time.sleep(1)
diff --git a/askbot/deployment/messages.py b/askbot/deployment/messages.py
new file mode 100644
index 00000000..1569de6c
--- /dev/null
+++ b/askbot/deployment/messages.py
@@ -0,0 +1,91 @@
+"""Messages used in the procedure of deploying Askbot
+"""
+import os.path
+from askbot.deployment import path_utils
+
+DEPLOY_PREAMBLE = """
+Deploying Askbot - Django Q&A forum application
+Problems installing? -> please email admin@askbot.org
+
+To CANCEL - hit Ctr-C at any time"""
+
+WHERE_TO_DEPLOY = 'Where to deploy (in which directory)?'
+
+WHERE_TO_DEPLOY_QUIT = 'Where deploy forum (directory)? (Ctrl-C to quit)'
+
+CANT_INSTALL_INTO_FILE = '%(path)s is a file\ncannot install there'
+
+SHOULD_ADD_APP_HERE = 'Directory %(path)s?\nalready has a Django ' \
+ + 'project - do you want to add askbot app to that project?'
+
+HOW_TO_DEPLOY_NEW = 'Done. Please find further instructions in the file below:'\
+ + '\n%(help_file)s'
+
+HOW_TO_ADD_ASKBOT_TO_DJANGO = HOW_TO_DEPLOY_NEW
+
+DIR_IS_NOT_WRITABLE = 'Directory %(dir)s is not writable'
+
+PARENT_DIR_IS_NOT_WRITABLE = """To create directory %(target_dir)s
+we need to add %(non_existing_tail)s to %(existing_prefix)s
+but %(existing_prefix)s is not writable"""
+
+CONFIRM_DIR_CREATION = """Adding new directories:\n%(existing_prefix)s <-/%(non_existing_tail)s
+Accept?"""
+
+INVALID_INPUT = 'Please type one of: %(opt_string)s ' \
+ + '(or hit Ctrl-C to quit)'
+
+DIR_NAME_TAKEN_BY_PYTHON = """Directory '%(dir)s' is aready used by other Python module.
+Please choose some other name for your django project"""
+
+DIR_NAME_TAKEN_BY_ASKBOT = """Please do not name your entire Django project 'askbot',
+because this name is already used by the askbot app itself"""
+
+def format_msg_dir_not_writable(directory):
+ """returns a meaningful message explaining why directory
+ is not writable by the user
+ """
+ if os.path.exists(directory):
+ if path_utils.directory_is_writable(directory):
+ return ''
+ else:
+ return DIR_IS_NOT_WRITABLE % {'dir': directory}
+ else:
+ prefix, tail = path_utils.split_at_break_point(directory)
+ data = {
+ 'existing_prefix': prefix,
+ 'non_existing_tail': tail,
+ 'target_dir': directory
+ }
+ return PARENT_DIR_IS_NOT_WRITABLE % data
+
+def format_msg_create(directory):
+ """returns a message explaining wha directories
+ are about to be created and asks user if they want to proceed
+ """
+ if os.path.exists(directory):
+ raise Exception('directory %s aready exists' % directory)
+ else:
+ prefix, tail = path_utils.split_at_break_point(directory)
+ data = {
+ 'existing_prefix': prefix,
+ 'non_existing_tail': tail,
+ }
+ return CONFIRM_DIR_CREATION % data
+
+def format_msg_dir_unclean_django(directory):
+ """retuns a message telling which of the parent
+ directories contains a django project
+ so that users don't create nested projects
+ """
+ parent_django_dir = path_utils.find_parent_dir_with_django(directory)
+
+def format_msg_bad_dir_name(directory):
+ """directory name must be bad - i.e. taken by other python module
+ on PYTHONPATH
+ """
+ dir_name = os.path.basename(directory)
+ if dir_name == 'askbot':
+ return DIR_NAME_TAKEN_BY_ASKBOT
+ else:
+ return DIR_NAME_TAKEN_BY_PYTHON % {'dir': dir_name}
diff --git a/askbot/deployment/path_utils.py b/askbot/deployment/path_utils.py
new file mode 100644
index 00000000..71e66182
--- /dev/null
+++ b/askbot/deployment/path_utils.py
@@ -0,0 +1,146 @@
+"""utilities in addition to os.path
+that
+* help to test existing paths on usability for the installation
+* create necessary directories
+* install deployment files
+"""
+import os
+import os.path
+import tempfile
+import re
+import glob
+import shutil
+import imp
+
+def split_at_break_point(directory):
+ """splits directory path into two pieces
+ first that exists and secon - that does not
+ by determining a point at which path breaks
+
+ exception will be raised if directory in fact exists
+ """
+ assert(os.path.exists(directory) == False)
+
+ head = directory
+ tail_bits = list()
+ while os.path.exists(head) == False:
+ head, tail = os.path.split(head)
+ tail_bits.insert(0, tail)
+ return head, os.path.join(*tail_bits)
+
+
+def directory_is_writable(directory):
+ """returns True if directory exists
+ and is writable, False otherwise
+ """
+ tempfile.tempdir = directory
+ try:
+ #run writability test
+ temp_path = tempfile.mktemp()
+ assert(os.path.dirname(temp_path) == directory)
+ temp_file = open(temp_path, 'w')
+ temp_file.close()
+ os.unlink(temp_path)
+ return True
+ except IOError:
+ return False
+
+
+def can_create_path(directory):
+ """returns True if user can write file into
+ directory even if it does not exist yet
+ and False otherwise
+ """
+ if os.path.exists(directory):
+ if not os.path.isdir(directory):
+ return False
+ else:
+ directory, junk = split_at_break_point(directory)
+ return directory_is_writable(directory)
+
+
+IMPORT_RE1 = re.compile(r'from django.*import')
+IMPORT_RE2 = re.compile(r'import django')
+def has_existing_django_project(directory):
+ """returns True is any of the .py files
+ in a given directory imports anything from django
+ """
+ file_list = glob.glob(directory + '*.py')
+ for file_name in file_list:
+ py_file = open(file_name)
+ for line in py_file:
+ if IMPORT_RE1.match(line) or IMPORT_RE2.match(line):
+ py_file.close()
+ return True
+ py_file.close()
+ return False
+
+
+def find_parent_dir_with_django(directory):
+ """returns path to Django project anywhere
+ above the directory
+ if nothing is found returns None
+ """
+ parent_dir = os.path.dirname(directory)
+ while parent_dir != directory:
+ if has_existing_django_project(parent_dir):
+ return parent_dir
+ else:
+ directory = parent_dir
+ parent_dir = os.path.dirname(directory)
+ return None
+
+
+def path_is_clean_for_django(directory):
+ """returns False if any of the parent directories
+ contains a Django project, otherwise True
+ does not check the current directory
+ """
+ django_dir = find_parent_dir_with_django(directory)
+ return (django_dir is None)
+
+
+def create_path(directory):
+ if os.path.isdir(directory):
+ return
+ elif os.path.exists(directory):
+ raise ValueError('expect directory or a non-existing path')
+ else:
+ os.makedirs(directory)
+
+SOURCE_DIR = os.path.dirname(os.path.dirname(__file__))
+def deploy_into(directory, new_project = None):
+ """will copy necessary files into the directory
+ """
+ assert(new_project is not None)
+ if new_project:
+ copy_files = ('__init__.py', 'settings.py', 'manage.py', 'urls.py')
+ print 'copying files: ',
+ for file_name in copy_files:
+ src = os.path.join(SOURCE_DIR, 'setup_templates', file_name)
+ print '%s ' % file_name,
+ shutil.copy(src, directory)
+ #copy log directory
+ src = os.path.join(SOURCE_DIR, 'setup_templates', 'log')
+ dst = os.path.join(directory, 'log')
+ shutil.copytree(src, dst)
+
+ print ''
+ app_dir = os.path.join(directory, 'askbot')
+
+ print 'copying directories: ',
+ copy_dirs = ('doc','cron','upfiles')
+ for dir_name in copy_dirs:
+ src = os.path.join(SOURCE_DIR, dir_name)
+ dst = os.path.join(app_dir, dir_name)
+ print dir_name + ' ',
+ shutil.copytree(src, dst)
+ print ''
+
+def dir_name_acceptable(directory):
+ dir_name = os.path.basename(directory)
+ try:
+ imp.find_module(dir_name)
+ return False
+ except ImportError:
+ return True
diff --git a/askbot/deps/README b/askbot/deps/README
new file mode 100644
index 00000000..2dfee4dd
--- /dev/null
+++ b/askbot/deps/README
@@ -0,0 +1,2 @@
+any python modules that are not accessible
+through easy_install, but are necessary for the askbot forum
diff --git a/__init__.py b/askbot/deps/__init__.py
index e69de29b..e69de29b 100644
--- a/__init__.py
+++ b/askbot/deps/__init__.py
diff --git a/askbot/deps/django_authopenid/README b/askbot/deps/django_authopenid/README
new file mode 100644
index 00000000..67c33d60
--- /dev/null
+++ b/askbot/deps/django_authopenid/README
@@ -0,0 +1,5 @@
+this is a forked version of django-authopenid module
+specifically for askbot forum project.
+
+most likely it is not useful for anything else and
+in fact will be phased out in askbot as well
diff --git a/django_authopenid/__init__.py b/askbot/deps/django_authopenid/__init__.py
index ff040ed7..ff040ed7 100644
--- a/django_authopenid/__init__.py
+++ b/askbot/deps/django_authopenid/__init__.py
diff --git a/django_authopenid/admin.py b/askbot/deps/django_authopenid/admin.py
index f64ee579..38bb85c3 100644
--- a/django_authopenid/admin.py
+++ b/askbot/deps/django_authopenid/admin.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
-from django_authopenid.models import UserAssociation
+from askbot.deps.django_authopenid.models import UserAssociation
class UserAssociationAdmin(admin.ModelAdmin):
diff --git a/django_authopenid/forms.py b/askbot/deps/django_authopenid/forms.py
index 2f34986c..2cfa9d31 100644
--- a/django_authopenid/forms.py
+++ b/askbot/deps/django_authopenid/forms.py
@@ -35,11 +35,12 @@ from django.contrib.auth.models import User
from django.contrib.auth import authenticate
from django.utils.translation import ugettext as _
from django.conf import settings
+from askbot.conf import settings as askbot_settings
import types
import re
from django.utils.safestring import mark_safe
-from recaptcha_django import ReCaptchaField
-from forum.utils.forms import NextUrlField, UserNameField, UserEmailField, SetPasswordForm
+from askbot.deps.recaptcha_django import ReCaptchaField
+from askbot.utils.forms import NextUrlField, UserNameField, UserEmailField, SetPasswordForm
EXTERNAL_LOGIN_APP = settings.LOAD_EXTERNAL_LOGIN_APP()
# needed for some linux distributions like debian
@@ -48,8 +49,8 @@ try:
except ImportError:
from yadis import xri
-from forum.utils.forms import clean_next
-from django_authopenid.models import ExternalLoginData
+from askbot.utils.forms import clean_next
+from askbot.deps.django_authopenid.models import ExternalLoginData
__all__ = ['OpenidSigninForm', 'ClassicLoginForm', 'OpenidVerifyForm',
'OpenidRegisterForm', 'ClassicRegisterForm', 'ChangePasswordForm',
@@ -254,7 +255,7 @@ class ChangeEmailForm(forms.Form):
def clean_email(self):
""" check if email don't exist """
if 'email' in self.cleaned_data:
- if settings.EMAIL_UNIQUE == True:
+ if askbot_settings.EMAIL_UNIQUE == True:
try:
user = User.objects.get(email = self.cleaned_data['email'])
if self.user and self.user == user:
diff --git a/django_authopenid/middleware.py b/askbot/deps/django_authopenid/middleware.py
index 2be8da90..2101813c 100644
--- a/django_authopenid/middleware.py
+++ b/askbot/deps/django_authopenid/middleware.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from django_authopenid import mimeparse
+from askbot.deps.django_authopenid import mimeparse
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.conf import settings
diff --git a/django_authopenid/mimeparse.py b/askbot/deps/django_authopenid/mimeparse.py
index ab02eab0..ab02eab0 100644
--- a/django_authopenid/mimeparse.py
+++ b/askbot/deps/django_authopenid/mimeparse.py
diff --git a/django_authopenid/models.py b/askbot/deps/django_authopenid/models.py
index a12c2fec..a12c2fec 100644
--- a/django_authopenid/models.py
+++ b/askbot/deps/django_authopenid/models.py
diff --git a/django_authopenid/urls.py b/askbot/deps/django_authopenid/urls.py
index 65afc45a..b4293031 100755..100644
--- a/django_authopenid/urls.py
+++ b/askbot/deps/django_authopenid/urls.py
@@ -16,7 +16,7 @@ from django.conf import settings
#settings.EXTERNAL_LOGIN_APP.views.signup_view()
#print settings.EXTERNAL_LOGIN_APP.__dict__.keys()
-urlpatterns = patterns('django_authopenid.views',
+urlpatterns = patterns('askbot.deps.django_authopenid.views',
# yadis rdf
url(r'^yadis.xrdf$', 'xrdf', name='yadis_xrdf'),
# manage account registration
@@ -45,11 +45,11 @@ urlpatterns = patterns('django_authopenid.views',
#todo move these out of this file completely
if settings.USE_EXTERNAL_LEGACY_LOGIN:
- from forum.forms import NotARobotForm
+ from askbot.forms import NotARobotForm
EXTERNAL_LOGIN_APP = settings.LOAD_EXTERNAL_LOGIN_APP()
urlpatterns += patterns('',
url('^%s$' % _('external-login/forgot-password/'),\
- 'django_authopenid.views.external_legacy_login_info', \
+ 'askbot.deps.django_authopenid.views.external_legacy_login_info', \
name='user_external_legacy_login_issues'),
url('^%s$' % _('external-login/signup/'), \
EXTERNAL_LOGIN_APP.views.signup,\
diff --git a/django_authopenid/util.py b/askbot/deps/django_authopenid/util.py
index cd2c2e2c..7de38d79 100644
--- a/django_authopenid/util.py
+++ b/askbot/deps/django_authopenid/util.py
@@ -15,7 +15,7 @@ except:
from yadis import xri
import time, base64, hashlib, operator, logging
-from forum.utils.forms import clean_next, get_next_url
+from askbot.utils.forms import clean_next, get_next_url
from models import Association, Nonce
diff --git a/django_authopenid/views.py b/askbot/deps/django_authopenid/views.py
index 4f7d3efa..83b360d9 100755..100644
--- a/django_authopenid/views.py
+++ b/askbot/deps/django_authopenid/views.py
@@ -35,6 +35,7 @@ from django.http import HttpResponseRedirect, get_host, Http404, \
from django.shortcuts import render_to_response
from django.template import RequestContext, loader, Context
from django.conf import settings
+from askbot.conf import settings as askbot_settings
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.contrib.auth import authenticate
@@ -60,21 +61,21 @@ except ImportError:
import re
import urllib
-from forum.forms import SimpleEmailSubscribeForm
-from django_authopenid.util import OpenID, DjangoOpenIDStore, from_openid_response
-from django_authopenid.models import UserAssociation, UserPasswordQueue, ExternalLoginData
-from django_authopenid.forms import OpenidSigninForm, ClassicLoginForm, OpenidRegisterForm, \
+from askbot.forms import SimpleEmailSubscribeForm
+from askbot.deps.django_authopenid.util import OpenID, DjangoOpenIDStore, from_openid_response
+from askbot.deps.django_authopenid.models import UserAssociation, UserPasswordQueue, ExternalLoginData
+from askbot.deps.django_authopenid.forms import OpenidSigninForm, ClassicLoginForm, OpenidRegisterForm, \
OpenidVerifyForm, ClassicRegisterForm, ChangePasswordForm, ChangeEmailForm, \
ChangeopenidForm, DeleteForm, EmailPasswordForm
import logging
-from forum.utils.forms import get_next_url
+from askbot.utils.forms import get_next_url
EXTERNAL_LOGIN_APP = settings.LOAD_EXTERNAL_LOGIN_APP()
-#todo: decouple from forum
+#todo: decouple from askbot
def login(request,user):
from django.contrib.auth import login as _login
- from forum.models import user_logged_in #custom signal
+ from askbot.models import signals
if settings.USE_EXTERNAL_LEGACY_LOGIN == True:
EXTERNAL_LOGIN_APP.api.login(request,user)
@@ -94,9 +95,10 @@ def login(request,user):
request.session['search_state'] = search_state
#5) send signal with old session key as argument
logging.debug('logged in user %s with session key %s' % (user.username, session_key))
- user_logged_in.send(user=user,session_key=session_key,sender=None)
+ #todo: move to auth app
+ signals.user_logged_in.send(user=user,session_key=session_key,sender=None)
-#todo: uncouple this from forum
+#todo: uncouple this from askbot
def logout(request):
from django.contrib.auth import logout as _logout#for login I've added wrapper below - called login
if 'search_state' in request.session:
@@ -153,7 +155,7 @@ def complete(request, on_success=None, on_failure=None, return_to=None):
on_success = on_success or default_on_success
on_failure = on_failure or default_on_failure
- logging.debug('in django_authopenid.complete')
+ logging.debug('in askbot.deps.django_authopenid.complete')
consumer = Consumer(request.session, DjangoOpenIDStore())
# make sure params are encoded in utf8
@@ -341,7 +343,7 @@ def signin(request,newquestion=False,newanswer=False):
logging.debug('request method was GET')
question = None
if newquestion == True:
- from forum.models import AnonymousQuestion as AQ
+ from askbot.models import AnonymousQuestion as AQ
session_key = request.session.session_key
logging.debug('retrieving anonymously posted question associated with session %s' % session_key)
qlist = AQ.objects.filter(session_key=session_key).order_by('-added_at')
@@ -349,7 +351,7 @@ def signin(request,newquestion=False,newanswer=False):
question = qlist[0]
answer = None
if newanswer == True:
- from forum.models import AnonymousAnswer as AA
+ from askbot.models import AnonymousAnswer as AA
session_key = request.session.session_key
logging.debug('retrieving posted answer associated with session %s' % session_key)
alist = AA.objects.filter(session_key=session_key).order_by('-added_at')
@@ -364,7 +366,7 @@ def signin(request,newquestion=False,newanswer=False):
'form2': form_signin,
'msg': request.GET.get('msg',''),
'sendpw_url': reverse('user_sendpw'),
- 'fb_api_key': settings.FB_API_KEY,
+ 'fb_api_key': askbot_settings.FB_API_KEY,
}, context_instance=RequestContext(request))
def complete_signin(request):
@@ -507,7 +509,7 @@ def register(request):
#if user just logged in and did not need to create the new account
if user_ != None:
- if settings.EMAIL_VALIDATION == 'on':
+ if askbot_settings.EMAIL_VALIDATION == True:
logging.debug('sending email validation')
send_new_email_key(user_,nomessage=True)
output = validation_email_sent(request)
@@ -616,7 +618,7 @@ def signup(request):
'authopenid/confirm_email.txt'
)
message_context = Context({
- 'signup_url': settings.APP_URL + reverse('user_signin'),
+ 'signup_url': askbot_settings.APP_URL + reverse('user_signin'),
'username': username,
'password': password,
})
@@ -749,7 +751,7 @@ def set_new_email(user, new_email, nomessage=False):
user.email = new_email
user.email_isvalid = False
user.save()
- if settings.EMAIL_VALIDATION == 'on':
+ if askbot_settings.EMAIL_VALIDATION == True:
send_new_email_key(user,nomessage=nomessage)
def _send_email_key(user):
@@ -760,7 +762,7 @@ def _send_email_key(user):
message_template = loader.get_template('authopenid/email_validation.txt')
import settings
message_context = Context({
- 'validation_link': settings.APP_URL + reverse('user_verifyemail', kwargs={'id':user.id,'key':user.email_key})
+ 'validation_link': askbot_settings.APP_URL + reverse('user_verifyemail', kwargs={'id':user.id,'key':user.email_key})
})
message = message_template.render(message_context)
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email])
@@ -787,7 +789,7 @@ def send_email_key(request):
authopenid/changeemail.html template
"""
- if settings.EMAIL_VALIDATION != 'off':
+ if askbot_settings.EMAIL_VALIDATION == True:
if request.user.email_isvalid:
return render_to_response('authopenid/changeemail.html',
{ 'email': request.user.email,
@@ -817,7 +819,7 @@ def verifyemail(request,id=None,key=None):
url = /email/verify/{{user.id}}/{{user.email_key}}/
"""
logging.debug('')
- if settings.EMAIL_VALIDATION != 'off':
+ if askbot.settings.EMAIL_VALIDATION == True:
user = User.objects.get(id=id)
if user:
if user.email_key == key:
@@ -854,7 +856,7 @@ def changeemail(request, action='change'):
if form.is_valid():
new_email = form.cleaned_data['email']
if new_email != user_.email:
- if settings.EMAIL_VALIDATION == 'on':
+ if askbot_settings.EMAIL_VALIDATION == True:
action = 'validate'
else:
action = 'done_novalidate'
@@ -1118,10 +1120,10 @@ def sendpw(request):
subject = _("Request for new password")
message_template = loader.get_template(
'authopenid/sendpw_email.txt')
- key_link = settings.APP_URL + reverse('user_confirmchangepw') + '?key=' + confirm_key
+ key_link = askbot_settings.APP_URL + reverse('user_confirmchangepw') + '?key=' + confirm_key
logging.debug('emailing new password for %s' % form.user_cache.username)
message_context = Context({
- 'site_url': settings.APP_URL + reverse('index'),
+ 'site_url': askbot_settings.APP_URL + reverse('index'),
'key_link': key_link,
'username': form.user_cache.username,
'password': new_pw,
diff --git a/forum_modules/grapefruit.py b/askbot/deps/grapefruit.py
index ca684745..ca684745 100644
--- a/forum_modules/grapefruit.py
+++ b/askbot/deps/grapefruit.py
diff --git a/askbot/deps/livesettings/README b/askbot/deps/livesettings/README
new file mode 100644
index 00000000..6fe70cc5
--- /dev/null
+++ b/askbot/deps/livesettings/README
@@ -0,0 +1,4 @@
+this is very slightly forked version of django-livesettings
+for use in the askbot forum project
+
+will attempt to re-merge into the original django-livesettings
diff --git a/askbot/deps/livesettings/__init__.py b/askbot/deps/livesettings/__init__.py
new file mode 100644
index 00000000..49aaacc9
--- /dev/null
+++ b/askbot/deps/livesettings/__init__.py
@@ -0,0 +1,16 @@
+"""Database persistent administrative settings with defaults.
+
+This code is a large fork of the excellent "dbsettings" code found at
+http://code.google.com/p/django-values/
+
+The items set here are intended to be changeable during runtime, and do not require a
+programmer to test or install.
+
+Appropriate: Your google code for adwords.
+Inappropriate: The keyedcache timeout for the store.
+
+"""
+
+from functions import *
+from models import *
+from values import * \ No newline at end of file
diff --git a/askbot/deps/livesettings/forms.py b/askbot/deps/livesettings/forms.py
new file mode 100644
index 00000000..ed4a7e5a
--- /dev/null
+++ b/askbot/deps/livesettings/forms.py
@@ -0,0 +1,38 @@
+from django import forms
+from askbot.deps.livesettings import *
+import logging
+
+log = logging.getLogger('configuration')
+
+class SettingsEditor(forms.Form):
+ "Base editor, from which customized forms are created"
+
+ def __init__(self, *args, **kwargs):
+ settings = kwargs.pop('settings')
+ super(SettingsEditor, self).__init__(*args, **kwargs)
+ flattened = []
+ groups = []
+ for setting in settings:
+ if isinstance(setting, ConfigurationGroup):
+ for s in setting:
+ flattened.append(s)
+ else:
+ flattened.append(setting)
+
+ for setting in flattened:
+ # Add the field to the customized field list
+ kw = {
+ 'label': setting.description,
+ 'help_text': setting.help_text,
+ # Provide current setting values for initializing the form
+ 'initial': setting.editor_value
+ }
+ field = setting.make_field(**kw)
+
+ k = '%s__%s' % (setting.group.key, setting.key)
+ self.fields[k] = field
+ if not setting.group in groups:
+ groups.append(setting.group)
+ #log.debug("Added field: %s = %s" % (k, str(field)))
+
+ self.groups = groups \ No newline at end of file
diff --git a/askbot/deps/livesettings/functions.py b/askbot/deps/livesettings/functions.py
new file mode 100644
index 00000000..99e5cc87
--- /dev/null
+++ b/askbot/deps/livesettings/functions.py
@@ -0,0 +1,247 @@
+from django.utils.translation import ugettext
+from askbot.deps.livesettings import values
+from askbot.deps.livesettings.models import SettingNotSet
+from askbot.deps.livesettings.utils import is_string_like
+
+import logging
+
+log = logging.getLogger('configuration')
+
+_NOTSET = object()
+
+class ConfigurationSettings(object):
+ """A singleton manager for ConfigurationSettings"""
+
+ class __impl(object):
+ def __init__(self):
+ self.settings = values.SortedDotDict()
+ self.prereg = {}
+
+ def __getitem__(self, key):
+ """Get an element either by ConfigurationGroup object or by its key"""
+ key = self._resolve_key(key)
+ return self.settings.get(key)
+
+ def __getattr__(self, key):
+ """Get an element either by ConfigurationGroup object or by its key"""
+ try:
+ return self[key]
+ except:
+ raise AttributeError, key
+
+ def __iter__(self):
+ for v in self.groups():
+ yield v
+
+ def __len__(self):
+ return len(self.settings)
+
+ def __contains__(self, key):
+ try:
+ key = self._resolve_key(key)
+ return self.settings.has_key(key)
+ except:
+ return False
+
+ def _resolve_key(self, raw):
+ if is_string_like(raw):
+ key = raw
+
+ elif isinstance(raw, values.ConfigurationGroup):
+ key = raw.key
+
+ else:
+ group = self.groups()[raw]
+ key = group.key
+
+ return key
+
+ def get_config(self, group, key):
+ try:
+ if isinstance(group, values.ConfigurationGroup):
+ group = group.key
+
+ cg = self.settings.get(group, None)
+ if not cg:
+ raise SettingNotSet('%s config group does not exist' % group)
+
+ else:
+ return cg[key]
+ except KeyError:
+ raise SettingNotSet('%s.%s' % (group, key))
+
+ def groups(self):
+ """Return ordered list"""
+ return self.settings.values()
+
+ def has_config(self, group, key):
+ if isinstance(group, values.ConfigurationGroup):
+ group = group.key
+
+ cfg = self.settings.get(group, None)
+ if cfg and key in cfg:
+ return True
+ else:
+ return False
+
+ def preregister_choice(self, group, key, choice):
+ """Setup a choice for a group/key which hasn't been instantiated yet."""
+ k = (group, key)
+ if self.prereg.has_key(k):
+ self.prereg[k].append(choice)
+ else:
+ self.prereg[k] = [choice]
+
+ def register(self, value):
+ g = value.group
+ if not isinstance(g, values.ConfigurationGroup):
+ raise ValueError('value.group should be an instance of ConfigurationGroup')
+
+ groupkey = g.key
+ valuekey = value.key
+
+ k = (groupkey, valuekey)
+ if self.prereg.has_key(k):
+ for choice in self.prereg[k]:
+ value.add_choice(choice)
+
+ if not groupkey in self.settings:
+ self.settings[groupkey] = g
+
+ self.settings[groupkey][valuekey] = value
+
+ return value
+
+ __instance = None
+
+ def __init__(self):
+ if ConfigurationSettings.__instance is None:
+ ConfigurationSettings.__instance = ConfigurationSettings.__impl()
+ #ConfigurationSettings.__instance.load_app_configurations()
+
+ self.__dict__['_ConfigurationSettings__instance'] = ConfigurationSettings.__instance
+
+ def __getattr__(self, attr):
+ """ Delegate access to implementation """
+ return getattr(self.__instance, attr)
+
+ def __getitem__(self, key):
+ return self.__instance[key]
+
+ def __len__(self):
+ return len(self.__instance)
+
+ def __setattr__(self, attr, value):
+ """ Delegate access to implementation """
+ return setattr(self.__instance, attr, value)
+
+ def __unicode__(self):
+ return u"ConfigurationSettings: " + unicode(self.groups())
+
+def config_exists(group, key):
+ """Test to see if a setting has been registered"""
+
+ return ConfigurationSettings().has_config(group, key)
+
+def config_get(group, key):
+ """Get a configuration setting"""
+ try:
+ return ConfigurationSettings().get_config(group, key)
+ except SettingNotSet:
+ log.debug('SettingNotSet: %s.%s', group, key)
+ raise
+
+def config_get_group(group):
+ return ConfigurationSettings()[group]
+
+def config_collect_values(group, groupkey, key, unique=True, skip_missing=True):
+ """Look up (group, groupkey) from config, then take the values returned and
+ use them as groups for a second-stage lookup.
+
+ For example:
+
+ config_collect_values(PAYMENT, MODULES, CREDITCHOICES)
+
+ Stage 1: ['PAYMENT_GOOGLE', 'PAYMENT_AUTHORIZENET']
+ Stage 2: config_value('PAYMENT_GOOGLE', 'CREDITCHOICES')
+ + config_value('PAYMENT_AUTHORIZENET', 'CREDITCHOICES')
+ Stage 3: (if unique is true) remove dupes
+ """
+ groups = config_value(group, groupkey)
+
+ ret = []
+ for g in groups:
+ try:
+ ret.append(config_value(g, key))
+ except KeyError, ke:
+ if not skip_missing:
+ raise SettingNotSet('No config %s.%s' % (g, key))
+
+ if unique:
+ out = []
+ for x in ret:
+ if not x in out:
+ out.append(x)
+ ret = out
+
+ return ret
+
+def config_register(value):
+ """Register a value or values.
+
+ Parameters:
+ -A Value
+ """
+ return ConfigurationSettings().register(value)
+
+def config_register_list(*args):
+ for value in args:
+ config_register(value)
+
+def config_value(group, key, default=_NOTSET):
+ """Get a value from the configuration system"""
+ try:
+ return config_get(group, key).value
+ except SettingNotSet:
+ if default != _NOTSET:
+ return default
+ raise
+
+def config_value_safe(group, key, default_value):
+ """Get a config value with a default fallback, safe for use during SyncDB."""
+ raw = default_value
+
+ try:
+ raw = config_value(group, key)
+ except SettingNotSet:
+ pass
+ except ImportError, e:
+ log.warn("Error getting %s.%s, OK if you are in SyncDB.", group, key)
+
+ return raw
+
+
+def config_choice_values(group, key, skip_missing=True, translate=False):
+ """Get pairs of key, label from the setting."""
+ try:
+ cfg = config_get(group, key)
+ choices = cfg.choice_values
+
+ except SettingNotSet:
+ if skip_missing:
+ return []
+ else:
+ raise SettingNotSet('%s.%s' % (group, key))
+
+ if translate:
+ choices = [(k, ugettext(v)) for k, v in choices]
+
+ return choices
+
+def config_add_choice(group, key, choice):
+ """Add a choice to a value"""
+ if config_exists(group, key):
+ cfg = config_get(group, key)
+ cfg.add_choice(choice)
+ else:
+ ConfigurationSettings().preregister_choice(group, key, choice)
diff --git a/askbot/deps/livesettings/locale/de/LC_MESSAGES/django.mo b/askbot/deps/livesettings/locale/de/LC_MESSAGES/django.mo
new file mode 100644
index 00000000..e176bc53
--- /dev/null
+++ b/askbot/deps/livesettings/locale/de/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/deps/livesettings/locale/de/LC_MESSAGES/django.po b/askbot/deps/livesettings/locale/de/LC_MESSAGES/django.po
new file mode 100644
index 00000000..1cef701b
--- /dev/null
+++ b/askbot/deps/livesettings/locale/de/LC_MESSAGES/django.po
@@ -0,0 +1,101 @@
+# Satchmo Translation Package
+# Copyright (C) 2008 Satchmo Project
+# This file is distributed under the same license as the Satchmo package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-03-22 15:10+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: values.py:88
+msgid "Base Settings"
+msgstr "Basiseinstellungen"
+
+#: values.py:194
+msgid "Default value: \"\""
+msgstr "Standardwert: \"\""
+
+#: values.py:201
+msgid "Default value: "
+msgstr "Standardwert: "
+
+#: values.py:204
+#, python-format
+msgid "Default value: %s"
+msgstr "Standardwert: %s"
+
+#: templates/livesettings/group_settings.html:10
+#: templates/livesettings/site_settings.html:10
+msgid "Home"
+msgstr "Start"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:7
+msgid "Log out"
+msgstr "Abmelden"
+
+#: templates/livesettings/group_settings.html:18
+#: templates/livesettings/site_settings.html:18
+#, fuzzy
+msgid "Please correct the error below."
+msgid_plural "Please correct the errors below."
+msgstr[0] ""
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+msgstr[1] ""
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:7
+#, fuzzy
+msgid "Documentation"
+msgstr ""
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:7
+msgid "Change password"
+msgstr "Passwort ändern"
+
+#: templates/livesettings/site_settings.html:11
+msgid "Edit Site Settings"
+msgstr ""
+
+#: templates/livesettings/group_settings.html:11
+msgid "Edit Group Settings"
+msgstr ""
+
+#: templates/livesettings/group_settings.html:24
+#, python-format
+msgid "Settings included in %(name)s."
+msgstr ""
+
+#: templates/livesettings/group_settings.html:49
+#: templates/livesettings/site_settings.html:61
+msgid "You don't have permission to edit values."
+msgstr ""
+
+#: templates/livesettings/site_settings.html:34
+#, python-format
+msgid "Group settings: %(name)s"
+msgstr ""
+
diff --git a/askbot/deps/livesettings/locale/en/LC_MESSAGES/django.mo b/askbot/deps/livesettings/locale/en/LC_MESSAGES/django.mo
new file mode 100644
index 00000000..c2bc0b94
--- /dev/null
+++ b/askbot/deps/livesettings/locale/en/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/deps/livesettings/locale/en/LC_MESSAGES/django.po b/askbot/deps/livesettings/locale/en/LC_MESSAGES/django.po
new file mode 100644
index 00000000..45eb23a5
--- /dev/null
+++ b/askbot/deps/livesettings/locale/en/LC_MESSAGES/django.po
@@ -0,0 +1,100 @@
+# Satchmo Translation Package
+# Copyright (C) 2008 Satchmo Project
+# This file is distributed under the same license as the Satchmo package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-12-31 00:49-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: values.py:88
+msgid "Base Settings"
+msgstr ""
+
+#: values.py:194
+msgid "Default value: \"\""
+msgstr ""
+
+#: values.py:201
+msgid "Default value: "
+msgstr ""
+
+#: values.py:204
+#, python-format
+msgid "Default value: %s"
+msgstr ""
+
+#: templates/livesettings/group_settings.html:10
+#: templates/livesettings/site_settings.html:10
+msgid "Home"
+msgstr ""
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:7
+msgid "Log out"
+msgstr ""
+
+#: templates/livesettings/group_settings.html:18
+#: templates/livesettings/site_settings.html:18
+#, fuzzy
+msgid "Please correct the error below."
+msgid_plural "Please correct the errors below."
+msgstr[0] ""
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+msgstr[1] ""
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:7
+msgid "Documentation"
+msgstr ""
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:7
+msgid "Change password"
+msgstr ""
+
+#: templates/livesettings/group_settings.html:11
+msgid "Edit Group Settings"
+msgstr ""
+
+#: templates/livesettings/group_settings.html:24
+#, python-format
+msgid "Settings included in %(name)s."
+msgstr ""
+
+#: templates/livesettings/group_settings.html:49
+#: templates/livesettings/site_settings.html:61
+msgid "You don't have permission to edit values."
+msgstr ""
+
+#: templates/livesettings/site_settings.html:11
+msgid "Edit Site Settings"
+msgstr ""
+
+#: templates/livesettings/site_settings.html:34
+#, python-format
+msgid "Group settings: %(name)s"
+msgstr ""
+
diff --git a/fbconnect/__init__.py b/askbot/deps/livesettings/locale/es/LC_MESSAGES/django.po
index e69de29b..e69de29b 100755..100644
--- a/fbconnect/__init__.py
+++ b/askbot/deps/livesettings/locale/es/LC_MESSAGES/django.po
diff --git a/askbot/deps/livesettings/locale/fr/LC_MESSAGES/django.mo b/askbot/deps/livesettings/locale/fr/LC_MESSAGES/django.mo
new file mode 100644
index 00000000..dd872edd
--- /dev/null
+++ b/askbot/deps/livesettings/locale/fr/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/deps/livesettings/locale/fr/LC_MESSAGES/django.po b/askbot/deps/livesettings/locale/fr/LC_MESSAGES/django.po
new file mode 100644
index 00000000..90475585
--- /dev/null
+++ b/askbot/deps/livesettings/locale/fr/LC_MESSAGES/django.po
@@ -0,0 +1,113 @@
+# Satchmo Translation Package
+# Copyright (C) 2008 Satchmo Project
+# Jacques Moulin <jacques@tpi.be>, 2008.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-11-02 16:11+0100\n"
+"PO-Revision-Date: 2008-11-02 17:51+0100\n"
+"Last-Translator: Jacques Moulin <jacques@tpi.be>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: French\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#: templates/livesettings/group_settings.html.py:10
+#: templates/livesettings/site_settings.html.py:25
+#: templates/livesettings/group_settings.html.py:10
+#: templates/livesettings/site_settings.html.py:25
+msgid "Home"
+msgstr "Accueil"
+
+#: models.py:76
+#: models.py:115
+msgid "Site"
+msgstr "Site"
+
+#: values.py:94
+msgid "Base Settings"
+msgstr "Configuration de base"
+
+#: values.py:200
+msgid "Default value: \"\""
+msgstr "Valeur par défaut: \"\""
+
+#: values.py:207
+msgid "Default value: "
+msgstr "Valeur par défaut:"
+
+#: values.py:210
+#, python-format
+msgid "Default value: %s"
+msgstr "Valeur par défaut: %s"
+
+#: templates/livesettings/group_settings.html.py:7
+#: templates/livesettings/site_settings.html.py:22
+#: templates/livesettings/group_settings.html.py:7
+#: templates/livesettings/site_settings.html.py:22
+msgid "Documentation"
+msgstr "Documentation"
+
+#: templates/livesettings/group_settings.html.py:7
+#: templates/livesettings/site_settings.html.py:22
+#: templates/livesettings/group_settings.html.py:7
+#: templates/livesettings/site_settings.html.py:22
+msgid "Change password"
+msgstr "Modifier le mot de passe"
+
+#: templates/livesettings/group_settings.html.py:7
+#: templates/livesettings/site_settings.html.py:22
+#: templates/livesettings/group_settings.html.py:7
+#: templates/livesettings/site_settings.html.py:22
+msgid "Log out"
+msgstr "Se déconnecter"
+
+#: templates/livesettings/group_settings.html.py:11
+#: templates/livesettings/group_settings.html.py:11
+msgid "Edit Group Settings"
+msgstr "Editer les paramètres de groupe"
+
+#: templates/livesettings/group_settings.html.py:18
+#: templates/livesettings/site_settings.html.py:43
+#: templates/livesettings/group_settings.html.py:18
+#: templates/livesettings/site_settings.html.py:41
+msgid "Please correct the error below."
+msgid_plural "Please correct the errors below."
+msgstr[0] "Veuillez corriger l'erreur ci-dessous:"
+msgstr[1] "Veuillez corriger les erreurs ci-dessous:"
+
+#: templates/livesettings/group_settings.html.py:24
+#: templates/livesettings/group_settings.html.py:24
+msgid "Settings included in %(name)s."
+msgstr "Paramètres inclus dans %(name)s."
+
+#: templates/livesettings/group_settings.html.py:49
+#: templates/livesettings/site_settings.html.py:89
+#: templates/livesettings/group_settings.html.py:49
+#: templates/livesettings/site_settings.html.py:87
+msgid "You don't have permission to edit values."
+msgstr "Vous n'avez pas le droit d'éditer les valeurs."
+
+#: templates/livesettings/site_settings.html.py:26
+#: templates/livesettings/site_settings.html.py:26
+msgid "Edit Site Settings"
+msgstr "Editer les paramètres du site"
+
+#: templates/livesettings/site_settings.html.py:59
+#: templates/livesettings/site_settings.html.py:58
+msgid "Group settings: %(name)s"
+msgstr "Paramètres du groupe: %(name)s"
+
+#: templates/livesettings/site_settings.html.py:86
+#: templates/livesettings/site_settings.html.py:84
+msgid "Uncollapse all"
+msgstr "Déployer tout"
+
+#: templates/livesettings/_admin_site_views.html.py:5
+msgid "Sites"
+msgstr "Sites"
+
diff --git a/askbot/deps/livesettings/locale/he/LC_MESSAGES/django.mo b/askbot/deps/livesettings/locale/he/LC_MESSAGES/django.mo
new file mode 100644
index 00000000..04270a04
--- /dev/null
+++ b/askbot/deps/livesettings/locale/he/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/deps/livesettings/locale/he/LC_MESSAGES/django.po b/askbot/deps/livesettings/locale/he/LC_MESSAGES/django.po
new file mode 100644
index 00000000..362f5612
--- /dev/null
+++ b/askbot/deps/livesettings/locale/he/LC_MESSAGES/django.po
@@ -0,0 +1,98 @@
+# translation of Satchmo
+# Copyright (C) 2008 The Satchmo Project
+# This file is distributed under the same license as the Satchmo package.
+#
+# Aviv Greenberg <avivgr@gmail.com>, 2008.
+msgid ""
+msgstr ""
+"Project-Id-Version: django\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-03-13 23:02+0200\n"
+"PO-Revision-Date: 2009-03-22 07:45\n"
+"Last-Translator: Aviv Greenberg <avivgr@gmail.com>\n"
+"Language-Team: <en@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: KBabel 1.11.4\n"
+"X-Translated-Using: django-rosetta 0.4.0\n"
+
+#: models.py:75 models.py:114
+msgid "Site"
+msgstr "×תר"
+
+#: values.py:96
+msgid "Base Settings"
+msgstr "תצורה בסיסית"
+
+#: values.py:202
+msgid "Default value: \"\""
+msgstr "ברירת מחדל:\"\""
+
+#: values.py:209
+msgid "Default value: "
+msgstr "ברירת מחדל:"
+
+#: values.py:212
+#, python-format
+msgid "Default value: %s"
+msgstr "ברירת מחדל:%s"
+
+#: templates/livesettings/_admin_site_views.html:4
+msgid "Sites"
+msgstr "×תרי×"
+
+#: templates/livesettings/group_settings.html:11
+#: templates/livesettings/site_settings.html:23
+msgid "Documentation"
+msgstr "תיעוד"
+
+#: templates/livesettings/group_settings.html:11
+#: templates/livesettings/site_settings.html:23
+msgid "Change password"
+msgstr "שינוי סיסמה"
+
+#: templates/livesettings/group_settings.html:11
+#: templates/livesettings/site_settings.html:23
+msgid "Log out"
+msgstr "יצי××”"
+
+#: templates/livesettings/group_settings.html:14
+#: templates/livesettings/site_settings.html:26
+msgid "Home"
+msgstr "דף הבית"
+
+#: templates/livesettings/group_settings.html:15
+msgid "Edit Group Settings"
+msgstr "ערוך הגדרות קבוצה"
+
+#: templates/livesettings/group_settings.html:22
+#: templates/livesettings/site_settings.html:44
+msgid "Please correct the error below."
+msgid_plural "Please correct the errors below."
+msgstr[0] "× × ×œ×ª×§×Ÿ ×ת השגי××” המופיעה מתחת."
+msgstr[1] "× × ×œ×ª×§×Ÿ ×ת השגי×ות המופיעות מתחת."
+
+#: templates/livesettings/group_settings.html:28
+#, python-format
+msgid "Settings included in %(name)s."
+msgstr "הגדרות כלולות %(name)s"
+
+#: templates/livesettings/group_settings.html:53
+#: templates/livesettings/site_settings.html:90
+msgid "You don't have permission to edit values."
+msgstr "×ינך מורשה לערוך ערכי×."
+
+#: templates/livesettings/site_settings.html:27
+msgid "Edit Site Settings"
+msgstr "ערוך הגדרות ×תר"
+
+#: templates/livesettings/site_settings.html:60
+#, python-format
+msgid "Group settings: %(name)s"
+msgstr "הגדרות קבוצה: %(name)s"
+
+#: templates/livesettings/site_settings.html:87
+msgid "Uncollapse all"
+msgstr "הסתר פרטי×"
diff --git a/askbot/deps/livesettings/locale/it/LC_MESSAGES/django.mo b/askbot/deps/livesettings/locale/it/LC_MESSAGES/django.mo
new file mode 100644
index 00000000..05c50952
--- /dev/null
+++ b/askbot/deps/livesettings/locale/it/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/deps/livesettings/locale/it/LC_MESSAGES/django.po b/askbot/deps/livesettings/locale/it/LC_MESSAGES/django.po
new file mode 100644
index 00000000..66401866
--- /dev/null
+++ b/askbot/deps/livesettings/locale/it/LC_MESSAGES/django.po
@@ -0,0 +1,106 @@
+# translation of django.po to Italiano
+# Copyright (C) 2008 Satchmo Project
+# This file is distributed under the same license as the PACKAGE package.
+#
+# costantino giuliodori <costantino.giuliodori@gmail.com>, 2007.
+# Alessandro Ronchi <alessandro.ronchi@soasi.com>, 2008.
+msgid ""
+msgstr ""
+"Project-Id-Version: django\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-27 09:16-0700\n"
+"PO-Revision-Date: 2008-09-30 13:13+0200\n"
+"Last-Translator: Alessandro Ronchi <alessandro.ronchi@soasi.com>\n"
+"Language-Team: Italiano <it@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+"Plural-Forms: nplurals=2; plural=n > 1\n"
+
+#: templates/livesettings/group_settings.html:10
+#: templates/livesettings/site_settings.html:25
+msgid "Home"
+msgstr "Pagina iniziale"
+
+#: models.py:76
+#: models.py:115
+msgid "Site"
+msgstr "Sito"
+
+#: values.py:94
+msgid "Base Settings"
+msgstr "Impostazioni base"
+
+#: values.py:200
+msgid "Default value: \"\""
+msgstr "Valore di default: \"\""
+
+#: values.py:207
+msgid "Default value: "
+msgstr "Valore di default: "
+
+#: values.py:210
+#, python-format
+msgid "Default value: %s"
+msgstr "Valore di default:%s"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:22
+# translated = "Extra di spedizione"
+msgid "Documentation"
+msgstr "Documentazione"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:22
+msgid "Change password"
+msgstr "Cambia Password"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:22
+msgid "Log out"
+msgstr "Esci"
+
+#: templates/livesettings/group_settings.html:11
+msgid "Edit Group Settings"
+msgstr "Modifica le impostazioni del Gruppo"
+
+#: templates/livesettings/group_settings.html:18
+#: templates/livesettings/site_settings.html:43
+# translated = ""
+msgid "Please correct the error below."
+msgid_plural "Please correct the errors below."
+msgstr[0] "Correggi l'errore indicato di seguito."
+msgstr[1] "Correggi gli errori indicati di seguito."
+
+#: templates/livesettings/group_settings.html:24
+# translated = "Modificare le impostazioni di gruppo"
+#, python-format
+msgid "Settings included in %(name)s."
+msgstr "Impostazioni incluse in %(name)s."
+
+#: templates/livesettings/group_settings.html:49
+#: templates/livesettings/site_settings.html:89
+# translated = "Impostazioni incluse in% (nome) s."
+msgid "You don't have permission to edit values."
+msgstr "Non hai il permesso di modificare questi valori."
+
+#: templates/livesettings/site_settings.html:26
+# translated = "Non avete il permesso di modificare i valori."
+msgid "Edit Site Settings"
+msgstr "Modifica le impostazioni del sito"
+
+#: templates/livesettings/site_settings.html:59
+# translated = "Modifica impostazioni sito"
+#, python-format
+msgid "Group settings: %(name)s"
+msgstr "Impostazioni di gruppo: %(name)s"
+
+#: templates/livesettings/site_settings.html:86
+msgid "Uncollapse all"
+msgstr "Espandi tutti"
+
+#: templates/livesettings/_admin_site_views.html:5
+msgid "Sites"
+msgstr "Siti"
+
diff --git a/askbot/deps/livesettings/locale/ko/LC_MESSAGES/django.mo b/askbot/deps/livesettings/locale/ko/LC_MESSAGES/django.mo
new file mode 100644
index 00000000..e0738605
--- /dev/null
+++ b/askbot/deps/livesettings/locale/ko/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/deps/livesettings/locale/ko/LC_MESSAGES/django.po b/askbot/deps/livesettings/locale/ko/LC_MESSAGES/django.po
new file mode 100644
index 00000000..0dbd2d4d
--- /dev/null
+++ b/askbot/deps/livesettings/locale/ko/LC_MESSAGES/django.po
@@ -0,0 +1,100 @@
+# Satchmo Translation Package
+# Copyright (C) 2008 Satchmo Project
+# This file is distributed under the same license as the Satchmo package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-12-31 00:49-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: values.py:88
+msgid "Base Settings"
+msgstr "기본 세팅"
+
+#: values.py:194
+msgid "Default value: \"\""
+msgstr "기본 값: \"\""
+
+#: values.py:201
+msgid "Default value: "
+msgstr "기본 값: "
+
+#: values.py:204
+#, python-format
+msgid "Default value: %s"
+msgstr "기본 값:%s"
+
+#: templates/livesettings/group_settings.html:10
+#: templates/livesettings/site_settings.html:10
+msgid "Home"
+msgstr "홈"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:7
+msgid "Log out"
+msgstr "로그 아웃"
+
+#: templates/livesettings/group_settings.html:18
+#: templates/livesettings/site_settings.html:18
+#, fuzzy
+msgid "Please correct the error below."
+msgid_plural "Please correct the errors below."
+msgstr[0] ""
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+msgstr[1] ""
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:7
+msgid "Documentation"
+msgstr "문서"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:7
+msgid "Change password"
+msgstr "패스워드 변경"
+
+#: templates/livesettings/group_settings.html:11
+msgid "Edit Group Settings"
+msgstr "그룹설정 수정"
+
+#: templates/livesettings/group_settings.html:24
+#, python-format
+msgid "Settings included in %(name)s."
+msgstr "%(name)sì„ í¬í•¨í•œ 설정"
+
+#: templates/livesettings/group_settings.html:49
+#: templates/livesettings/site_settings.html:61
+msgid "You don't have permission to edit values."
+msgstr "ì´ ê°’ì„ ìˆ˜ì •í•  ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤."
+
+#: templates/livesettings/site_settings.html:11
+msgid "Edit Site Settings"
+msgstr "사ì´íŠ¸ 설정 수정"
+
+#: templates/livesettings/site_settings.html:34
+#, python-format
+msgid "Group settings: %(name)s"
+msgstr "그룹 설정: %(name)s"
+
diff --git a/askbot/deps/livesettings/locale/pl/LC_MESSAGES/django.mo b/askbot/deps/livesettings/locale/pl/LC_MESSAGES/django.mo
new file mode 100644
index 00000000..f45e49ed
--- /dev/null
+++ b/askbot/deps/livesettings/locale/pl/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/deps/livesettings/locale/pl/LC_MESSAGES/django.po b/askbot/deps/livesettings/locale/pl/LC_MESSAGES/django.po
new file mode 100644
index 00000000..1e7b4199
--- /dev/null
+++ b/askbot/deps/livesettings/locale/pl/LC_MESSAGES/django.po
@@ -0,0 +1,97 @@
+# Satchmo Translation Package
+# Copyright (C) 2008 Satchmo Project
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-03 18:10+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: <jerzyk@jerzyk.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: templates/livesettings/group_settings.html:10
+#: templates/livesettings/site_settings.html:25
+msgid "Home"
+msgstr "Strona startowa"
+
+#: models.py:76
+#: models.py:115
+msgid "Site"
+msgstr "Strona"
+
+#: values.py:93
+msgid "Base Settings"
+msgstr "Ustawienia podstawowe"
+
+#: values.py:199
+msgid "Default value: \"\""
+msgstr "Domyślna wartość: \"\""
+
+#: values.py:206
+msgid "Default value: "
+msgstr "Domyślna wartość: "
+
+#: values.py:209
+#, python-format
+msgid "Default value: %s"
+msgstr "Domyślna wartość: %s"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:22
+msgid "Documentation"
+msgstr "Dokumentacja"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:22
+msgid "Change password"
+msgstr "Zmiana hasła"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:22
+msgid "Log out"
+msgstr "Wyloguj"
+
+#: templates/livesettings/group_settings.html:11
+msgid "Edit Group Settings"
+msgstr "Edycja Ustawień dla Grupy"
+
+#: templates/livesettings/group_settings.html:18
+#: templates/livesettings/site_settings.html:43
+msgid "Please correct the error below."
+msgid_plural "Please correct the errors below."
+msgstr[0] "Proszę poprawić poniższy błąd."
+msgstr[1] "Proszę poprawić poniższe błędy."
+
+#: templates/livesettings/group_settings.html:24
+#, python-format
+msgid "Settings included in %(name)s."
+msgstr "Ustawienia w %(name)s."
+
+#: templates/livesettings/group_settings.html:49
+#: templates/livesettings/site_settings.html:89
+msgid "You don't have permission to edit values."
+msgstr "Nie masz uprawnień do zmiany tych wartości."
+
+#: templates/livesettings/site_settings.html:26
+msgid "Edit Site Settings"
+msgstr "Edytuj ustawienia serwisu"
+
+#: templates/livesettings/site_settings.html:59
+#, python-format
+msgid "Group settings: %(name)s"
+msgstr "Ustawienia grupy: %(name)s"
+
+#: templates/livesettings/site_settings.html:86
+msgid "Uncollapse all"
+msgstr "Rozwiń wszystko"
+
+#: templates/livesettings/_admin_site_views.html:5
+msgid "Sites"
+msgstr "Strony"
+
diff --git a/askbot/deps/livesettings/locale/pt_BR/LC_MESSAGES/django.mo b/askbot/deps/livesettings/locale/pt_BR/LC_MESSAGES/django.mo
new file mode 100644
index 00000000..a8bfb8b2
--- /dev/null
+++ b/askbot/deps/livesettings/locale/pt_BR/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/deps/livesettings/locale/pt_BR/LC_MESSAGES/django.po b/askbot/deps/livesettings/locale/pt_BR/LC_MESSAGES/django.po
new file mode 100644
index 00000000..72d49df7
--- /dev/null
+++ b/askbot/deps/livesettings/locale/pt_BR/LC_MESSAGES/django.po
@@ -0,0 +1,100 @@
+# Satchmo Translation Package
+# Copyright (C) 2008 Satchmo Project
+# This file is distributed under the same license as the PACKAGE package.
+# Terry Laundos Aguiar <terry@s1solucoes.com.br>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-05 23:50-0300\n"
+"PO-Revision-Date: 2008-09-05 23:51-0300\n"
+"Last-Translator: Terry Laundos Aguiar <terry@s1solucoes.com.br>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: templates/livesettings/group_settings.html:10
+#: templates/livesettings/site_settings.html:25
+msgid "Home"
+msgstr "Inicial"
+
+#: models.py:76
+#: models.py:115
+#, fuzzy
+msgid "Site"
+msgstr "Estado"
+
+#: values.py:93
+msgid "Base Settings"
+msgstr "Configurações Iniciais"
+
+#: values.py:199
+msgid "Default value: \"\""
+msgstr "Valor padrão: \"\""
+
+#: values.py:206
+msgid "Default value: "
+msgstr "Valor padrão: "
+
+#: values.py:209
+#, python-format
+msgid "Default value: %s"
+msgstr "Valor padrão: %s"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:22
+msgid "Documentation"
+msgstr "Documentação"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:22
+msgid "Change password"
+msgstr "Mudar senha"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:22
+msgid "Log out"
+msgstr "Deslogar"
+
+#: templates/livesettings/group_settings.html:11
+msgid "Edit Group Settings"
+msgstr "Editar preferências de grupo"
+
+#: templates/livesettings/group_settings.html:18
+#: templates/livesettings/site_settings.html:43
+msgid "Please correct the error below."
+msgid_plural "Please correct the errors below."
+msgstr[0] ""
+msgstr[1] ""
+
+#: templates/livesettings/group_settings.html:24
+#, python-format
+msgid "Settings included in %(name)s."
+msgstr "Configurações inclusas no %(name)s."
+
+#: templates/livesettings/group_settings.html:49
+#: templates/livesettings/site_settings.html:89
+msgid "You don't have permission to edit values."
+msgstr "Você não tem permissão para editar valores."
+
+#: templates/livesettings/site_settings.html:26
+msgid "Edit Site Settings"
+msgstr "Editar configurações do site"
+
+#: templates/livesettings/site_settings.html:59
+#, python-format
+msgid "Group settings: %(name)s"
+msgstr "Configurações de grupo: %(name)s"
+
+#: templates/livesettings/site_settings.html:86
+#, fuzzy
+msgid "Uncollapse all"
+msgstr "Desmarcar todos"
+
+#: templates/livesettings/_admin_site_views.html:5
+#, fuzzy
+msgid "Sites"
+msgstr "Notas"
+
diff --git a/askbot/deps/livesettings/locale/ru/LC_MESSAGES/django.mo b/askbot/deps/livesettings/locale/ru/LC_MESSAGES/django.mo
new file mode 100644
index 00000000..42e6074a
--- /dev/null
+++ b/askbot/deps/livesettings/locale/ru/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/deps/livesettings/locale/ru/LC_MESSAGES/django.po b/askbot/deps/livesettings/locale/ru/LC_MESSAGES/django.po
new file mode 100644
index 00000000..a0db054b
--- /dev/null
+++ b/askbot/deps/livesettings/locale/ru/LC_MESSAGES/django.po
@@ -0,0 +1,85 @@
+# Satchmo Translation Package
+# Copyright (C) 2008 Satchmo Project
+# This file is distributed under the same license as the Satchmo package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Satchmo\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-12-31 00:49-0600\n"
+"PO-Revision-Date: 2009-03-02 21:52+0300\n"
+"Last-Translator: Данил Семеленов <danil.mail@gmail.com>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language-Team: \n"
+
+#: values.py:88
+msgid "Base Settings"
+msgstr "ОÑновные наÑтройки"
+
+#: values.py:194
+msgid "Default value: \"\""
+msgstr "Значение по умолчанию: \"\""
+
+#: values.py:201
+msgid "Default value: "
+msgstr "Значение по умолчанию: "
+
+#: values.py:204
+#, python-format
+msgid "Default value: %s"
+msgstr "Значение по умолчанию: %s"
+
+#: templates/livesettings/group_settings.html:10
+#: templates/livesettings/site_settings.html:10
+msgid "Home"
+msgstr ""
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:7
+msgid "Log out"
+msgstr ""
+
+#: templates/livesettings/group_settings.html:18
+#: templates/livesettings/site_settings.html:18
+#, fuzzy
+msgid "Please correct the error below."
+msgid_plural "Please correct the errors below."
+msgstr[0] ""
+msgstr[1] ""
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:7
+msgid "Documentation"
+msgstr ""
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:7
+msgid "Change password"
+msgstr ""
+
+#: templates/livesettings/group_settings.html:11
+msgid "Edit Group Settings"
+msgstr "Изменить группу наÑтроек"
+
+#: templates/livesettings/group_settings.html:24
+#, python-format
+msgid "Settings included in %(name)s."
+msgstr "ÐаÑтройки включены в %(name)s."
+
+#: templates/livesettings/group_settings.html:49
+#: templates/livesettings/site_settings.html:61
+msgid "You don't have permission to edit values."
+msgstr "У Ð²Ð°Ñ Ð½ÐµÑ‚ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÑÑ‚ÑŒ значение."
+
+#: templates/livesettings/site_settings.html:11
+msgid "Edit Site Settings"
+msgstr "Изменить наÑтройки Ñайта"
+
+#: templates/livesettings/site_settings.html:34
+#, python-format
+msgid "Group settings: %(name)s"
+msgstr "Группа наÑтроек: %(name)s"
+
diff --git a/askbot/deps/livesettings/locale/sv/LC_MESSAGES/django.mo b/askbot/deps/livesettings/locale/sv/LC_MESSAGES/django.mo
new file mode 100644
index 00000000..caed0ab9
--- /dev/null
+++ b/askbot/deps/livesettings/locale/sv/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/deps/livesettings/locale/sv/LC_MESSAGES/django.po b/askbot/deps/livesettings/locale/sv/LC_MESSAGES/django.po
new file mode 100644
index 00000000..6b096f6b
--- /dev/null
+++ b/askbot/deps/livesettings/locale/sv/LC_MESSAGES/django.po
@@ -0,0 +1,92 @@
+# Satchmo Translation Package
+# Copyright (C) 2008 Satchmo Project
+# This file is distributed under the same license as the PACKAGE package.
+# N.L. <kotorinl@yahoo.co.uk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Satchmo svn\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-04-30 23:40+0200\n"
+"PO-Revision-Date: 2008-04-30 23:35+0100\n"
+"Last-Translator: N.L. <kotorinl@yahoo.co.uk>\n"
+"Language-Team: Group\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-Language: Swedish\n"
+"X-Poedit-Basepath: ../../../\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Country: SWEDEN\n"
+
+#: values.py:89
+msgid "Base Settings"
+msgstr "Grundinställningar"
+
+#: values.py:195
+msgid "Default value: \"\""
+msgstr "Förvalt värde: \"\""
+
+#: values.py:202
+msgid "Default value: "
+msgstr "Förvalt värde:"
+
+#: values.py:205
+#, python-format
+msgid "Default value: %s"
+msgstr "Förvalt värde: %s"
+
+#: templates/livesettings/group_settings.html:10
+#: templates/livesettings/site_settings.html:25
+msgid "Home"
+msgstr "Hem"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:22
+msgid "Log out"
+msgstr "Logga ut"
+
+#: templates/livesettings/group_settings.html:18
+#: templates/livesettings/site_settings.html:41
+msgid "Please correct the error below."
+msgid_plural "Please correct the errors below."
+msgstr[0] "Var god rätta till felet nedan."
+msgstr[1] "Var god rätta till felen nedan."
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:22
+msgid "Documentation"
+msgstr "Dokumentation"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:22
+msgid "Change password"
+msgstr "Byt lösenord"
+
+#: templates/livesettings/site_settings.html:26
+msgid "Edit Site Settings"
+msgstr "Ändra sajtinställningar"
+
+#: templates/livesettings/group_settings.html:11
+msgid "Edit Group Settings"
+msgstr "Redigera gruppinställningar"
+
+#: templates/livesettings/group_settings.html:24
+#, python-format
+msgid "Settings included in %(name)s."
+msgstr "Inställningar som ingår i %(name)s."
+
+#: templates/livesettings/group_settings.html:49
+#: templates/livesettings/site_settings.html:87
+msgid "You don't have permission to edit values."
+msgstr "Du har inte tillåtelse att ändra värden."
+
+#: templates/livesettings/site_settings.html:58
+#, python-format
+msgid "Group settings: %(name)s"
+msgstr "Gruppinställningar: %(name)s"
+
+#: templates/livesettings/site_settings.html:84
+msgid "Uncollapse all"
+msgstr "Visa alla"
+
diff --git a/askbot/deps/livesettings/locale/tr/LC_MESSAGES/django.mo b/askbot/deps/livesettings/locale/tr/LC_MESSAGES/django.mo
new file mode 100644
index 00000000..d56ad423
--- /dev/null
+++ b/askbot/deps/livesettings/locale/tr/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/deps/livesettings/locale/tr/LC_MESSAGES/django.po b/askbot/deps/livesettings/locale/tr/LC_MESSAGES/django.po
new file mode 100644
index 00000000..bb2a1506
--- /dev/null
+++ b/askbot/deps/livesettings/locale/tr/LC_MESSAGES/django.po
@@ -0,0 +1,102 @@
+# Satchmo Translation Package
+# Copyright (C) 2008 Satchmo Project
+# This file is distributed under the same license as the Satchmo package.
+# Selin Çuhadar <selincuhadar@gmail.com>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Satchmo\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-12-31 00:49-0600\n"
+"PO-Revision-Date: 2008-06-09 18:18+0200\n"
+"Last-Translator: Selin Çuhadar <selincuhadar@gmail.com>\n"
+"Language-Team: Turkish <selincuhadar@gmail.com>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-Country: TURKEY\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#: values.py:88
+msgid "Base Settings"
+msgstr "Temel Ayarlar"
+
+#: values.py:194
+msgid "Default value: \"\""
+msgstr "Geçerli Değer: \"\""
+
+#: values.py:201
+msgid "Default value: "
+msgstr "Geçerli Değer:"
+
+#: values.py:204
+#, python-format
+msgid "Default value: %s"
+msgstr "Geçerli Değer: %s"
+
+#: templates/livesettings/group_settings.html:10
+#: templates/livesettings/site_settings.html:10
+msgid "Home"
+msgstr "Ev"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:7
+msgid "Log out"
+msgstr "Oturumu kapa"
+
+#: templates/livesettings/group_settings.html:18
+#: templates/livesettings/site_settings.html:18
+#, fuzzy
+msgid "Please correct the error below."
+msgid_plural "Please correct the errors below."
+msgstr[0] ""
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+msgstr[1] ""
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\n"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:7
+msgid "Documentation"
+msgstr "Dokümentasyon"
+
+#: templates/livesettings/group_settings.html:7
+#: templates/livesettings/site_settings.html:7
+msgid "Change password"
+msgstr "Åžifreyi deÄŸiÅŸtir"
+
+#: templates/livesettings/group_settings.html:11
+msgid "Edit Group Settings"
+msgstr "Grup Ayarlarını Düzenle"
+
+#: templates/livesettings/group_settings.html:24
+#, python-format
+msgid "Settings included in %(name)s."
+msgstr "%(name)s ayarlara dahil edildi."
+
+#: templates/livesettings/group_settings.html:49
+#: templates/livesettings/site_settings.html:61
+msgid "You don't have permission to edit values."
+msgstr "Değerleri düzenlemek için gerekli izniniz yok."
+
+#: templates/livesettings/site_settings.html:11
+msgid "Edit Site Settings"
+msgstr "Site Ayarlarını Düzenle"
+
+#: templates/livesettings/site_settings.html:34
+#, python-format
+msgid "Group settings: %(name)s"
+msgstr "Grup ayarları: %(name)s"
+
diff --git a/askbot/deps/livesettings/models.py b/askbot/deps/livesettings/models.py
new file mode 100644
index 00000000..1a57dfc5
--- /dev/null
+++ b/askbot/deps/livesettings/models.py
@@ -0,0 +1,170 @@
+from django.conf import settings
+from django.contrib.sites.models import Site
+from django.db import models
+from django.db.models import loading
+from django.utils.translation import ugettext_lazy as _
+from keyedcache import cache_key, cache_get, cache_set, NotCachedError
+from keyedcache.models import CachedObjectMixin
+from askbot.deps.livesettings.overrides import get_overrides
+import logging
+
+log = logging.getLogger('configuration.models')
+
+__all__ = ['SettingNotSet', 'Setting', 'LongSetting', 'find_setting']
+
+def _safe_get_siteid(site):
+ if not site:
+ try:
+ site = Site.objects.get_current()
+ siteid = site.id
+ except:
+ siteid = settings.SITE_ID
+ else:
+ siteid = site.id
+ return siteid
+
+def find_setting(group, key, site=None):
+ """Get a setting or longsetting by group and key, cache and return it."""
+
+ siteid = _safe_get_siteid(site)
+ setting = None
+
+ use_db, overrides = get_overrides(siteid)
+ ck = cache_key('Setting', siteid, group, key)
+
+ if use_db:
+ try:
+ setting = cache_get(ck)
+
+ except NotCachedError, nce:
+ if loading.app_cache_ready():
+ try:
+ setting = Setting.objects.get(site__id__exact=siteid, key__exact=key, group__exact=group)
+
+ except Setting.DoesNotExist:
+ # maybe it is a "long setting"
+ try:
+ setting = LongSetting.objects.get(site__id__exact=siteid, key__exact=key, group__exact=group)
+
+ except LongSetting.DoesNotExist:
+ pass
+
+ cache_set(ck, value=setting)
+
+ else:
+ grp = overrides.get(group, None)
+ if grp and grp.has_key(key):
+ val = grp[key]
+ setting = ImmutableSetting(key=key, group=group, value=val)
+ log.debug('Returning overridden: %s', setting)
+
+ if not setting:
+ raise SettingNotSet(key, cachekey=ck)
+
+ return setting
+
+class SettingNotSet(Exception):
+ def __init__(self, k, cachekey=None):
+ self.key = k
+ self.cachekey = cachekey
+ self.args = [self.key, self.cachekey]
+
+class SettingManager(models.Manager):
+ def get_query_set(self):
+ all = super(SettingManager, self).get_query_set()
+ siteid = _safe_get_siteid(None)
+ return all.filter(site__id__exact=siteid)
+
+
+class ImmutableSetting(object):
+
+ def __init__(self, group="", key="", value="", site=1):
+ self.site = site
+ self.group = group
+ self.key = key
+ self.value = value
+
+ def cache_key(self, *args, **kwargs):
+ return cache_key('OverrideSetting', self.site, self.group, self.key)
+
+ def delete(self):
+ pass
+
+ def save(self, *args, **kwargs):
+ pass
+
+ def __repr__(self):
+ return "ImmutableSetting: %s.%s=%s" % (self.group, self.key, self.value)
+
+
+class Setting(models.Model, CachedObjectMixin):
+ site = models.ForeignKey(Site, verbose_name=_('Site'))
+ group = models.CharField(max_length=100, blank=False, null=False)
+ key = models.CharField(max_length=100, blank=False, null=False)
+ value = models.CharField(max_length=255, blank=True)
+
+ objects = SettingManager()
+
+ def __nonzero__(self):
+ return self.id is not None
+
+ def cache_key(self, *args, **kwargs):
+ return cache_key('Setting', self.site, self.group, self.key)
+
+ def delete(self):
+ self.cache_delete()
+ super(Setting, self).delete()
+
+ def save(self, force_insert=False, force_update=False):
+ try:
+ site = self.site
+ except Site.DoesNotExist:
+ self.site = Site.objects.get_current()
+
+ super(Setting, self).save(force_insert=force_insert, force_update=force_update)
+
+ self.cache_set()
+
+ class Meta:
+ unique_together = ('site', 'group', 'key')
+
+
+class LongSettingManager(models.Manager):
+ def get_query_set(self):
+ all = super(LongSettingManager, self).get_query_set()
+ siteid = _safe_get_siteid(None)
+ return all.filter(site__id__exact=siteid)
+
+class LongSetting(models.Model, CachedObjectMixin):
+ """A Setting which can handle more than 255 characters"""
+ site = models.ForeignKey(Site, verbose_name=_('Site'))
+ group = models.CharField(max_length=100, blank=False, null=False)
+ key = models.CharField(max_length=100, blank=False, null=False)
+ value = models.TextField(blank=True)
+
+ objects = LongSettingManager()
+
+ def __nonzero__(self):
+ return self.id is not None
+
+ def cache_key(self, *args, **kwargs):
+ # note same cache pattern as Setting. This is so we can look up in one check.
+ # they can't overlap anyway, so this is moderately safe. At the worst, the
+ # Setting will override a LongSetting.
+ return cache_key('Setting', self.site, self.group, self.key)
+
+ def delete(self):
+ self.cache_delete()
+ super(LongSetting, self).delete()
+
+ def save(self, force_insert=False, force_update=False):
+ try:
+ site = self.site
+ except Site.DoesNotExist:
+ self.site = Site.objects.get_current()
+ super(LongSetting, self).save(force_insert=force_insert, force_update=force_update)
+ self.cache_set()
+
+ class Meta:
+ unique_together = ('site', 'group', 'key')
+
diff --git a/askbot/deps/livesettings/overrides.py b/askbot/deps/livesettings/overrides.py
new file mode 100644
index 00000000..3d8404ef
--- /dev/null
+++ b/askbot/deps/livesettings/overrides.py
@@ -0,0 +1,55 @@
+"""Allows askbot.deps.livesettings to be "locked down" and no longer use the settings page or the database
+for settings retrieval.
+"""
+
+from django.conf import settings as djangosettings
+from django.contrib.sites.models import Site
+import logging
+
+__all__ = ['get_overrides']
+
+def _safe_get_siteid(site):
+ if not site:
+ try:
+ site = Site.objects.get_current()
+ siteid = site.id
+ except:
+ siteid = djangosettings.SITE_ID
+ else:
+ siteid = site.id
+ return siteid
+
+def get_overrides(siteid=-1):
+ """Check to see if askbot.deps.livesettings is allowed to use the database. If not, then
+ it will only use the values in the dictionary, LIVESETTINGS_OPTIONS[SITEID]['SETTINGS'],
+ this allows 'lockdown' of a live site.
+
+ The LIVESETTINGS dict must be formatted as follows::
+
+ LIVESETTINGS_OPTIONS = {
+ 1 : {
+ 'DB' : [True/False],
+ SETTINGS = {
+ 'GROUPKEY' : {'KEY', val, 'KEY2', val},
+ 'GROUPKEY2' : {'KEY', val, 'KEY2', val},
+ }
+ }
+ }
+
+ In the settings dict above, the "val" entries must exactly match the format
+ stored in the database for a setting. Do not use a literal True or an integer,
+ it needs to be the string representation of them.
+
+ Returns a tuple (DB_ALLOWED, SETTINGS)
+ """
+ overrides = (True, {})
+ if hasattr(djangosettings, 'LIVESETTINGS_OPTIONS'):
+ if siteid == -1:
+ siteid = _safe_get_siteid(None)
+
+ opts = djangosettings.LIVESETTINGS_OPTIONS
+ if opts.has_key(siteid):
+ opts = opts[siteid]
+ overrides = (opts.get('DB', True), opts['SETTINGS'])
+
+ return overrides
diff --git a/askbot/deps/livesettings/signals.py b/askbot/deps/livesettings/signals.py
new file mode 100644
index 00000000..ddea31f5
--- /dev/null
+++ b/askbot/deps/livesettings/signals.py
@@ -0,0 +1,3 @@
+import django.dispatch
+
+configuration_value_changed = django.dispatch.Signal()
diff --git a/askbot/deps/livesettings/templates/livesettings/_admin_site_views.html b/askbot/deps/livesettings/templates/livesettings/_admin_site_views.html
new file mode 100644
index 00000000..17d08f58
--- /dev/null
+++ b/askbot/deps/livesettings/templates/livesettings/_admin_site_views.html
@@ -0,0 +1,15 @@
+{% load i18n %}
+<div id="content-related">
+ <div class="module" id="sites-module">
+ <h2 class="module-title">{% trans 'Sites' %}</h2>
+ <div class="module-content">
+ <ul>
+ {% for label, link in links %}
+ <li>
+ <a href="{{ link }}">{{ label }}</a>
+ </li>
+ {% endfor %}
+ </ul>
+ </div>
+ </div>
+</div>
diff --git a/askbot/deps/livesettings/templates/livesettings/group_settings.html b/askbot/deps/livesettings/templates/livesettings/group_settings.html
new file mode 100644
index 00000000..e56f764f
--- /dev/null
+++ b/askbot/deps/livesettings/templates/livesettings/group_settings.html
@@ -0,0 +1,81 @@
+{% extends "admin/base_site.html" %}
+{% load i18n admin_modify config_tags %}
+{% block extrastyle %}
+{{ block.super }}
+<link rel="stylesheet" type="text/css" href="{% load adminmedia %}{% admin_media_prefix %}css/base.css" />
+{% endblock %}
+
+{% block stylesheet %}{% load adminmedia %}{% admin_media_prefix %}css/forms.css{% endblock %}
+{% block coltype %}colMS{% endblock %}
+{% block bodyclass %}dashboard{% endblock %}
+{% block userlinks %}<a href="/admin/doc/">{% trans 'Documentation' %}</a> / <a href="/admin/password_change/">{% trans 'Change password' %}</a> / <a href="/admin/logout/">{% trans 'Log out' %}</a>{% endblock %}
+{% block breadcrumbs %}{% if not is_popup %}
+<div class="breadcrumbs">
+ <a href="/admin/">{% trans "Home" %}</a> &rsaquo;
+ {% trans "Edit Group Settings" %}
+</div>
+{% endif %}{% endblock %}
+{% block content %}
+<div id="content-main">
+{% if form.errors %}
+ <p class="errornote">
+ {% blocktrans count form.errors|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %}
+ </p>
+{% endif %}
+{% if form.fields %}
+<form method="post">
+ <div class="module">
+ <table summary="{% filter capfirst %}{% blocktrans with group.name as name %}Settings included in {{ name }}.{% endblocktrans %}{% endfilter %}" width="100%">
+ {% for field in form %}
+ {% if field.is_hidden %}
+ <!-- skip hidden field {{field.key}} -->
+ {% else %}
+ {% if field.errors %}
+ <tr class="error">
+ <td colspan="2">{{ field.errors }}</td>
+ </tr>
+ {% endif %}
+ <tr{% if field.errors %} class="error"{% endif %}>
+ <td style="width: 50%;">
+ {{ field.label_tag }}
+ {% if field.help_text %}
+ <p class="help">{{ field.help_text|safe }}</p>
+ {% endif %}
+ {% if field.field.default_text %}
+ <p class="help">{{ field.field.default_text|safe }}</p>
+ {% endif %}
+ </td>
+ <td>{{ field }}</td>
+ </tr>
+ {% endif %}
+ {% endfor %}
+ </table>
+ {% for field in form %}
+ {% if field.is_hidden %}
+ {{field}}
+ {% endif %}
+ {% endfor %}
+ </div>
+ <input type="submit" value="Save" class="default" />
+</form>
+{% else %}
+ <p>{% trans "You don't have permission to edit values." %}</p>
+{% endif %}
+</div>
+{% if all_groups %}
+<div id="content-related">
+ <div class="module">
+ <h2>{% trans "Setting groups" %}</h2>
+ <ul>
+ {% for g in all_groups %}
+ {% ifequal g.key group.key %}
+ <li><b>{{g.name}}</b></li>
+ {% else %}
+ <li><a href="{% url group_settings g.key %}">{{g.name}}</a></li>
+ {% endifequal %}
+ {% endfor %}
+ </ul>
+ </div>
+</div>
+{% endif %}
+{% endblock %}
diff --git a/askbot/deps/livesettings/templates/livesettings/site_settings.html b/askbot/deps/livesettings/templates/livesettings/site_settings.html
new file mode 100644
index 00000000..35333778
--- /dev/null
+++ b/askbot/deps/livesettings/templates/livesettings/site_settings.html
@@ -0,0 +1,101 @@
+{% extends "admin/base_site.html" %}
+{% load i18n admin_modify config_tags %}
+
+{% block stylesheet %}{% load adminmedia %}{% admin_media_prefix %}css/forms.css{% endblock %}
+{% block extrahead %}
+<script type="text/javascript" src="{% url admin:jsi18n %}"></script>
+<script type="text/javascript" src="{% admin_media_prefix %}js/core.js"></script>
+<script type="text/javascript" src="{% admin_media_prefix %}js/admin/CollapsedFieldsets.js"></script>
+{% endblock %}
+{% block extrastyle %}
+{{ block.super }}
+<link rel="stylesheet" type="text/css" href="{% load adminmedia %}{% admin_media_prefix %}css/base.css" />
+<style type="text/css">
+ul.fieldref { margin: 0; padding: 0; font-size: 9px; }
+ul.fieldref li { float: left; margin: 0 10px 0 0; list-style: none; }
+fieldset.collapsed h2 { display: block !important; }
+fieldset.collapsed h2 a { display: inline !important; }
+div.fieldcontainer { float: left; margin-right: 0; }
+</style>
+{% endblock %}
+{% block coltype %}colMS{% endblock %}
+{% block bodyclass %}dashboard{% endblock %}
+{% block userlinks %}<a href="/admin/doc/">{% trans 'Documentation' %}</a> / <a href="/admin/password_change/">{% trans 'Change password' %}</a> / <a href="/admin/logout/">{% trans 'Log out' %}</a>{% endblock %}
+{% block breadcrumbs %}{% if not is_popup %}
+<div class="breadcrumbs">
+ <a href="/admin/">{% trans "Home" %}</a> &rsaquo;
+ {% trans "Edit Site Settings" %}
+</div>
+{% endif %}{% endblock %}
+{% block content %}
+{% comment %}
+<div class="fieldcontainer">
+<ul class="fieldref">
+{% for group in form.groups %}
+ <li><a onclick="javascript:CollapsedFieldsets.show({{ forloop.counter0 }});" href="#{{ group.key }}">{{ group.name }}</a></li>
+{% endfor %}
+</ul>
+</div>
+{% endcomment %}
+<span style="clear: both;" />
+<div id="content-main">
+{% if not use_db %}
+ <p>{% trans "Livesettings are disabled for this site." %}</p>
+ <p>{% trans "All configuration options must be edited in the site settings.py file" %}</p>
+ </div>
+ {% admin_site_views 'satchmo_site_settings' %}
+{% else %}
+ {% if form.errors %}
+ <p class="errornote">
+ {% blocktrans count form.errors|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %}
+ </p>
+ {% endif %}
+ {% if form.fields %}
+ <form method="post">
+ {% for field in form %}
+ {% if field.is_hidden %}
+ {{ field }}
+ {% else %}
+ {% ifchanged field.field.group %}{% with field.field.group as group %}
+ {% if not forloop.first %}
+ </table>
+ </fieldset>
+ {% endif %}
+ <fieldset class="module collapse">
+ <h2 id="{{ group.key }}">{{ group.name }}</h2>
+ <table summary="{% blocktrans with group.name as name %}Group settings: {{ name }}{% endblocktrans %}" style="width: 100%">
+ {% endwith %}{% endifchanged %}
+
+ {% if field.errors %}
+ <tr class="error">
+ <td colspan="2">{{ field.errors }}</td>
+ </tr>
+ {% endif %}
+ <tr{% if field.errors %} class="error"{% endif %}>
+ <td style="width: 50%;">
+ {{ field.label_tag }}
+ {% if field.help_text %}
+ <p class="help">{{ field.help_text|break_at:40|safe }}</p>
+ {% endif %}
+ {% if field.field.default_text %}
+ <p class="help">{{ field.field.default_text|break_at:40}}</p>
+ {% endif %}
+ </td>
+ <td>{{ field }}</td>
+ </tr>
+ {% endif %}
+ {% endfor %}
+ </table>
+ </div>
+ {% admin_site_views 'satchmo_site_settings' %}
+ <br class="clear:both;" />
+ <input type="submit" value="Save" class="default" />
+ <p><a onclick="javascript:CollapsedFieldsets.uncollapse_all(); return false;" href="#">{% trans 'Uncollapse all' %}</a></p>
+ <p><a href="{% url settings_export %}">Export</a></p>
+ </form>
+ {% else %}
+ <p>{% trans "You don't have permission to edit values." %}</p>
+ {% endif %}
+{% endif %}
+</div>
+{% endblock %}
diff --git a/askbot/deps/livesettings/templates/livesettings/text.txt b/askbot/deps/livesettings/templates/livesettings/text.txt
new file mode 100644
index 00000000..d57a57e3
--- /dev/null
+++ b/askbot/deps/livesettings/templates/livesettings/text.txt
@@ -0,0 +1 @@
+{{ text|safe }} \ No newline at end of file
diff --git a/forum/importers/__init__.py b/askbot/deps/livesettings/templatetags/__init__.py
index e69de29b..e69de29b 100644
--- a/forum/importers/__init__.py
+++ b/askbot/deps/livesettings/templatetags/__init__.py
diff --git a/askbot/deps/livesettings/templatetags/config_tags.py b/askbot/deps/livesettings/templatetags/config_tags.py
new file mode 100644
index 00000000..ab5cf6b4
--- /dev/null
+++ b/askbot/deps/livesettings/templatetags/config_tags.py
@@ -0,0 +1,91 @@
+from django import template
+from django.contrib.sites.models import Site
+from django.core import urlresolvers
+from askbot.deps.livesettings import config_value
+from askbot.deps.livesettings.utils import url_join
+import logging
+
+log = logging.getLogger('configuration.config_tags')
+
+register = template.Library()
+
+def force_space(value, chars=40):
+ """Forces spaces every `chars` in value"""
+
+ chars = int(chars)
+ if len(value) < chars:
+ return value
+ else:
+ out = []
+ start = 0
+ end = 0
+ looping = True
+
+ while looping:
+ start = end
+ end += chars
+ out.append(value[start:end])
+ looping = end < len(value)
+
+ return ' '.join(out)
+
+def break_at(value, chars=40):
+ """Force spaces into long lines which don't have spaces"""
+ #todo: EF - lazy patch
+ return value
+
+ chars = int(chars)
+ value = unicode(value)
+ if len(value) < chars:
+ return value
+ else:
+ out = []
+ line = value.split(' ')
+ for word in line:
+ if len(word) > chars:
+ out.append(force_space(word, chars))
+ else:
+ out.append(word)
+
+ return " ".join(out)
+
+register.filter('break_at', break_at)
+
+def config_boolean(option):
+ """Looks up the configuration option, returning true or false."""
+ args = option.split('.')
+ try:
+ val = config_value(*args)
+ except:
+ log.warn('config_boolean tag: Tried to look up config setting "%s", got SettingNotSet, returning False', option)
+ val = False
+ if val:
+ return "true"
+ else:
+ return ""
+
+register.filter('config_boolean', config_boolean)
+
+def admin_site_views(view):
+ """Returns a formatted list of sites, rendering for view, if any"""
+
+ if view:
+ path = urlresolvers.reverse(view)
+ else:
+ path = None
+
+ links = []
+ for site in Site.objects.all():
+ paths = ["http://", site.domain]
+ if path:
+ paths.append(path)
+
+ links.append((site.name, url_join(paths)))
+
+ ret = {
+ 'links' : links,
+ }
+ return ret
+
+
+register.inclusion_tag('askbot.deps.livesettings/_admin_site_views.html')(admin_site_views)
diff --git a/askbot/deps/livesettings/tests.py b/askbot/deps/livesettings/tests.py
new file mode 100644
index 00000000..aab61f4a
--- /dev/null
+++ b/askbot/deps/livesettings/tests.py
@@ -0,0 +1,545 @@
+from django.conf import settings as djangosettings
+from django.test import TestCase
+import keyedcache
+from askbot.deps.livesettings import *
+import logging
+log = logging.getLogger('test');
+
+class ConfigurationFunctionTest(TestCase):
+
+ def testSetSingleConfigItem(self):
+ value = IntegerValue(BASE_GROUP, 'SingleItem')
+ config_register(value)
+ self.assert_(config_exists(BASE_GROUP, 'SingleItem'))
+
+ def testSetTwoConfigItems(self):
+ s = [IntegerValue(BASE_GROUP, 'testTwoA'), StringValue(BASE_GROUP, 'testTwoB')]
+ config_register_list(*s)
+
+ self.assert_(config_exists(BASE_GROUP, 'testTwoA'))
+ self.assert_(config_exists(BASE_GROUP, 'testTwoB'))
+
+ def testSetGroup(self):
+ g1 = ConfigurationGroup('test1','test1')
+ value = IntegerValue(g1, 'SingleGroupedItem')
+ config_register(value)
+ self.assertFalse(config_exists(BASE_GROUP, 'SingleGroupedItem'))
+ self.assert_(config_exists(g1, 'SingleGroupedItem'))
+
+
+class ConfigurationTestSettings(TestCase):
+
+ def setUp(self):
+ # clear out cache from previous runs
+ keyedcache.cache_delete()
+ g = ConfigurationGroup('test2','test2')
+ self.g = g
+ config_register(StringValue(g, 's1'))
+ config_register(IntegerValue(g, 's2', default=10))
+ config_register(IntegerValue(g, 's3', default=10))
+
+ def testSetSetting(self):
+ c = config_get('test2', 's1')
+ c.update('test')
+
+ self.assertEqual(c.value, 'test')
+ self.assertEqual(c.setting.value, 'test')
+
+ def testSettingDefault(self):
+ c = config_get('test2', 's2')
+ self.assertEqual(c.value, 10)
+
+ def testSetAndReset(self):
+ """Test setting one value and then updating"""
+ c = config_get('test2', 's1')
+ c.update('test1')
+
+ self.assertEqual(c.value, 'test1')
+
+ # should be true, since it is an update
+ self.assert_(c.update('test2'))
+ self.assertEqual(c.value, 'test2')
+
+ def testTwice(self):
+ """Config items should respond False to duplicate requests to update."""
+
+ c = config_get('test2', 's1')
+ c.update('test1')
+
+ self.assertFalse(c.update('test1'))
+
+
+ def testDeletesDefault(self):
+ c = config_get('test2', 's3')
+ # false because it isn't saving a default value
+ self.assertFalse(c.update(10))
+
+ self.assert_(c.update(20))
+ self.assertEqual(c.value, 20)
+ try:
+ s = c.setting
+ except SettingNotSet:
+ self.fail("Should have a setting now")
+
+ # now delete and go back to no setting by setting the default
+ self.assert_(c.update(10))
+ self.assertEqual(c.value, 10)
+
+ try:
+ s = c.setting
+ self.fail('Should throw SettingNotSet')
+ except SettingNotSet:
+ pass
+
+
+class ConfigTestDotAccess(TestCase):
+ def setUp(self):
+ # clear out cache from previous runs
+ keyedcache.cache_delete()
+
+ g = ConfigurationGroup('test3','test3')
+ self.g = g
+ c1 = config_register(BooleanValue(g, 's1', default=True))
+ c2 = config_register(IntegerValue(g, 's2', default=10))
+ c2.update(100)
+
+ def testDotAccess(self):
+ self.assert_(ConfigurationSettings().test3.s1.value)
+ self.assertEqual(ConfigurationSettings().test3.s2.value, 100)
+
+ def testSettingProperty(self):
+ c = config_get('test3','s2')
+ s = c.setting
+ self.assert_(s.value, 100)
+
+ def testDictValues(self):
+ d = self.g.dict_values()
+ self.assertEqual(d, {'s1': True, 's2' : 100})
+
+class ConfigTestModuleValue(TestCase):
+ def setUp(self):
+ # clear out cache from previous runs
+ keyedcache.cache_delete()
+
+ g = ConfigurationGroup('modules','module test')
+ self.g = g
+ self.c = config_register(ModuleValue(g, 'test'))
+
+ # def testModule(self):
+ # c = config_get('modules', 'test')
+ # c.update('satchmo_store')
+
+ # self.assert_(hasattr(self.c.value, 'get_version'))
+
+class ConfigTestSortOrder(TestCase):
+ def setUp(self):
+ # clear out cache from previous runs
+ keyedcache.cache_delete()
+
+ g1 = ConfigurationGroup('group1', 'Group 1', ordering=-1001)
+ g2 = ConfigurationGroup('group2', 'Group 2', ordering=-1002)
+ g3 = ConfigurationGroup('group3', 'Group 3', ordering=-1003)
+
+ self.g1 = g1
+ self.g2 = g2
+ self.g3 = g3
+
+ self.g1c1 = config_register(IntegerValue(g1, 'c1'))
+ self.g1c2 = config_register(IntegerValue(g1, 'c2'))
+ self.g1c3 = config_register(IntegerValue(g1, 'c3'))
+
+ self.g2c1 = config_register(IntegerValue(g2, 'c1'))
+ self.g2c2 = config_register(IntegerValue(g2, 'c2'))
+ self.g2c3 = config_register(IntegerValue(g2, 'c3'))
+
+ self.g3c1 = config_register(IntegerValue(g3, 'c1'))
+ self.g3c2 = config_register(IntegerValue(g3, 'c2'))
+ self.g3c3 = config_register(IntegerValue(g3, 'c3'))
+
+ def testGroupOrdering(self):
+ mgr = ConfigurationSettings()
+ self.assertEqual(mgr[2].key, self.g1.key)
+ self.assertEqual(mgr[1].key, self.g2.key)
+ self.assertEqual(mgr[0].key, self.g3.key)
+
+
+class TestMultipleValues(TestCase):
+
+ def setUp(self):
+ # clear out cache from previous runs
+ keyedcache.cache_delete()
+
+ g1 = ConfigurationGroup('m1', 'Multiple Group 1', ordering=1000)
+ self.g1 = g1
+
+ self.g1c1 = config_register(MultipleStringValue(g1,
+ 'c1',
+ choices=((1,'one'),(2,'two'),(3,'three'))))
+
+ def testSave(self):
+
+ c = config_get('m1','c1')
+ c.update([1,2])
+ self.assertEqual(c.value, [1,2])
+
+ def testAddChoice(self):
+
+ config_add_choice('m1','c1',(4, 'four'))
+ c = config_get('m1','c1')
+ self.assertEqual(c.choices, ((1,'one'),(2,'two'),(3,'three'),(4,'four')))
+
+ def testChoiceValues(self):
+ self.g1c1.update([1,2])
+
+ self.assertEqual(self.g1c1.value, [1,2])
+ self.assertEqual(self.g1c1.choice_values, [(1, 'one'),(2, 'two')])
+
+ choices = config_choice_values('m1', 'c1')
+ self.assertEqual(choices, [(1, 'one'),(2, 'two')])
+
+class TestMultipleValuesWithDefault(TestCase):
+
+ def setUp(self):
+ # clear out cache from previous runs
+ keyedcache.cache_delete()
+
+ g1 = ConfigurationGroup('mv2', 'Multiple Group 2', ordering=1000)
+ self.g1 = g1
+
+ self.g1c1 = config_register(MultipleStringValue(g1,
+ 'c1',
+ choices=((1,'one'),(2,'two'),(3,'three')),
+ default=[1,2]))
+
+ def testDefault(self):
+
+ c = config_get('mv2','c1')
+ self.assertEqual(c.value, [1,2])
+
+ c.update([1,2,3])
+ self.assertEqual(c.value, [1,2,3])
+
+class ConfigTestChoices(TestCase):
+
+ def testAddPreregisteredChoice(self):
+ """Test that we can register choices before the config is actually set up."""
+ config_add_choice('ctg1', 'c1', ('a', 'Item A'))
+ config_add_choice('ctg1', 'c1', ('b', 'Item B'))
+ config_add_choice('ctg1', 'c1', ('c', 'Item C'))
+
+ g1 = ConfigurationGroup('ctg1', 'Choice 1', ordering=1000)
+ config_register(StringValue(g1, 'c1'))
+
+ c = config_get('ctg1','c1')
+
+ self.assertEqual(c.choices, [('a','Item A'), ('b','Item B'), ('c','Item C')])
+
+
+class ConfigTestRequires(TestCase):
+
+ def setUp(self):
+ # clear out cache from previous runs
+ keyedcache.cache_delete()
+
+ g1 = ConfigurationGroup('req1', 'Requirements 1', ordering=1000)
+
+ self.g1 = g1
+
+ bool1 = config_register(BooleanValue(g1, 'bool1', default=False, ordering=1))
+ bool2 = config_register(BooleanValue(g1, 'bool2', ordering=2))
+
+ self.g1c1 = config_register(IntegerValue(g1, 'c1', requires=bool1, ordering=3))
+
+ self.g1c2 = config_register(IntegerValue(g1, 'c2', requires=bool2, ordering=4))
+ self.g1c3 = config_register(IntegerValue(g1, 'c3', ordering=5))
+
+ bool2.update(True)
+
+ def testSimpleRequires(self):
+
+ v = config_value('req1', 'bool2')
+ self.assertTrue(v)
+
+ keys = [cfg.key for cfg in self.g1]
+ self.assertEqual(keys, ['bool1', 'bool2', 'c2','c3'])
+
+ c = config_get('req1','bool1')
+ c.update(True)
+
+ keys = [cfg.key for cfg in self.g1]
+ self.assertEqual(keys, ['bool1', 'bool2', 'c1', 'c2', 'c3'])
+
+class ConfigTestRequiresChoices(TestCase):
+
+ def setUp(self):
+ # clear out cache from previous runs
+ keyedcache.cache_delete()
+
+ g1 = ConfigurationGroup('req2', 'Requirements 2', ordering=1000)
+
+ self.g1 = g1
+
+ choices1 = config_register(MultipleStringValue(BASE_GROUP, 'rc1', ordering=1))
+
+ self.g1c1 = config_register(IntegerValue(g1, 'c1', requires=choices1, ordering=3))
+ self.g1c2 = config_register(IntegerValue(g1, 'c2', requires=choices1, ordering=4))
+ self.g1c3 = config_register(IntegerValue(g1, 'c3', ordering=5))
+
+ choices1.update('c1')
+
+ g2 = ConfigurationGroup('req3', 'Requirements 3', ordering=1000)
+
+ self.g2 = g2
+
+ choices2 = config_register(StringValue(BASE_GROUP, 'choices2', ordering=1))
+
+ self.g2c1 = config_register(IntegerValue(g2, 'c1', requires=choices2, ordering=3))
+ self.g2c2 = config_register(IntegerValue(g2, 'c2', requires=choices2, ordering=4))
+ self.g2c3 = config_register(IntegerValue(g2, 'c3', requires=choices2, ordering=5))
+
+ choices2.update('c1')
+
+ def testSimpleRequiresChoices(self):
+
+ v = config_value('BASE', 'rc1')
+ self.assertEquals(v, ['c1'])
+
+ g = config_get_group('req2')
+ keys = [cfg.key for cfg in g]
+ self.assertEqual(keys, ['c1','c3'])
+
+ c = config_get('BASE', 'rc1')
+ c.update(['c1','c2'])
+
+ g = config_get_group('req2')
+ keys = [cfg.key for cfg in g]
+ self.assertEqual(keys, ['c1', 'c2', 'c3'])
+
+ def testRequiresSingleValue(self):
+ v = config_value('BASE', 'choices2')
+ self.assertEquals(v, 'c1')
+
+ keys = [cfg.key for cfg in self.g2]
+ self.assertEqual(keys, ['c1'])
+
+ c = config_get('BASE', 'choices2')
+ c.update('c2')
+
+ keys = [cfg.key for cfg in self.g2]
+ self.assertEqual(keys, ['c2'])
+
+class ConfigTestRequiresValue(TestCase):
+
+ def setUp(self):
+ # clear out cache from previous runs
+ keyedcache.cache_delete()
+
+ g1 = ConfigurationGroup('reqval', 'Requirements 3', ordering=1000)
+
+ self.g1 = g1
+
+ choices1 = config_register(MultipleStringValue(BASE_GROUP, 'valchoices', ordering=1))
+
+ self.g1c1 = config_register(IntegerValue(g1, 'c1', requires=choices1, requiresvalue='foo', ordering=3))
+ self.g1c2 = config_register(IntegerValue(g1, 'c2', requires=choices1, requiresvalue='bar', ordering=4))
+ self.g1c3 = config_register(IntegerValue(g1, 'c3', ordering=5))
+
+ choices1.update('foo')
+
+ g2 = ConfigurationGroup('reqval2', 'Requirements 4', ordering=1000)
+
+ self.g2 = g2
+
+ choices2 = config_register(StringValue(BASE_GROUP, 'valchoices2', ordering=1,
+ choices=(('a','test a'),('b', 'test b'),('c', 'test c'))))
+
+ self.g2c1 = config_register(IntegerValue(g2, 'c1', requires=choices2, requiresvalue='a', ordering=3))
+ self.g2c2 = config_register(IntegerValue(g2, 'c2', requires=choices2, requiresvalue='b', ordering=4))
+ self.g2c3 = config_register(IntegerValue(g2, 'c3', requires=choices2, requiresvalue='c', ordering=5))
+
+ choices2.update('a')
+
+ def testRequiresValue(self):
+ v = config_value('BASE', 'valchoices')
+ self.assertEquals(v, ['foo'])
+
+ g = config_get_group('reqval')
+
+ keys = [cfg.key for cfg in g]
+ self.assertEqual(keys, ['c1','c3'])
+
+ c = config_get('BASE', 'valchoices')
+ c.update(['foo','bar'])
+
+ g = config_get_group('reqval')
+ keys = [cfg.key for cfg in g]
+ self.assertEqual(keys, ['c1', 'c2', 'c3'])
+
+ def testRequiresSingleValue(self):
+ v = config_value('BASE', 'valchoices2')
+ self.assertEquals(v, 'a')
+
+ keys = [cfg.key for cfg in self.g2]
+ self.assertEqual(keys, ['c1'])
+
+ c = config_get('BASE', 'valchoices2')
+ c.update('b')
+
+ keys = [cfg.key for cfg in self.g2]
+ self.assertEqual(keys, ['c2'])
+
+class ConfigTestGroupRequires(TestCase):
+ def setUp(self):
+ # clear out cache from previous runs
+ keyedcache.cache_delete()
+
+ choices1 = config_register(MultipleStringValue(BASE_GROUP, 'groupchoice', ordering=1))
+ choices2 = config_register(MultipleStringValue(BASE_GROUP, 'groupchoice2', ordering=1))
+
+ g1 = ConfigurationGroup('groupreq', 'Requirements 4', ordering=1000, requires=choices1)
+ self.g1 = g1
+
+ self.g1c1 = config_register(IntegerValue(g1, 'c1', ordering=3))
+ self.g1c2 = config_register(IntegerValue(g1, 'c2', requires=choices2, requiresvalue='bar', ordering=4))
+ self.g1c3 = config_register(IntegerValue(g1, 'c3', ordering=5))
+
+ def testRequiresValue(self):
+ c = config_get('BASE', 'groupchoice')
+ self.assertEquals(c.value, [])
+
+ keys = [cfg.key for cfg in self.g1]
+ self.assertEqual(keys, [])
+
+ c2 = config_get('BASE', 'groupchoice2')
+ c2.update('bar')
+
+ keys = [cfg.key for cfg in self.g1]
+ self.assertEqual(keys, ['c2'])
+
+ c.update(['groupreq'])
+
+ keys = [cfg.key for cfg in self.g1]
+ self.assertEqual(keys, ['c1', 'c2', 'c3'])
+
+class ConfigCollectGroup(TestCase):
+ def setUp(self):
+ keyedcache.cache_delete()
+ choices = config_register(MultipleStringValue(BASE_GROUP, 'collect', ordering=1))
+ self.choices = choices
+
+ g1 = ConfigurationGroup('coll1', 'Collection 1')
+ g2 = ConfigurationGroup('coll2', 'Collection 2')
+ g3 = ConfigurationGroup('coll3', 'Collection 3')
+
+ g1c1 = config_register(StringValue(g1, 'test'))
+ g1c2 = config_register(StringValue(g1, 'test1'))
+ g2c1 = config_register(StringValue(g2, 'test'))
+ g3c1 = config_register(StringValue(g3, 'test'))
+
+ g1c1.update('set a')
+ g1c2.update('set b')
+ g2c1.update('set a')
+ g3c1.update('set d')
+
+ choices.update(['coll1','coll3'])
+
+ def testCollectSimple(self):
+ v = config_collect_values('BASE', 'collect', 'test')
+
+ self.assertEqual(v, ['set a', 'set d'])
+
+ def testCollectUnique(self):
+ self.choices.update(['coll1','coll2','coll3'])
+
+ v = config_collect_values('BASE', 'collect', 'test', unique=False)
+
+ self.assertEqual(v, ['set a', 'set a', 'set d'])
+
+ v = config_collect_values('BASE', 'collect', 'test', unique=True)
+
+ self.assertEqual(v, ['set a', 'set d'])
+
+class LongSettingTest(TestCase):
+ def setUp(self):
+ keyedcache.cache_delete()
+ wide = config_register(LongStringValue(BASE_GROUP, 'LONG', ordering=1, default="woot"))
+ self.wide = wide
+ self.wide.update('*' * 1000)
+
+ def testLongStorage(self):
+ w = config_value('BASE', 'LONG')
+ self.assertEqual(len(w), 1000)
+ self.assertEqual(w, '*'*1000)
+
+ def testShortInLong(self):
+ self.wide.update("test")
+ w = config_value('BASE', 'LONG')
+ self.assertEqual(len(w), 4)
+ self.assertEqual(w, 'test')
+
+ def testDelete(self):
+ remember = self.wide.setting.id
+ self.wide.update('woot')
+
+ try:
+ q = LongSetting.objects.get(pk = remember)
+ self.fail("Should be deletec")
+ except LongSetting.DoesNotExist:
+ pass
+
+class OverrideTest(TestCase):
+ """Test settings overrides"""
+ def setUp(self):
+ # clear out cache from previous runs
+ keyedcache.cache_delete()
+
+ djangosettings.LIVESETTINGS_OPTIONS = {
+ 1 : {
+ 'DB' : False,
+ 'SETTINGS' : {
+ 'overgroup' : {
+ 's2' : '100',
+ 'choices' : '["one","two","three"]'
+ }
+ }
+ }
+ }
+
+ g = ConfigurationGroup('overgroup','Override Group')
+ self.g = g
+ config_register(StringValue(g, 's1'))
+ config_register(IntegerValue(g, 's2', default=10))
+ config_register(IntegerValue(g, 's3', default=10))
+ config_register(MultipleStringValue(g, 'choices'))
+
+ def tearDown(self):
+ djangosettings.LIVESETTINGS_OPTIONS = {}
+
+ def testOverriddenSetting(self):
+ """Accessing an overridden setting should give the override value."""
+ c = config_get('overgroup', 's2')
+ self.assertEquals(c.value, 100)
+
+ def testCantChangeSetting(self):
+ """When overridden, setting a value should not work, should get the overridden value"""
+ c = config_get('overgroup', 's2')
+ c.update(1)
+
+ c = config_get('overgroup', 's2')
+ self.assertEquals(c.value, 100)
+
+ def testNotOverriddenSetting(self):
+ """Settings which are not overridden should return their defaults"""
+ c = config_get('overgroup', 's3')
+
+ self.assertEquals(c.value, 10)
+
+ def testOverriddenListSetting(self):
+ """Make sure lists work when overridden"""
+
+ c = config_get('overgroup', 'choices')
+ v = c.value
+ self.assertEqual(len(v), 3)
+ self.assertEqual(v[0], "one")
+ self.assertEqual(v[1], "two")
+ self.assertEqual(v[2], "three")
diff --git a/askbot/deps/livesettings/urls.py b/askbot/deps/livesettings/urls.py
new file mode 100644
index 00000000..b608bf1f
--- /dev/null
+++ b/askbot/deps/livesettings/urls.py
@@ -0,0 +1,7 @@
+from django.conf.urls.defaults import *
+
+urlpatterns = patterns('askbot.deps.livesettings.views',
+ url(r'^$', 'site_settings', {}, name='site_settings'),
+ url(r'^export/$', 'export_as_python', {}, name='settings_export'),
+ url(r'^(?P<group>[^/]+)/$', 'group_settings', name='group_settings'),
+)
diff --git a/askbot/deps/livesettings/utils.py b/askbot/deps/livesettings/utils.py
new file mode 100644
index 00000000..c0e0e293
--- /dev/null
+++ b/askbot/deps/livesettings/utils.py
@@ -0,0 +1,87 @@
+import sys
+import types
+import os
+
+def can_loop_over(maybe):
+ """Test value to see if it is list like"""
+ try:
+ iter(maybe)
+ except:
+ return 0
+ else:
+ return 1
+
+def is_list_or_tuple(maybe):
+ return isinstance(maybe, (types.TupleType, types.ListType))
+
+
+def is_scalar(maybe):
+ """Test to see value is a string, an int, or some other scalar type"""
+ return is_string_like(maybe) or not can_loop_over(maybe)
+
+def is_string_like(maybe):
+ """Test value to see if it acts like a string"""
+ try:
+ maybe+""
+ except TypeError:
+ return 0
+ else:
+ return 1
+
+
+def flatten_list(sequence, scalarp=is_scalar, result=None):
+ """flatten out a list by putting sublist entries in the main list"""
+ if result is None:
+ result = []
+
+ for item in sequence:
+ if scalarp(item):
+ result.append(item)
+ else:
+ flatten_list(item, scalarp, result)
+
+def load_module(module):
+ """Load a named python module."""
+ try:
+ module = sys.modules[module]
+ except KeyError:
+ __import__(module)
+ module = sys.modules[module]
+ return module
+
+def get_flat_list(sequence):
+ """flatten out a list and return the flat list"""
+ flat = []
+ flatten_list(sequence, result=flat)
+ return flat
+
+def url_join(*args):
+ """Join any arbitrary strings into a forward-slash delimited string.
+ Do not strip leading / from first element, nor trailing / from last element.
+
+ This function can take lists as arguments, flattening them appropriately.
+
+ example:
+ url_join('one','two',['three','four'],'five') => 'one/two/three/four/five'
+ """
+ if len(args) == 0:
+ return ""
+
+ args = get_flat_list(args)
+
+ if len(args) == 1:
+ return str(args[0])
+
+ else:
+ args = [str(arg).replace("\\", "/") for arg in args]
+
+ work = [args[0]]
+ for arg in args[1:]:
+ if arg.startswith("/"):
+ work.append(arg[1:])
+ else:
+ work.append(arg)
+
+ joined = reduce(os.path.join, work)
+
+ return joined.replace("\\", "/")
diff --git a/askbot/deps/livesettings/values.py b/askbot/deps/livesettings/values.py
new file mode 100644
index 00000000..6bde7f5a
--- /dev/null
+++ b/askbot/deps/livesettings/values.py
@@ -0,0 +1,628 @@
+"""Taken and modified from the dbsettings project.
+
+http://code.google.com/p/django-values/
+"""
+from decimal import Decimal
+from django import forms
+from django.core.exceptions import ImproperlyConfigured
+from django.utils import simplejson
+from django.utils.datastructures import SortedDict
+from django.utils.encoding import smart_str
+from django.utils.translation import gettext, ugettext_lazy as _
+from askbot.deps.livesettings.models import find_setting, LongSetting, Setting, SettingNotSet
+from askbot.deps.livesettings.overrides import get_overrides
+from askbot.deps.livesettings.utils import load_module, is_string_like, is_list_or_tuple
+import datetime
+import logging
+import signals
+
+__all__ = ['BASE_GROUP', 'ConfigurationGroup', 'Value', 'BooleanValue', 'DecimalValue', 'DurationValue',
+ 'FloatValue', 'IntegerValue', 'ModuleValue', 'PercentValue', 'PositiveIntegerValue', 'SortedDotDict',
+ 'StringValue', 'LongStringValue', 'MultipleStringValue']
+
+_WARN = {}
+
+log = logging.getLogger('configuration')
+
+NOTSET = object()
+
+class SortedDotDict(SortedDict):
+
+ def __getattr__(self, key):
+ try:
+ return self[key]
+ except:
+ raise AttributeError, key
+
+ def __iter__(self):
+ vals = self.values()
+ for k in vals:
+ yield k
+
+ def values(self):
+ vals = super(SortedDotDict, self).values()
+ vals = [v for v in vals if isinstance(v, (ConfigurationGroup, Value))]
+ vals.sort()
+ return vals
+
+class ConfigurationGroup(SortedDotDict):
+ """A simple wrapper for a group of configuration values"""
+ def __init__(self, key, name, *args, **kwargs):
+ """Create a new ConfigurationGroup.
+
+ Arguments:
+ - key
+ - group name - for display to user
+
+ Named Arguments:
+ - ordering: integer, optional, defaults to 1.
+ - requires: See `Value` requires. The default `requires` all member values will have if not overridden.
+ - requiresvalue: See `Values` requires_value. The default `requires_value` if not overridden on the `Value` objects.
+ """
+ self.key = key
+ self.name = name
+ self.ordering = kwargs.pop('ordering', 1)
+ self.requires = kwargs.pop('requires', None)
+ if self.requires:
+ reqval = kwargs.pop('requiresvalue', key)
+ if not is_list_or_tuple(reqval):
+ reqval = (reqval, reqval)
+
+ self.requires_value = reqval[0]
+ self.requires.add_choice(reqval)
+
+ super(ConfigurationGroup, self).__init__(*args, **kwargs)
+
+ def __cmp__(self, other):
+ return cmp((self.ordering, self.name), (other.ordering, other.name))
+
+ def __eq__(self, other):
+ return (type(self) == type(other)
+ and self.ordering == other.ordering
+ and self.name == other.name)
+
+ def __ne__(self, other):
+ return not self == other
+
+ def dict_values(self, load_modules=True):
+ vals = {}
+ keys = super(ConfigurationGroup, self).keys()
+ for key in keys:
+ v = self[key]
+ if isinstance(v, Value):
+ value = v.value
+ else:
+ value = v
+ vals[key] = value
+ return vals
+
+ def values(self):
+ vals = super(ConfigurationGroup, self).values()
+ return [v for v in vals if v.enabled()]
+
+BASE_GROUP = ConfigurationGroup('BASE', _('Base Settings'), ordering=0)
+
+class Value(object):
+
+ creation_counter = 0
+
+ def __init__(self, group, key, **kwargs):
+ """
+ Create a new Value object for configuration.
+
+ Args:
+ - `ConfigurationGroup`
+ - key - a string key
+
+ Named arguments:
+ - `description` - Will be passed to the field for form usage. Should be a translation proxy. Ex: _('example')
+ - `help_text` - Will be passed to the field for form usage.
+ - `choices` - If given, then the form field will use a select box
+ - `ordering` - Defaults to alphabetical by key if not given.
+ - `requires` - If given as a `Value`, then this field will only be rendered if that Value evaluates true (for Boolean requires) or the proper key is in the associated value.
+ - `requiresvalue` - If set, then this field will only be rendered if that value is in the list returned by self.value. Defaults to self.key.
+ - `hidden` - If true, then render a hidden field.
+ - `default` - If given, then this Value will return that default whenever it has no assocated `Setting`.
+ - `update_callback` - if given, then this value will call the callback whenever updated
+ """
+ self.group = group
+ self.key = key
+ self.description = kwargs.get('description', None)
+ self.help_text = kwargs.get('help_text')
+ self.choices = kwargs.get('choices',[])
+ self.ordering = kwargs.pop('ordering', 0)
+ self.hidden = kwargs.pop('hidden', False)
+ self.update_callback = kwargs.pop('update_callback', None)
+ self.requires = kwargs.pop('requires', None)
+ if self.requires:
+ reqval = kwargs.pop('requiresvalue', key)
+ if not is_list_or_tuple(reqval):
+ reqval = (reqval, reqval)
+
+ self.requires_value = reqval[0]
+ self.requires.add_choice(reqval)
+
+ elif group.requires:
+ self.requires = group.requires
+ self.requires_value = group.requires_value
+
+ if kwargs.has_key('default'):
+ self.default = kwargs.pop('default')
+ self.use_default = True
+ else:
+ self.use_default = False
+
+ self.creation_counter = Value.creation_counter
+ Value.creation_counter += 1
+
+ def __cmp__(self, other):
+ return cmp((self.ordering, self.description, self.creation_counter), (other.ordering, other.description, other.creation_counter))
+
+ def __eq__(self, other):
+ if type(self) == type(other):
+ return self.value == other.value
+ else:
+ return self.value == other
+
+ def __iter__(self):
+ return iter(self.value)
+
+ def __unicode__(self):
+ return unicode(self.value)
+
+ def __str__(self):
+ return str(self.value)
+
+ def add_choice(self, choice):
+ """Add a choice if it doesn't already exist."""
+ if not is_list_or_tuple(choice):
+ choice = (choice, choice)
+ skip = False
+ for k, v in self.choices:
+ if k == choice[0]:
+ skip = True
+ break
+ if not skip:
+ self.choices += (choice, )
+
+ def choice_field(self, **kwargs):
+ if self.hidden:
+ kwargs['widget'] = forms.MultipleHiddenInput()
+ return forms.ChoiceField(choices=self.choices, **kwargs)
+
+ def _choice_values(self):
+ choices = self.choices
+ vals = self.value
+ return [x for x in choices if x[0] in vals]
+
+ choice_values = property(fget=_choice_values)
+
+ def copy(self):
+ new_value = self.__class__(self.key)
+ new_value.__dict__ = self.__dict__.copy()
+ return new_value
+
+ def _default_text(self):
+ if not self.use_default:
+ note = ""
+ else:
+ if self.default == "":
+ note = _('Default value: ""')
+
+ elif self.choices:
+ work = []
+ for x in self.choices:
+ if x[0] in self.default:
+ work.append(smart_str(x[1]))
+ note = gettext('Default value: ') + ", ".join(work)
+
+ else:
+ note = _("Default value: %s") % unicode(self.default)
+
+ return note
+
+ default_text = property(fget=_default_text)
+
+ def enabled(self):
+ enabled = False
+ try:
+ if not self.requires:
+ enabled = True
+ else:
+ v = self.requires.value
+ if self.requires.choices:
+ enabled = self.requires_value == v or self.requires_value in v
+ elif v:
+ enabled = True
+ except SettingNotSet:
+ pass
+ return enabled
+
+ def make_field(self, **kwargs):
+ if self.choices:
+ if self.hidden:
+ kwargs['widget'] = forms.MultipleHiddenInput()
+ field = self.choice_field(**kwargs)
+ else:
+ if self.hidden:
+ kwargs['widget'] = forms.HiddenInput()
+ field = self.field(**kwargs)
+
+ field.group = self.group
+ field.default_text = self.default_text
+ return field
+
+ def make_setting(self, db_value):
+ log.debug('new setting %s.%s', self.group.key, self.key)
+ return Setting(group=self.group.key, key=self.key, value=db_value)
+
+ def _setting(self):
+ return find_setting(self.group.key, self.key)
+
+ setting = property(fget = _setting)
+
+ def _value(self):
+ use_db, overrides = get_overrides()
+
+ if not use_db:
+ try:
+ val = overrides[self.group.key][self.key]
+ except KeyError:
+ if self.use_default:
+ val = self.default
+ else:
+ raise SettingNotSet('%s.%s is not in your LIVESETTINGS_OPTIONS' % (self.group.key, self.key))
+
+ else:
+ try:
+ val = self.setting.value
+
+ except SettingNotSet, sns:
+ if self.use_default:
+ val = self.default
+ if overrides:
+ # maybe override the default
+ grp = overrides.get(self.group.key, {})
+ if grp.has_key(self.key):
+ val = grp[self.key]
+ else:
+ val = NOTSET
+
+ except AttributeError, ae:
+ log.error("Attribute error: %s", ae)
+ log.error("%s: Could not get _value of %s", self.key, self.setting)
+ raise(ae)
+
+ except Exception, e:
+ global _WARN
+ log.error(e)
+ if str(e).find("configuration_setting") > -1:
+ if not _WARN.has_key('configuration_setting'):
+ log.warn('Error loading setting %s.%s from table, OK if you are in syncdb', self.group.key, self.key)
+ _WARN['configuration_setting'] = True
+
+ if self.use_default:
+ val = self.default
+ else:
+ raise ImproperlyConfigured("All settings used in startup must have defaults, %s.%s does not", self.group.key, self.key)
+ else:
+ import traceback
+ traceback.print_exc()
+ log.warn("Problem finding settings %s.%s, %s", self.group.key, self.key, e)
+ raise SettingNotSet("Startup error, couldn't load %s.%s" %(self.group.key, self.key))
+ return val
+
+ def update(self, value):
+ use_db, overrides = get_overrides()
+
+ if use_db:
+ current_value = self.value
+
+ new_value = self.to_python(value)
+ if current_value != new_value:
+ if self.update_callback:
+ new_value = apply(self.update_callback, (current_value, new_value))
+
+ db_value = self.get_db_prep_save(new_value)
+
+ try:
+ s = self.setting
+ s.value = db_value
+
+ except SettingNotSet:
+ s = self.make_setting(db_value)
+
+ if self.use_default and self.default == new_value:
+ if s.id:
+ log.info("Deleted setting %s.%s", self.group.key, self.key)
+ s.delete()
+ else:
+ log.info("Updated setting %s.%s = %s", self.group.key, self.key, value)
+ s.save()
+
+ signals.configuration_value_changed.send(self, old_value=current_value, new_value=new_value, setting=self)
+
+ return True
+ else:
+ log.debug('not updating setting %s.%s - askbot.deps.livesettings db is disabled',self.group.key, self.key)
+
+ return False
+
+ @property
+ def value(self):
+ val = self._value()
+ return self.to_python(val)
+
+ @property
+ def editor_value(self):
+ val = self._value()
+ return self.to_editor(val)
+
+ # Subclasses should override the following methods where applicable
+
+ def to_python(self, value):
+ "Returns a native Python object suitable for immediate use"
+ if value == NOTSET:
+ value = None
+ return value
+
+ def get_db_prep_save(self, value):
+ "Returns a value suitable for storage into a CharField"
+ if value == NOTSET:
+ value = ""
+ return unicode(value)
+
+ def to_editor(self, value):
+ "Returns a value suitable for display in a form widget"
+ if value == NOTSET:
+ return NOTSET
+ return unicode(value)
+
+###############
+# VALUE TYPES #
+###############
+
+class BooleanValue(Value):
+
+ class field(forms.BooleanField):
+
+ def __init__(self, *args, **kwargs):
+ kwargs['required'] = False
+ forms.BooleanField.__init__(self, *args, **kwargs)
+
+ def add_choice(self, choice):
+ # ignore choice adding for boolean types
+ pass
+
+ def to_python(self, value):
+ if value in (True, 't', 'True', 1, '1'):
+ return True
+ return False
+
+ to_editor = to_python
+
+class DecimalValue(Value):
+ class field(forms.DecimalField):
+
+ def __init__(self, *args, **kwargs):
+ kwargs['required'] = False
+ forms.DecimalField.__init__(self, *args, **kwargs)
+
+ def to_python(self, value):
+ if value==NOTSET:
+ return Decimal("0")
+
+ try:
+ return Decimal(value)
+ except TypeError, te:
+ log.warning("Can't convert %s to Decimal for settings %s.%s", value, self.group.key, self.key)
+ raise TypeError(te)
+
+ def to_editor(self, value):
+ if value == NOTSET:
+ return "0"
+ else:
+ return unicode(value)
+
+# DurationValue has a lot of duplication and ugliness because of issue #2443
+# Until DurationField is sorted out, this has to do some extra work
+class DurationValue(Value):
+
+ class field(forms.CharField):
+ def clean(self, value):
+ try:
+ return datetime.timedelta(seconds=float(value))
+ except (ValueError, TypeError):
+ raise forms.ValidationError('This value must be a real number.')
+ except OverflowError:
+ raise forms.ValidationError('The maximum allowed value is %s' % datetime.timedelta.max)
+
+ def to_python(self, value):
+ if value == NOTSET:
+ value = 0
+ if isinstance(value, datetime.timedelta):
+ return value
+ try:
+ return datetime.timedelta(seconds=float(value))
+ except (ValueError, TypeError):
+ raise forms.ValidationError('This value must be a real number.')
+ except OverflowError:
+ raise forms.ValidationError('The maximum allowed value is %s' % datetime.timedelta.max)
+
+ def get_db_prep_save(self, value):
+ if value == NOTSET:
+ return NOTSET
+ else:
+ return unicode(value.days * 24 * 3600 + value.seconds + float(value.microseconds) / 1000000)
+
+class FloatValue(Value):
+
+ class field(forms.FloatField):
+
+ def __init__(self, *args, **kwargs):
+ kwargs['required'] = False
+ forms.FloatField.__init__(self, *args, **kwargs)
+
+ def to_python(self, value):
+ if value == NOTSET:
+ value = 0
+ return float(value)
+
+ def to_editor(self, value):
+ if value == NOTSET:
+ return "0"
+ else:
+ return unicode(value)
+
+class IntegerValue(Value):
+ class field(forms.IntegerField):
+
+ def __init__(self, *args, **kwargs):
+ kwargs['required'] = False
+ forms.IntegerField.__init__(self, *args, **kwargs)
+
+ def to_python(self, value):
+ if value == NOTSET:
+ value = 0
+ return int(value)
+
+ def to_editor(self, value):
+ if value == NOTSET:
+ return "0"
+ else:
+ return unicode(value)
+
+
+class PercentValue(Value):
+
+ class field(forms.DecimalField):
+
+ def __init__(self, *args, **kwargs):
+ kwargs['required'] = False
+ forms.DecimalField.__init__(self, 100, 0, 5, 2, *args, **kwargs)
+
+ class widget(forms.TextInput):
+ def render(self, *args, **kwargs):
+ # Place a percent sign after a smaller text field
+ attrs = kwargs.pop('attrs', {})
+ attrs['size'] = attrs['max_length'] = 6
+ return forms.TextInput.render(self, attrs=attrs, *args, **kwargs) + '%'
+
+ def to_python(self, value):
+ if value == NOTSET:
+ value = 0
+ return Decimal(value) / 100
+
+ def to_editor(self, value):
+ if value == NOTSET:
+ return "0"
+ else:
+ return unicode(value)
+
+class PositiveIntegerValue(IntegerValue):
+
+ class field(forms.IntegerField):
+
+ def __init__(self, *args, **kwargs):
+ kwargs['min_value'] = 0
+ forms.IntegerField.__init__(self, *args, **kwargs)
+
+
+class StringValue(Value):
+
+ class field(forms.CharField):
+ def __init__(self, *args, **kwargs):
+ kwargs['required'] = False
+ forms.CharField.__init__(self, *args, **kwargs)
+
+ def to_python(self, value):
+ if value == NOTSET:
+ value = ""
+ return unicode(value)
+
+ to_editor = to_python
+
+class LongStringValue(Value):
+
+ class field(forms.CharField):
+ def __init__(self, *args, **kwargs):
+ kwargs['required'] = False
+ kwargs['widget'] = forms.Textarea()
+ forms.CharField.__init__(self, *args, **kwargs)
+
+ def make_setting(self, db_value):
+ log.debug('new long setting %s.%s', self.group.key, self.key)
+ return LongSetting(group=self.group.key, key=self.key, value=db_value)
+
+ def to_python(self, value):
+ if value == NOTSET:
+ value = ""
+ return unicode(value)
+
+ to_editor = to_python
+
+
+class MultipleStringValue(Value):
+
+ class field(forms.CharField):
+
+ def __init__(self, *args, **kwargs):
+ kwargs['required'] = False
+ forms.CharField.__init__(self, *args, **kwargs)
+
+ def choice_field(self, **kwargs):
+ kwargs['required'] = False
+ return forms.MultipleChoiceField(choices=self.choices, **kwargs)
+
+ def get_db_prep_save(self, value):
+ if is_string_like(value):
+ value = [value]
+ return simplejson.dumps(value)
+
+ def to_python(self, value):
+ if not value or value == NOTSET:
+ return []
+ if is_list_or_tuple(value):
+ return value
+ else:
+ try:
+ return simplejson.loads(value)
+ except:
+ if is_string_like(value):
+ return [value]
+ else:
+ log.warning('Could not decode returning empty list: %s', value)
+ return []
+
+
+ to_editor = to_python
+
+class ModuleValue(Value):
+ """Handles setting modules, storing them as strings in the db."""
+
+ class field(forms.CharField):
+
+ def __init__(self, *args, **kwargs):
+ kwargs['required'] = False
+ forms.CharField.__init__(self, *args, **kwargs)
+
+ def load_module(self, module):
+ """Load a child module"""
+ value = self._value()
+ if value == NOTSET:
+ raise SettingNotSet("%s.%s", self.group.key, self.key)
+ else:
+ return load_module("%s.%s" % (value, module))
+
+ def to_python(self, value):
+ if value == NOTSET:
+ v = {}
+ else:
+ v = load_module(value)
+ return v
+
+ def to_editor(self, value):
+ if value == NOTSET:
+ value = ""
+ return value
+
diff --git a/askbot/deps/livesettings/views.py b/askbot/deps/livesettings/views.py
new file mode 100644
index 00000000..000a7bbd
--- /dev/null
+++ b/askbot/deps/livesettings/views.py
@@ -0,0 +1,93 @@
+from django.http import HttpResponseRedirect
+from django.core.urlresolvers import reverse
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+from django.contrib.admin.views.decorators import staff_member_required
+from django.views.decorators.cache import never_cache
+from askbot.deps.livesettings import ConfigurationSettings, forms
+from askbot.deps.livesettings.overrides import get_overrides
+import logging
+
+log = logging.getLogger('configuration.views')
+
+def group_settings(request, group, template='askbot.deps.livesettings/group_settings.html'):
+ # Determine what set of settings this editor is used for
+
+ use_db, overrides = get_overrides();
+
+ mgr = ConfigurationSettings()
+
+ settings = mgr[group]
+ title = settings.name
+ log.debug('title: %s', title)
+
+ if use_db:
+ # Create an editor customized for the current user
+ #editor = forms.customized_editor(settings)
+
+ if request.method == 'POST':
+ # Populate the form with user-submitted data
+ data = request.POST.copy()
+ form = forms.SettingsEditor(data, settings=settings)
+ if form.is_valid():
+ form.full_clean()
+ for name, value in form.cleaned_data.items():
+ group, key = name.split('__')
+ cfg = mgr.get_config(group, key)
+ if cfg.update(value):
+
+ # Give user feedback as to which settings were changed
+ request.user.message_set.create(message='Updated %s on %s' % (cfg.key, cfg.group.key))
+
+ return HttpResponseRedirect(request.path)
+ else:
+ # Leave the form populated with current setting values
+ #form = editor()
+ form = forms.SettingsEditor(settings=settings)
+ else:
+ form = None
+
+ return render_to_response(template, {
+ 'all_groups': mgr.groups(),
+ 'title': title,
+ 'group' : settings,
+ 'form': form,
+ 'use_db' : use_db
+ }, context_instance=RequestContext(request))
+group_settings = never_cache(staff_member_required(group_settings))
+
+# Site-wide setting editor is identical, but without a group
+# staff_member_required is implied, since it calls group_settings
+def site_settings(request):
+ mgr = ConfigurationSettings()
+ default_group= mgr.groups()[0].key
+ return HttpResponseRedirect(reverse('group_settings', args=[default_group]))
+ #return group_settings(request, group=None, template='askbot.deps.livesettings/site_settings.html')
+
+def export_as_python(request):
+ """Export site settings as a dictionary of dictionaries"""
+
+ from askbot.deps.livesettings.models import Setting, LongSetting
+ import pprint
+
+ work = {}
+ both = list(Setting.objects.all())
+ both.extend(list(LongSetting.objects.all()))
+
+ for s in both:
+ if not work.has_key(s.site.id):
+ work[s.site.id] = {}
+ sitesettings = work[s.site.id]
+
+ if not sitesettings.has_key(s.group):
+ sitesettings[s.group] = {}
+ sitegroup = sitesettings[s.group]
+
+ sitegroup[s.key] = s.value
+
+ pp = pprint.PrettyPrinter(indent=4)
+ pretty = pp.pformat(work)
+
+ return render_to_response('askbot.deps.livesettings/text.txt', { 'text' : pretty }, mimetype='text/plain')
+
+export_as_python = never_cache(staff_member_required(export_as_python))
diff --git a/askbot/deps/recaptcha_django/.svn/all-wcprops b/askbot/deps/recaptcha_django/.svn/all-wcprops
new file mode 100644
index 00000000..43324b46
--- /dev/null
+++ b/askbot/deps/recaptcha_django/.svn/all-wcprops
@@ -0,0 +1,17 @@
+K 25
+svn:wc:ra_dav:version-url
+V 38
+/svn/!svn/ver/6/trunk/recaptcha_django
+END
+middleware.py
+K 25
+svn:wc:ra_dav:version-url
+V 52
+/svn/!svn/ver/2/trunk/recaptcha_django/middleware.py
+END
+__init__.py
+K 25
+svn:wc:ra_dav:version-url
+V 50
+/svn/!svn/ver/6/trunk/recaptcha_django/__init__.py
+END
diff --git a/askbot/deps/recaptcha_django/.svn/entries b/askbot/deps/recaptcha_django/.svn/entries
new file mode 100644
index 00000000..17e2d172
--- /dev/null
+++ b/askbot/deps/recaptcha_django/.svn/entries
@@ -0,0 +1,52 @@
+8
+
+dir
+6
+http://recaptcha-django.googlecode.com/svn/trunk/recaptcha_django
+http://recaptcha-django.googlecode.com/svn
+
+
+
+2009-12-12T22:16:04.511967Z
+6
+xdissent
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+af963488-c9ea-11dd-a8b6-f5aca7b582bb
+
+middleware.py
+file
+
+
+
+
+2010-06-13T21:04:19.000000Z
+3cf99bc9362dde824315288bfbfadb1a
+2008-12-14T15:07:18.967792Z
+2
+xdissent
+
+__init__.py
+file
+
+
+
+
+2010-06-13T21:04:19.000000Z
+a0c7720be84083264fcdfbf35f031062
+2009-12-12T22:16:04.511967Z
+6
+xdissent
+
diff --git a/askbot/deps/recaptcha_django/.svn/format b/askbot/deps/recaptcha_django/.svn/format
new file mode 100644
index 00000000..45a4fb75
--- /dev/null
+++ b/askbot/deps/recaptcha_django/.svn/format
@@ -0,0 +1 @@
+8
diff --git a/askbot/deps/recaptcha_django/.svn/text-base/__init__.py.svn-base b/askbot/deps/recaptcha_django/.svn/text-base/__init__.py.svn-base
new file mode 100644
index 00000000..c95cbca2
--- /dev/null
+++ b/askbot/deps/recaptcha_django/.svn/text-base/__init__.py.svn-base
@@ -0,0 +1,76 @@
+"""
+recaptcha-django
+
+ReCAPTCHA (Completely Automated Public Turing test to tell Computers and
+Humans Apart - while helping digitize books, newspapers, and old time radio
+shows) module for django
+"""
+
+from django.forms import Widget, Field, ValidationError
+from django.conf import settings
+from django.utils.translation import get_language, ugettext_lazy as _
+from django.utils.html import conditional_escape
+from django.utils.safestring import mark_safe
+from recaptcha.client import captcha
+
+
+HUMAN_ERRORS = {
+ 'unknown': _(u'Unknown error.'),
+ 'invalid-site-public-key': _(u'ReCAPTCHA is wrongly configured.'),
+ 'invalid-site-private-key': _(u'ReCAPTCHA is wrongly configured.'),
+ 'invalid-request-cookie': _(u'Bad reCAPTCHA challenge parameter.'),
+ 'incorrect-captcha-sol': _(u'The CAPTCHA solution was incorrect.'),
+ 'verify-params-incorrect': _(u'Bad reCAPTCHA verification parameters.'),
+ 'invalid-referrer': _(u'Provided reCAPTCHA API keys are not valid for this domain.'),
+ 'recaptcha-not-reachable': _(u'ReCAPTCHA could not be reached.')
+}
+
+
+class ReCaptchaWidget(Widget):
+ """
+ A Widget that renders a ReCAPTCHA form
+ """
+ options = ['theme', 'lang', 'custom_theme_widget', 'tabindex']
+
+ def render(self, name, value, attrs=None):
+ final_attrs = self.build_attrs(attrs)
+ error = final_attrs.get('error', None)
+ html = captcha.displayhtml(settings.RECAPTCHA_PUBLIC_KEY, error=error)
+ options = u',\n'.join([u'%s: "%s"' % (k, conditional_escape(v)) \
+ for k, v in final_attrs.items() if k in self.options])
+ return mark_safe(u"""<script type="text/javascript">
+ var RecaptchaOptions = {
+ %s
+ };
+ </script>
+ %s
+ """ % (options, html))
+
+
+ def value_from_datadict(self, data, files, name):
+ """
+ Generates Widget value from data dictionary.
+ """
+ try:
+ return {'challenge': data['recaptcha_challenge_field'],
+ 'response': data['recaptcha_response_field'],
+ 'ip': data['recaptcha_ip_field']}
+ except KeyError:
+ return None
+
+class ReCaptchaField(Field):
+ """
+ Field definition for a ReCAPTCHA
+ """
+ widget = ReCaptchaWidget
+
+ def clean(self, value):
+ if value is None:
+ raise ValidationError(_('Invalid request'))
+ resp = captcha.submit(value.get('challenge', None),
+ value.get('response', None),
+ settings.RECAPTCHA_PRIVATE_KEY,
+ value.get('ip', None))
+ if not resp.is_valid:
+ self.widget.attrs['error'] = resp.error_code
+ raise ValidationError(HUMAN_ERRORS.get(resp.error_code, _(u'Unknown error.')))
diff --git a/askbot/deps/recaptcha_django/.svn/text-base/middleware.py.svn-base b/askbot/deps/recaptcha_django/.svn/text-base/middleware.py.svn-base
new file mode 100644
index 00000000..4d592e63
--- /dev/null
+++ b/askbot/deps/recaptcha_django/.svn/text-base/middleware.py.svn-base
@@ -0,0 +1,12 @@
+class ReCaptchaMiddleware(object):
+ """
+ A tiny middleware to automatically add IP address to ReCaptcha
+ POST requests
+ """
+ def process_request(self, request):
+ if request.method == 'POST' and \
+ 'recaptcha_challenge_field' in request.POST and \
+ 'recaptcha_ip_field' not in request.POST:
+ data = request.POST.copy()
+ data['recaptcha_ip_field'] = request.META['REMOTE_ADDR']
+ request.POST = data
diff --git a/askbot/deps/recaptcha_django/__init__.py b/askbot/deps/recaptcha_django/__init__.py
new file mode 100644
index 00000000..3423a106
--- /dev/null
+++ b/askbot/deps/recaptcha_django/__init__.py
@@ -0,0 +1,80 @@
+"""
+recaptcha-django
+
+ReCAPTCHA (Completely Automated Public Turing test to tell Computers and
+Humans Apart - while helping digitize books, newspapers, and old time radio
+shows) module for django
+"""
+
+from django.forms import Widget, Field, ValidationError
+from django.conf import settings
+from django.utils.translation import get_language, ugettext_lazy as _
+from django.utils.html import conditional_escape
+from django.utils.safestring import mark_safe
+from recaptcha.client import captcha
+from askbot.conf import settings as askbot_settings
+
+
+HUMAN_ERRORS = {
+ 'unknown': _(u'Unknown error.'),
+ 'invalid-site-public-key': _(u'ReCAPTCHA is wrongly configured.'),
+ 'invalid-site-private-key': _(u'ReCAPTCHA is wrongly configured.'),
+ 'invalid-request-cookie': _(u'Bad reCAPTCHA challenge parameter.'),
+ 'incorrect-captcha-sol': _(u'The CAPTCHA solution was incorrect.'),
+ 'verify-params-incorrect': _(u'Bad reCAPTCHA verification parameters.'),
+ 'invalid-referrer': _(u'Provided reCAPTCHA API keys are not valid for this domain.'),
+ 'recaptcha-not-reachable': _(u'ReCAPTCHA could not be reached.')
+}
+
+
+class ReCaptchaWidget(Widget):
+ """
+ A Widget that renders a ReCAPTCHA form
+ """
+ options = ['theme', 'lang', 'custom_theme_widget', 'tabindex']
+
+ def render(self, name, value, attrs=None):
+ final_attrs = self.build_attrs(attrs)
+ error = final_attrs.get('error', None)
+ html = captcha.displayhtml(
+ askbot_settings.RECAPTCHA_PUBLIC_KEY,
+ error=error
+ )
+ options = u',\n'.join([u'%s: "%s"' % (k, conditional_escape(v)) \
+ for k, v in final_attrs.items() if k in self.options])
+ return mark_safe(u"""<script type="text/javascript">
+ var RecaptchaOptions = {
+ %s
+ };
+ </script>
+ %s
+ """ % (options, html))
+
+
+ def value_from_datadict(self, data, files, name):
+ """
+ Generates Widget value from data dictionary.
+ """
+ try:
+ return {'challenge': data['recaptcha_challenge_field'],
+ 'response': data['recaptcha_response_field'],
+ 'ip': data['recaptcha_ip_field']}
+ except KeyError:
+ return None
+
+class ReCaptchaField(Field):
+ """
+ Field definition for a ReCAPTCHA
+ """
+ widget = ReCaptchaWidget
+
+ def clean(self, value):
+ if value is None:
+ raise ValidationError(_('Invalid request'))
+ resp = captcha.submit(value.get('challenge', None),
+ value.get('response', None),
+ askbot_settings.RECAPTCHA_PRIVATE_KEY,
+ value.get('ip', None))
+ if not resp.is_valid:
+ self.widget.attrs['error'] = resp.error_code
+ raise ValidationError(HUMAN_ERRORS.get(resp.error_code, _(u'Unknown error.')))
diff --git a/askbot/deps/recaptcha_django/docs/.svn/all-wcprops b/askbot/deps/recaptcha_django/docs/.svn/all-wcprops
new file mode 100644
index 00000000..6ecb5451
--- /dev/null
+++ b/askbot/deps/recaptcha_django/docs/.svn/all-wcprops
@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 26
+/svn/!svn/ver/2/trunk/docs
+END
+overview.txt
+K 25
+svn:wc:ra_dav:version-url
+V 39
+/svn/!svn/ver/2/trunk/docs/overview.txt
+END
diff --git a/askbot/deps/recaptcha_django/docs/.svn/entries b/askbot/deps/recaptcha_django/docs/.svn/entries
new file mode 100644
index 00000000..08b3cefa
--- /dev/null
+++ b/askbot/deps/recaptcha_django/docs/.svn/entries
@@ -0,0 +1,40 @@
+8
+
+dir
+6
+http://recaptcha-django.googlecode.com/svn/trunk/docs
+http://recaptcha-django.googlecode.com/svn
+
+
+
+2008-12-14T15:07:18.967792Z
+2
+xdissent
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+af963488-c9ea-11dd-a8b6-f5aca7b582bb
+
+overview.txt
+file
+
+
+
+
+2010-06-13T21:04:19.000000Z
+c99e6eadb3fe754f0fdfd181b80ffbe4
+2008-12-14T15:07:18.967792Z
+2
+xdissent
+
diff --git a/askbot/deps/recaptcha_django/docs/.svn/format b/askbot/deps/recaptcha_django/docs/.svn/format
new file mode 100644
index 00000000..45a4fb75
--- /dev/null
+++ b/askbot/deps/recaptcha_django/docs/.svn/format
@@ -0,0 +1 @@
+8
diff --git a/askbot/deps/recaptcha_django/docs/.svn/text-base/overview.txt.svn-base b/askbot/deps/recaptcha_django/docs/.svn/text-base/overview.txt.svn-base
new file mode 100644
index 00000000..7af69d72
--- /dev/null
+++ b/askbot/deps/recaptcha_django/docs/.svn/text-base/overview.txt.svn-base
@@ -0,0 +1 @@
+TODO: add docs
diff --git a/askbot/deps/recaptcha_django/docs/overview.txt b/askbot/deps/recaptcha_django/docs/overview.txt
new file mode 100644
index 00000000..7af69d72
--- /dev/null
+++ b/askbot/deps/recaptcha_django/docs/overview.txt
@@ -0,0 +1 @@
+TODO: add docs
diff --git a/askbot/deps/recaptcha_django/middleware.py b/askbot/deps/recaptcha_django/middleware.py
new file mode 100644
index 00000000..4d592e63
--- /dev/null
+++ b/askbot/deps/recaptcha_django/middleware.py
@@ -0,0 +1,12 @@
+class ReCaptchaMiddleware(object):
+ """
+ A tiny middleware to automatically add IP address to ReCaptcha
+ POST requests
+ """
+ def process_request(self, request):
+ if request.method == 'POST' and \
+ 'recaptcha_challenge_field' in request.POST and \
+ 'recaptcha_ip_field' not in request.POST:
+ data = request.POST.copy()
+ data['recaptcha_ip_field'] = request.META['REMOTE_ADDR']
+ request.POST = data
diff --git a/forum/documentation/HOW_TO_DEBUG b/askbot/doc/HOW_TO_DEBUG
index fbbdb1f7..fbbdb1f7 100644
--- a/forum/documentation/HOW_TO_DEBUG
+++ b/askbot/doc/HOW_TO_DEBUG
diff --git a/forum/documentation/INSTALL b/askbot/doc/INSTALL
index 73714566..4589e1ba 100644
--- a/forum/documentation/INSTALL
+++ b/askbot/doc/INSTALL
@@ -1,7 +1,7 @@
CONTENTS
------------------
-A. PREREQUISITES
-B. INSTALLATION
+A. INSTALLATION
+B. DEPLOYMENT
1. Settings file
2. Database
3. Running Askbot in the development server
@@ -14,66 +14,69 @@ 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.
+A. INSTALLATION
+
+NOTE: if you need to install in non-standard locations
+please take a look here: http://askbot.org/wiki/index.php/Installing_software_components_at_non-standard_locations
+
+type
+
+> python setup.py install
+
+or
+
+> easy_install askbot
+
+then, if you need to start a new deployment, type
+
+> startforum
+
+Please read a few paragraphs of the following section on
+how to initialize the application
-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
+ATTENTION WINDOWS USERS: you will need to manually install
+binary for mysql-python from here
+http://www.codegood.com/archives/4
-1. Python2.5/2.6, Django v1.1.1
+B. DEPLOYMENT
-1A If you are using MySQL, mysql client for python must be installed
-[sudo] easy_install mysql-python
+if you are adding askbot to your existing project that already
+has other apps, you'll need to "merge" some of the files in
+directory askbot/install_templates into your corresponding project files
+more instuctions about this are to follow soon - if you have questions
+ask on the forum
-2. Python-openid v2.2
-http://openidenabled.com/python-openid/
-[sudo] easy_install python-openid
+for new deployment
+> startforum
-4. html5lib
-http://code.google.com/p/html5lib/
-Used for HTML sanitizer
-[sudo] easy_install html5lib
+and answer questions in the end you should be able to get almost
+working installation, you'll need to edit file settings.py
+and at least enter database name, user name and password
-5. Markdown2
-http://code.google.com/p/python-markdown2/
-[sudo] easy_install markdown2
+then type
-6. Django Debug Toolbar
-http://github.com/robhudson/django-debug-toolbar/tree/master
+> python manage.py syncdb
+> python manage.py migrate forum
-7. djangosphinx (optional - for full text questions+answer+tag)
-http://github.com/dcramer/django-sphinx/tree/master/djangosphinx
+now run:
-8. sphinx search engine (optional, works together with djangosphinx)
-http://sphinxsearch.com/downloads.html
+> python manage.py runserver `hostname -i`:8000 #or use some other port
+
+command `hostname -i` returns IP address on Unix, you can type the IP by hand too
+
+
+
+
+
+
+NOTES BELOW ARE OUTDATED, but may be useful
+if you have questions - please ask at http://askbot.org
-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
@@ -254,14 +257,16 @@ WSGIPythonEggs /var/python/eggs #must be readable and writable by apache
and uncomment #'djangosphinx',
-6. Email subscriptions
+6. Email subsctiptions and badge awards
+
+ copy file forum/cron/askbot_cron_job
+ somewhere in your user space (outside of forum)
+ edit paths in that file
- This function at the moment requires Django 1.1
+ set up a cron job to call it say hourly
- 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
+ the commands within askbot_cron_job can also be called manually
+ from the command line for the testing purposes
7. Sitemap
Sitemap will be available at /<settings_local.FORUM_SCRIPT_ALIAS>sitemap.xml
diff --git a/forum/documentation/INSTALL.pip b/askbot/doc/INSTALL.pip
index 2f817ff8..2f817ff8 100644
--- a/forum/documentation/INSTALL.pip
+++ b/askbot/doc/INSTALL.pip
diff --git a/forum/documentation/INSTALL.webfaction b/askbot/doc/INSTALL.webfaction
index a449ffe6..a449ffe6 100644
--- a/forum/documentation/INSTALL.webfaction
+++ b/askbot/doc/INSTALL.webfaction
diff --git a/forum/documentation/ROADMAP.rst b/askbot/doc/ROADMAP.rst
index c79e0ae4..c79e0ae4 100644
--- a/forum/documentation/ROADMAP.rst
+++ b/askbot/doc/ROADMAP.rst
diff --git a/forum/documentation/TODO.rst b/askbot/doc/TODO.rst
index b89013b0..b89013b0 100644
--- a/forum/documentation/TODO.rst
+++ b/askbot/doc/TODO.rst
diff --git a/forum/documentation/UPGRADE b/askbot/doc/UPGRADE
index 538b75a0..538b75a0 100644
--- a/forum/documentation/UPGRADE
+++ b/askbot/doc/UPGRADE
diff --git a/forum/documentation/WISH_LIST b/askbot/doc/WISH_LIST
index 2b53662c..2b53662c 100644
--- a/forum/documentation/WISH_LIST
+++ b/askbot/doc/WISH_LIST
diff --git a/forum/documentation/askbot-requirements.txt b/askbot/doc/askbot-requirements.txt
index 66a37fbe..66a37fbe 100644
--- a/forum/documentation/askbot-requirements.txt
+++ b/askbot/doc/askbot-requirements.txt
diff --git a/forum/documentation/scratch b/askbot/doc/scratch
index ca4e67e9..948055fa 100644
--- a/forum/documentation/scratch
+++ b/askbot/doc/scratch
@@ -5,3 +5,8 @@ Name duplicates previous WSGI daemon definition
different keys - empty space counts for translation keys
{% blocktrans %}page number {{num}} {% endblocktrans %}
{% blocktrans %}page number {{num}}{% endblocktrans %}
+
+for admin interface downloaded two packages:
+django-keyedcache
+django-livesettings
+from http://bitbucket.org/bkroeze/
diff --git a/askbot/feed.py b/askbot/feed.py
new file mode 100644
index 00000000..a204b98d
--- /dev/null
+++ b/askbot/feed.py
@@ -0,0 +1,63 @@
+"""
+#-------------------------------------------------------------------------------
+# Name: Syndication feed class for subscription
+# Purpose:
+#
+# Author: Mike
+#
+# Created: 29/01/2009
+# Copyright: (c) CNPROG.COM 2009
+# Licence: GPL V2
+#-------------------------------------------------------------------------------
+"""
+#!/usr/bin/env python
+#encoding:utf-8
+from django.contrib.syndication.feeds import Feed, FeedDoesNotExist
+from django.utils.translation import ugettext as _
+from askbot.models import Question
+from askbot.conf import settings as askbot_settings
+class RssLastestQuestionsFeed(Feed):
+ """rss feed class for the latest questions
+ """
+ title = askbot_settings.APP_TITLE + _(' - ')+ _('latest questions')
+ link = askbot_settings.APP_URL
+ description = askbot_settings.APP_DESCRIPTION
+ #ttl = 10
+ copyright = askbot_settings.APP_COPYRIGHT
+
+ def item_link(self, item):
+ """get full url to the item
+ """
+ return self.link + item.get_absolute_url()
+
+ def item_author_name(self, item):
+ """get name of author
+ """
+ return item.author.username
+
+ def item_author_link(self, item):
+ """get url of the author's profile
+ """
+ return item.author.get_profile_url()
+
+ def item_pubdate(self, item):
+ """get date of creation for the item
+ """
+ return item.added_at
+
+ def items(self, item):
+ """get questions for the feed
+ """
+ return Question.objects.filter(
+ deleted=False
+ ).order_by(
+ '-last_activity_at'
+ )[:30]
+
+def main():
+ """main function for use as a script
+ """
+ pass
+
+if __name__ == '__main__':
+ main()
diff --git a/forum/forms.py b/askbot/forms.py
index e9781dc9..7c35126e 100755..100644
--- a/forum/forms.py
+++ b/askbot/forms.py
@@ -1,16 +1,14 @@
import re
-from datetime import date
from django import forms
-from models import *
-from const import * #todo: clean out import * thing
-from forum import const
+from askbot import models
+from askbot 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
-from recaptcha_django import ReCaptchaField
-from django.conf import settings
+from askbot.utils.forms import NextUrlField, UserNameField
+from askbot.deps.recaptcha_django import ReCaptchaField
+from askbot.conf import settings as askbot_settings
import logging
@@ -18,7 +16,9 @@ class TitleField(forms.CharField):
def __init__(self, *args, **kwargs):
super(TitleField, self).__init__(*args, **kwargs)
self.required = True
- self.widget = forms.TextInput(attrs={'size' : 70, 'autocomplete' : 'off'})
+ self.widget = forms.TextInput(
+ attrs={'size' : 70, 'autocomplete' : 'off'}
+ )
self.max_length = 255
self.label = _('title')
self.help_text = _('please enter a descriptive title for your question')
@@ -65,15 +65,16 @@ class TagNamesField(forms.CharField):
tag_strings = split_re.split(data)
out_tag_list = []
tag_count = len(tag_strings)
- if tag_count > const.MAX_TAGS_PER_POST:
+ if tag_count > askbot_settings.MAX_TAGS_PER_POST:
+ max_tags = askbot_settings.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 tag or less',
'please use %(tag_count)d tags or less',
- tag_count) % {'tag_count':tag_count}
+ tag_count) % {'tag_count':max_tags}
raise forms.ValidationError(msg)
for tag in tag_strings:
tag_length = len(tag)
- if tag_length > const.MAX_TAG_LENGTH:
+ if tag_length > askbot_settings.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
@@ -96,8 +97,8 @@ class WikiField(forms.BooleanField):
self.required = False
self.label = _('community wiki')
self.help_text = _('if you choose community wiki option, the question and answer do not generate points and name of author will not be shown')
- def clean(self,value):
- return value and settings.WIKI_ON
+ def clean(self, value):
+ return value and askbot_settings.WIKI_ON
class EmailNotifyField(forms.BooleanField):
def __init__(self, *args, **kwargs):
@@ -137,7 +138,7 @@ class AdvancedSearchForm(forms.Form):
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)
+ tags = forms.CharField(max_length=256, required=False)
author = forms.IntegerField(required=False)
page_size = forms.ChoiceField(choices=const.PAGE_SIZE_CHOICES, required=False)
page = forms.IntegerField(required=False)
@@ -145,7 +146,7 @@ class AdvancedSearchForm(forms.Form):
def clean_tags(self):
if 'tags' in self.cleaned_data:
tags_input = self.cleaned_data['tags'].strip()
- split_re = re.compile(TAG_SPLIT_REGEX)
+ split_re = re.compile(const.TAG_SPLIT_REGEX)
tag_strings = split_re.split(tags_input)
tagname_re = re.compile(const.TAG_REGEX, re.UNICODE)
out = set()
@@ -230,8 +231,8 @@ class AnswerForm(forms.Form):
email_notify = EmailNotifyField()
def __init__(self, question, user, *args, **kwargs):
super(AnswerForm, self).__init__(*args, **kwargs)
- self.fields['email_notify'].widget.attrs['id'] = 'question-subscribe-updates';
- if question.wiki and settings.WIKI_ON:
+ self.fields['email_notify'].widget.attrs['id'] = 'question-subscribe-updates'
+ if question.wiki and askbot_settings.WIKI_ON:
self.fields['wiki'].initial = True
if user.is_authenticated():
if user in question.followed_by.all():
@@ -241,7 +242,7 @@ class AnswerForm(forms.Form):
class CloseForm(forms.Form):
- reason = forms.ChoiceField(choices=CLOSE_REASONS)
+ reason = forms.ChoiceField(choices=const.CLOSE_REASONS)
class RetagQuestionForm(forms.Form):
tags = TagNamesField()
@@ -292,7 +293,7 @@ class EditAnswerForm(forms.Form):
class EditUserForm(forms.Form):
email = forms.EmailField(label=u'Email', help_text=_('this email does not have to be linked to gravatar'), required=True, max_length=255, widget=forms.TextInput(attrs={'size' : 35}))
- if settings.EDITABLE_SCREEN_NAME:
+ if askbot_settings.EDITABLE_SCREEN_NAME:
username = UserNameField(label=_('Screen name'))
realname = forms.CharField(label=_('Real name'), required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35}))
website = forms.URLField(label=_('Website'), required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35}))
@@ -303,7 +304,7 @@ class EditUserForm(forms.Form):
def __init__(self, user, *args, **kwargs):
super(EditUserForm, self).__init__(*args, **kwargs)
logging.debug('initializing the form')
- if settings.EDITABLE_SCREEN_NAME:
+ if askbot_settings.EDITABLE_SCREEN_NAME:
self.fields['username'].initial = user.username
self.fields['username'].user_instance = user
self.fields['email'].initial = user.email
@@ -322,10 +323,10 @@ class EditUserForm(forms.Form):
"""For security reason one unique email in database"""
if self.user.email != self.cleaned_data['email']:
#todo dry it, there is a similar thing in openidauth
- if settings.EMAIL_UNIQUE == True:
+ if askbot_settings.EMAIL_UNIQUE == True:
if 'email' in self.cleaned_data:
try:
- user = User.objects.get(email = self.cleaned_data['email'])
+ User.objects.get(email = self.cleaned_data['email'])
except User.DoesNotExist:
return self.cleaned_data['email']
except User.MultipleObjectsReturned:
@@ -334,7 +335,7 @@ class EditUserForm(forms.Form):
return self.cleaned_data['email']
class TagFilterSelectionForm(forms.ModelForm):
- tag_filter_setting = forms.ChoiceField(choices=TAG_EMAIL_FILTER_CHOICES, #imported from forum/const.py
+ tag_filter_setting = forms.ChoiceField(choices=const.TAG_EMAIL_FILTER_CHOICES,
initial='ignored',
label=_('Choose email tag filter'),
widget=forms.RadioSelect)
@@ -351,38 +352,50 @@ class TagFilterSelectionForm(forms.ModelForm):
return False
+class EmailFeedSettingField(forms.ChoiceField):
+ def __init__(self, *arg, **kwarg):
+ kwarg['choices'] = const.NOTIFICATION_DELIVERY_SCHEDULE_CHOICES
+ kwarg['initial'] = askbot_settings.DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE
+ kwarg['widget'] = forms.RadioSelect
+ super(EmailFeedSettingField, self).__init__(*arg, **kwarg)
+
class EditUserEmailFeedsForm(forms.Form):
- WN = (('w',_('weekly')),('n',_('no email')))
- DWN = (('d',_('daily')),('w',_('weekly')),('n',_('no email')))
FORM_TO_MODEL_MAP = {
- 'all_questions':'q_all',
- 'asked_by_me':'q_ask',
- 'answered_by_me':'q_ans',
- 'individually_selected':'q_sel',
+ 'all_questions':'q_all',
+ 'asked_by_me':'q_ask',
+ 'answered_by_me':'q_ans',
+ 'individually_selected':'q_sel',
+ 'mentions_and_comments':'m_and_c',
}
NO_EMAIL_INITIAL = {
- 'all_questions':'n',
- 'asked_by_me':'n',
- 'answered_by_me':'n',
- 'individually_selected':'n',
+ 'all_questions':'n',
+ 'asked_by_me':'n',
+ 'answered_by_me':'n',
+ 'individually_selected':'n',
+ 'mentions_and_comments':'n',
}
- asked_by_me = forms.ChoiceField(choices=DWN,initial='w',
- widget=forms.RadioSelect,
- label=_('Asked by me'))
- answered_by_me = forms.ChoiceField(choices=DWN,initial='w',
- widget=forms.RadioSelect,
- label=_('Answered by me'))
- individually_selected = forms.ChoiceField(choices=DWN,initial='w',
- widget=forms.RadioSelect,
- label=_('Individually selected'))
- all_questions = forms.ChoiceField(choices=DWN,initial='w',
- widget=forms.RadioSelect,
- label=_('Entire forum (tag filtered)'),)
-
- def set_initial_values(self,user=None):
- KEY_MAP = dict([(v,k) for k,v in self.FORM_TO_MODEL_MAP.iteritems()])
+
+ asked_by_me = EmailFeedSettingField(
+ label=_('Asked by me')
+ )
+ answered_by_me = EmailFeedSettingField(
+ label=_('Answered by me')
+ )
+ individually_selected = EmailFeedSettingField(
+ label=_('Individually selected')
+ )
+ all_questions = EmailFeedSettingField(
+ label=_('Entire forum (tag filtered)'),
+ )
+
+ mentions_and_comments = EmailFeedSettingField(
+ label=_('Comments and posts mentioning me'),
+ )
+
+ def set_initial_values(self, user=None):
+ KEY_MAP = dict([(v, k) for k, v in self.FORM_TO_MODEL_MAP.iteritems()])
if user != None:
- settings = EmailFeedSetting.objects.filter(subscriber=user)
+ settings = models.EmailFeedSetting.objects.filter(subscriber=user)
initial_values = {}
for setting in settings:
feed_type = setting.feed_type
@@ -398,6 +411,7 @@ class EditUserEmailFeedsForm(forms.Form):
self.cleaned_data['asked_by_me'] = 'n'
self.cleaned_data['answered_by_me'] = 'n'
self.cleaned_data['individually_selected'] = 'n'
+ self.cleaned_data['mentions_and_comments'] = 'n'
self.initial = self.NO_EMAIL_INITIAL
return self
@@ -407,8 +421,10 @@ class EditUserEmailFeedsForm(forms.Form):
"""
changed = False
for form_field, feed_type in self.FORM_TO_MODEL_MAP.items():
- s, created = EmailFeedSetting.objects.get_or_create(subscriber=user,\
- feed_type=feed_type)
+ s, created = models.EmailFeedSetting.objects.get_or_create(
+ subscriber=user,
+ feed_type=feed_type
+ )
if save_unbound:
#just save initial values instead
if form_field in self.initial:
@@ -425,7 +441,7 @@ class EditUserEmailFeedsForm(forms.Form):
if created:
s.save()
if form_field == 'individually_selected':
- feed_type = ContentType.objects.get_for_model(Question)
+ feed_type = ContentType.objects.get_for_model(models.Question)
user.followed_questions.clear()
return changed
@@ -434,15 +450,17 @@ class SimpleEmailSubscribeForm(forms.Form):
('y',_('okay, let\'s try!')),
('n',_('no community email please, thanks'))
)
- subscribe = forms.ChoiceField(widget=forms.widgets.RadioSelect(), \
- error_messages={'required':_('please choose one of the options above')},
- choices=SIMPLE_SUBSCRIBE_CHOICES)
+ subscribe = forms.ChoiceField(
+ widget=forms.widgets.RadioSelect,
+ error_messages={'required':_('please choose one of the options above')},
+ choices=SIMPLE_SUBSCRIBE_CHOICES
+ )
- def save(self,user=None):
+ def save(self, user=None):
EFF = EditUserEmailFeedsForm
if self.cleaned_data['subscribe'] == 'y':
email_settings_form = EFF()
logging.debug('%s wants to subscribe' % user.username)
else:
email_settings_form = EFF(initial=EFF.NO_EMAIL_INITIAL)
- email_settings_form.save(user,save_unbound=True)
+ email_settings_form.save(user, save_unbound=True)
diff --git a/forum/importers/stackexchange/__init__.py b/askbot/importers/__init__.py
index e69de29b..e69de29b 100644
--- a/forum/importers/stackexchange/__init__.py
+++ b/askbot/importers/__init__.py
diff --git a/forum/importers/stackexchange/ANOMALIES b/askbot/importers/stackexchange/ANOMALIES
index 05a7dbdb..05a7dbdb 100644
--- a/forum/importers/stackexchange/ANOMALIES
+++ b/askbot/importers/stackexchange/ANOMALIES
diff --git a/forum/importers/stackexchange/README b/askbot/importers/stackexchange/README
index 598a8555..598a8555 100644
--- a/forum/importers/stackexchange/README
+++ b/askbot/importers/stackexchange/README
diff --git a/forum/importers/stackexchange/management/__init__.py b/askbot/importers/stackexchange/__init__.py
index e69de29b..e69de29b 100644
--- a/forum/importers/stackexchange/management/__init__.py
+++ b/askbot/importers/stackexchange/__init__.py
diff --git a/forum/importers/stackexchange/management/commands/__init__.py b/askbot/importers/stackexchange/management/__init__.py
index e69de29b..e69de29b 100644
--- a/forum/importers/stackexchange/management/commands/__init__.py
+++ b/askbot/importers/stackexchange/management/__init__.py
diff --git a/forum/management/commands/__init__.py b/askbot/importers/stackexchange/management/commands/__init__.py
index e69de29b..e69de29b 100755..100644
--- a/forum/management/commands/__init__.py
+++ b/askbot/importers/stackexchange/management/commands/__init__.py
diff --git a/forum/importers/stackexchange/management/commands/load_stackexchange.py b/askbot/importers/stackexchange/management/commands/load_stackexchange.py
index ee22e33a..031a2d79 100644
--- a/forum/importers/stackexchange/management/commands/load_stackexchange.py
+++ b/askbot/importers/stackexchange/management/commands/load_stackexchange.py
@@ -4,14 +4,14 @@ from django.template.defaultfilters import slugify #todo: adopt unicode-aware sl
import os
import re
import sys
-import forum.importers.stackexchange.parse_models as se_parser
+import askbot.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
+import askbot.models as askbot
+import askbot.deps.django_authopenid.models as askbot_openid
+import askbot.importers.stackexchange.models as se
+from askbot.forms import EditUserEmailFeedsForm
+from askbot.conf import settings as askbot_settings
from django.contrib.auth.models import Message as DjangoMessage
from django.utils.translation import ugettext as _
#from markdown2 import Markdown
@@ -209,7 +209,7 @@ class X(object):#
@classmethod
def get_email(cls, email):#todo: fix fringe case - user did not give email!
if email is None:
- return settings.ANONYMOUS_USER_EMAIL
+ return askbot_settings.ANONYMOUS_USER_EMAIL
else:
assert(email != '')
return email
@@ -741,10 +741,9 @@ class Command(BaseCommand):
#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
+ u_openid = askbot_openid.UserAssociation()
+ u_openid.openid_url = se_u.open_id
+ u_openid.user = u
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)'
@@ -797,8 +796,4 @@ class Command(BaseCommand):
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/askbot/importers/stackexchange/models.py
index a30a9859..a30a9859 100644
--- a/forum/importers/stackexchange/models.py
+++ b/askbot/importers/stackexchange/models.py
diff --git a/forum/importers/stackexchange/parse_models.py b/askbot/importers/stackexchange/parse_models.py
index 64796e57..64796e57 100644
--- a/forum/importers/stackexchange/parse_models.py
+++ b/askbot/importers/stackexchange/parse_models.py
diff --git a/locale/de/LC_MESSAGES/django.mo b/askbot/locale/de/LC_MESSAGES/django.mo
index fd451a6d..fd451a6d 100644
--- a/locale/de/LC_MESSAGES/django.mo
+++ b/askbot/locale/de/LC_MESSAGES/django.mo
Binary files differ
diff --git a/locale/de/LC_MESSAGES/django.po b/askbot/locale/de/LC_MESSAGES/django.po
index b5de1030..b5de1030 100644
--- a/locale/de/LC_MESSAGES/django.po
+++ b/askbot/locale/de/LC_MESSAGES/django.po
diff --git a/askbot/locale/en/LC_MESSAGES/django.mo b/askbot/locale/en/LC_MESSAGES/django.mo
new file mode 100644
index 00000000..eacc102a
--- /dev/null
+++ b/askbot/locale/en/LC_MESSAGES/django.mo
Binary files differ
diff --git a/locale/en/LC_MESSAGES/django.po b/askbot/locale/en/LC_MESSAGES/django.po
index 5fd49fbb..3da33966 100644
--- a/locale/en/LC_MESSAGES/django.po
+++ b/askbot/locale/en/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-05-09 19:39-0400\n"
+"POT-Creation-Date: 2010-06-03 18:48-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Evgeny Fadeev <evgeny.fadeev@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,77 +16,77 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: django_authopenid/forms.py:71 django_authopenid/views.py:132
+#: django_authopenid/forms.py:72 django_authopenid/views.py:134
msgid "i-names are not supported"
msgstr ""
-#: django_authopenid/forms.py:134
+#: django_authopenid/forms.py:135
msgid "Account with this name already exists on the forum"
msgstr ""
-#: django_authopenid/forms.py:135
+#: django_authopenid/forms.py:136
msgid "can't have two logins to the same account yet, sorry."
msgstr ""
-#: django_authopenid/forms.py:157
+#: django_authopenid/forms.py:158
msgid "Please enter valid username and password (both are case-sensitive)."
msgstr ""
-#: django_authopenid/forms.py:160 django_authopenid/forms.py:210
+#: django_authopenid/forms.py:161 django_authopenid/forms.py:211
msgid "This account is inactive."
msgstr ""
-#: django_authopenid/forms.py:162
+#: django_authopenid/forms.py:163
msgid "Login failed."
msgstr ""
-#: django_authopenid/forms.py:164
+#: django_authopenid/forms.py:165
msgid "Please enter username and password"
msgstr ""
-#: django_authopenid/forms.py:166
+#: django_authopenid/forms.py:167
msgid "Please enter your password"
msgstr ""
-#: django_authopenid/forms.py:168
+#: django_authopenid/forms.py:169
msgid "Please enter user name"
msgstr ""
-#: django_authopenid/forms.py:206
+#: django_authopenid/forms.py:207
msgid ""
"Please enter a valid username and password. Note that "
"both fields are case-sensitive."
msgstr ""
-#: django_authopenid/forms.py:229
+#: django_authopenid/forms.py:230
msgid "Current password"
msgstr ""
-#: django_authopenid/forms.py:240
+#: django_authopenid/forms.py:241
msgid ""
"Old password is incorrect. Please enter the correct "
"password."
msgstr ""
-#: django_authopenid/forms.py:305
+#: django_authopenid/forms.py:306
msgid "Your user name (<i>required</i>)"
msgstr ""
-#: django_authopenid/forms.py:320
+#: django_authopenid/forms.py:321
msgid "Incorrect username."
msgstr "sorry, there is no such user name"
#: django_authopenid/urls.py:23 django_authopenid/urls.py:24
#: django_authopenid/urls.py:25 django_authopenid/urls.py:27
-#: fbconnect/urls.py:12 fbconnect/urls.py:13 fbconnect/urls.py:14
+#: fbconnect/urls.py:14 fbconnect/urls.py:15 fbconnect/urls.py:16
msgid "signin/"
msgstr ""
-#: django_authopenid/urls.py:24 fbconnect/urls.py:13 fbconnect/urls.py:17
+#: django_authopenid/urls.py:24 fbconnect/urls.py:15 fbconnect/urls.py:19
msgid "newquestion/"
msgstr ""
-#: django_authopenid/urls.py:25 fbconnect/urls.py:14 fbconnect/urls.py:18
+#: django_authopenid/urls.py:25 fbconnect/urls.py:16 fbconnect/urls.py:20
msgid "newanswer/"
msgstr ""
@@ -98,8 +98,8 @@ msgstr ""
msgid "complete/"
msgstr ""
-#: django_authopenid/urls.py:29 fbconnect/urls.py:16 fbconnect/urls.py:17
-#: fbconnect/urls.py:18
+#: django_authopenid/urls.py:29 fbconnect/urls.py:18 fbconnect/urls.py:19
+#: fbconnect/urls.py:20
msgid "register/"
msgstr ""
@@ -144,7 +144,7 @@ msgstr ""
msgid "openid/"
msgstr ""
-#: django_authopenid/urls.py:43 forum/urls.py:52 forum/urls.py:56
+#: django_authopenid/urls.py:43 forum/urls.py:113 forum/urls.py:120
msgid "delete/"
msgstr ""
@@ -156,628 +156,1143 @@ msgstr ""
msgid "external-login/signup/"
msgstr ""
-#: django_authopenid/views.py:139
+#: django_authopenid/views.py:141
#, python-format
msgid "OpenID %(openid_url)s is invalid"
msgstr ""
-#: django_authopenid/views.py:614
+#: django_authopenid/views.py:616
msgid "Welcome email subject line"
msgstr "Welcome to the Q&A forum"
-#: django_authopenid/views.py:720
+#: django_authopenid/views.py:722
msgid "Password changed."
msgstr ""
-#: django_authopenid/views.py:732 django_authopenid/views.py:738
+#: django_authopenid/views.py:734 django_authopenid/views.py:740
#, python-format
msgid "your email needs to be validated see %(details_url)s"
msgstr ""
"Your email needs to be validated. Please see details <a "
"id='validate_email_alert' href='%(details_url)s'>here</a>."
-#: django_authopenid/views.py:759
+#: django_authopenid/views.py:761
msgid "Email verification subject line"
msgstr "Verification Email from Q&A forum"
-#: django_authopenid/views.py:850
+#: django_authopenid/views.py:852
msgid "your email was not changed"
msgstr ""
-#: django_authopenid/views.py:898 django_authopenid/views.py:1056
+#: django_authopenid/views.py:900 django_authopenid/views.py:1058
#, python-format
msgid "No OpenID %s found associated in our database"
msgstr ""
-#: django_authopenid/views.py:902 django_authopenid/views.py:1063
+#: django_authopenid/views.py:904 django_authopenid/views.py:1065
#, python-format
msgid "The OpenID %s isn't associated to current user logged in"
msgstr ""
-#: django_authopenid/views.py:910
+#: django_authopenid/views.py:912
msgid "Email Changed."
msgstr ""
-#: django_authopenid/views.py:988
+#: django_authopenid/views.py:990
msgid "This OpenID is already associated with another account."
msgstr ""
-#: django_authopenid/views.py:993
+#: django_authopenid/views.py:995
#, python-format
msgid "OpenID %s is now associated with your account."
msgstr ""
-#: django_authopenid/views.py:1066
+#: django_authopenid/views.py:1068
msgid "Account deleted."
msgstr ""
-#: django_authopenid/views.py:1118
+#: django_authopenid/views.py:1120
msgid "Request for new password"
msgstr ""
-#: django_authopenid/views.py:1132
+#: django_authopenid/views.py:1134
msgid "A new password and the activation link were sent to your email address."
msgstr ""
-#: django_authopenid/views.py:1164
+#: django_authopenid/views.py:1166
#, python-format
msgid ""
"Could not change password. Confirmation key '%s' is not "
"registered."
msgstr ""
-#: django_authopenid/views.py:1174
+#: django_authopenid/views.py:1176
msgid ""
"Can not change password. User don't exist anymore in our "
"database."
msgstr ""
-#: django_authopenid/views.py:1184
+#: django_authopenid/views.py:1186
#, python-format
msgid "Password changed for %s. You may now sign in."
msgstr ""
-#: forum/auth.py:505
+#: forum/auth.py:528
msgid "Your question and all of it's answers have been deleted"
msgstr ""
-#: forum/auth.py:507
+#: forum/auth.py:531
msgid "Your question has been deleted"
msgstr ""
-#: forum/auth.py:510
+#: forum/auth.py:535
msgid "The question and all of it's answers have been deleted"
msgstr ""
-#: forum/auth.py:512
+#: forum/auth.py:538
msgid "The question has been deleted"
msgstr ""
-#: forum/const.py:8
-msgid "duplicate question"
+#: forum/feed.py:22
+msgid " - "
msgstr ""
-#: forum/const.py:9
-msgid "question is off-topic or not relevant"
+#: forum/feed.py:22
+msgid "latest questions"
msgstr ""
-#: forum/const.py:10
-msgid "too subjective and argumentative"
+#: forum/forms.py:23 forum/skins/default/templates/answer_edit_tips.html:35
+#: forum/skins/default/templates/answer_edit_tips.html:39
+#: forum/skins/default/templates/question_edit_tips.html:32
+#: forum/skins/default/templates/question_edit_tips.html:37
+msgid "title"
msgstr ""
-#: forum/const.py:11
-msgid "not a real question"
+#: forum/forms.py:24
+msgid "please enter a descriptive title for your question"
msgstr ""
-#: forum/const.py:12
-msgid "the question is answered, right answer was accepted"
+#: forum/forms.py:29
+msgid "title must be > 10 characters"
msgstr ""
-#: forum/const.py:13
-msgid "question is not relevant or outdated"
+#: forum/forms.py:38
+msgid "content"
msgstr ""
-#: forum/const.py:14
-msgid "question contains offensive or malicious remarks"
+#: forum/forms.py:44
+msgid "question content must be > 10 characters"
msgstr ""
-#: forum/const.py:15
-msgid "spam or advertising"
+#: forum/forms.py:53 forum/skins/default/templates/header.html:28
+msgid "tags"
msgstr ""
-#: forum/const.py:16
-msgid "too localized"
+#: forum/forms.py:55
+msgid ""
+"Tags are short keywords, with no spaces within. Up to five tags can be used."
msgstr ""
-#: forum/const.py:37 forum/skins/default/templates/questions.html:70
-#: forum/skins/default/templates/questions.html:75
-msgid "newest"
+#: forum/forms.py:62 forum/skins/default/templates/question_retag.html:39
+msgid "tags are required"
msgstr ""
-#: forum/const.py:38 forum/skins/default/templates/questions.html:64
-#: forum/skins/default/templates/users.html:28
-msgid "oldest"
+#: forum/forms.py:71
+#, python-format
+msgid "please use %(tag_count)d tag or less"
+msgid_plural "please use %(tag_count)d tags or less"
+msgstr[0] ""
+msgstr[1] ""
+
+#: forum/forms.py:80
+#, python-format
+msgid "each tag must be shorter than %(max_chars)d character"
+msgid_plural "each tag must be shorter than %(max_chars)d characters"
+msgstr[0] ""
+msgstr[1] ""
+
+#: forum/forms.py:88
+msgid "use-these-chars-in-tags"
msgstr ""
-#: forum/const.py:39 forum/skins/default/templates/questions.html:89
-#: forum/skins/default/templates/questions.html:94
-msgid "active"
+#: forum/forms.py:98
+#: forum/skins/default/templates/post_contributor_info.html:7
+#: forum/skins/default/templates/question_summary_list_roll.html:26
+#: forum/skins/default/templates/question_summary_list_roll.html:38
+msgid "community wiki"
msgstr ""
-#: forum/const.py:40 forum/skins/default/templates/questions.html:83
-msgid "inactive"
+#: forum/forms.py:99
+msgid ""
+"if you choose community wiki option, the question and answer do not generate "
+"points and name of author will not be shown"
msgstr ""
-#: forum/const.py:41
-msgid "hottest"
+#: forum/forms.py:115
+msgid "update summary:"
msgstr ""
-#: forum/const.py:42
-msgid "coldest"
+#: forum/forms.py:116
+msgid ""
+"enter a brief summary of your revision (e.g. fixed spelling, grammar, "
+"improved style, this field is optional)"
msgstr ""
-#: forum/const.py:43
-msgid "most voted"
+#: forum/forms.py:119
+msgid "Automatically accept user's contributions for the email updates"
msgstr ""
-#: forum/const.py:44
-msgid "least voted"
+#: forum/forms.py:210
+msgid "Your name:"
msgstr ""
-#: forum/const.py:45
-msgid "relevance"
+#: forum/forms.py:211
+msgid "Email (not shared with anyone):"
msgstr ""
-#: forum/const.py:52 forum/skins/default/templates/questions.html:52
-msgid "all"
+#: forum/forms.py:212
+msgid "Your message:"
msgstr ""
-#: forum/const.py:53 forum/skins/default/templates/questions.html:53
-msgid "unanswered"
+#: forum/forms.py:295
+msgid "this email does not have to be linked to gravatar"
msgstr ""
-#: forum/const.py:54 forum/skins/default/templates/questions.html:55
-msgid "favorite"
+#: forum/forms.py:297
+msgid "Screen name"
msgstr ""
-#: forum/const.py:97
-msgid "question"
+#: forum/forms.py:298
+msgid "Real name"
msgstr ""
-#: forum/const.py:98 forum/skins/default/templates/book.html:110
-msgid "answer"
+#: forum/forms.py:299
+msgid "Website"
msgstr ""
-#: forum/const.py:99
-msgid "commented question"
+#: forum/forms.py:300
+msgid "Location"
msgstr ""
-#: forum/const.py:100
-msgid "commented answer"
+#: forum/forms.py:301
+msgid "Date of birth"
msgstr ""
-#: forum/const.py:101
-msgid "edited question"
+#: forum/forms.py:301
+msgid "will not be shown, used to calculate age, format: YYYY-MM-DD"
msgstr ""
-#: forum/const.py:102
-msgid "edited answer"
+#: forum/forms.py:302 forum/skins/default/templates/account_settings.html:21
+#: forum/skins/default/templates/authopenid/settings.html:21
+msgid "Profile"
msgstr ""
-#: forum/const.py:103
-msgid "received award"
-msgstr "received badge"
+#: forum/forms.py:333 forum/forms.py:334
+msgid "this email has already been registered, please use another one"
+msgstr ""
-#: forum/const.py:104
-msgid "marked best answer"
+#: forum/forms.py:340
+msgid "Choose email tag filter"
msgstr ""
-#: forum/const.py:105
-msgid "upvoted"
+#: forum/forms.py:379
+msgid "Asked by me"
msgstr ""
-#: forum/const.py:106
-msgid "downvoted"
+#: forum/forms.py:382
+msgid "Answered by me"
msgstr ""
-#: forum/const.py:107
-msgid "canceled vote"
+#: forum/forms.py:385
+msgid "Individually selected"
msgstr ""
-#: forum/const.py:108
-msgid "deleted question"
+#: forum/forms.py:388
+msgid "Entire forum (tag filtered)"
msgstr ""
-#: forum/const.py:109
-msgid "deleted answer"
+#: forum/forms.py:392
+msgid "Comments and posts mentioning me"
msgstr ""
-#: forum/const.py:110
-msgid "marked offensive"
+#: forum/forms.py:450
+msgid "okay, let's try!"
msgstr ""
-#: forum/const.py:111
-msgid "updated tags"
+#: forum/forms.py:451
+msgid "no community email please, thanks"
+msgstr "no askbot email please, thanks"
+
+#: forum/forms.py:455
+msgid "please choose one of the options above"
msgstr ""
-#: forum/const.py:112
-msgid "selected favorite"
+#: forum/urls.py:37
+msgid "upfiles/"
msgstr ""
-#: forum/const.py:113
-msgid "completed user profile"
+#: forum/urls.py:42
+msgid "about/"
msgstr ""
-#: forum/const.py:114
-msgid "email update sent to user"
+#: forum/urls.py:43 forum/conf/site_settings.py:75
+msgid "faq/"
msgstr ""
-#: forum/const.py:118
-msgid "question_answered"
-msgstr "answered question"
+#: forum/urls.py:44
+msgid "privacy/"
+msgstr ""
-#: forum/const.py:119
-msgid "question_commented"
-msgstr "commented question"
+#: forum/urls.py:45
+msgid "logout/"
+msgstr ""
-#: forum/const.py:120
-msgid "answer_commented"
+#: forum/urls.py:47 forum/urls.py:52 forum/urls.py:57 forum/urls.py:120
+msgid "answers/"
msgstr ""
-#: forum/const.py:121
-msgid "answer_accepted"
+#: forum/urls.py:47 forum/urls.py:102 forum/urls.py:113 forum/urls.py:120
+msgid "comments/"
msgstr ""
-#: forum/const.py:125
-msgid "[closed]"
+#: forum/urls.py:52 forum/urls.py:72 forum/urls.py:166
+#: forum/skins/default/templates/user_info.html:47
+msgid "edit/"
msgstr ""
-#: forum/const.py:126
-msgid "[deleted]"
+#: forum/urls.py:57 forum/urls.py:97
+msgid "revisions/"
msgstr ""
-#: forum/const.py:127 forum/views/readers.py:396 forum/views/readers.py:417
-msgid "initial version"
+#: forum/urls.py:62 forum/urls.py:67 forum/urls.py:72 forum/urls.py:77
+#: forum/urls.py:82 forum/urls.py:87 forum/urls.py:92 forum/urls.py:97
+#: forum/urls.py:102 forum/urls.py:113
+msgid "questions/"
msgstr ""
-#: forum/const.py:128
-msgid "retagged"
+#: forum/urls.py:67 forum_modules/books/urls.py:8
+msgid "ask/"
msgstr ""
-#: forum/const.py:132
-msgid "exclude ignored tags"
+#: forum/urls.py:77
+msgid "close/"
msgstr ""
-#: forum/const.py:132
-msgid "allow only selected tags"
+#: forum/urls.py:82
+msgid "reopen/"
msgstr ""
-#: forum/feed.py:18
-msgid " - "
+#: forum/urls.py:87
+msgid "answer/"
msgstr ""
-#: forum/feed.py:18
-msgid "latest questions"
+#: forum/urls.py:92
+msgid "vote/"
msgstr ""
-#: forum/forms.py:23 forum/skins/default/templates/answer_edit_tips.html:35
-#: forum/skins/default/templates/answer_edit_tips.html:39
-#: forum/skins/default/templates/question_edit_tips.html:32
-#: forum/skins/default/templates/question_edit_tips.html:37
-msgid "title"
+#: forum/urls.py:107
+msgid "command/"
msgstr ""
-#: forum/forms.py:24
-msgid "please enter a descriptive title for your question"
+#: forum/urls.py:127 forum/views/readers.py:256
+msgid "question/"
msgstr ""
-#: forum/forms.py:29
-msgid "title must be > 10 characters"
+#: forum/urls.py:132
+msgid "tags/"
msgstr ""
-#: forum/forms.py:38
-msgid "content"
+#: forum/urls.py:137 forum/urls.py:143
+msgid "mark-tag/"
msgstr ""
-#: forum/forms.py:44
-msgid "question content must be > 10 characters"
+#: forum/urls.py:137
+msgid "interesting/"
msgstr ""
-#: forum/forms.py:53 forum/skins/default/templates/header.html:28
-msgid "tags"
+#: forum/urls.py:143
+msgid "ignored/"
msgstr ""
-#: forum/forms.py:55
+#: forum/urls.py:149
+msgid "unmark-tag/"
+msgstr ""
+
+#: forum/urls.py:155 forum/urls.py:166 forum/urls.py:171
+msgid "users/"
+msgstr ""
+
+#: forum/urls.py:160
+msgid "moderate-user/"
+msgstr ""
+
+#: forum/urls.py:176 forum/urls.py:181
+msgid "badges/"
+msgstr ""
+
+#: forum/urls.py:186
+msgid "messages/"
+msgstr ""
+
+#: forum/urls.py:186
+msgid "markread/"
+msgstr ""
+
+#: forum/urls.py:197
+msgid "upload/"
+msgstr ""
+
+#: forum/urls.py:198
+msgid "search/"
+msgstr ""
+
+#: forum/urls.py:199
+msgid "feedback/"
+msgstr ""
+
+#: forum/urls.py:200
+msgid "account/"
+msgstr ""
+
+#: forum/conf/email.py:12
+msgid "Email and email alert settings"
+msgstr ""
+
+#: forum/conf/email.py:20
+msgid "Maximum number of news entries in an email alert"
+msgstr ""
+
+#: forum/conf/email.py:30
+msgid "Default news notification frequency"
+msgstr ""
+
+#: forum/conf/email.py:32
msgid ""
-"Tags are short keywords, with no spaces within. Up to five tags can be used."
+"This option currently defines default frequency of emailed updates in the "
+"following five categories: questions asked by user, answered by user, "
+"individually selected, entire forum (per person tag filter applies) and "
+"posts mentioning the user and comment responses"
msgstr ""
-#: forum/forms.py:62 forum/skins/default/templates/question_retag.html:39
-msgid "tags are required"
+#: forum/conf/email.py:47
+msgid "Require email verification before allowing to post"
+msgstr ""
+
+#: forum/conf/email.py:48
+msgid ""
+"Active email verification is done by sending a verification key in email"
+msgstr ""
+
+#: forum/conf/email.py:57
+msgid "Allow only one account per email address"
msgstr ""
-#: forum/forms.py:70
+#: forum/conf/email.py:66
+msgid "Fake email for anonymous user"
+msgstr ""
+
+#: forum/conf/email.py:67
+msgid "Use this setting to control gravatar for email-less user"
+msgstr ""
+
+#: forum/conf/external_keys.py:11
+msgid "Keys to connect the site with external services like Facebook, etc."
+msgstr ""
+
+#: forum/conf/external_keys.py:18
+msgid "Google site verification key"
+msgstr ""
+
+#: forum/conf/external_keys.py:20
#, python-format
-msgid "please use %(tag_count)d tag or less"
-msgid_plural "please use %(tag_count)d tags or less"
-msgstr[0] ""
-msgstr[1] ""
+msgid ""
+"This key helps google index your site please obtain is at <a href=\"%"
+"(google_webmasters_tools_url)s\">google webmasters tools site</a>"
+msgstr ""
+
+#: forum/conf/external_keys.py:34
+msgid "Google Analytics key"
+msgstr ""
-#: forum/forms.py:79
+#: forum/conf/external_keys.py:36
#, python-format
-msgid "each tag must be shorter than %(max_chars)d character"
-msgid_plural "each tag must be shorter than %(max_chars)d characters"
-msgstr[0] ""
-msgstr[1] ""
+msgid ""
+"Obtain is at <a href=\"%(ga_site)s\">Google Analytics</a> site, if you wish "
+"to use Google Analytics to monitor your site"
+msgstr ""
-#: forum/forms.py:87
-msgid "use-these-chars-in-tags"
+#: forum/conf/external_keys.py:49
+msgid "Recaptcha private key"
msgstr ""
-#: forum/forms.py:97
-#: forum/skins/default/templates/post_contributor_info.html:7
-#: forum/skins/default/templates/question_summary_list_roll.html:26
-#: forum/skins/default/templates/question_summary_list_roll.html:38
-msgid "community wiki"
+#: forum/conf/external_keys.py:52
+msgid ""
+"Recaptcha is a tool that helps distinguish real people from annoying spam "
+"robots. Please get this and a public key at the <a href=\"http://recaptcha."
+"net\">recaptcha.net</a>"
msgstr ""
-#: forum/forms.py:98
+#: forum/conf/external_keys.py:65
+msgid "Recaptcha public key"
+msgstr ""
+
+#: forum/conf/external_keys.py:73
+msgid "Facebook public API key"
+msgstr ""
+
+#: forum/conf/external_keys.py:76
msgid ""
-"if you choose community wiki option, the question and answer do not generate "
-"points and name of author will not be shown"
+"Facebook API key and Facebook secret allow to use Facebook Connect login "
+"method at your site. Please obtain these keys at <a href=\"http://www."
+"facebook.com/developers/createapp.php\">facebook create app</a> site"
msgstr ""
-#: forum/forms.py:114
-msgid "update summary:"
+#: forum/conf/external_keys.py:91
+msgid "Facebook secret key"
msgstr ""
-#: forum/forms.py:115
+#: forum/conf/flatpages.py:10
+msgid "Flatpages - about, privacy policy, etc."
+msgstr ""
+
+#: forum/conf/flatpages.py:17
+msgid "Text the Q&A forum About page (html format)"
+msgstr ""
+
+#: forum/conf/flatpages.py:20
msgid ""
-"enter a brief summary of your revision (e.g. fixed spelling, grammar, "
-"improved style, this field is optional)"
+"Save, then <a href=\"http://validator.w3.org/\">use HTML validator</a> on "
+"the \"about\" page to check your input."
msgstr ""
-#: forum/forms.py:118
-msgid "Automatically accept user's contributions for the email updates"
+#: forum/conf/flatpages.py:30
+msgid "Text the Q&A forum Privacy Policy (html format)"
msgstr ""
-#: forum/forms.py:209
-msgid "Your name:"
+#: forum/conf/flatpages.py:33
+msgid ""
+"Save, then <a href=\"http://validator.w3.org/\">use HTML validator</a> on "
+"the \"privacy\" page to check your input."
msgstr ""
-#: forum/forms.py:210
-msgid "Email (not shared with anyone):"
+#: forum/conf/forum_data_rules.py:12
+msgid "Settings for forum data entry and display"
msgstr ""
-#: forum/forms.py:211
-msgid "Your message:"
+#: forum/conf/forum_data_rules.py:20
+msgid "Check to enable community wiki feature"
msgstr ""
-#: forum/forms.py:294
-msgid "this email does not have to be linked to gravatar"
+#: forum/conf/forum_data_rules.py:29
+msgid "Maximum length of tag (number of characters)"
msgstr ""
-#: forum/forms.py:296
-msgid "Screen name"
+#: forum/conf/forum_data_rules.py:38
+msgid "Maximum number of tags per question"
msgstr ""
-#: forum/forms.py:297
-msgid "Real name"
+#: forum/conf/forum_data_rules.py:50
+msgid "Number of questions to list by default"
msgstr ""
-#: forum/forms.py:298
-msgid "Website"
+#: forum/conf/forum_data_rules.py:60
+msgid "What should \"unanswered question\" mean?"
msgstr ""
-#: forum/forms.py:299
-msgid "Location"
+#: forum/conf/minimum_reputation.py:11
+msgid "Minimum reputation required to perform actions"
msgstr ""
-#: forum/forms.py:300
-msgid "Date of birth"
+#: forum/conf/minimum_reputation.py:20
+msgid "Upvote"
msgstr ""
-#: forum/forms.py:300
-msgid "will not be shown, used to calculate age, format: YYYY-MM-DD"
+#: forum/conf/minimum_reputation.py:29
+msgid "Downvote"
msgstr ""
-#: forum/forms.py:301 forum/skins/default/templates/account_settings.html:21
-#: forum/skins/default/templates/authopenid/settings.html:21
-msgid "Profile"
+#: forum/conf/minimum_reputation.py:38
+msgid "Flag offensive"
msgstr ""
-#: forum/forms.py:332 forum/forms.py:333
-msgid "this email has already been registered, please use another one"
+#: forum/conf/minimum_reputation.py:47
+msgid "Leave comments"
msgstr ""
-#: forum/forms.py:339
-msgid "Choose email tag filter"
+#: forum/conf/minimum_reputation.py:56
+msgid "Delete comments posted by others"
msgstr ""
-#: forum/forms.py:355 forum/forms.py:356
-msgid "weekly"
+#: forum/conf/minimum_reputation.py:65
+msgid "Upload files"
msgstr ""
-#: forum/forms.py:355 forum/forms.py:356
-msgid "no email"
+#: forum/conf/minimum_reputation.py:74
+msgid "Close own questions"
msgstr ""
-#: forum/forms.py:356
-msgid "daily"
+#: forum/conf/minimum_reputation.py:83
+msgid "Retag questions posted by other people"
msgstr ""
-#: forum/forms.py:371
-msgid "Asked by me"
+#: forum/conf/minimum_reputation.py:92
+msgid "Reopen own questions"
msgstr ""
-#: forum/forms.py:374
-msgid "Answered by me"
+#: forum/conf/minimum_reputation.py:101
+msgid "Edit community wiki posts"
msgstr ""
-#: forum/forms.py:377
-msgid "Individually selected"
+#: forum/conf/minimum_reputation.py:110
+msgid "Edit posts authored by other people"
msgstr ""
-#: forum/forms.py:380
-msgid "Entire forum (tag filtered)"
+#: forum/conf/minimum_reputation.py:119
+msgid "View offensive flags"
msgstr ""
-#: forum/forms.py:434
-msgid "okay, let's try!"
+#: forum/conf/minimum_reputation.py:128
+msgid "Disable nofollow directive on links"
msgstr ""
-#: forum/forms.py:435
-msgid "no community email please, thanks"
-msgstr "no askbot email please, thanks"
+#: forum/conf/minimum_reputation.py:137
+msgid "Close questions asked by others"
+msgstr ""
-#: forum/forms.py:438
-msgid "please choose one of the options above"
+#: forum/conf/minimum_reputation.py:146
+msgid "Lock posts"
msgstr ""
-#: forum/urls.py:28
-msgid "upfiles/"
+#: forum/conf/reputation_changes.py:12
+msgid "Reputaion loss and gain rules"
msgstr ""
-#: forum/urls.py:33
-msgid "about/"
+#: forum/conf/reputation_changes.py:21
+msgid "Maximum daily reputation gain per user"
msgstr ""
-#: forum/urls.py:34
-msgid "faq/"
+#: forum/conf/reputation_changes.py:30
+msgid "Gain for receiving an upvote"
msgstr ""
-#: forum/urls.py:35
-msgid "privacy/"
+#: forum/conf/reputation_changes.py:39
+msgid "Gain for the author of accepted answer"
msgstr ""
-#: forum/urls.py:36
-msgid "logout/"
+#: forum/conf/reputation_changes.py:48
+msgid "Gain for accepting best answer"
msgstr ""
-#: forum/urls.py:37 forum/urls.py:38 forum/urls.py:39 forum/urls.py:56
-msgid "answers/"
+#: forum/conf/reputation_changes.py:57
+msgid "Gain for post owner on canceled downvote"
msgstr ""
-#: forum/urls.py:37 forum/urls.py:49 forum/urls.py:52 forum/urls.py:56
-msgid "comments/"
+#: forum/conf/reputation_changes.py:66
+msgid "Gain for voter on canceling downvote"
msgstr ""
-#: forum/urls.py:38 forum/urls.py:43 forum/urls.py:78
-#: forum/skins/default/templates/user_info.html:47
-msgid "edit/"
+#: forum/conf/reputation_changes.py:76
+msgid "Loss for voter for canceling of answer acceptance"
msgstr ""
-#: forum/urls.py:39 forum/urls.py:48
-msgid "revisions/"
+#: forum/conf/reputation_changes.py:86
+msgid "Loss for author whose answer was \"un-accepted\""
msgstr ""
-#: forum/urls.py:40 forum/urls.py:41 forum/urls.py:42 forum/urls.py:43
-#: forum/urls.py:44 forum/urls.py:45 forum/urls.py:46 forum/urls.py:47
-#: forum/urls.py:48 forum/urls.py:49 forum/urls.py:52
-msgid "questions/"
+#: forum/conf/reputation_changes.py:96
+msgid "Loss for giving a downvote"
msgstr ""
-#: forum/urls.py:41 forum_modules/books/urls.py:8
-msgid "ask/"
+#: forum/conf/reputation_changes.py:106
+msgid "Loss for owner of post that was flagged offensive"
msgstr ""
-#: forum/urls.py:42
-msgid "unanswered/"
+#: forum/conf/reputation_changes.py:116
+msgid "Loss for owner of post that was downvoted"
msgstr ""
-#: forum/urls.py:44
-msgid "close/"
+#: forum/conf/reputation_changes.py:126
+msgid "Loss for owner of post that was flagged 3 times per same revision"
msgstr ""
-#: forum/urls.py:45
-msgid "reopen/"
+#: forum/conf/reputation_changes.py:136
+msgid "Loss for owner of post that was flagged 5 times per same revision"
msgstr ""
-#: forum/urls.py:46
-msgid "answer/"
+#: forum/conf/reputation_changes.py:146
+msgid "Loss for post owner when upvote is canceled"
msgstr ""
-#: forum/urls.py:47
-msgid "vote/"
+#: forum/conf/site_settings.py:13
+msgid "Q&A forum website parameters and urls"
msgstr ""
-#: forum/urls.py:50
-msgid "command/"
+#: forum/conf/site_settings.py:21
+msgid "Site title for the Q&A forum"
msgstr ""
-#: forum/urls.py:60 forum/views/readers.py:265
-msgid "question/"
+#: forum/conf/site_settings.py:30
+msgid "Comma separated list of Q&A site keywords"
msgstr ""
-#: forum/urls.py:61 forum/urls.py:62
-msgid "tags/"
+#: forum/conf/site_settings.py:39
+msgid "Copyright message to show in the footer"
msgstr ""
-#: forum/urls.py:64 forum/urls.py:68
-msgid "mark-tag/"
+#: forum/conf/site_settings.py:48
+msgid "Site description for the search engines"
msgstr ""
-#: forum/urls.py:64
-msgid "interesting/"
+#: forum/conf/site_settings.py:56
+msgid "Askbot"
msgstr ""
-#: forum/urls.py:68
-msgid "ignored/"
+#: forum/conf/site_settings.py:58
+msgid "Short name for your Q&A forum"
msgstr ""
-#: forum/urls.py:72
-msgid "unmark-tag/"
+#: forum/conf/site_settings.py:67
+msgid "Base URL for your Q&A forum, must start with http or https"
msgstr ""
-#: forum/urls.py:76 forum/urls.py:78 forum/urls.py:79
-msgid "users/"
+#: forum/conf/site_settings.py:77
+msgid "Link shown in the greeting message shown to the anonymous user"
msgstr ""
-#: forum/urls.py:77
-msgid "moderate-user/"
+#: forum/conf/site_settings.py:78
+msgid ""
+"If you change this url from the default - then you will also probably want "
+"to adjust translation of the following string: "
msgstr ""
-#: forum/urls.py:80 forum/urls.py:81
-msgid "badges/"
+#: forum/conf/site_settings.py:91
+msgid "Feedback site URL"
msgstr ""
-#: forum/urls.py:82
-msgid "messages/"
+#: forum/conf/site_settings.py:92
+msgid "If left empty, a simple internal feedback form will be used instead"
msgstr ""
-#: forum/urls.py:82
-msgid "markread/"
+#: forum/conf/skin_counter_settings.py:11
+msgid "Skin: view, vote and answer counters"
msgstr ""
-#: forum/urls.py:84
-msgid "nimda/"
+#: forum/conf/skin_counter_settings.py:19
+msgid "Vote counter value to give \"full color\""
msgstr ""
-#: forum/urls.py:86
-msgid "upload/"
+#: forum/conf/skin_counter_settings.py:28
+msgid "Background color for votes = 0"
msgstr ""
-#: forum/urls.py:87
-msgid "search/"
+#: forum/conf/skin_counter_settings.py:29
+#: forum/conf/skin_counter_settings.py:39
+#: forum/conf/skin_counter_settings.py:49
+#: forum/conf/skin_counter_settings.py:59
+#: forum/conf/skin_counter_settings.py:69
+#: forum/conf/skin_counter_settings.py:81
+#: forum/conf/skin_counter_settings.py:100
+#: forum/conf/skin_counter_settings.py:110
+#: forum/conf/skin_counter_settings.py:120
+#: forum/conf/skin_counter_settings.py:132
+#: forum/conf/skin_counter_settings.py:142
+#: forum/conf/skin_counter_settings.py:154
+#: forum/conf/skin_counter_settings.py:175
+#: forum/conf/skin_counter_settings.py:185
+#: forum/conf/skin_counter_settings.py:195
+#: forum/conf/skin_counter_settings.py:205
+#: forum/conf/skin_counter_settings.py:217
+#: forum/conf/skin_counter_settings.py:227
+#: forum/conf/skin_counter_settings.py:239
+#: forum/conf/skin_counter_settings.py:249
+msgid "HTML color name of hex value"
msgstr ""
-#: forum/urls.py:88
-msgid "feedback/"
+#: forum/conf/skin_counter_settings.py:38
+msgid "Foreground color for votes = 0"
msgstr ""
-#: forum/urls.py:89 forum/urls.py:90
-msgid "account/"
+#: forum/conf/skin_counter_settings.py:48
+msgid "Background color for votes = 1"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:58
+msgid "Foreground color for votes = 1"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:68
+msgid "Background color for votes = MAX"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:80
+msgid "Foreground color for votes = MAX"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:90
+msgid "View counter value to give \"full color\""
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:99
+msgid "Background color for views = 0"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:109
+msgid "Foreground color for views = 0"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:119
+msgid "Background color for views = 1"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:131
+msgid "Foreground color for views = 1"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:141
+msgid "Background color for views = MAX"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:153
+msgid "Foreground color for views = MAX"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:163
+msgid "Answer counter value to give \"full color\""
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:174
+msgid "Background color for answers = 0"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:184
+msgid "Foreground color for answers = 0"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:194
+msgid "Background color for answers = 1"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:204
+msgid "Foreground color for answers = 1"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:216
+msgid "Background color for answers = MAX"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:226
+msgid "Foreground color for answers = MAX"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:238
+msgid "Background color for accepted"
+msgstr ""
+
+#: forum/conf/skin_counter_settings.py:248
+msgid "Foreground color for accepted answer"
+msgstr ""
+
+#: forum/conf/skin_general_settings.py:11
+msgid "Skin: general settings"
+msgstr ""
+
+#: forum/conf/skin_general_settings.py:20
+msgid "Select skin"
+msgstr ""
+
+#: forum/conf/skin_general_settings.py:29
+msgid "Skin media revision number"
+msgstr ""
+
+#: forum/conf/skin_general_settings.py:31
+msgid ""
+"Increment this number when you change image in skin media or stylesheet. "
+"This helps avoid showing your users outdated images from their browser cache."
+msgstr ""
+
+#: forum/conf/user_settings.py:10
+msgid "User policy settings"
+msgstr ""
+
+#: forum/conf/user_settings.py:18
+msgid "Allow editing user screen name"
+msgstr ""
+
+#: forum/conf/user_settings.py:28
+msgid "Minimum allowed length for screen name"
+msgstr ""
+
+#: forum/conf/vote_rules.py:13
+msgid "Limits applicable to votes and moderation flags"
+msgstr ""
+
+#: forum/conf/vote_rules.py:22
+msgid "Number of votes a user can cast per day"
+msgstr ""
+
+#: forum/conf/vote_rules.py:31
+msgid "Maximum number of flags per user per day"
+msgstr ""
+
+#: forum/conf/vote_rules.py:40
+msgid "Threshold for warning about remaining daily votes"
+msgstr ""
+
+#: forum/conf/vote_rules.py:49
+msgid "Number of days to allow canceling votes"
+msgstr ""
+
+#: forum/conf/vote_rules.py:58
+msgid "Number of flags required to automatically hide posts"
+msgstr ""
+
+#: forum/conf/vote_rules.py:67
+msgid "Number of flags required to automatically delete posts"
+msgstr ""
+
+#: forum/const/__init__.py:9
+msgid "duplicate question"
+msgstr ""
+
+#: forum/const/__init__.py:10
+msgid "question is off-topic or not relevant"
+msgstr ""
+
+#: forum/const/__init__.py:11
+msgid "too subjective and argumentative"
+msgstr ""
+
+#: forum/const/__init__.py:12
+msgid "not a real question"
+msgstr ""
+
+#: forum/const/__init__.py:13
+msgid "the question is answered, right answer was accepted"
+msgstr ""
+
+#: forum/const/__init__.py:14
+msgid "question is not relevant or outdated"
+msgstr ""
+
+#: forum/const/__init__.py:15
+msgid "question contains offensive or malicious remarks"
+msgstr ""
+
+#: forum/const/__init__.py:16
+msgid "spam or advertising"
+msgstr ""
+
+#: forum/const/__init__.py:17
+msgid "too localized"
+msgstr ""
+
+#: forum/const/__init__.py:38 forum/skins/default/templates/questions.html:70
+#: forum/skins/default/templates/questions.html:75
+msgid "newest"
+msgstr ""
+
+#: forum/const/__init__.py:39 forum/skins/default/templates/questions.html:64
+#: forum/skins/default/templates/users.html:28
+msgid "oldest"
+msgstr ""
+
+#: forum/const/__init__.py:40 forum/skins/default/templates/questions.html:89
+#: forum/skins/default/templates/questions.html:94
+msgid "active"
+msgstr ""
+
+#: forum/const/__init__.py:41 forum/skins/default/templates/questions.html:83
+msgid "inactive"
+msgstr ""
+
+#: forum/const/__init__.py:42
+msgid "hottest"
+msgstr ""
+
+#: forum/const/__init__.py:43
+msgid "coldest"
+msgstr ""
+
+#: forum/const/__init__.py:44
+msgid "most voted"
+msgstr ""
+
+#: forum/const/__init__.py:45
+msgid "least voted"
+msgstr ""
+
+#: forum/const/__init__.py:46
+msgid "relevance"
+msgstr ""
+
+#: forum/const/__init__.py:53 forum/skins/default/templates/questions.html:52
+msgid "all"
+msgstr ""
+
+#: forum/const/__init__.py:54 forum/skins/default/templates/questions.html:53
+msgid "unanswered"
+msgstr ""
+
+#: forum/const/__init__.py:55 forum/skins/default/templates/questions.html:55
+msgid "favorite"
+msgstr ""
+
+#: forum/const/__init__.py:67
+msgid "Question has no answers"
+msgstr ""
+
+#: forum/const/__init__.py:68
+msgid "Question has no accepted answers"
+msgstr ""
+
+#: forum/const/__init__.py:106
+msgid "question"
+msgstr ""
+
+#: forum/const/__init__.py:107 forum/skins/default/templates/book.html:110
+msgid "answer"
+msgstr ""
+
+#: forum/const/__init__.py:108
+msgid "commented question"
+msgstr ""
+
+#: forum/const/__init__.py:109
+msgid "commented answer"
+msgstr ""
+
+#: forum/const/__init__.py:110
+msgid "edited question"
+msgstr ""
+
+#: forum/const/__init__.py:111
+msgid "edited answer"
+msgstr ""
+
+#: forum/const/__init__.py:112
+msgid "received award"
+msgstr "received badge"
+
+#: forum/const/__init__.py:113
+msgid "marked best answer"
+msgstr ""
+
+#: forum/const/__init__.py:114
+msgid "upvoted"
+msgstr ""
+
+#: forum/const/__init__.py:115
+msgid "downvoted"
+msgstr ""
+
+#: forum/const/__init__.py:116
+msgid "canceled vote"
+msgstr ""
+
+#: forum/const/__init__.py:117
+msgid "deleted question"
+msgstr ""
+
+#: forum/const/__init__.py:118
+msgid "deleted answer"
+msgstr ""
+
+#: forum/const/__init__.py:119
+msgid "marked offensive"
+msgstr ""
+
+#: forum/const/__init__.py:120
+msgid "updated tags"
+msgstr ""
+
+#: forum/const/__init__.py:121
+msgid "selected favorite"
+msgstr ""
+
+#: forum/const/__init__.py:122
+msgid "completed user profile"
+msgstr ""
+
+#: forum/const/__init__.py:123
+msgid "email update sent to user"
+msgstr ""
+
+#: forum/const/__init__.py:124
+msgid "mentioned in the post"
+msgstr ""
+
+#: forum/const/__init__.py:171
+msgid "question_answered"
+msgstr "answered question"
+
+#: forum/const/__init__.py:172
+msgid "question_commented"
+msgstr "commented question"
+
+#: forum/const/__init__.py:173
+msgid "answer_commented"
+msgstr ""
+
+#: forum/const/__init__.py:174
+msgid "answer_accepted"
+msgstr ""
+
+#: forum/const/__init__.py:178
+msgid "[closed]"
+msgstr ""
+
+#: forum/const/__init__.py:179
+msgid "[deleted]"
+msgstr ""
+
+#: forum/const/__init__.py:180 forum/views/readers.py:387
+#: forum/views/readers.py:408
+msgid "initial version"
+msgstr ""
+
+#: forum/const/__init__.py:181
+msgid "retagged"
+msgstr ""
+
+#: forum/const/__init__.py:186
+msgid "exclude ignored tags"
+msgstr ""
+
+#: forum/const/__init__.py:187
+msgid "allow only selected tags"
+msgstr ""
+
+#: forum/const/__init__.py:191
+msgid "instantly"
+msgstr ""
+
+#: forum/const/__init__.py:192
+msgid "daily"
+msgstr ""
+
+#: forum/const/__init__.py:193
+msgid "weekly"
+msgstr ""
+
+#: forum/const/__init__.py:194
+msgid "no email"
+msgstr ""
+
+#: forum/const/message_keys.py:19
+#, python-format
+msgid "First time here? Check out the <a href=\"%s\">FAQ</a>!"
msgstr ""
#: forum/importers/stackexchange/management/commands/load_stackexchange.py:124
msgid "Congratulations, you are now an Administrator"
msgstr ""
-#: forum/management/commands/send_email_alerts.py:236
+#: forum/management/commands/send_email_alerts.py:380
+#: forum/models/__init__.py:320
msgid "email update message subject"
msgstr "news from Q&A forum"
-#: forum/management/commands/send_email_alerts.py:238
+#: forum/management/commands/send_email_alerts.py:382
#, python-format
msgid "%(name)s, this is an update message header for %(num)d question"
msgid_plural "%(name)s, this is an update message header for %(num)d questions"
@@ -788,54 +1303,49 @@ msgstr[1] ""
"<p>Dear %(name)s,</p><p>The following %(num)d questions have been updated on "
"the Q&A forum:</p>"
-#: forum/management/commands/send_email_alerts.py:255
+#: forum/management/commands/send_email_alerts.py:399
msgid "new question"
msgstr ""
-#: forum/management/commands/send_email_alerts.py:272
+#: forum/management/commands/send_email_alerts.py:416
msgid ""
"Please visit the forum and see what's new! Could you spread the word about "
"it - can somebody you know help answering those questions or benefit from "
"posting one?"
msgstr ""
-#: forum/management/commands/send_email_alerts.py:284
+#: forum/management/commands/send_email_alerts.py:428
msgid ""
"Your most frequent subscription setting is 'daily' on selected questions. If "
"you are receiving more than one email per dayplease tell about this issue to "
"the forum administrator."
msgstr ""
-#: forum/management/commands/send_email_alerts.py:290
+#: forum/management/commands/send_email_alerts.py:434
msgid ""
"Your most frequent subscription setting is 'weekly' if you are receiving "
"this email more than once a week please report this issue to the forum "
"administrator."
msgstr ""
-#: forum/management/commands/send_email_alerts.py:296
+#: forum/management/commands/send_email_alerts.py:440
msgid ""
"There is a chance that you may be receiving links seen before - due to a "
"technicality that will eventually go away. "
msgstr ""
-#: forum/management/commands/send_email_alerts.py:311
+#: forum/management/commands/send_email_alerts.py:455
#, python-format
msgid ""
-"go to %(link)s to change frequency of email updates or %(email)s "
-"administrator"
+"go to %(email_settings_link)s to change frequency of email updates or %"
+"(admin_email)s administrator"
msgstr ""
-"<p>Please remember that you can always <a href='%(link)s'>adjust</a> "
+"<p>Please remember that you can always <a href='%(email_settings_link)s'>adjust</a> "
"frequency of the email updates or turn them off entirely.<br/>If you believe "
"that this message was sent in an error, please email about it the forum "
-"administrator at %(email)s.</p><p>Sincerely,</p><p>Your friendly Q&A forum "
+"administrator at %(admin_email)s.</p><p>Sincerely,</p><p>Your friendly Q&A forum "
"server.</p>"
-#: forum/middleware/anon_user.py:34
-#, python-format
-msgid "First time here? Check out the <a href=\"%s\">FAQ</a>!"
-msgstr ""
-
#: forum/migrations/0005_install_badges.py:10
msgid "Disciplined"
msgstr ""
@@ -1268,76 +1778,84 @@ msgstr ""
msgid "Created a tag used by 50 questions"
msgstr ""
-#: forum/models/question.py:499
+#: forum/models/question.py:531
#, python-format
msgid "%(author)s modified the question"
msgstr ""
-#: forum/models/question.py:503
+#: forum/models/question.py:535
#, python-format
msgid "%(people)s posted %(new_answer_count)s new answers"
msgstr ""
-#: forum/models/question.py:508
+#: forum/models/question.py:540
#, python-format
msgid "%(people)s commented the question"
msgstr ""
-#: forum/models/question.py:513
+#: forum/models/question.py:545
#, python-format
msgid "%(people)s commented answers"
msgstr ""
-#: forum/models/question.py:515
+#: forum/models/question.py:547
#, python-format
msgid "%(people)s commented an answer"
msgstr ""
-#: forum/models/repute.py:13 forum/skins/default/templates/badges.html:54
+#: forum/models/repute.py:16 forum/skins/default/templates/badges.html:54
msgid "gold"
msgstr ""
-#: forum/models/repute.py:14 forum/skins/default/templates/badges.html:62
+#: forum/models/repute.py:17 forum/skins/default/templates/badges.html:62
msgid "silver"
msgstr ""
-#: forum/models/repute.py:15 forum/skins/default/templates/badges.html:69
+#: forum/models/repute.py:18 forum/skins/default/templates/badges.html:69
msgid "bronze"
msgstr ""
-#: forum/models/tag.py:81
+#: forum/models/tag.py:84
msgid "interesting"
msgstr ""
-#: forum/models/tag.py:81
+#: forum/models/tag.py:84
msgid "ignored"
msgstr ""
-#: forum/models/user.py:36
+#: forum/models/user.py:212
msgid "Entire forum"
msgstr ""
-#: forum/models/user.py:37
+#: forum/models/user.py:213
msgid "Questions that I asked"
msgstr ""
-#: forum/models/user.py:38
+#: forum/models/user.py:214
msgid "Questions that I answered"
msgstr ""
-#: forum/models/user.py:39
+#: forum/models/user.py:215
msgid "Individually selected questions"
msgstr ""
-#: forum/models/user.py:42
-msgid "Weekly"
+#: forum/models/user.py:216
+msgid "Mentions and comment responses"
msgstr ""
-#: forum/models/user.py:43
+#: forum/models/user.py:219
+msgid "Instantly"
+msgstr ""
+
+#: forum/models/user.py:220
msgid "Daily"
msgstr ""
-#: forum/models/user.py:44
+#: forum/models/user.py:221
+msgid "Weekly"
+msgstr ""
+
+#: forum/models/user.py:222
msgid "No email"
msgstr ""
@@ -1419,6 +1937,8 @@ msgstr ""
#: forum/skins/default/templates/authopenid/changepw.html:5
#: forum/skins/default/templates/authopenid/changepw.html:14
#: forum/skins/default/templates/authopenid/settings.html:29
+#: livesettings/templates/livesettings/group_settings.html:11
+#: livesettings/templates/livesettings/site_settings.html:23
msgid "Change password"
msgstr ""
@@ -1469,8 +1989,8 @@ msgstr ""
#: forum/skins/default/templates/answer_edit.html:28
#: forum/skins/default/templates/ask.html:26
#: forum/skins/default/templates/ask.html:29
-#: forum/skins/default/templates/question.html:46
-#: forum/skins/default/templates/question.html:49
+#: forum/skins/default/templates/question.html:48
+#: forum/skins/default/templates/question.html:51
#: forum/skins/default/templates/question_edit.html:25
#: forum/skins/default/templates/question_edit.html:28
msgid "hide preview"
@@ -1478,7 +1998,7 @@ msgstr ""
#: forum/skins/default/templates/answer_edit.html:28
#: forum/skins/default/templates/ask.html:29
-#: forum/skins/default/templates/question.html:49
+#: forum/skins/default/templates/question.html:51
#: forum/skins/default/templates/question_edit.html:28
msgid "show preview"
msgstr ""
@@ -1506,7 +2026,7 @@ msgstr ""
#: forum/skins/default/templates/answer_edit.html:63
#: forum/skins/default/templates/ask.html:98
#: forum/skins/default/templates/ask_form.html:39
-#: forum/skins/default/templates/question.html:418
+#: forum/skins/default/templates/question.html:420
#: forum/skins/default/templates/question_edit.html:92
msgid "Toggle the real time Markdown editor preview"
msgstr ""
@@ -1514,7 +2034,7 @@ msgstr ""
#: forum/skins/default/templates/answer_edit.html:63
#: forum/skins/default/templates/ask.html:98
#: forum/skins/default/templates/ask_form.html:39
-#: forum/skins/default/templates/question.html:419
+#: forum/skins/default/templates/question.html:421
#: forum/skins/default/templates/question_edit.html:92
msgid "toggle preview"
msgstr ""
@@ -1812,7 +2332,7 @@ msgid "views"
msgstr ""
#: forum/skins/default/templates/book.html:125
-#: forum/skins/default/templates/question.html:136
+#: forum/skins/default/templates/question.html:138
#: forum/skins/default/templates/question_list.html:19
#: forum/skins/default/templates/question_summary_list_roll.html:52
#: forum/skins/default/templates/tags.html:50
@@ -1850,21 +2370,21 @@ msgstr ""
msgid "home"
msgstr ""
-#: forum/skins/default/templates/faq.html:11
+#: forum/skins/default/templates/faq.html:12
msgid "Frequently Asked Questions "
msgstr ""
-#: forum/skins/default/templates/faq.html:16
+#: forum/skins/default/templates/faq.html:17
msgid "What kinds of questions can I ask here?"
msgstr ""
-#: forum/skins/default/templates/faq.html:17
+#: forum/skins/default/templates/faq.html:18
msgid ""
"Most importanly - questions should be <strong>relevant</strong> to this "
"community."
msgstr ""
-#: forum/skins/default/templates/faq.html:18
+#: forum/skins/default/templates/faq.html:19
msgid ""
"Before asking the question - please make sure to use search to see whether "
"your question has alredy been answered."
@@ -1872,21 +2392,21 @@ msgstr ""
"Before you ask - please make sure to search for a similar question. You can "
"search questions by their title or tags."
-#: forum/skins/default/templates/faq.html:21
+#: forum/skins/default/templates/faq.html:22
msgid "What questions should I avoid asking?"
msgstr "What kinds of questions should be avoided?"
-#: forum/skins/default/templates/faq.html:22
+#: forum/skins/default/templates/faq.html:23
msgid ""
"Please avoid asking questions that are not relevant to this community, too "
"subjective and argumentative."
msgstr ""
-#: forum/skins/default/templates/faq.html:27
+#: forum/skins/default/templates/faq.html:28
msgid "What should I avoid in my answers?"
msgstr ""
-#: forum/skins/default/templates/faq.html:28
+#: forum/skins/default/templates/faq.html:29
msgid ""
"is a Q&A site, not a discussion group. Therefore - please avoid having "
"discussions in your answers, comment facility allows some space for brief "
@@ -1897,19 +2417,19 @@ msgstr ""
"they tend to dilute the essense of questions and answers. For the brief "
"discussions please use commenting facility."
-#: forum/skins/default/templates/faq.html:32
+#: forum/skins/default/templates/faq.html:33
msgid "Who moderates this community?"
msgstr ""
-#: forum/skins/default/templates/faq.html:33
+#: forum/skins/default/templates/faq.html:34
msgid "The short answer is: <strong>you</strong>."
msgstr ""
-#: forum/skins/default/templates/faq.html:34
+#: forum/skins/default/templates/faq.html:35
msgid "This website is moderated by the users."
msgstr ""
-#: forum/skins/default/templates/faq.html:35
+#: forum/skins/default/templates/faq.html:36
msgid ""
"The reputation system allows users earn the authorization to perform a "
"variety of moderation tasks."
@@ -1917,11 +2437,11 @@ msgstr ""
"Karma system allows users to earn rights to perform a variety of moderation "
"tasks"
-#: forum/skins/default/templates/faq.html:40
+#: forum/skins/default/templates/faq.html:41
msgid "How does reputation system work?"
msgstr "How does karma system work?"
-#: forum/skins/default/templates/faq.html:41
+#: forum/skins/default/templates/faq.html:42
msgid "Rep system summary"
msgstr ""
"When a question or answer is upvoted, the user who posted them will gain "
@@ -1929,15 +2449,17 @@ msgstr ""
"rough measure of the community trust to him/her. Various moderation tasks "
"are gradually assigned to the users based on those points."
-#: forum/skins/default/templates/faq.html:42
+#: forum/skins/default/templates/faq.html:43
+#, python-format
msgid ""
"For example, if you ask an interesting question or give a helpful answer, "
"your input will be upvoted. On the other hand if the answer is misleading - "
-"it will be downvoted. Each vote in favor will generate <strong>10</strong> "
-"points, each vote against will subtract <strong>2</strong> points. There is "
-"a limit of <strong>200</strong> points that can be accumulated per question "
-"or answer. The table below explains reputation point requirements for each "
-"type of moderation task."
+"it will be downvoted. Each vote in favor will generate <strong>%"
+"(REP_GAIN_FOR_RECEIVING_UPVOTE)s</strong> points, each vote against will "
+"subtract <strong>%(REP_LOSS_FOR_RECEIVING_DOWNVOTE)s</strong> points. There "
+"is a limit of <strong>%(MAX_REP_GAIN_PER_USER_PER_DAY)s</strong> points that "
+"can be accumulated for a question or answer per day. The table below "
+"explains reputation point requirements for each type of moderation task."
msgstr ""
#: forum/skins/default/templates/faq.html:53
@@ -1945,52 +2467,44 @@ msgstr ""
msgid "upvote"
msgstr ""
-#: forum/skins/default/templates/faq.html:57
+#: forum/skins/default/templates/faq.html:58
msgid "use tags"
msgstr ""
-#: forum/skins/default/templates/faq.html:62
+#: forum/skins/default/templates/faq.html:63
msgid "add comments"
msgstr ""
-#: forum/skins/default/templates/faq.html:66
+#: forum/skins/default/templates/faq.html:67
#: forum/skins/default/templates/user_votes.html:17
msgid "downvote"
msgstr ""
-#: forum/skins/default/templates/faq.html:69
+#: forum/skins/default/templates/faq.html:70
msgid "open and close own questions"
msgstr ""
-#: forum/skins/default/templates/faq.html:73
+#: forum/skins/default/templates/faq.html:74
msgid "retag questions"
msgstr ""
-#: forum/skins/default/templates/faq.html:78
+#: forum/skins/default/templates/faq.html:79
msgid "edit community wiki questions"
msgstr ""
-#: forum/skins/default/templates/faq.html:83
+#: forum/skins/default/templates/faq.html:84
msgid "edit any answer"
msgstr ""
-#: forum/skins/default/templates/faq.html:87
-msgid "open any closed question"
-msgstr ""
-
-#: forum/skins/default/templates/faq.html:91
+#: forum/skins/default/templates/faq.html:88
msgid "delete any comment"
msgstr ""
#: forum/skins/default/templates/faq.html:95
-msgid "delete any questions and answers and perform other moderation tasks"
-msgstr ""
-
-#: forum/skins/default/templates/faq.html:103
msgid "how to validate email title"
msgstr "How to validate email and why?"
-#: forum/skins/default/templates/faq.html:105
+#: forum/skins/default/templates/faq.html:97
#, python-format
msgid ""
"how to validate email info with %(send_email_key_url)s %(gravatar_faq_url)s"
@@ -2008,11 +2522,11 @@ msgstr ""
"Also, when you sign up for the first time - create a unique <a href='%"
"(gravatar_faq_url)s'><strong>gravatar</strong></a> personal image.</p>"
-#: forum/skins/default/templates/faq.html:110
+#: forum/skins/default/templates/faq.html:102
msgid "what is gravatar"
msgstr "How to change my picture (gravatar) and what is gravatar?"
-#: forum/skins/default/templates/faq.html:111
+#: forum/skins/default/templates/faq.html:103
msgid "gravatar faq info"
msgstr ""
"<p>The picture that appears on the users profiles is called "
@@ -2029,44 +2543,44 @@ msgstr ""
"be sure to use the same email address that you used to register with us). "
"Default image that looks like a kitchen tile is generated automatically.</p>"
-#: forum/skins/default/templates/faq.html:114
+#: forum/skins/default/templates/faq.html:106
msgid "To register, do I need to create new password?"
msgstr ""
-#: forum/skins/default/templates/faq.html:115
+#: forum/skins/default/templates/faq.html:107
msgid ""
"No, you don't have to. You can login through any service that supports "
"OpenID, e.g. Google, Yahoo, AOL, etc."
msgstr ""
-#: forum/skins/default/templates/faq.html:116
+#: forum/skins/default/templates/faq.html:108
msgid "Login now!"
msgstr ""
-#: forum/skins/default/templates/faq.html:121
+#: forum/skins/default/templates/faq.html:113
msgid "Why other people can edit my questions/answers?"
msgstr ""
-#: forum/skins/default/templates/faq.html:122
+#: forum/skins/default/templates/faq.html:114
msgid "Goal of this site is..."
msgstr ""
-#: forum/skins/default/templates/faq.html:122
+#: forum/skins/default/templates/faq.html:114
msgid ""
"So questions and answers can be edited like wiki pages by experienced users "
"of this site and this improves the overall quality of the knowledge base "
"content."
msgstr ""
-#: forum/skins/default/templates/faq.html:123
+#: forum/skins/default/templates/faq.html:115
msgid "If this approach is not for you, we respect your choice."
msgstr ""
-#: forum/skins/default/templates/faq.html:127
+#: forum/skins/default/templates/faq.html:119
msgid "Still have questions?"
msgstr ""
-#: forum/skins/default/templates/faq.html:128
+#: forum/skins/default/templates/faq.html:120
#, python-format
msgid ""
"Please ask your question at %(ask_question_url)s, help make our community "
@@ -2075,12 +2589,12 @@ msgstr ""
"Please <a href='%(ask_question_url)s'>ask</a> your question, help make our "
"community better!"
-#: forum/skins/default/templates/faq.html:130
+#: forum/skins/default/templates/faq.html:122
#: forum/skins/default/templates/header.html:27
msgid "questions"
msgstr ""
-#: forum/skins/default/templates/faq.html:130
+#: forum/skins/default/templates/faq.html:122
msgid "."
msgstr ""
@@ -2164,11 +2678,11 @@ msgstr ""
#: forum/skins/default/templates/header.html:10
msgid "logout"
-msgstr ""
+msgstr "sign out"
#: forum/skins/default/templates/header.html:12
msgid "login"
-msgstr ""
+msgstr "Hi, there! Please sign in"
#: forum/skins/default/templates/header.html:22
msgid "back to home page"
@@ -2178,28 +2692,85 @@ msgstr ""
msgid "users"
msgstr "people"
-#: forum/skins/default/templates/header.html:31
-msgid "books"
-msgstr ""
-
-#: forum/skins/default/templates/header.html:33
+#: forum/skins/default/templates/header.html:30
#: forum/templatetags/extra_tags.py:177 forum/templatetags/extra_tags.py:206
msgid "badges"
msgstr ""
-#: forum/skins/default/templates/header.html:34
-#: forum/skins/default/templates/header.html:38
+#: forum/skins/default/templates/header.html:31
msgid "ask a question"
msgstr ""
-#: forum/skins/default/templates/header.html:36
-msgid "unanswered questions"
-msgstr "unanswered"
-
#: forum/skins/default/templates/input_bar.html:33
msgid "search"
msgstr ""
+#: forum/skins/default/templates/instant_notification.html:3
+#, python-format
+msgid "<p>Dear %(receiving_user_name)s,</p>"
+msgstr ""
+
+#: forum/skins/default/templates/instant_notification.html:6
+#, python-format
+msgid ""
+"\n"
+"<p>%(update_author_name)s left a <a href=\"%%(post_url)s\">new comment</a>\n"
+"for question \"%(origin_post_title)s\"</p>\n"
+msgstr ""
+
+#: forum/skins/default/templates/instant_notification.html:12
+#, python-format
+msgid ""
+"\n"
+"<p>%(update_author_name)s left a <a href=\"%(post_url)s\">new comment</a>\n"
+" for an answer to question \"%(origin_post_title)s\"</p>\n"
+msgstr ""
+
+#: forum/skins/default/templates/instant_notification.html:18
+#, python-format
+msgid ""
+"\n"
+"<p>%(update_author_name)s answered a question \n"
+"<a href=\"%(post_url)s\">%(origin_post_title)s</a></p>\n"
+msgstr ""
+
+#: forum/skins/default/templates/instant_notification.html:24
+#, python-format
+msgid ""
+"\n"
+"<p>%(update_author_name)s asked a question \n"
+"<a href=\"%(post_url)s\">%(origin_post_title)s</a></p>\n"
+msgstr ""
+
+#: forum/skins/default/templates/instant_notification.html:29
+#, python-format
+msgid ""
+"\n"
+"<p>%(update_author_name)s updated an answer to the question\n"
+"<a href=\"%(post_url)s\">%(origin_post_title)s</a></p>\n"
+msgstr ""
+
+#: forum/skins/default/templates/instant_notification.html:34
+#, python-format
+msgid ""
+"\n"
+"<p>%(update_author_name)s updated a question \n"
+"<a href=\"%(post_url)s\">%(origin_post_title)s</a></p>\n"
+msgstr ""
+
+#: forum/skins/default/templates/instant_notification.html:40
+#, python-format
+msgid ""
+"\n"
+"<p>Please note - you can easily <a href=\"%(user_subscriptions_url)s"
+"\">change</a>\n"
+"how often you receive these notifications.</p>\n"
+msgstr ""
+
+#: forum/skins/default/templates/instant_notification.html:44
+msgid "<p>Sincerely,<br/>Forum Administrator</p>"
+msgstr ""
+
#: forum/skins/default/templates/logout.html:6
#: forum/skins/default/templates/logout.html:16
msgid "Logout"
@@ -2277,144 +2848,87 @@ msgstr ""
msgid "Privacy policy"
msgstr ""
-#: forum/skins/default/templates/privacy.html:15
-msgid "general message about privacy"
-msgstr ""
-"Respecting users privacy is an important core principle of this Q&amp;A "
-"forum. Information on this page details how this forum protects your "
-"privacy, and what type of information is collected."
-
-#: forum/skins/default/templates/privacy.html:18
-msgid "Site Visitors"
-msgstr ""
-
-#: forum/skins/default/templates/privacy.html:20
-msgid "what technical information is collected about visitors"
-msgstr ""
-"Information on question views, revisions of questions and answers - both "
-"times and content are recorded for each user in order to correctly count "
-"number of views, maintain data integrity and report relevant updates."
-
-#: forum/skins/default/templates/privacy.html:23
-msgid "Personal Information"
-msgstr ""
-
-#: forum/skins/default/templates/privacy.html:25
-msgid "details on personal information policies"
-msgstr ""
-"Members of this community may choose to display personally identifiable "
-"information in their profiles. Forum will never display such information "
-"without a request from the user."
-
-#: forum/skins/default/templates/privacy.html:28
-msgid "Other Services"
-msgstr ""
-
-#: forum/skins/default/templates/privacy.html:30
-msgid "details on sharing data with third parties"
-msgstr ""
-"None of the data that is not openly shown on the forum by the choice of the "
-"user is shared with any third party."
-
-#: forum/skins/default/templates/privacy.html:35
-msgid "cookie policy details"
-msgstr ""
-"Forum software relies on the internet cookie technology to keep track of "
-"user sessions. Cookies must be enabled in your browser so that forum can "
-"work for you."
-
-#: forum/skins/default/templates/privacy.html:37
-msgid "Policy Changes"
-msgstr ""
-
-#: forum/skins/default/templates/privacy.html:38
-msgid "how privacy policies can be changed"
-msgstr ""
-"These policies may be adjusted to improve protection of user's privacy. "
-"Whenever such changes occur, users will be notified via the internal "
-"messaging system. "
-
-#: forum/skins/default/templates/question.html:78
-#: forum/skins/default/templates/question.html:79
-#: forum/skins/default/templates/question.html:95
+#: forum/skins/default/templates/question.html:80
+#: forum/skins/default/templates/question.html:81
#: forum/skins/default/templates/question.html:97
+#: forum/skins/default/templates/question.html:99
msgid "i like this post (click again to cancel)"
msgstr ""
-#: forum/skins/default/templates/question.html:81
-#: forum/skins/default/templates/question.html:99
-#: forum/skins/default/templates/question.html:251
+#: forum/skins/default/templates/question.html:83
+#: forum/skins/default/templates/question.html:101
+#: forum/skins/default/templates/question.html:253
msgid "current number of votes"
msgstr ""
-#: forum/skins/default/templates/question.html:90
-#: forum/skins/default/templates/question.html:91
-#: forum/skins/default/templates/question.html:104
-#: forum/skins/default/templates/question.html:105
+#: forum/skins/default/templates/question.html:92
+#: forum/skins/default/templates/question.html:93
+#: forum/skins/default/templates/question.html:106
+#: forum/skins/default/templates/question.html:107
msgid "i dont like this post (click again to cancel)"
msgstr ""
-#: forum/skins/default/templates/question.html:109
-#: forum/skins/default/templates/question.html:110
+#: forum/skins/default/templates/question.html:111
+#: forum/skins/default/templates/question.html:112
msgid "mark this question as favorite (click again to cancel)"
msgstr ""
-#: forum/skins/default/templates/question.html:116
-#: forum/skins/default/templates/question.html:117
+#: forum/skins/default/templates/question.html:118
+#: forum/skins/default/templates/question.html:119
msgid "remove favorite mark from this question (click again to restore mark)"
msgstr ""
-#: forum/skins/default/templates/question.html:141
-#: forum/skins/default/templates/question.html:288
+#: forum/skins/default/templates/question.html:143
+#: forum/skins/default/templates/question.html:290
#: forum/skins/default/templates/revisions_answer.html:58
#: forum/skins/default/templates/revisions_question.html:58
msgid "edit"
msgstr ""
-#: forum/skins/default/templates/question.html:146
+#: forum/skins/default/templates/question.html:148
msgid "reopen"
msgstr ""
-#: forum/skins/default/templates/question.html:150
+#: forum/skins/default/templates/question.html:152
msgid "close"
msgstr ""
-#: forum/skins/default/templates/question.html:156
-#: forum/skins/default/templates/question.html:293
+#: forum/skins/default/templates/question.html:158
+#: forum/skins/default/templates/question.html:295
msgid ""
"report as offensive (i.e containing spam, advertising, malicious text, etc.)"
msgstr ""
-#: forum/skins/default/templates/question.html:157
-#: forum/skins/default/templates/question.html:294
+#: forum/skins/default/templates/question.html:159
+#: forum/skins/default/templates/question.html:296
msgid "flag offensive"
msgstr ""
-#: forum/skins/default/templates/question.html:165
-#: forum/skins/default/templates/question.html:305
+#: forum/skins/default/templates/question.html:167
+#: forum/skins/default/templates/question.html:307
msgid "delete"
msgstr ""
-#: forum/skins/default/templates/question.html:183
-#: forum/skins/default/templates/question.html:325
+#: forum/skins/default/templates/question.html:185
+#: forum/skins/default/templates/question.html:327
msgid "delete this comment"
msgstr ""
-#: forum/skins/default/templates/question.html:194
-#: forum/skins/default/templates/question.html:336
+#: forum/skins/default/templates/question.html:196
+#: forum/skins/default/templates/question.html:338
msgid "add comment"
msgstr "post a comment"
-#: forum/skins/default/templates/question.html:198
-#: forum/skins/default/templates/question.html:340
+#: forum/skins/default/templates/question.html:200
+#: forum/skins/default/templates/question.html:342
#, python-format
msgid "see <strong>%(counter)s</strong> more"
msgid_plural "see <strong>%(counter)s</strong> more"
msgstr[0] ""
msgstr[1] ""
-#: forum/skins/default/templates/question.html:200
-#: forum/skins/default/templates/question.html:342
+#: forum/skins/default/templates/question.html:202
+#: forum/skins/default/templates/question.html:344
#, python-format
msgid "see <strong>%(counter)s</strong> more comment"
msgid_plural ""
@@ -2423,18 +2937,18 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
-#: forum/skins/default/templates/question.html:213
+#: forum/skins/default/templates/question.html:215
#, python-format
msgid ""
"The question has been closed for the following reason \"%(close_reason)s\" by"
msgstr ""
-#: forum/skins/default/templates/question.html:215
+#: forum/skins/default/templates/question.html:217
#, python-format
msgid "close date %(closed_at)s"
msgstr ""
-#: forum/skins/default/templates/question.html:223
+#: forum/skins/default/templates/question.html:225
#, python-format
msgid ""
"\n"
@@ -2447,75 +2961,75 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
-#: forum/skins/default/templates/question.html:231
+#: forum/skins/default/templates/question.html:233
msgid "oldest answers will be shown first"
msgstr ""
-#: forum/skins/default/templates/question.html:231
+#: forum/skins/default/templates/question.html:233
msgid "oldest answers"
msgstr "oldest"
-#: forum/skins/default/templates/question.html:233
+#: forum/skins/default/templates/question.html:235
msgid "newest answers will be shown first"
msgstr ""
-#: forum/skins/default/templates/question.html:233
+#: forum/skins/default/templates/question.html:235
msgid "newest answers"
msgstr "newest"
-#: forum/skins/default/templates/question.html:235
+#: forum/skins/default/templates/question.html:237
msgid "most voted answers will be shown first"
msgstr ""
-#: forum/skins/default/templates/question.html:235
+#: forum/skins/default/templates/question.html:237
msgid "popular answers"
msgstr "most voted"
-#: forum/skins/default/templates/question.html:249
-#: forum/skins/default/templates/question.html:250
+#: forum/skins/default/templates/question.html:251
+#: forum/skins/default/templates/question.html:252
msgid "i like this answer (click again to cancel)"
msgstr ""
-#: forum/skins/default/templates/question.html:256
-#: forum/skins/default/templates/question.html:257
+#: forum/skins/default/templates/question.html:258
+#: forum/skins/default/templates/question.html:259
msgid "i dont like this answer (click again to cancel)"
msgstr ""
-#: forum/skins/default/templates/question.html:262
-#: forum/skins/default/templates/question.html:263
+#: forum/skins/default/templates/question.html:264
+#: forum/skins/default/templates/question.html:265
msgid "mark this answer as favorite (click again to undo)"
msgstr ""
-#: forum/skins/default/templates/question.html:268
-#: forum/skins/default/templates/question.html:269
+#: forum/skins/default/templates/question.html:270
+#: forum/skins/default/templates/question.html:271
msgid "the author of the question has selected this answer as correct"
msgstr ""
-#: forum/skins/default/templates/question.html:282
+#: forum/skins/default/templates/question.html:284
msgid "answer permanent link"
msgstr ""
-#: forum/skins/default/templates/question.html:283
+#: forum/skins/default/templates/question.html:285
msgid "permanent link"
msgstr "link"
-#: forum/skins/default/templates/question.html:305
+#: forum/skins/default/templates/question.html:307
msgid "undelete"
msgstr ""
-#: forum/skins/default/templates/question.html:364
-#: forum/skins/default/templates/question.html:367
+#: forum/skins/default/templates/question.html:366
+#: forum/skins/default/templates/question.html:369
msgid "Notify me once a day when there are any new answers"
msgstr ""
"<strong>Notify me</strong> once a day by email when there are any new "
"answers or updates"
-#: forum/skins/default/templates/question.html:370
+#: forum/skins/default/templates/question.html:372
msgid "Notify me weekly when there are any new answers"
msgstr ""
"<strong>Notify me</strong> weekly when there are any new answers or updates"
-#: forum/skins/default/templates/question.html:375
+#: forum/skins/default/templates/question.html:377
#, python-format
msgid ""
"You can always adjust frequency of email updates from your %(profile_url)s"
@@ -2523,21 +3037,21 @@ msgstr ""
"(note: you can always <strong><a href='%(profile_url)s?"
"sort=email_subscriptions'>change</a></strong> how often you receive updates)"
-#: forum/skins/default/templates/question.html:380
+#: forum/skins/default/templates/question.html:382
msgid "once you sign in you will be able to subscribe for any updates here"
msgstr ""
"<span class='strong'>Here</span> (once you log in) you will be able to sign "
"up for the periodic email updates about this question."
-#: forum/skins/default/templates/question.html:391
+#: forum/skins/default/templates/question.html:393
msgid "Your answer"
msgstr ""
-#: forum/skins/default/templates/question.html:393
+#: forum/skins/default/templates/question.html:395
msgid "Be the first one to answer this question!"
msgstr ""
-#: forum/skins/default/templates/question.html:399
+#: forum/skins/default/templates/question.html:401
msgid "you can answer anonymously and then login"
msgstr ""
"<span class='strong big'>Please start posting your answer anonymously</span> "
@@ -2546,7 +3060,7 @@ msgstr ""
"answer</strong>, for discussions, <strong>please use comments</strong> and "
"<strong>please do remember to vote</strong> (after you log in)!"
-#: forum/skins/default/templates/question.html:403
+#: forum/skins/default/templates/question.html:405
msgid "answer your own question only to give an answer"
msgstr ""
"<span class='big strong'>You are welcome to answer your own question</span>, "
@@ -2556,7 +3070,7 @@ msgstr ""
"forget to vote :)</strong> for the answers that you liked (or perhaps did "
"not like)! "
-#: forum/skins/default/templates/question.html:405
+#: forum/skins/default/templates/question.html:407
msgid "please only give an answer, no discussions"
msgstr ""
"<span class='big strong'>Please try to give a substantial answer</span>. If "
@@ -2566,47 +3080,47 @@ msgstr ""
"please <strong>don't forget to vote</strong> - it really helps to select the "
"best questions and answers!"
-#: forum/skins/default/templates/question.html:441
+#: forum/skins/default/templates/question.html:443
msgid "Login/Signup to Post Your Answer"
msgstr ""
-#: forum/skins/default/templates/question.html:444
+#: forum/skins/default/templates/question.html:446
msgid "Answer Your Own Question"
msgstr ""
-#: forum/skins/default/templates/question.html:446
+#: forum/skins/default/templates/question.html:448
msgid "Answer the question"
msgstr "Post Your Answer"
-#: forum/skins/default/templates/question.html:460
+#: forum/skins/default/templates/question.html:462
msgid "Question tags"
msgstr "Tags"
-#: forum/skins/default/templates/question.html:465
-#: forum/skins/default/templates/questions.html:257
+#: forum/skins/default/templates/question.html:467
+#: forum/skins/default/templates/questions.html:261
#: forum/skins/default/templates/tag_selector.html:11
#: forum/skins/default/templates/tag_selector.html:28
#, python-format
msgid "see questions tagged '%(tag_name)s'"
msgstr ""
-#: forum/skins/default/templates/question.html:471
+#: forum/skins/default/templates/question.html:473
msgid "question asked"
msgstr "Asked"
-#: forum/skins/default/templates/question.html:474
+#: forum/skins/default/templates/question.html:476
msgid "question was seen"
msgstr "Seen"
-#: forum/skins/default/templates/question.html:474
+#: forum/skins/default/templates/question.html:476
msgid "times"
msgstr ""
-#: forum/skins/default/templates/question.html:477
+#: forum/skins/default/templates/question.html:479
msgid "last updated"
msgstr "Last updated"
-#: forum/skins/default/templates/question.html:483
+#: forum/skins/default/templates/question.html:485
msgid "Related questions"
msgstr ""
@@ -2792,102 +3306,112 @@ msgstr ""
#: forum/skins/default/templates/questions.html:141
#, python-format
-msgid " %(q_num)s question found"
-msgid_plural "%(q_num)s questions found"
-msgstr[0] "One question found"
+msgid ""
+"\n"
+" %(q_num)s question found\n"
+" "
+msgid_plural ""
+"\n"
+" %(q_num)s questions found\n"
+" "
+msgstr[0] ""
+"\n"
+"<div class=\"questions-count\">%(q_num)s</div><p>question</p>"
msgstr[1] ""
+"\n"
+"<div class=\"questions-count\">%(q_num)s</div><p>questions<p>"
-#: forum/skins/default/templates/questions.html:143
+#: forum/skins/default/templates/questions.html:147
#, python-format
msgid "%(q_num)s question"
msgid_plural "%(q_num)s questions"
msgstr[0] ""
msgstr[1] ""
-#: forum/skins/default/templates/questions.html:147
+#: forum/skins/default/templates/questions.html:151
#, python-format
msgid "with %(author_name)s's contributions"
msgstr ""
-#: forum/skins/default/templates/questions.html:151
+#: forum/skins/default/templates/questions.html:155
msgid "tagged"
msgstr ""
-#: forum/skins/default/templates/questions.html:157
+#: forum/skins/default/templates/questions.html:161
msgid "Search tips:"
msgstr ""
-#: forum/skins/default/templates/questions.html:161
+#: forum/skins/default/templates/questions.html:165
msgid "reset author"
msgstr ""
-#: forum/skins/default/templates/questions.html:165
+#: forum/skins/default/templates/questions.html:169
msgid "reset tags"
msgstr ""
-#: forum/skins/default/templates/questions.html:169
#: forum/skins/default/templates/questions.html:173
+#: forum/skins/default/templates/questions.html:177
msgid "start over"
msgstr ""
-#: forum/skins/default/templates/questions.html:175
+#: forum/skins/default/templates/questions.html:179
msgid " - to expand, or dig in by adding more tags and revising the query."
msgstr ""
-#: forum/skins/default/templates/questions.html:178
+#: forum/skins/default/templates/questions.html:182
msgid "Search tip:"
msgstr ""
-#: forum/skins/default/templates/questions.html:178
+#: forum/skins/default/templates/questions.html:182
msgid "add tags and a query to focus your search"
msgstr ""
-#: forum/skins/default/templates/questions.html:190
+#: forum/skins/default/templates/questions.html:194
msgid "There are no unanswered questions here"
msgstr ""
-#: forum/skins/default/templates/questions.html:193
+#: forum/skins/default/templates/questions.html:197
msgid "No favorite questions here. "
msgstr ""
-#: forum/skins/default/templates/questions.html:194
+#: forum/skins/default/templates/questions.html:198
msgid "Please start (bookmark) some questions when you visit them"
msgstr ""
-#: forum/skins/default/templates/questions.html:199
+#: forum/skins/default/templates/questions.html:203
msgid "You can expand your search by "
msgstr ""
-#: forum/skins/default/templates/questions.html:203
+#: forum/skins/default/templates/questions.html:207
msgid "resetting author"
msgstr ""
-#: forum/skins/default/templates/questions.html:207
+#: forum/skins/default/templates/questions.html:211
msgid "resetting tags"
msgstr ""
-#: forum/skins/default/templates/questions.html:211
#: forum/skins/default/templates/questions.html:215
+#: forum/skins/default/templates/questions.html:219
msgid "starting over"
msgstr ""
-#: forum/skins/default/templates/questions.html:220
+#: forum/skins/default/templates/questions.html:224
msgid "Please always feel free to ask your question!"
msgstr ""
-#: forum/skins/default/templates/questions.html:224
+#: forum/skins/default/templates/questions.html:228
msgid "Did not find what you were looking for?"
msgstr ""
-#: forum/skins/default/templates/questions.html:225
+#: forum/skins/default/templates/questions.html:229
msgid "Please, post your question!"
msgstr ""
-#: forum/skins/default/templates/questions.html:241
+#: forum/skins/default/templates/questions.html:245
msgid "Contributors"
msgstr ""
-#: forum/skins/default/templates/questions.html:254
+#: forum/skins/default/templates/questions.html:258
msgid "Related tags"
msgstr "Tags"
@@ -3034,7 +3558,7 @@ msgid "change picture"
msgstr ""
#: forum/skins/default/templates/user_info.html:25
-#: forum/skins/default/templates/users.html:26 forum/views/users.py:933
+#: forum/skins/default/templates/users.html:26 forum/views/users.py:959
msgid "reputation"
msgstr "karma"
@@ -3168,19 +3692,19 @@ msgstr[1] ""
msgid "User profile"
msgstr ""
-#: forum/skins/default/templates/user_tabs.html:7 forum/views/users.py:907
+#: forum/skins/default/templates/user_tabs.html:7 forum/views/users.py:933
msgid "overview"
msgstr ""
-#: forum/skins/default/templates/user_tabs.html:9 forum/views/users.py:915
+#: forum/skins/default/templates/user_tabs.html:9 forum/views/users.py:941
msgid "recent activity"
msgstr ""
-#: forum/skins/default/templates/user_tabs.html:12 forum/views/users.py:925
+#: forum/skins/default/templates/user_tabs.html:12 forum/views/users.py:951
msgid "comments and answers to others questions"
msgstr ""
-#: forum/skins/default/templates/user_tabs.html:13 forum/views/users.py:924
+#: forum/skins/default/templates/user_tabs.html:13 forum/views/users.py:950
msgid "responses"
msgstr ""
@@ -3192,11 +3716,11 @@ msgstr "Graph of user karma"
msgid "reputation history"
msgstr "karma history"
-#: forum/skins/default/templates/user_tabs.html:20 forum/views/users.py:951
+#: forum/skins/default/templates/user_tabs.html:20 forum/views/users.py:977
msgid "user vote record"
msgstr ""
-#: forum/skins/default/templates/user_tabs.html:20 forum/views/users.py:950
+#: forum/skins/default/templates/user_tabs.html:20 forum/views/users.py:976
msgid "casted votes"
msgstr "votes"
@@ -3208,13 +3732,13 @@ msgstr ""
msgid "favorites"
msgstr ""
-#: forum/skins/default/templates/user_tabs.html:27 forum/views/users.py:960
+#: forum/skins/default/templates/user_tabs.html:27 forum/views/users.py:986
msgid "email subscription settings"
msgstr ""
-#: forum/skins/default/templates/user_tabs.html:28 forum/views/users.py:959
+#: forum/skins/default/templates/user_tabs.html:28 forum/views/users.py:985
msgid "email subscriptions"
-msgstr ""
+msgstr "subscriptions"
#: forum/skins/default/templates/users.html:6
#: forum/skins/default/templates/users.html:24
@@ -3798,7 +4322,7 @@ msgstr ""
#: forum/skins/default/templates/fbconnect/xd_receiver.html:5
#, python-format
-msgid "Connect to %(APP_SHORT_NAME)s with Facebook!"
+msgid "Connect to %(settings.APP_SHORT_NAME)s with Facebook!"
msgstr ""
#: forum/templatetags/extra_filters.py:100
@@ -3836,82 +4360,82 @@ msgid_plural "%(min)d mins ago"
msgstr[0] ""
msgstr[1] ""
-#: forum/utils/forms.py:30
+#: forum/utils/forms.py:32
msgid "this field is required"
msgstr ""
-#: forum/utils/forms.py:45
+#: forum/utils/forms.py:46
msgid "choose a username"
msgstr "Choose screen name"
-#: forum/utils/forms.py:50
+#: forum/utils/forms.py:52
msgid "user name is required"
msgstr ""
-#: forum/utils/forms.py:51
+#: forum/utils/forms.py:53
msgid "sorry, this name is taken, please choose another"
msgstr ""
-#: forum/utils/forms.py:52
+#: forum/utils/forms.py:54
msgid "sorry, this name is not allowed, please choose another"
msgstr ""
-#: forum/utils/forms.py:53
+#: forum/utils/forms.py:55
msgid "sorry, there is no user with this name"
msgstr ""
-#: forum/utils/forms.py:54
+#: forum/utils/forms.py:56
msgid "sorry, we have a serious error - user name is taken by several users"
msgstr ""
-#: forum/utils/forms.py:55
+#: forum/utils/forms.py:57
msgid "user name can only consist of letters, empty space and underscore"
msgstr ""
-#: forum/utils/forms.py:109
+#: forum/utils/forms.py:118
msgid "your email address"
msgstr "Your email <i>(never shared)</i>"
-#: forum/utils/forms.py:110
+#: forum/utils/forms.py:119
msgid "email address is required"
msgstr ""
-#: forum/utils/forms.py:111
+#: forum/utils/forms.py:120
msgid "please enter a valid email address"
msgstr ""
-#: forum/utils/forms.py:112
+#: forum/utils/forms.py:121
msgid "this email is already used by someone else, please choose another"
msgstr ""
-#: forum/utils/forms.py:140
+#: forum/utils/forms.py:149
msgid "choose password"
msgstr "Password"
-#: forum/utils/forms.py:141
+#: forum/utils/forms.py:150
msgid "password is required"
msgstr ""
-#: forum/utils/forms.py:144
+#: forum/utils/forms.py:153
msgid "retype password"
msgstr "Password <i>(please retype)</i>"
-#: forum/utils/forms.py:145
+#: forum/utils/forms.py:154
msgid "please, retype your password"
msgstr ""
-#: forum/utils/forms.py:146
+#: forum/utils/forms.py:155
msgid "sorry, entered passwords did not match, please try again"
msgstr ""
-#: forum/views/commands.py:209
+#: forum/views/commands.py:218
#, python-format
msgid "subscription saved, %(email)s needs validation, see %(details_url)s"
msgstr ""
"Your subscription is saved, but email address %(email)s needs to be "
"validated, please see <a href='%(details_url)s'>more details here</a>"
-#: forum/views/commands.py:217
+#: forum/views/commands.py:226
msgid "email update frequency has been set to daily"
msgstr ""
@@ -3927,76 +4451,76 @@ msgstr ""
msgid "We look forward to hearing your feedback! Please, give it next time :)"
msgstr ""
-#: forum/views/users.py:867 forum/views/users.py:871
+#: forum/views/users.py:893 forum/views/users.py:897
msgid "changes saved"
msgstr ""
-#: forum/views/users.py:877
+#: forum/views/users.py:903
msgid "email updates canceled"
msgstr ""
-#: forum/views/users.py:908
+#: forum/views/users.py:934
msgid "user profile"
msgstr ""
-#: forum/views/users.py:909
+#: forum/views/users.py:935
msgid "user profile overview"
msgstr ""
-#: forum/views/users.py:916
+#: forum/views/users.py:942
msgid "recent user activity"
msgstr ""
-#: forum/views/users.py:917
+#: forum/views/users.py:943
msgid "profile - recent activity"
msgstr ""
-#: forum/views/users.py:926
+#: forum/views/users.py:952
msgid "profile - responses"
msgstr ""
-#: forum/views/users.py:934
+#: forum/views/users.py:960
msgid "user reputation in the community"
msgstr "user karma"
-#: forum/views/users.py:935
+#: forum/views/users.py:961
msgid "profile - user reputation"
msgstr "Profile - User's Karma"
-#: forum/views/users.py:941
+#: forum/views/users.py:967
msgid "favorite questions"
msgstr ""
-#: forum/views/users.py:942
+#: forum/views/users.py:968
msgid "users favorite questions"
msgstr ""
-#: forum/views/users.py:943
+#: forum/views/users.py:969
msgid "profile - favorite questions"
msgstr ""
-#: forum/views/users.py:952
+#: forum/views/users.py:978
msgid "profile - votes"
msgstr ""
-#: forum/views/users.py:961
+#: forum/views/users.py:987
msgid "profile - email subscriptions"
msgstr ""
-#: forum/views/writers.py:70
+#: forum/views/writers.py:67
msgid "uploading images is limited to users with >60 reputation points"
msgstr "sorry, file uploading requires karma >60"
-#: forum/views/writers.py:72
+#: forum/views/writers.py:69
msgid "allowed file types are 'jpg', 'jpeg', 'gif', 'bmp', 'png', 'tiff'"
msgstr ""
-#: forum/views/writers.py:74
+#: forum/views/writers.py:71
#, python-format
msgid "maximum upload file size is %sK"
msgstr ""
-#: forum/views/writers.py:76
+#: forum/views/writers.py:73
#, python-format
msgid ""
"Error uploading file. Please contact the site administrator. Thank you. %s"
@@ -4028,6 +4552,184 @@ msgstr ""
msgid "books/"
msgstr ""
+#: keyedcache/views.py:14
+msgid "Yes"
+msgstr ""
+
+#: keyedcache/views.py:15
+msgid "No"
+msgstr ""
+
+#: keyedcache/views.py:19
+msgid "Key to delete"
+msgstr ""
+
+#: keyedcache/views.py:20
+msgid "Include Children?"
+msgstr ""
+
+#: keyedcache/views.py:21
+msgid "Delete all keys?"
+msgstr ""
+
+#: keyedcache/templates/keyedcache/delete.html:6
+#: keyedcache/templates/keyedcache/stats.html:6
+#: keyedcache/templates/keyedcache/view.html:6
+#: livesettings/templates/livesettings/group_settings.html:14
+#: livesettings/templates/livesettings/site_settings.html:26
+msgid "Home"
+msgstr ""
+
+#: keyedcache/templates/keyedcache/delete.html:7
+#: keyedcache/templates/keyedcache/view.html:7
+msgid "Cache"
+msgstr ""
+
+#: keyedcache/templates/keyedcache/delete.html:8
+msgid "Cache Delete"
+msgstr ""
+
+#: keyedcache/templates/keyedcache/stats.html:7
+msgid "Cache Stats"
+msgstr ""
+
+#: keyedcache/templates/keyedcache/view.html:8
+msgid "Cache View"
+msgstr ""
+
+#: livesettings/models.py:101 livesettings/models.py:140
+msgid "Site"
+msgstr ""
+
+#: livesettings/values.py:103
+msgid "Base Settings"
+msgstr ""
+
+#: livesettings/values.py:210
+msgid "Default value: \"\""
+msgstr ""
+
+#: livesettings/values.py:217
+msgid "Default value: "
+msgstr ""
+
+#: livesettings/values.py:220
+#, python-format
+msgid "Default value: %s"
+msgstr ""
+
+#: livesettings/templates/livesettings/_admin_site_views.html:4
+msgid "Sites"
+msgstr ""
+
+#: livesettings/templates/livesettings/group_settings.html:11
+#: livesettings/templates/livesettings/site_settings.html:23
+msgid "Documentation"
+msgstr ""
+
+#: livesettings/templates/livesettings/group_settings.html:11
+#: livesettings/templates/livesettings/site_settings.html:23
+msgid "Log out"
+msgstr ""
+
+#: livesettings/templates/livesettings/group_settings.html:15
+msgid "Edit Group Settings"
+msgstr ""
+
+#: livesettings/templates/livesettings/group_settings.html:22
+#: livesettings/templates/livesettings/site_settings.html:50
+msgid "Please correct the error below."
+msgid_plural "Please correct the errors below."
+msgstr[0] ""
+msgstr[1] ""
+
+#: livesettings/templates/livesettings/group_settings.html:28
+#, python-format
+msgid "Settings included in %(name)s."
+msgstr ""
+
+#: livesettings/templates/livesettings/group_settings.html:62
+#: livesettings/templates/livesettings/site_settings.html:97
+msgid "You don't have permission to edit values."
+msgstr ""
+
+#: livesettings/templates/livesettings/group_settings.html:68
+msgid "Setting groups"
+msgstr ""
+
+#: livesettings/templates/livesettings/site_settings.html:27
+msgid "Edit Site Settings"
+msgstr ""
+
+#: livesettings/templates/livesettings/site_settings.html:43
+msgid "Livesettings are disabled for this site."
+msgstr ""
+
+#: livesettings/templates/livesettings/site_settings.html:44
+msgid "All configuration options must be edited in the site settings.py file"
+msgstr ""
+
+#: livesettings/templates/livesettings/site_settings.html:66
+#, python-format
+msgid "Group settings: %(name)s"
+msgstr ""
+
+#: livesettings/templates/livesettings/site_settings.html:93
+msgid "Uncollapse all"
+msgstr ""
+
+#, fuzzy
+#~ msgid "user_subscriptions_url"
+#~ msgstr "subscriptions"
+
+#, fuzzy
+#~ msgid ""
+#~ "go to %(email_settings_url)s to change frequency of email updates or %"
+#~ "(admin_email)s administrator"
+#~ msgstr ""
+#~ "<p>Please remember that you can always <a href='%(link)s'>adjust</a> "
+#~ "frequency of the email updates or turn them off entirely.<br/>If you "
+#~ "believe that this message was sent in an error, please email about it the "
+#~ "forum administrator at %(email)s.</p><p>Sincerely,</p><p>Your friendly "
+#~ "Q&A forum server.</p>"
+
+#~ msgid "%(q_num)s question found"
+#~ msgid_plural "%(q_num)s questions found"
+#~ msgstr[0] "One question found"
+#~ msgstr[1] ""
+
+#~ msgid "unanswered questions"
+#~ msgstr "unanswered"
+
+#~ msgid "general message about privacy"
+#~ msgstr ""
+#~ "Respecting users privacy is an important core principle of this Q&amp;A "
+#~ "forum. Information on this page details how this forum protects your "
+#~ "privacy, and what type of information is collected."
+
+#~ msgid "what technical information is collected about visitors"
+#~ msgstr ""
+#~ "Information on question views, revisions of questions and answers - both "
+#~ "times and content are recorded for each user in order to correctly count "
+#~ "number of views, maintain data integrity and report relevant updates."
+
+#~ msgid "details on personal information policies"
+#~ msgstr ""
+#~ "Members of this community may choose to display personally identifiable "
+#~ "information in their profiles. Forum will never display such information "
+#~ "without a request from the user."
+
+#~ msgid "details on sharing data with third parties"
+#~ msgstr ""
+#~ "None of the data that is not openly shown on the forum by the choice of "
+#~ "the user is shared with any third party."
+
+#~ msgid "how privacy policies can be changed"
+#~ msgstr ""
+#~ "These policies may be adjusted to improve protection of user's privacy. "
+#~ "Whenever such changes occur, users will be notified via the internal "
+#~ "messaging system. "
+
#~ msgid "welcome to website"
#~ msgstr "Welcome to Q&amp;A forum"
@@ -4037,15 +4739,9 @@ msgstr ""
#~ msgid "all awards"
#~ msgstr "all badges"
-#~ msgid "complete list of questions"
-#~ msgstr "list of all questions"
-
#~ msgid "popular tags"
#~ msgstr "tags"
-#~ msgid "list of unanswered questions"
-#~ msgstr "unanswered questions"
-
#~ msgid ""
#~ " have total %(q_num)s questions containing %(searchtitle)s in full text "
#~ msgid_plural ""
@@ -4090,13 +4786,6 @@ msgstr ""
#~ msgstr "<a href='%(gravatar_faq_url)s'>gravatar</a>"
#~ msgid ""
-#~ "Sincerely,<br />\n"
-#~ " Forum Administrator"
-#~ msgstr ""
-#~ "Sincerely,\n"
-#~ "Q&A Forum Administrator"
-
-#~ msgid ""
#~ "\n"
#~ " have total %(q_num)s unanswered questions\n"
#~ " "
@@ -4112,18 +4801,3 @@ msgstr ""
#~ "\n"
#~ "<div class=\"questions-count\">%(q_num)s</div><p>questions without an "
#~ "accepted answer</p>"
-
-#~ msgid ""
-#~ "\n"
-#~ " have total %(q_num)s questions\n"
-#~ " "
-#~ msgid_plural ""
-#~ "\n"
-#~ " have total %(q_num)s questions\n"
-#~ " "
-#~ msgstr[0] ""
-#~ "\n"
-#~ "<div class=\"questions-count\">%(q_num)s</div><p>question</p>"
-#~ msgstr[1] ""
-#~ "\n"
-#~ "<div class=\"questions-count\">%(q_num)s</div><p>questions<p>"
diff --git a/locale/es/LC_MESSAGES/django.mo b/askbot/locale/es/LC_MESSAGES/django.mo
index 27fb5837..27fb5837 100644
--- a/locale/es/LC_MESSAGES/django.mo
+++ b/askbot/locale/es/LC_MESSAGES/django.mo
Binary files differ
diff --git a/locale/es/LC_MESSAGES/django.po b/askbot/locale/es/LC_MESSAGES/django.po
index 5d5019d5..5d5019d5 100644
--- a/locale/es/LC_MESSAGES/django.po
+++ b/askbot/locale/es/LC_MESSAGES/django.po
diff --git a/locale/ru/LC_MESSAGES/django.mo b/askbot/locale/ru/LC_MESSAGES/django.mo
index 8afb2eaf..8afb2eaf 100644
--- a/locale/ru/LC_MESSAGES/django.mo
+++ b/askbot/locale/ru/LC_MESSAGES/django.mo
Binary files differ
diff --git a/locale/ru/LC_MESSAGES/django.po b/askbot/locale/ru/LC_MESSAGES/django.po
index aab57c2a..886316fa 100644
--- a/locale/ru/LC_MESSAGES/django.po
+++ b/askbot/locale/ru/LC_MESSAGES/django.po
@@ -2,7 +2,7 @@
# Copyright (C) 2009 Gang Chen
# This file is distributed under the same license as the Askbot package.
# FIRST AUTHOR <evgeny.fadeev@gmail.com>, 2010.
-#
+#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
@@ -17,39 +17,39 @@ msgstr ""
"X-Translated-Using: django-rosetta 0.5.3\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n"
-#: django_authopenid/forms.py:71 django_authopenid/views.py:132
+#: django_authopenid/forms.py:72 django_authopenid/views.py:133
msgid "i-names are not supported"
msgstr "извините, но i-names не поддерживаютÑÑ"
-#: django_authopenid/forms.py:134
+#: django_authopenid/forms.py:135
msgid "Account with this name already exists on the forum"
msgstr "аккаунт Ñ Ñ‚Ð°ÐºÐ¸Ð¼ именем уже ÑущеÑтвует на форуме"
-#: django_authopenid/forms.py:135
+#: django_authopenid/forms.py:136
msgid "can't have two logins to the same account yet, sorry."
msgstr "извините, но пока Ð½ÐµÐ»ÑŒÐ·Ñ Ð²Ñ…Ð¾Ð´Ð¸Ñ‚ÑŒ в аккаунт больше чем одним методом"
-#: django_authopenid/forms.py:157
+#: django_authopenid/forms.py:158
msgid "Please enter valid username and password (both are case-sensitive)."
msgstr "ПожалуйÑта введите Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸ пароль (Ñ ÑƒÑ‡ÐµÑ‚Ð¾Ð¼ региÑтра букв)"
-#: django_authopenid/forms.py:160 django_authopenid/forms.py:210
+#: django_authopenid/forms.py:161 django_authopenid/forms.py:211
msgid "This account is inactive."
msgstr "Этот аккаунт деактивирован"
-#: django_authopenid/forms.py:162
+#: django_authopenid/forms.py:163
msgid "Login failed."
msgstr "Логин неудачен"
-#: django_authopenid/forms.py:164
+#: django_authopenid/forms.py:165
msgid "Please enter username and password"
msgstr "ПожалуйÑта, введите Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸ пароль"
-#: django_authopenid/forms.py:166
+#: django_authopenid/forms.py:167
msgid "Please enter your password"
msgstr "ПожалуйÑта, введите пароль"
-#: django_authopenid/forms.py:168
+#: django_authopenid/forms.py:169
msgid "Please enter user name"
msgstr "ПожалуйÑта, введите Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ"
@@ -57,7 +57,7 @@ msgstr "ПожалуйÑта, введите Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ"
msgid "Please enter a valid username and password. Note that both fields are case-sensitive."
msgstr "ПожалуйÑта введите Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸ пароль (обратите внимание - региÑÑ‚Ñ€ букв важен Ð´Ð»Ñ Ð¾Ð±Ð¾Ð¸Ñ… параметров)"
-#: django_authopenid/forms.py:229
+#: django_authopenid/forms.py:230
msgid "Current password"
msgstr "ÐаÑтоÑщий пароль"
@@ -65,11 +65,11 @@ msgstr "ÐаÑтоÑщий пароль"
msgid "Old password is incorrect. Please enter the correct password."
msgstr "Старый пароль неверен. ПожалуйÑта, введите правильный пароль."
-#: django_authopenid/forms.py:305
+#: django_authopenid/forms.py:306
msgid "Your user name (<i>required</i>)"
msgstr "Ваше Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ <i>(обÑзательно)</i>"
-#: django_authopenid/forms.py:320
+#: django_authopenid/forms.py:321
msgid "Incorrect username."
msgstr "Ðеправильное Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ."
@@ -153,68 +153,68 @@ msgstr "вход-Ñ-партнерÑкого-Ñайта/напомпнить-пÐ
msgid "external-login/signup/"
msgstr "вход-Ñ-партнерÑкого-Ñайта/Ñоздать-аккаунт/"
-#: django_authopenid/views.py:139
+#: django_authopenid/views.py:140
#, python-format
msgid "OpenID %(openid_url)s is invalid"
msgstr "OpenID %(openid_url)s недейÑтвителен"
-#: django_authopenid/views.py:614
+#: django_authopenid/views.py:615
msgid "Welcome email subject line"
msgstr "добро пожаловать на форум!"
-#: django_authopenid/views.py:720
+#: django_authopenid/views.py:721
msgid "Password changed."
msgstr "Пароль изменен."
-#: django_authopenid/views.py:732 django_authopenid/views.py:738
+#: django_authopenid/views.py:733 django_authopenid/views.py:739
#, python-format
msgid "your email needs to be validated see %(details_url)s"
msgstr "пожалуйÑта подтвердите Ð°Ð´Ñ€ÐµÑ Ð’Ð°ÑˆÐµÐ¹ Ñлектронной почты (<a href=\"%(details_url)s\">Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð´ÐµÑÑŒ</a>)"
-#: django_authopenid/views.py:759
+#: django_authopenid/views.py:760
msgid "Email verification subject line"
msgstr "[форум]: подтвердите Ð°Ð´Ñ€ÐµÑ Ð’Ð°ÑˆÐµÐ¹ Ñлектронной почты"
-#: django_authopenid/views.py:850
+#: django_authopenid/views.py:851
msgid "your email was not changed"
msgstr "Ð°Ð´Ñ€ÐµÑ Ð’Ð°ÑˆÐµÐ¹ Ñлектронной почты не изменён"
-#: django_authopenid/views.py:898 django_authopenid/views.py:1056
+#: django_authopenid/views.py:899 django_authopenid/views.py:1057
#, python-format
msgid "No OpenID %s found associated in our database"
msgstr "в нашей базе данных нет OpenID %s"
-#: django_authopenid/views.py:902 django_authopenid/views.py:1063
+#: django_authopenid/views.py:903 django_authopenid/views.py:1064
#, python-format
msgid "The OpenID %s isn't associated to current user logged in"
msgstr "OpenID %s не принадлежит данному пользователю"
-#: django_authopenid/views.py:910
+#: django_authopenid/views.py:911
msgid "Email Changed."
msgstr "ÐÐ´Ñ€ÐµÑ Ñлектронной почты изменён."
-#: django_authopenid/views.py:988
+#: django_authopenid/views.py:989
msgid "This OpenID is already associated with another account."
msgstr "Данный OpenID уже иÑпользуетÑÑ Ð² другом аккаунте."
-#: django_authopenid/views.py:993
+#: django_authopenid/views.py:994
#, python-format
msgid "OpenID %s is now associated with your account."
msgstr "Ваш аккаунт теперь Ñоединен Ñ OpenID %s"
-#: django_authopenid/views.py:1066
+#: django_authopenid/views.py:1067
msgid "Account deleted."
msgstr "Ðккаунт удален."
-#: django_authopenid/views.py:1118
+#: django_authopenid/views.py:1119
msgid "Request for new password"
msgstr "[форум]: замена паролÑ"
-#: django_authopenid/views.py:1132
+#: django_authopenid/views.py:1133
msgid "A new password and the activation link were sent to your email address."
msgstr "Ðовый пароль и ÑÑылка Ð´Ð»Ñ ÐµÐ³Ð¾ активации были выÑланы по Вашему адреÑу Ñлектронной почты."
-#: django_authopenid/views.py:1164
+#: django_authopenid/views.py:1165
#, python-format
msgid "Could not change password. Confirmation key '%s' is not registered."
msgstr "Пароль не был изменён, т.к. ключ '%s' в нашей базе данных не найден."
@@ -223,24 +223,24 @@ msgstr "Пароль не был изменён, Ñ‚.к. ключ '%s' в нашÐ
msgid "Can not change password. User don't exist anymore in our database."
msgstr "Пароль изменить невозможно, Ñ‚.к. аккаунт Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð±Ñ‹Ð» удален."
-#: django_authopenid/views.py:1184
+#: django_authopenid/views.py:1185
#, python-format
msgid "Password changed for %s. You may now sign in."
msgstr "Пароль Ð´Ð»Ñ %s изменен. Теперь вы можете Ñ Ð½Ð¸Ð¼ войти в Ñайт."
-#: forum/auth.py:505
+#: forum/auth.py:470
msgid "Your question and all of it's answers have been deleted"
msgstr "Ваш Ð²Ð¾Ð¿Ñ€Ð¾Ñ Ð¸ вÑе оветы на него были удалены"
-#: forum/auth.py:507
+#: forum/auth.py:472
msgid "Your question has been deleted"
msgstr "Ваш Ð²Ð¾Ð¿Ñ€Ð¾Ñ Ð±Ñ‹Ð» удалён"
-#: forum/auth.py:510
+#: forum/auth.py:475
msgid "The question and all of it's answers have been deleted"
msgstr "Ð’Ð¾Ð¿Ñ€Ð¾Ñ Ð¸ вÑе оветы на него были удалены"
-#: forum/auth.py:512
+#: forum/auth.py:477
msgid "The question has been deleted"
msgstr "Ð’Ð¾Ð¿Ñ€Ð¾Ñ Ð±Ñ‹Ð» удалён"
@@ -473,19 +473,19 @@ msgstr "Ñамые новые вопроÑÑ‹"
msgid "title"
msgstr "заголовок"
-#: forum/forms.py:24
+#: forum/forms.py:25
msgid "please enter a descriptive title for your question"
msgstr "пожалуйÑта, введите информативный заголовок раÑкрывающий Ñуть вашего вопроÑа"
-#: forum/forms.py:29
+#: forum/forms.py:30
msgid "title must be > 10 characters"
msgstr "заголовок должен иметь более 10-ти букв"
-#: forum/forms.py:38
+#: forum/forms.py:39
msgid "content"
msgstr "оÑновное Ñодержание"
-#: forum/forms.py:44
+#: forum/forms.py:45
msgid "question content must be > 10 characters"
msgstr "Ñодержание вопроÑа должно быть более 10-ти букв"
@@ -503,7 +503,7 @@ msgstr "Теги - Ñто ключевые Ñлова характеризующ
msgid "tags are required"
msgstr "тематичеÑкие отметки (ключевые Ñлова) обÑзательны"
-#: forum/forms.py:70
+#: forum/forms.py:72
#, python-format
msgid "please use %(tag_count)d tag or less"
msgid_plural "please use %(tag_count)d tags or less"
@@ -511,7 +511,7 @@ msgstr[0] "пожалуйÑта введите не более %(tag_count)d ÑÐ
msgstr[1] "пожалуйÑта введите не более %(tag_count)d Ñлова"
msgstr[2] "пожалуйÑта введите не более %(tag_count)d Ñлов"
-#: forum/forms.py:79
+#: forum/forms.py:81
#, python-format
msgid "each tag must be shorter than %(max_chars)d character"
msgid_plural "each tag must be shorter than %(max_chars)d characters"
@@ -519,7 +519,7 @@ msgstr[0] "каждое Ñлово должно быть не более %(max_c
msgstr[1] "каждое Ñлово должно быть не более %(max_chars)d буквы"
msgstr[2] "каждое Ñлово должно быть не более %(max_chars)d букв"
-#: forum/forms.py:87
+#: forum/forms.py:89
msgid "use-these-chars-in-tags"
msgstr "допуÑкаетÑÑ Ð¸Ñпользование только Ñимвола Ð´ÐµÑ„Ð¸Ñ \"-\""
@@ -536,7 +536,7 @@ msgstr "общее вики"
msgid "if you choose community wiki option, the question and answer do not generate points and name of author will not be shown"
msgstr "еÑли вы отметите \"общее вики\", то голоÑа на ответ и Ð²Ð¾Ð¿Ñ€Ð¾Ñ Ð½Ðµ принеÑут Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² репутации"
-#: forum/forms.py:114
+#: forum/forms.py:116
msgid "update summary:"
msgstr "Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾Ð± обновлениÑÑ…:"
@@ -544,47 +544,47 @@ msgstr "Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾Ð± обновлениÑÑ…:"
msgid "enter a brief summary of your revision (e.g. fixed spelling, grammar, improved style, this field is optional)"
msgstr "еÑли у Ð’Ð°Ñ ÐµÑÑ‚ÑŒ желание, то кратко опишите здеÑÑŒ Ñуть вашей правки (например - иÑправление орфографии, грамматики, ÑтилÑ)"
-#: forum/forms.py:118
+#: forum/forms.py:120
msgid "Automatically accept user's contributions for the email updates"
msgstr "ÐвоматичеÑки принÑÑ‚ÑŒ ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾Ñ‚ Ñтого Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð´Ð»Ñ Ñ€Ð°ÑÑылки по Ñлетронной почте"
-#: forum/forms.py:209
+#: forum/forms.py:211
msgid "Your name:"
msgstr "Ваше имÑ:"
-#: forum/forms.py:210
+#: forum/forms.py:212
msgid "Email (not shared with anyone):"
msgstr "ÐÐ´Ñ€ÐµÑ Ñлектронной почты (держитÑÑ Ð² Ñекрете):"
-#: forum/forms.py:211
+#: forum/forms.py:213
msgid "Your message:"
msgstr "Ваше Ñообщение:"
-#: forum/forms.py:294
+#: forum/forms.py:296
msgid "this email does not have to be linked to gravatar"
msgstr "Этот Ð°Ð´Ñ€ÐµÑ Ð½Ðµ обÑзательно должен быть аÑÑоциирован Ñ Ð³Ð»Ð¾Ð±Ð°Ð»ÑŒÐ½Ñ‹Ð¼ аватаром (gravatar)"
-#: forum/forms.py:296
+#: forum/forms.py:298
msgid "Screen name"
msgstr "Ð˜Ð¼Ñ Ð´Ð»Ñ Ð¿ÑƒÐ±Ð»Ð¸ÐºÐ¸"
-#: forum/forms.py:297
+#: forum/forms.py:299
msgid "Real name"
msgstr "ÐаÑтоÑщее имÑ"
-#: forum/forms.py:298
+#: forum/forms.py:300
msgid "Website"
msgstr "ВебÑайт"
-#: forum/forms.py:299
+#: forum/forms.py:301
msgid "Location"
msgstr "МеÑтоположение"
-#: forum/forms.py:300
+#: forum/forms.py:302
msgid "Date of birth"
msgstr "День рождениÑ"
-#: forum/forms.py:300
+#: forum/forms.py:302
msgid "will not be shown, used to calculate age, format: YYYY-MM-DD"
msgstr "показываетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ возраÑÑ‚, формат ГГГГ-ММ-ДД"
@@ -595,51 +595,51 @@ msgstr "показываетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ возраÑÑ‚, формат ГГÐ
msgid "Profile"
msgstr "Профиль"
-#: forum/forms.py:332 forum/forms.py:333
+#: forum/forms.py:334 forum/forms.py:335
msgid "this email has already been registered, please use another one"
msgstr "Ñтот Ð°Ð´Ñ€ÐµÑ ÑƒÐ¶Ðµ зарегиÑтрирован, пожалуйÑта введите другой"
-#: forum/forms.py:339
+#: forum/forms.py:341
msgid "Choose email tag filter"
msgstr "Выберите тип фильтра по темам (ключевым Ñловам)"
-#: forum/forms.py:355 forum/forms.py:356
+#: forum/forms.py:357 forum/forms.py:358
msgid "weekly"
msgstr "еженедельно"
-#: forum/forms.py:355 forum/forms.py:356
+#: forum/forms.py:357 forum/forms.py:358
msgid "no email"
msgstr "не поÑылать Ñлектронную почту"
-#: forum/forms.py:356
+#: forum/forms.py:358
msgid "daily"
msgstr "ежедневно"
-#: forum/forms.py:371
+#: forum/forms.py:373
msgid "Asked by me"
msgstr "Заданные мной"
-#: forum/forms.py:374
+#: forum/forms.py:376
msgid "Answered by me"
msgstr "Отвеченные мной"
-#: forum/forms.py:377
+#: forum/forms.py:379
msgid "Individually selected"
msgstr "Выбранные индивидуально"
-#: forum/forms.py:380
+#: forum/forms.py:382
msgid "Entire forum (tag filtered)"
msgstr "ВеÑÑŒ форум (фильтрованный по темам)"
-#: forum/forms.py:434
+#: forum/forms.py:436
msgid "okay, let's try!"
msgstr "ну хорошо, давайте попробуем!"
-#: forum/forms.py:435
+#: forum/forms.py:437
msgid "no community email please, thanks"
msgstr "ÑпаÑибо, но не надо"
-#: forum/forms.py:438
+#: forum/forms.py:440
msgid "please choose one of the options above"
msgstr "пожалуйÑта Ñделайте Ваш выбор (Ñм. выше)"
@@ -775,7 +775,7 @@ msgstr "обратнаÑ-ÑвÑзь/"
msgid "Congratulations, you are now an Administrator"
msgstr "ПоздравлÑем, теперь Ð’Ñ‹ админиÑтратор на нашем форуме"
-#: forum/management/commands/send_email_alerts.py:236
+#: forum/management/commands/send_email_alerts.py:312
msgid "email update message subject"
msgstr "новоÑти Ñ Ñ„Ð¾Ñ€ÑƒÐ¼Ð°"
@@ -787,7 +787,7 @@ msgstr[0] "%(name)s, в Ñтом вопроÑе еÑÑ‚ÑŒ новоÑти"
msgstr[1] "%(name)s, в Ñтих %(num)d вопроÑах еÑÑ‚ÑŒ новоÑти"
msgstr[2] "%(name)s, в Ñтих %(num)d вопроÑах еÑÑ‚ÑŒ новоÑти"
-#: forum/management/commands/send_email_alerts.py:255
+#: forum/management/commands/send_email_alerts.py:331
msgid "new question"
msgstr "новый вопроÑ"
@@ -807,7 +807,7 @@ msgstr "Ð’Ñ‹ выбрали получать ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾ новоÑÑ‚Ñ
msgid "There is a chance that you may be receiving links seen before - due to a technicality that will eventually go away. "
msgstr "Ðе иÑключено что здеÑÑŒ еÑÑ‚ÑŒ ÑÑылки которые Ð’Ñ‹ раньше видели. Это результат техничеÑкой детали, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ñо временем переÑтанет ÑÐµÐ±Ñ Ð¿Ñ€Ð¾ÑвлÑÑ‚ÑŒ."
-#: forum/management/commands/send_email_alerts.py:311
+#: forum/management/commands/send_email_alerts.py:387
#, python-format
msgid "go to %(link)s to change frequency of email updates or %(email)s administrator"
msgstr "<a href=\"%(link)s\">ЗдеÑÑŒ</a> Ð’Ñ‹ можете изменить чаÑтоту раÑÑылки. ЕÑли возникнет необходимоÑÑ‚ÑŒ - пожалуйÑта ÑвÑжитеÑÑŒ Ñ Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñтратором форума по %(email)s."
@@ -1294,31 +1294,31 @@ msgstr "интереÑные"
msgid "ignored"
msgstr "игнорируемые"
-#: forum/models/user.py:36
+#: forum/models/user.py:37
msgid "Entire forum"
msgstr "ВеÑÑŒ форум"
-#: forum/models/user.py:37
+#: forum/models/user.py:38
msgid "Questions that I asked"
msgstr "ВопроÑÑ‹ заданные мной"
-#: forum/models/user.py:38
+#: forum/models/user.py:39
msgid "Questions that I answered"
msgstr "ВопроÑÑ‹ отвеченные мной"
-#: forum/models/user.py:39
+#: forum/models/user.py:40
msgid "Individually selected questions"
msgstr "Индивидуально избранные вопроÑÑ‹"
-#: forum/models/user.py:42
+#: forum/models/user.py:43
msgid "Weekly"
msgstr "Раз в неделю"
-#: forum/models/user.py:43
+#: forum/models/user.py:44
msgid "Daily"
msgstr "Раз в день"
-#: forum/models/user.py:44
+#: forum/models/user.py:45
msgid "No email"
msgstr "Отменить"
@@ -1423,6 +1423,8 @@ msgstr "ÐаÑтройки аккаунта"
#: forum/skins/default/templates/authopenid/changepw.html:5
#: forum/skins/default/templates/authopenid/changepw.html:14
#: forum/skins/default/templates/authopenid/settings.html:29
+#: livesettings/templates/livesettings/group_settings.html:11
+#: livesettings/templates/livesettings/site_settings.html:23
msgid "Change password"
msgstr "Сменить пароль"
@@ -1498,8 +1500,8 @@ msgstr "Править ответ"
#: forum/skins/default/templates/answer_edit.html:28
#: forum/skins/default/templates/ask.html:26
#: forum/skins/default/templates/ask.html:29
-#: forum/skins/default/templates/question.html:46
-#: forum/skins/default/templates/question.html:49
+#: forum/skins/default/templates/question.html:48
+#: forum/skins/default/templates/question.html:51
#: forum/skins/default/templates/question_edit.html:25
#: forum/skins/default/templates/question_edit.html:28
msgid "hide preview"
@@ -1510,7 +1512,7 @@ msgstr "Ñкрыть предварительный проÑмотр"
#: forum/skins/askbot/templates/question_edit.html:28
#: forum/skins/default/templates/answer_edit.html:28
#: forum/skins/default/templates/ask.html:29
-#: forum/skins/default/templates/question.html:49
+#: forum/skins/default/templates/question.html:51
#: forum/skins/default/templates/question_edit.html:28
msgid "show preview"
msgstr "показать предварительный проÑмотр"
@@ -1553,7 +1555,7 @@ msgstr "выбрать верÑию"
#: forum/skins/default/templates/answer_edit.html:63
#: forum/skins/default/templates/ask.html:98
#: forum/skins/default/templates/ask_form.html:39
-#: forum/skins/default/templates/question.html:418
+#: forum/skins/default/templates/question.html:420
#: forum/skins/default/templates/question_edit.html:92
msgid "Toggle the real time Markdown editor preview"
msgstr "Включить/выключить предварительный проÑмотр текÑта"
@@ -1565,7 +1567,7 @@ msgstr "Включить/выключить предварительный прÐ
#: forum/skins/default/templates/answer_edit.html:63
#: forum/skins/default/templates/ask.html:98
#: forum/skins/default/templates/ask_form.html:39
-#: forum/skins/default/templates/question.html:419
+#: forum/skins/default/templates/question.html:421
#: forum/skins/default/templates/question_edit.html:92
msgid "toggle preview"
msgstr "включить/выключить предварительный проÑмотр"
@@ -1867,7 +1869,7 @@ msgstr "проÑмотров"
#: forum/skins/askbot/templates/tags.html:50
#: forum/skins/askbot/templates/users_questions.html:34
#: forum/skins/default/templates/book.html:125
-#: forum/skins/default/templates/question.html:136
+#: forum/skins/default/templates/question.html:138
#: forum/skins/default/templates/question_list.html:19
#: forum/skins/default/templates/question_summary_list_roll.html:52
#: forum/skins/default/templates/tags.html:50
@@ -2964,7 +2966,7 @@ msgstr "изменить изображение"
#: forum/skins/askbot/templates/user_info.html:25
#: forum/skins/askbot/templates/users.html:26
#: forum/skins/default/templates/user_info.html:25
-#: forum/skins/default/templates/users.html:26 forum/views/users.py:933
+#: forum/skins/default/templates/users.html:26 forum/views/users.py:934
msgid "reputation"
msgstr "карма"
@@ -4081,24 +4083,24 @@ msgstr[2] "<span class=\"count\">%(counter)s</span> Значков"
msgid "no items in counter"
msgstr "нет"
-#: forum/templatetags/extra_tags.py:53
+#: forum/templatetags/extra_tags.py:54
#, python-format
msgid "%(username)s gravatar image"
msgstr "%(username)s Gravatar"
-#: forum/templatetags/extra_tags.py:178 forum/templatetags/extra_tags.py:205
+#: forum/templatetags/extra_tags.py:179 forum/templatetags/extra_tags.py:206
msgid "reputation points"
msgstr "очки кармы"
-#: forum/templatetags/extra_tags.py:265
+#: forum/templatetags/extra_tags.py:266
msgid "2 days ago"
msgstr "2 Ð´Ð½Ñ Ð½Ð°Ð·Ð°Ð´"
-#: forum/templatetags/extra_tags.py:267
+#: forum/templatetags/extra_tags.py:268
msgid "yesterday"
msgstr "вчера"
-#: forum/templatetags/extra_tags.py:269
+#: forum/templatetags/extra_tags.py:270
#, python-format
msgid "%(hr)d hour ago"
msgid_plural "%(hr)d hours ago"
@@ -4106,7 +4108,7 @@ msgstr[0] "%(hr)d Ñ‡Ð°Ñ Ð½Ð°Ð·Ð°Ð´"
msgstr[1] "%(hr)d чаÑов назад"
msgstr[2] "%(hr)d чаÑа назад"
-#: forum/templatetags/extra_tags.py:271
+#: forum/templatetags/extra_tags.py:272
#, python-format
msgid "%(min)d min ago"
msgid_plural "%(min)d mins ago"
@@ -4114,80 +4116,80 @@ msgstr[0] "%(min)d минуту назад"
msgstr[1] "%(min)d минут назад"
msgstr[2] "%(min)d минуты назад"
-#: forum/utils/forms.py:30
+#: forum/utils/forms.py:31
msgid "this field is required"
msgstr "Ñто поле обÑзательное"
-#: forum/utils/forms.py:45
+#: forum/utils/forms.py:46
msgid "choose a username"
msgstr "выбрать Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ"
-#: forum/utils/forms.py:50
+#: forum/utils/forms.py:51
msgid "user name is required"
msgstr "Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¾Ð±Ñзательно"
-#: forum/utils/forms.py:51
+#: forum/utils/forms.py:52
msgid "sorry, this name is taken, please choose another"
msgstr "к Ñожалению, Ñто Ð¸Ð¼Ñ Ð¸ÑпользуетÑÑ, выберите другое"
-#: forum/utils/forms.py:52
+#: forum/utils/forms.py:53
msgid "sorry, this name is not allowed, please choose another"
msgstr "к Ñожалению, Ñто Ð¸Ð¼Ñ Ð½Ðµ разрешено, выберите другое"
-#: forum/utils/forms.py:53
+#: forum/utils/forms.py:54
msgid "sorry, there is no user with this name"
msgstr "е Ñожалению, Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ñ Ñ‚Ð°ÐºÐ¸Ð¼ именем не ÑущеÑтвует"
-#: forum/utils/forms.py:54
+#: forum/utils/forms.py:55
msgid "sorry, we have a serious error - user name is taken by several users"
msgstr "е Ñожалению, у Ð½Ð°Ñ ÐµÑÑ‚ÑŒ ÑÐµÑ€ÑŒÐµÐ·Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° - Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸ÑпользуетÑÑ Ð½ÐµÑколькими пользователÑми"
-#: forum/utils/forms.py:55
+#: forum/utils/forms.py:56
msgid "user name can only consist of letters, empty space and underscore"
msgstr "Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¼Ð¾Ð¶ÐµÑ‚ ÑоÑтоÑÑ‚ÑŒ только из букв, пробелов и подчеркиваний"
-#: forum/utils/forms.py:109
+#: forum/utils/forms.py:110
msgid "your email address"
msgstr "ваш email"
-#: forum/utils/forms.py:110
+#: forum/utils/forms.py:111
msgid "email address is required"
msgstr "email обÑзательное"
-#: forum/utils/forms.py:111
+#: forum/utils/forms.py:112
msgid "please enter a valid email address"
msgstr "пожалуйÑта, введите работающий Ð°Ð´Ñ€ÐµÑ Ñлектронной почты"
-#: forum/utils/forms.py:112
+#: forum/utils/forms.py:113
msgid "this email is already used by someone else, please choose another"
msgstr "Ñтот email уже иÑпользуетÑÑ ÐºÐµÐ¼-то еще, пожалуйÑта, выберите другое"
-#: forum/utils/forms.py:140
+#: forum/utils/forms.py:141
msgid "choose password"
msgstr "выбрать пароль"
-#: forum/utils/forms.py:141
+#: forum/utils/forms.py:142
msgid "password is required"
msgstr "пароль обÑзателен"
-#: forum/utils/forms.py:144
+#: forum/utils/forms.py:145
msgid "retype password"
msgstr "введите пароль еще раз"
-#: forum/utils/forms.py:145
+#: forum/utils/forms.py:146
msgid "please, retype your password"
msgstr "пожалуйÑта, повторите Ñвой пароль"
-#: forum/utils/forms.py:146
+#: forum/utils/forms.py:147
msgid "sorry, entered passwords did not match, please try again"
msgstr "к Ñожалению, пароли не Ñовпадают, попробуйте еще раз"
-#: forum/views/commands.py:209
+#: forum/views/commands.py:217
#, python-format
msgid "subscription saved, %(email)s needs validation, see %(details_url)s"
msgstr "подпиÑка Ñохранена, %(email)s требует проверки, Ñм. %(details_url)s"
-#: forum/views/commands.py:217
+#: forum/views/commands.py:225
msgid "email update frequency has been set to daily"
msgstr "чаÑтота обновлений по email была уÑтановлена в ежедневную"
@@ -4203,76 +4205,76 @@ msgstr "СпаÑибо за отзыв!"
msgid "We look forward to hearing your feedback! Please, give it next time :)"
msgstr "Мы Ñ Ð½ÐµÑ‚ÐµÑ€Ð¿ÐµÐ½Ð¸ÐµÐ¼ ждем ваших отзывов!"
-#: forum/views/users.py:867 forum/views/users.py:871
+#: forum/views/users.py:868 forum/views/users.py:872
msgid "changes saved"
msgstr "Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñохранены"
-#: forum/views/users.py:877
+#: forum/views/users.py:878
msgid "email updates canceled"
msgstr "Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ð¾ email отменены"
-#: forum/views/users.py:908
+#: forum/views/users.py:909
msgid "user profile"
msgstr "профиль пользователÑ"
-#: forum/views/users.py:909
+#: forum/views/users.py:910
msgid "user profile overview"
msgstr "обзор Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ"
-#: forum/views/users.py:916
+#: forum/views/users.py:917
msgid "recent user activity"
msgstr "поÑледние данные по активноÑти пользователÑ"
-#: forum/views/users.py:917
+#: forum/views/users.py:918
msgid "profile - recent activity"
msgstr "профиль - поÑледние данные по активноÑти"
-#: forum/views/users.py:926
+#: forum/views/users.py:927
msgid "profile - responses"
msgstr "профиль - ответы"
-#: forum/views/users.py:934
+#: forum/views/users.py:935
msgid "user reputation in the community"
msgstr "карма Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð² ÑообщеÑтве"
-#: forum/views/users.py:935
+#: forum/views/users.py:936
msgid "profile - user reputation"
msgstr "профиль - карма пользователÑ"
-#: forum/views/users.py:941
+#: forum/views/users.py:942
msgid "favorite questions"
msgstr "избранные вопроÑÑ‹"
-#: forum/views/users.py:942
+#: forum/views/users.py:943
msgid "users favorite questions"
msgstr "избранные вопроÑÑ‹ пользователей"
-#: forum/views/users.py:943
+#: forum/views/users.py:944
msgid "profile - favorite questions"
msgstr "профиль - избранные вопроÑÑ‹"
-#: forum/views/users.py:952
+#: forum/views/users.py:953
msgid "profile - votes"
msgstr "профиль - голоÑа"
-#: forum/views/users.py:961
+#: forum/views/users.py:962
msgid "profile - email subscriptions"
msgstr "профиль - email подпиÑки"
-#: forum/views/writers.py:70
+#: forum/views/writers.py:69
msgid "uploading images is limited to users with >60 reputation points"
msgstr "загрузка изображений доÑтупна только пользователÑм Ñ Ñ€ÐµÐ¿ÑƒÑ‚Ð°Ñ†Ð¸ÐµÐ¹ > 60"
-#: forum/views/writers.py:72
+#: forum/views/writers.py:71
msgid "allowed file types are 'jpg', 'jpeg', 'gif', 'bmp', 'png', 'tiff'"
msgstr "допуÑтимые типы файлов: 'JPG ',' JPEG ',' GIF ',' BMP ',' PNG ',' TIFF'"
-#: forum/views/writers.py:74
+#: forum/views/writers.py:73
#, python-format
msgid "maximum upload file size is %sK"
msgstr "макÑимальный размер загружаемого файла - %s K"
-#: forum/views/writers.py:76
+#: forum/views/writers.py:75
#, python-format
msgid "Error uploading file. Please contact the site administrator. Thank you. %s"
msgstr "Ошибка при загрузке файла. ПожалуйÑта, ÑвÑжитеÑÑŒ Ñ Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñтрацией Ñайта. СпаÑибо. %s"
@@ -4303,9 +4305,6 @@ msgstr "С возвращением, %s, вы вошли в ÑиÑтему"
msgid "books/"
msgstr "books/"
-#~ msgid "account_settings"
-#~ msgstr "наÑтройки-аккаунта"
-
#~ msgid "nimda/"
#~ msgstr "админиÑтрациÑ/"
@@ -4327,9 +4326,6 @@ msgstr "books/"
#~ msgid "no OSQA community email please, thanks"
#~ msgstr "ÑпаÑибо, но Ñлектронной почты не надо"
-#~ msgid "list of unanswered questions"
-#~ msgstr "ÑпиÑок неотвеченных вопроÑов"
-
#~ msgid "These login credentials are already associated with your account."
#~ msgstr "Эта Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ ÑƒÐ¶Ðµ аÑÑоциирована Ñ Ð’Ð°ÑˆÐµÐ¹ учетной запиÑью."
diff --git a/locale/sr/LC_MESSAGES/django.mo b/askbot/locale/sr/LC_MESSAGES/django.mo
index bdc63f43..bdc63f43 100644
--- a/locale/sr/LC_MESSAGES/django.mo
+++ b/askbot/locale/sr/LC_MESSAGES/django.mo
Binary files differ
diff --git a/locale/sr/LC_MESSAGES/django.po b/askbot/locale/sr/LC_MESSAGES/django.po
index d4980ec9..d4980ec9 100644
--- a/locale/sr/LC_MESSAGES/django.po
+++ b/askbot/locale/sr/LC_MESSAGES/django.po
diff --git a/locale/tr/LC_MESSAGES/django.mo b/askbot/locale/tr/LC_MESSAGES/django.mo
index 0bc6227d..0bc6227d 100644
--- a/locale/tr/LC_MESSAGES/django.mo
+++ b/askbot/locale/tr/LC_MESSAGES/django.mo
Binary files differ
diff --git a/locale/tr/LC_MESSAGES/django.po b/askbot/locale/tr/LC_MESSAGES/django.po
index 0bc2ee80..0bc2ee80 100644
--- a/locale/tr/LC_MESSAGES/django.po
+++ b/askbot/locale/tr/LC_MESSAGES/django.po
diff --git a/locale/vi/LC_MESSAGES/django.mo b/askbot/locale/vi/LC_MESSAGES/django.mo
index 67785c70..67785c70 100644
--- a/locale/vi/LC_MESSAGES/django.mo
+++ b/askbot/locale/vi/LC_MESSAGES/django.mo
Binary files differ
diff --git a/locale/vi/LC_MESSAGES/django.po b/askbot/locale/vi/LC_MESSAGES/django.po
index 0c8cb9af..0c8cb9af 100644
--- a/locale/vi/LC_MESSAGES/django.po
+++ b/askbot/locale/vi/LC_MESSAGES/django.po
diff --git a/locale/zh-cn/LC_MESSAGES/django.mo b/askbot/locale/zh-cn/LC_MESSAGES/django.mo
index a73a9675..a73a9675 100644
--- a/locale/zh-cn/LC_MESSAGES/django.mo
+++ b/askbot/locale/zh-cn/LC_MESSAGES/django.mo
Binary files differ
diff --git a/locale/zh-cn/LC_MESSAGES/django.po b/askbot/locale/zh-cn/LC_MESSAGES/django.po
index e08a05d2..e08a05d2 100644
--- a/locale/zh-cn/LC_MESSAGES/django.po
+++ b/askbot/locale/zh-cn/LC_MESSAGES/django.po
diff --git a/forum/middleware/__init__.py b/askbot/management/__init__.py
index e69de29b..e69de29b 100755..100644
--- a/forum/middleware/__init__.py
+++ b/askbot/management/__init__.py
diff --git a/forum/migrations/__init__.py b/askbot/management/commands/__init__.py
index e69de29b..e69de29b 100644
--- a/forum/migrations/__init__.py
+++ b/askbot/management/commands/__init__.py
diff --git a/forum/management/commands/add_admin.py b/askbot/management/commands/add_admin.py
index 8ff49193..8ff49193 100644
--- a/forum/management/commands/add_admin.py
+++ b/askbot/management/commands/add_admin.py
diff --git a/forum/management/commands/base_command.py b/askbot/management/commands/base_command.py
index c073bf7a..46a2d7a7 100755..100644
--- a/forum/management/commands/base_command.py
+++ b/askbot/management/commands/base_command.py
@@ -1,5 +1,4 @@
-#!/usr/bin/env python
-#encoding:utf-8
+"""
#-------------------------------------------------------------------------------
# Name: Award badges command
# Purpose: This is a command file croning in background process regularly to
@@ -11,15 +10,11 @@
# Copyright: (c) Mike 2009
# Licence: GPL V2
#-------------------------------------------------------------------------------
+"""
+#!/usr/bin/env python
+#encoding:utf-8
-from datetime import datetime, date
from django.core.management.base import NoArgsCommand
-from django.db import connection
-from django.shortcuts import get_object_or_404
-from django.contrib.contenttypes.models import ContentType
-
-from forum.models import *
-from forum.const import *
class BaseCommand(NoArgsCommand):
def update_activities_auditted(self, cursor, activity_ids):
@@ -28,8 +23,3 @@ class BaseCommand(NoArgsCommand):
query = "UPDATE activity SET is_auditted = 1 WHERE id in (%s)"\
% ','.join('%s' % item for item in activity_ids)
cursor.execute(query)
-
-
-
-
-
diff --git a/forum/management/commands/clean_award_badges.py b/askbot/management/commands/clean_award_badges.py
index 117e3a5f..49e79fca 100755..100644
--- a/forum/management/commands/clean_award_badges.py
+++ b/askbot/management/commands/clean_award_badges.py
@@ -1,3 +1,4 @@
+"""
#-------------------------------------------------------------------------------
# Name: Award badges command
# Purpose: This is a command file croning in background process regularly to
@@ -9,14 +10,13 @@
# Copyright: (c) Mike 2009
# Licence: GPL V2
#-------------------------------------------------------------------------------
+"""
#!/usr/bin/env python
#encoding:utf-8
from django.core.management.base import NoArgsCommand
from django.db import connection
-from django.shortcuts import get_object_or_404
from django.contrib.contenttypes.models import ContentType
-
-from forum.models import *
+from askbot import models
class Command(NoArgsCommand):
def handle_noargs(self, **options):
@@ -29,18 +29,18 @@ class Command(NoArgsCommand):
connection.close()
def clean_awards(self):
- Award.objects.all().delete()
+ models.Award.objects.all().delete()
- award_type =ContentType.objects.get_for_model(Award)
- Activity.objects.filter(content_type=award_type).delete()
+ award_type =ContentType.objects.get_for_model(models.Award)
+ models.Activity.objects.filter(content_type=award_type).delete()
- for user in User.objects.all():
+ for user in models.User.objects.all():
user.gold = 0
user.silver = 0
user.bronze = 0
user.save()
- for badge in Badge.objects.all():
+ for badge in models.Badge.objects.all():
badge.awarded_count = 0
badge.save()
@@ -56,4 +56,4 @@ def main():
pass
if __name__ == '__main__':
- main() \ No newline at end of file
+ main()
diff --git a/forum/management/commands/message_to_everyone.py b/askbot/management/commands/message_to_everyone.py
index c020c178..c020c178 100755..100644
--- a/forum/management/commands/message_to_everyone.py
+++ b/askbot/management/commands/message_to_everyone.py
diff --git a/forum/management/commands/multi_award_badges.py b/askbot/management/commands/multi_award_badges.py
index 6b330cf9..430c6364 100755..100644
--- a/forum/management/commands/multi_award_badges.py
+++ b/askbot/management/commands/multi_award_badges.py
@@ -1,5 +1,5 @@
-#!/usr/bin/env python
#encoding:utf-8
+"""
#-------------------------------------------------------------------------------
# Name: Award badges command
# Purpose: This is a command file croning in background process regularly to
@@ -11,73 +11,16 @@
# Copyright: (c) Mike 2009
# Licence: GPL V2
#-------------------------------------------------------------------------------
+"""
+#!/usr/bin/env python
-from datetime import datetime, date
-from django.core.management.base import NoArgsCommand
from django.db import connection
from django.shortcuts import get_object_or_404
from django.contrib.contenttypes.models import ContentType
-from forum.models import *
-from forum.const import *
-from base_command import BaseCommand
-"""
-(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);
-
-
-TYPE_ACTIVITY_ASK_QUESTION=1
-TYPE_ACTIVITY_ANSWER=2
-TYPE_ACTIVITY_COMMENT_QUESTION=3
-TYPE_ACTIVITY_COMMENT_ANSWER=4
-TYPE_ACTIVITY_UPDATE_QUESTION=5
-TYPE_ACTIVITY_UPDATE_ANSWER=6
-TYPE_ACTIVITY_PRIZE=7
-TYPE_ACTIVITY_MARK_ANSWER=8
-TYPE_ACTIVITY_VOTE_UP=9
-TYPE_ACTIVITY_VOTE_DOWN=10
-TYPE_ACTIVITY_CANCEL_VOTE=11
-TYPE_ACTIVITY_DELETE_QUESTION=12
-TYPE_ACTIVITY_DELETE_ANSWER=13
-TYPE_ACTIVITY_MARK_OFFENSIVE=14
-TYPE_ACTIVITY_UPDATE_TAGS=15
-TYPE_ACTIVITY_FAVORITE=16
-TYPE_ACTIVITY_USER_FULL_UPDATED = 17
-"""
+from askbot.models import Badge, User, Award, Question, Answer, Tag
+from askbot import const
+from askbot.management.commands.base_command import BaseCommand
class Command(BaseCommand):
def handle_noargs(self, **options):
@@ -114,7 +57,7 @@ class Command(BaseCommand):
query = "SELECT act.id, act.user_id, act.object_id FROM activity act, question q WHERE act.object_id = q.id AND\
act.activity_type = %s AND\
q.vote_up_count >=3 AND \
- act.is_auditted = 0" % (TYPE_ACTIVITY_DELETE_QUESTION)
+ act.is_auditted = 0" % (const.TYPE_ACTIVITY_DELETE_QUESTION)
self.__process_activities_badge(query, 1, Question)
def delete_answer_be_voted_up_3(self):
@@ -124,7 +67,7 @@ class Command(BaseCommand):
query = "SELECT act.id, act.user_id, act.object_id FROM activity act, answer an WHERE act.object_id = an.id AND\
act.activity_type = %s AND\
an.vote_up_count >=3 AND \
- act.is_auditted = 0" % (TYPE_ACTIVITY_DELETE_ANSWER)
+ act.is_auditted = 0" % (const.TYPE_ACTIVITY_DELETE_ANSWER)
self.__process_activities_badge(query, 1, Answer)
def delete_question_be_vote_down_3(self):
@@ -134,7 +77,7 @@ class Command(BaseCommand):
query = "SELECT act.id, act.user_id, act.object_id FROM activity act, question q WHERE act.object_id = q.id AND\
act.activity_type = %s AND\
q.vote_down_count >=3 AND \
- act.is_auditted = 0" % (TYPE_ACTIVITY_DELETE_QUESTION)
+ act.is_auditted = 0" % (const.TYPE_ACTIVITY_DELETE_QUESTION)
content_type = ContentType.objects.get_for_model(Question)
self.__process_activities_badge(query, 2, Question)
@@ -145,7 +88,7 @@ class Command(BaseCommand):
query = "SELECT act.id, act.user_id, act.object_id FROM activity act, answer an WHERE act.object_id = an.id AND\
act.activity_type = %s AND\
an.vote_down_count >=3 AND \
- act.is_auditted = 0" % (TYPE_ACTIVITY_DELETE_ANSWER)
+ act.is_auditted = 0" % (const.TYPE_ACTIVITY_DELETE_ANSWER)
self.__process_activities_badge(query, 2, Answer)
def answer_be_voted_up_10(self):
@@ -156,7 +99,7 @@ class Command(BaseCommand):
activity act, answer a WHERE act.object_id = a.id AND\
act.activity_type = %s AND \
a.vote_up_count >= 10 AND\
- act.is_auditted = 0" % (TYPE_ACTIVITY_ANSWER)
+ act.is_auditted = 0" % (const.TYPE_ACTIVITY_ANSWER)
self.__process_activities_badge(query, 3, Answer)
def question_be_voted_up_10(self):
@@ -167,7 +110,7 @@ class Command(BaseCommand):
activity act, question q WHERE act.object_id = q.id AND\
act.activity_type = %s AND \
q.vote_up_count >= 10 AND\
- act.is_auditted = 0" % (TYPE_ACTIVITY_ASK_QUESTION)
+ act.is_auditted = 0" % (const.TYPE_ACTIVITY_ASK_QUESTION)
self.__process_activities_badge(query, 4, Question)
def question_view_1000(self):
@@ -179,7 +122,8 @@ class Command(BaseCommand):
act.object_id = q.id AND \
q.view_count >= 1000 AND\
act.object_id NOT IN \
- (SELECT object_id FROM award WHERE award.badge_id = %s)" % (TYPE_ACTIVITY_ASK_QUESTION, 6)
+ (SELECT object_id FROM award WHERE award.badge_id = %s)" \
+ % (const.TYPE_ACTIVITY_ASK_QUESTION, 6)
self.__process_activities_badge(query, 6, Question, False)
def answer_self_question_be_voted_up_3(self):
@@ -192,7 +136,8 @@ class Command(BaseCommand):
an.vote_up_count >= 3 AND\
act.user_id = (SELECT user_id FROM question q WHERE q.id = an.question_id) AND\
act.object_id NOT IN \
- (SELECT object_id FROM award WHERE award.badge_id = %s)" % (TYPE_ACTIVITY_ANSWER, 17)
+ (SELECT object_id FROM award WHERE award.badge_id = %s)" \
+ % (const.TYPE_ACTIVITY_ANSWER, 17)
self.__process_activities_badge(query, 17, Question, False)
def answer_be_voted_up_100(self):
diff --git a/forum/management/commands/once_award_badges.py b/askbot/management/commands/once_award_badges.py
index 60457373..6351ac9a 100755..100644
--- a/forum/management/commands/once_award_badges.py
+++ b/askbot/management/commands/once_award_badges.py
@@ -17,8 +17,8 @@ from django.db import connection
from django.shortcuts import get_object_or_404
from django.contrib.contenttypes.models import ContentType
-from forum.models import *
-from forum.const import *
+from askbot.models import User, Activity, Badge, Award, Question, Answer
+from askbot import const
from base_command import BaseCommand
"""
(1, '炼狱法师', 3, '炼狱法师', '删除自己有3个以上赞æˆç¥¨çš„帖å­', 1, 0),
@@ -79,15 +79,15 @@ TYPE_ACTIVITY_USER_FULL_UPDATED = 17
"""
BADGE_AWARD_TYPE_FIRST = {
- TYPE_ACTIVITY_MARK_OFFENSIVE : 7,
- TYPE_ACTIVITY_CANCEL_VOTE: 8,
- TYPE_ACTIVITY_VOTE_DOWN : 9,
- TYPE_ACTIVITY_UPDATE_QUESTION : 10,
- TYPE_ACTIVITY_UPDATE_ANSWER : 10,
- TYPE_ACTIVITY_UPDATE_TAGS : 11,
- TYPE_ACTIVITY_MARK_ANSWER : 12,
- TYPE_ACTIVITY_VOTE_UP : 14,
- TYPE_ACTIVITY_USER_FULL_UPDATED: 16
+ const.TYPE_ACTIVITY_MARK_OFFENSIVE : 7,
+ const.TYPE_ACTIVITY_CANCEL_VOTE: 8,
+ const.TYPE_ACTIVITY_VOTE_DOWN : 9,
+ const.TYPE_ACTIVITY_UPDATE_QUESTION : 10,
+ const.TYPE_ACTIVITY_UPDATE_ANSWER : 10,
+ const.TYPE_ACTIVITY_UPDATE_TAGS : 11,
+ const.TYPE_ACTIVITY_MARK_ANSWER : 12,
+ const.TYPE_ACTIVITY_VOTE_UP : 14,
+ const.TYPE_ACTIVITY_USER_FULL_UPDATED: 16
}
@@ -192,10 +192,12 @@ class Command(BaseCommand):
"""
For user asked question and got first upvote, we award him following badge:
"""
- query = "SELECT act.user_id, q.vote_up_count, act.object_id FROM " \
- "activity act, question q WHERE act.activity_type = %s AND " \
- "act.object_id = q.id AND " \
- "act.user_id NOT IN (SELECT distinct user_id FROM award WHERE badge_id = %s)" % (TYPE_ACTIVITY_ASK_QUESTION, 13)
+ query = ('SELECT act.user_id, q.vote_up_count, act.object_id FROM ' \
+ + 'activity act, question q WHERE act.activity_type = %s AND ' \
+ + 'act.object_id = q.id AND ' \
+ + 'act.user_id NOT IN ' \
+ + '(SELECT distinct user_id FROM award WHERE badge_id = %s)') \
+ % (const.TYPE_ACTIVITY_ASK_QUESTION, 13)
cursor = connection.cursor()
try:
cursor.execute(query)
@@ -222,10 +224,12 @@ class Command(BaseCommand):
(15, '教师', 3, '教师', '第一次回答问题并且得到一个以上赞æˆç¥¨', 0, 0),
"""
- query = "SELECT act.user_id, a.vote_up_count, act.object_id FROM " \
- "activity act, answer a WHERE act.activity_type = %s AND " \
- "act.object_id = a.id AND " \
- "act.user_id NOT IN (SELECT distinct user_id FROM award WHERE badge_id = %s)" % (TYPE_ACTIVITY_ANSWER, 15)
+ query = ("SELECT act.user_id, a.vote_up_count, act.object_id FROM "\
+ + "activity act, answer a WHERE act.activity_type = %s AND "\
+ + "act.object_id = a.id AND "\
+ + "act.user_id NOT IN "\
+ + "(SELECT distinct user_id FROM award WHERE badge_id = %s)") \
+ % (const.TYPE_ACTIVITY_ANSWER, 15)
cursor = connection.cursor()
try:
cursor.execute(query)
@@ -250,11 +254,13 @@ class Command(BaseCommand):
"""
(32, '学问家', 2, '学问家', '第一次回答被投赞æˆç¥¨10次以上', 0, 0)
"""
- query = "SELECT act.user_id, act.object_id FROM " \
- "activity act, answer a WHERE act.object_id = a.id AND " \
- "act.activity_type = %s AND " \
- "a.vote_up_count >= 10 AND " \
- "act.user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s)" % (TYPE_ACTIVITY_ANSWER, 32)
+ query = ("SELECT act.user_id, act.object_id FROM " \
+ + "activity act, answer a WHERE act.object_id = a.id AND "\
+ + "act.activity_type = %s AND "\
+ + "a.vote_up_count >= 10 AND "\
+ + "act.user_id NOT IN "\
+ + "(SELECT user_id FROM award WHERE badge_id = %s)") \
+ % (const.TYPE_ACTIVITY_ANSWER, 32)
cursor = connection.cursor()
try:
cursor.execute(query)
@@ -278,11 +284,16 @@ class Command(BaseCommand):
"""
(26, '优秀市民', 2, '优秀市民', '投票300次以上', 0, 0)
"""
- query = "SELECT count(*) vote_count, user_id FROM activity WHERE " \
- "activity_type = %s OR " \
- "activity_type = %s AND " \
- "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) " \
- "GROUP BY user_id HAVING vote_count >= 300" % (TYPE_ACTIVITY_VOTE_UP, TYPE_ACTIVITY_VOTE_DOWN, 26)
+ query = ("SELECT count(*) vote_count, user_id FROM activity WHERE " \
+ + "activity_type = %s OR " \
+ + "activity_type = %s AND " \
+ + "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) " \
+ + "GROUP BY user_id HAVING vote_count >= 300") \
+ % (
+ const.TYPE_ACTIVITY_VOTE_UP,
+ const.TYPE_ACTIVITY_VOTE_DOWN,
+ 2
+ )
self.__award_for_count_num(query, 26)
@@ -290,11 +301,16 @@ class Command(BaseCommand):
"""
(27, '编辑主任', 2, '编辑主任', '编辑了100个帖å­', 0, 0)
"""
- query = "SELECT count(*) vote_count, user_id FROM activity WHERE " \
- "activity_type = %s OR " \
- "activity_type = %s AND " \
- "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) " \
- "GROUP BY user_id HAVING vote_count >= 100" % (TYPE_ACTIVITY_UPDATE_QUESTION, TYPE_ACTIVITY_UPDATE_ANSWER, 27)
+ query = ("SELECT count(*) vote_count, user_id FROM activity WHERE " \
+ + "activity_type = %s OR " \
+ + "activity_type = %s AND " \
+ + "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) " \
+ + "GROUP BY user_id HAVING vote_count >= 100" )\
+ % (
+ const.TYPE_ACTIVITY_UPDATE_QUESTION,
+ const.TYPE_ACTIVITY_UPDATE_ANSWER,
+ 27
+ )
self.__award_for_count_num(query, 27)
@@ -302,11 +318,16 @@ class Command(BaseCommand):
"""
(5, '评论家', 3, '评论家', '评论10次以上', 0, 0),
"""
- query = "SELECT count(*) vote_count, user_id FROM activity WHERE " \
- "activity_type = %s OR " \
- "activity_type = %s AND " \
- "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) " \
- "GROUP BY user_id HAVING vote_count >= 10" % (TYPE_ACTIVITY_COMMENT_QUESTION, TYPE_ACTIVITY_COMMENT_ANSWER, 5)
+ query = ("SELECT count(*) vote_count, user_id FROM activity WHERE " \
+ + "activity_type = %s OR " \
+ + "activity_type = %s AND " \
+ + "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) " \
+ + "GROUP BY user_id HAVING vote_count >= 10" )\
+ % (
+ const.TYPE_ACTIVITY_COMMENT_QUESTION,
+ const.TYPE_ACTIVITY_COMMENT_ANSWER,
+ 5
+ )
self.__award_for_count_num(query, 5)
def __award_for_count_num(self, query, badge):
diff --git a/forum/management/commands/pg_base_command.py b/askbot/management/commands/pg_base_command.py
index b3167dcf..3ff7853d 100755..100644
--- a/forum/management/commands/pg_base_command.py
+++ b/askbot/management/commands/pg_base_command.py
@@ -18,8 +18,8 @@ from django.db import connection
from django.shortcuts import get_object_or_404
from django.contrib.contenttypes.models import ContentType
-from forum.models import *
-from forum.const import *
+from askbot.models import *
+from askbot.const import *
class BaseCommand(NoArgsCommand):
def update_activities_auditted(self, cursor, activity_ids):
diff --git a/forum/management/commands/pg_clean_award_badges.py b/askbot/management/commands/pg_clean_award_badges.py
index b3925a68..934d1f1d 100755..100644
--- a/forum/management/commands/pg_clean_award_badges.py
+++ b/askbot/management/commands/pg_clean_award_badges.py
@@ -16,7 +16,7 @@ from django.db import connection
from django.shortcuts import get_object_or_404
from django.contrib.contenttypes.models import ContentType
-from forum.models import *
+from askbot.models import *
class Command(NoArgsCommand):
def handle_noargs(self, **options):
diff --git a/forum/management/commands/pg_multi_award_badges.py b/askbot/management/commands/pg_multi_award_badges.py
index 75f84bfe..6a4ef2f6 100755..100644
--- a/forum/management/commands/pg_multi_award_badges.py
+++ b/askbot/management/commands/pg_multi_award_badges.py
@@ -18,8 +18,8 @@ from django.db import connection
from django.shortcuts import get_object_or_404
from django.contrib.contenttypes.models import ContentType
-from forum.models import *
-from forum.const import *
+from askbot.models import *
+from askbot.const import *
from pg_base_command import BaseCommand
"""
(1, '????', 3, '????', '?????3?????????', 1, 0),
diff --git a/forum/management/commands/pg_once_award_badges.py b/askbot/management/commands/pg_once_award_badges.py
index b2f79363..7decbc2d 100755..100644
--- a/forum/management/commands/pg_once_award_badges.py
+++ b/askbot/management/commands/pg_once_award_badges.py
@@ -17,8 +17,8 @@ from django.db import connection
from django.shortcuts import get_object_or_404
from django.contrib.contenttypes.models import ContentType
-from forum.models import *
-from forum.const import *
+from askbot.models import *
+from askbot.const import *
from pg_base_command import BaseCommand
"""
(1, '????', 3, '????', '?????3?????????', 1, 0),
diff --git a/forum/management/commands/remove_admin.py b/askbot/management/commands/remove_admin.py
index edc22f3d..edc22f3d 100644
--- a/forum/management/commands/remove_admin.py
+++ b/askbot/management/commands/remove_admin.py
diff --git a/forum/management/commands/sample_command.py b/askbot/management/commands/sample_command.py
index 55e67235..bcdcb58e 100755..100644
--- a/forum/management/commands/sample_command.py
+++ b/askbot/management/commands/sample_command.py
@@ -1,5 +1,5 @@
from django.core.management.base import NoArgsCommand
-from forum.models import Comment
+from askbot.models import Comment
class Command(NoArgsCommand):
def handle_noargs(self, **options):
diff --git a/askbot/management/commands/send_email_alerts.py b/askbot/management/commands/send_email_alerts.py
new file mode 100644
index 00000000..94474963
--- /dev/null
+++ b/askbot/management/commands/send_email_alerts.py
@@ -0,0 +1,477 @@
+from django.core.management.base import NoArgsCommand
+from django.db import connection
+from django.db.models import Q, F
+from askbot.models import User, Question, Answer, Tag, QuestionRevision
+from askbot.models import AnswerRevision, Activity, EmailFeedSetting
+from askbot.models import Comment
+from django.core.mail import EmailMessage
+from django.utils.translation import ugettext as _
+from django.utils.translation import ungettext
+import datetime
+from django.conf import settings
+from askbot.conf import settings as askbot_settings
+from django.utils.datastructures import SortedDict
+from django.contrib.contenttypes.models import ContentType
+from askbot import const
+
+DEBUG_THIS_COMMAND = False
+
+def get_all_origin_posts(mentions):
+ origin_posts = set()
+ for mention in mentions:
+ post = mention.content_object
+ origin_posts.add(post.get_origin_post())
+ return list(origin_posts)
+
+#todo: refactor this as class
+def extend_question_list(src, dst, limit=False, add_mention=False):
+ """src is a query set with questions
+ or None
+ dst - is an ordered dictionary
+ update reporting cutoff time for each question
+ to the latest value to be more permissive about updates
+ """
+ if src is None:#is not QuerySet
+ return #will not do anything if subscription of this type is not used
+ if limit and len(dst.keys()) >= askbot_settings.MAX_ALERTS_PER_EMAIL:
+ return
+ cutoff_time = src.cutoff_time#todo: this limits use of function to query sets
+ #but sometimes we have a list on the input (like in the case of comment)
+ for q in src:
+ if q in dst:
+ meta_data = dst[q]
+ else:
+ meta_data = {'cutoff_time': cutoff_time}
+ dst[q] = meta_data
+
+ if cutoff_time > meta_data['cutoff_time']:
+ #the latest cutoff time wins for a given question
+ #if the question falls into several subscription groups
+ #this makes mailer more eager in sending email
+ meta_data['cutoff_time'] = cutoff_time
+ if add_mention:
+ if 'mentions' in meta_data:
+ meta_data['mentions'] += 1
+ else:
+ meta_data['mentions'] = 1
+
+def format_action_count(string, number, output):
+ if number > 0:
+ output.append(_(string) % {'num':number})
+
+class Command(NoArgsCommand):
+ def handle_noargs(self, **options):
+ try:
+ try:
+ self.send_email_alerts()
+ except Exception, e:
+ print e
+ finally:
+ connection.close()
+
+ def get_updated_questions_for_user(self,user):
+ """
+ retreive relevant question updates for the user
+ according to their subscriptions and recorded question
+ views
+ """
+
+ user_feeds = EmailFeedSetting.objects.filter(subscriber=user).exclude(frequency='n')
+
+ should_proceed = False
+ for feed in user_feeds:
+ if feed.should_send_now() == True:
+ should_proceed = True
+ break
+
+ #shortcirquit - if there is no ripe feed to work on for this user
+ if should_proceed == False:
+ return {}
+
+ #these are placeholders for separate query sets per question group
+ #there are four groups - one for each EmailFeedSetting.feed_type
+ #and each group has subtypes A and B
+ #that's because of the strange thing commented below
+ #see note on Q and F objects marked with todo tag
+ q_sel_A = None
+ q_sel_B = None
+
+ q_ask_A = None
+ q_ask_B = None
+
+ q_ans_A = None
+ q_ans_B = None
+
+ q_all_A = None
+ q_all_B = None
+
+ q_m_and_c_A = None#mentions and post comments
+ q_m_and_c_B = None
+
+ #base question query set for this user
+ #basic things - not deleted, not closed, not too old
+ #not last edited by the same user
+ base_qs = Question.objects.exclude(
+ last_activity_by=user
+ ).exclude(
+ last_activity_at__lt=user.date_joined#exclude old stuff
+ ).exclude(
+ deleted=True
+ ).exclude(
+ closed=True
+ ).order_by('-last_activity_at')
+ #todo: for some reason filter on did not work as expected ~Q(viewed__who=user) |
+ # Q(viewed__who=user,viewed__when__lt=F('last_activity_at'))
+ #returns way more questions than you might think it should
+ #so because of that I've created separate query sets Q_set2 and Q_set3
+ #plus two separate queries run faster!
+
+ #build two two queries based
+
+ #questions that are not seen by the user at all
+ not_seen_qs = base_qs.filter(~Q(viewed__who=user))
+ #questions that were seen, but before last modification
+ seen_before_last_mod_qs = base_qs.filter(
+ Q(
+ viewed__who=user,
+ viewed__when__lt=F('last_activity_at')
+ )
+ )
+
+ for feed in user_feeds:
+ #each group of updates represented by the corresponding
+ #query set has it's own cutoff time
+ #that cutoff time is computed for each user individually
+ #and stored as a parameter "cutoff_time"
+ #
+ #we won't send email for a given question if an email has been
+ #sent after that cutoff_time
+ if feed.should_send_now():
+
+ if DEBUG_THIS_COMMAND == False:
+ feed.mark_reported_now()
+ cutoff_time = feed.get_previous_report_cutoff_time()
+
+ #shorten variables for convenience
+ Q_set_A = not_seen_qs
+ Q_set_B = seen_before_last_mod_qs
+
+ if feed.feed_type == 'q_sel':
+ q_sel_A = Q_set_A.filter(followed_by=user)
+ q_sel_A.cutoff_time = cutoff_time #store cutoff time per query set
+ q_sel_B = Q_set_B.filter(followed_by=user)
+ q_sel_B.cutoff_time = cutoff_time #store cutoff time per query set
+
+ elif feed.feed_type == 'q_ask':
+ q_ask_A = Q_set_A.filter(author=user)
+ q_ask_A.cutoff_time = cutoff_time
+ q_ask_B = Q_set_B.filter(author=user)
+ q_ask_B.cutoff_time = cutoff_time
+
+ elif feed.feed_type == 'q_ans':
+ q_ans_A = Q_set_A.filter(answers__author=user)
+ q_ans_A = q_ans_A[:askbot_settings.MAX_ALERTS_PER_EMAIL]
+ q_ans_A.cutoff_time = cutoff_time
+
+ q_ans_B = Q_set_B.filter(answers__author=user)
+ q_ans_B = q_ans_B[:askbot_settings.MAX_ALERTS_PER_EMAIL]
+ q_ans_B.cutoff_time = cutoff_time
+
+ elif feed.feed_type == 'q_all':
+ if user.tag_filter_setting == 'ignored':
+
+ ignored_tags = Tag.objects.filter(
+ user_selections__reason='bad',
+ user_selections__user=user
+ )
+
+ q_all_A = Q_set_A.exclude( tags__in=ignored_tags )
+
+ q_all_B = Q_set_B.exclude( tags__in=ignored_tags )
+ else:
+ selected_tags = Tag.objects.filter(
+ user_selections__reason='good',
+ user_selections__user=user
+ )
+ q_all_A = Q_set_A.filter( tags__in=selected_tags )
+ q_all_B = Q_set_B.filter( tags__in=selected_tags )
+
+ q_all_A = q_all_A[:askbot_settings.MAX_ALERTS_PER_EMAIL]
+ q_all_B = q_all_B[:askbot_settings.MAX_ALERTS_PER_EMAIL]
+ q_all_A.cutoff_time = cutoff_time
+ q_all_B.cutoff_time = cutoff_time
+
+ #build ordered list questions for the email report
+ q_list = SortedDict()
+
+ #todo: refactor q_list into a separate class
+ extend_question_list(q_sel_A, q_list)
+ extend_question_list(q_sel_B, q_list)
+
+ #build list of comment and mention responses here
+ #it is separate because posts are not marked as changed
+ #when people add comments
+ #mention responses could be collected in the loop above, but
+ #it is inconvenient, because feed_type m_and_c bundles the two
+ #also we collect metadata for these here
+ if user_feeds.exists(feed_type='m_and_c'):
+ feed = user_feeds.get(feed_type='m_and_c')
+ if feed.should_report_now():
+ cutoff_time = feed.get_previous_report_cutoff_time()
+ comments = Comment.objects.filter(
+ added_at__gt = cutoff_time,
+ user__ne = user,
+ )
+ q_commented = list()
+ for c in comments:
+ post = c.content_object
+ if post.author != user:
+ continue
+
+ #skip is post was seen by the user after
+ #the comment posting time
+
+ if isinstance(post, Question):
+ q_commented.append(post)
+ elif isinstance(post, Answer):
+ q_commented.append(post.question)
+
+ for q in q_commented:
+ if q in q_list:
+ meta_data = q_list[q]
+ if meta_data['cutoff_time'] < cutoff_time:
+ meta_data['cutoff_time'] = cutoff_time
+ if 'comments' in meta_data:
+ meta_data['comments'] += 1
+ else:
+ meta_data['comments'] = 1
+
+ mentions = Activity.objects.get_mentions(
+ mentioned_at__gt = cutoff_time,
+ mentioned_whom = user
+ )
+
+ mention_posts = get_all_origin_posts(mentions)
+ q_mentions_id = [q.id for q in mention_posts]
+
+ q_mentions_A = Q_set_A.filter(id__in = q_mentions_id)
+ q_mentions_A.cutoff_time = cutoff_time
+ extend_question_list(q_mentions_A, q_list, add_mention=True)
+
+ q_mentions_B = Q_set_B.filter(id__in = q_mentions_id)
+ q_mentions_B.cutoff_time = cutoff_time
+ extend_question_list(q_mentions_B, q_list, add_mention=True)
+
+ if user.tag_filter_setting == 'interesting':
+ extend_question_list(q_all_A, q_list)
+ extend_question_list(q_all_B, q_list)
+
+ extend_question_list(q_ask_A, q_list, limit=True)
+ extend_question_list(q_ask_B, q_list, limit=True)
+
+ extend_question_list(q_ans_A, q_list, limit=True)
+ extend_question_list(q_ans_B, q_list, limit=True)
+
+ if user.tag_filter_setting == 'ignored':
+ extend_question_list(q_all_A, q_list, limit=True)
+ extend_question_list(q_all_B, q_list, limit=True)
+
+ ctype = ContentType.objects.get_for_model(Question)
+ EMAIL_UPDATE_ACTIVITY = const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT
+
+ #up to this point we still don't know if emails about
+ #collected questions were sent recently
+ #the next loop examines activity record and decides
+ #for each question, whether it needs to be included or not
+ #into the report
+
+ for q, meta_data in q_list.items():
+ #this loop edits meta_data for each question
+ #so that user will receive counts on new edits new answers, etc
+ #and marks questions that need to be skipped
+ #because an email about them was sent recently enough
+
+ #also it keeps a record of latest email activity per question per user
+ try:
+ #todo: is it possible to use content_object here, instead of
+ #content type and object_id pair?
+ update_info = Activity.objects.get(
+ user=user,
+ content_type=ctype,
+ object_id=q.id,
+ activity_type=EMAIL_UPDATE_ACTIVITY
+ )
+ emailed_at = update_info.active_at
+ except Activity.DoesNotExist:
+ update_info = Activity(
+ user=user,
+ content_object=q,
+ activity_type=EMAIL_UPDATE_ACTIVITY
+ )
+ emailed_at = datetime.datetime(1970, 1, 1)#long time ago
+ except Activity.MultipleObjectsReturned:
+ raise Exception(
+ 'server error - multiple question email activities '
+ 'found per user-question pair'
+ )
+
+ cutoff_time = meta_data['cutoff_time']#cutoff time for the question
+
+ #skip question if we need to wait longer because
+ #the delay before the next email has not yet elapsed
+ #or if last email was sent after the most recent modification
+ if emailed_at > cutoff_time or emailed_at > q.last_activity_at:
+ meta_data['skip'] = True
+ continue
+
+ #collect info on all sorts of news that happened after
+ #the most recent emailing to the user about this question
+ q_rev = QuestionRevision.objects.filter(
+ question=q,
+ revised_at__gt=emailed_at
+ )
+
+ q_rev = q_rev.exclude(author=user)
+
+ #now update all sorts of metadata per question
+ meta_data['q_rev'] = len(q_rev)
+ if len(q_rev) > 0 and q.added_at == q_rev[0].revised_at:
+ meta_data['q_rev'] = 0
+ meta_data['new_q'] = True
+ else:
+ meta_data['new_q'] = False
+
+ new_ans = Answer.objects.filter(
+ question=q,
+ added_at__gt=emailed_at
+ )
+
+ new_ans = new_ans.exclude(author=user)
+ meta_data['new_ans'] = len(new_ans)
+ ans_rev = AnswerRevision.objects.filter(
+ answer__question=q,
+ revised_at__gt=emailed_at
+ )
+ ans_rev = ans_rev.exclude(author=user)
+ meta_data['ans_rev'] = len(ans_rev)
+
+ #finally skip question if there are no news indeed
+ if len(q_rev) + len(new_ans) + len(ans_rev) == 0:
+ meta_data['skip'] = True
+ else:
+ meta_data['skip'] = False
+ update_info.active_at = datetime.datetime.now()
+ if DEBUG_THIS_COMMAND == False:
+ update_info.save() #save question email update activity
+ #q_list is actually an ordered dictionary
+ #print 'user %s gets %d' % (user.username, len(q_list.keys()))
+ #todo: sort question list by update time
+ return q_list
+
+ def send_email_alerts(self):
+ #does not change the database, only sends the email
+ #todo: move this to template
+ for user in User.objects.all():
+ #todo: q_list is a dictionary, not a list
+ q_list = self.get_updated_questions_for_user(user)
+ if len(q_list.keys()) == 0:
+ continue
+ num_q = 0
+ num_moot = 0
+ for meta_data in q_list.values():
+ if meta_data['skip']:
+ num_moot = True
+ else:
+ num_q += 1
+ if num_q > 0:
+ url_prefix = askbot_settings.APP_URL
+ subject = _('email update message subject')
+ print 'have %d updated questions for %s' % (num_q, user.username)
+ text = ungettext('%(name)s, this is an update message header for %(num)d question',
+ '%(name)s, this is an update message header for %(num)d questions',num_q) \
+ % {'num':num_q, 'name':user.username}
+
+ text += '<ul>'
+ items_added = 0
+ items_unreported = 0
+ for q, meta_data in q_list.items():
+ act_list = []
+ if meta_data['skip']:
+ continue
+ if items_added >= askbot_settings.MAX_ALERTS_PER_EMAIL:
+ items_unreported = num_q - items_added #may be inaccurate actually, but it's ok
+
+ else:
+ items_added += 1
+ if meta_data['new_q']:
+ act_list.append(_('new question'))
+ format_action_count('%(num)d rev', meta_data['q_rev'],act_list)
+ format_action_count('%(num)d ans', meta_data['new_ans'],act_list)
+ format_action_count('%(num)d ans rev',meta_data['ans_rev'],act_list)
+ act_token = ', '.join(act_list)
+ text += '<li><a href="%s?sort=latest">%s</a> <font color="#777777">(%s)</font></li>' \
+ % (url_prefix + q.get_absolute_url(), q.title, act_token)
+ text += '</ul>'
+ text += '<p></p>'
+ #if len(q_list.keys()) >= askbot_settings.MAX_ALERTS_PER_EMAIL:
+ # text += _('There may be more questions updated since '
+ # 'you have logged in last time as this list is '
+ # 'abridged for your convinience. Please visit '
+ # 'the askbot and see what\'s new!<br>'
+ # )
+
+ text += _(
+ 'Please visit the askbot and see what\'s new! '
+ 'Could you spread the word about it - '
+ 'can somebody you know help answering those questions or '
+ 'benefit from posting one?'
+ )
+
+ feeds = EmailFeedSetting.objects.filter(
+ subscriber=user,
+ )
+ feed_freq = [feed.frequency for feed in feeds]
+ text += '<p></p>'
+ if 'd' in feed_freq:
+ text += _('Your most frequent subscription setting is \'daily\' '
+ 'on selected questions. If you are receiving more than one '
+ 'email per day'
+ 'please tell about this issue to the askbot administrator.'
+ )
+ elif 'w' in feed_freq:
+ text += _('Your most frequent subscription setting is \'weekly\' '
+ 'if you are receiving this email more than once a week '
+ 'please report this issue to the askbot administrator.'
+ )
+ text += ' '
+ text += _(
+ 'There is a chance that you may be receiving links seen '
+ 'before - due to a technicality that will eventually go away. '
+ )
+ # text += '</p>'
+ #if num_moot > 0:
+ # text += '<p></p>'
+ # text += ungettext('There is also one question which was recently '\
+ # +'updated but you might not have seen its latest version.',
+ # 'There are also %(num)d more questions which were recently updated '\
+ # +'but you might not have seen their latest version.',num_moot) \
+ # % {'num':num_moot,}
+ # text += _('Perhaps you could look up previously sent askbot reminders in your mailbox.')
+ # text += '</p>'
+
+ link = url_prefix + user.get_profile_url() + '?sort=email_subscriptions'
+ text += _('go to %(email_settings_link)s to change frequency of email updates or %(admin_email)s administrator') \
+ % {'email_settings_link':link, 'admin_email':settings.ADMINS[0][1]}
+ if DEBUG_THIS_COMMAND == False:
+ msg = EmailMessage(subject, text, settings.DEFAULT_FROM_EMAIL, [user.email])
+ msg.content_subtype = 'html'
+ msg.send()
+ else:
+ msg2 = EmailMessage(
+ subject,
+ text,
+ settings.DEFAULT_FROM_EMAIL,
+ ['your@email.com']
+ )
+ msg2.content_subtype = 'html'
+ msg2.send()
diff --git a/forum/management/commands/subscribe_everyone.py b/askbot/management/commands/subscribe_everyone.py
index c79528f3..d45d33ec 100755..100644
--- a/forum/management/commands/subscribe_everyone.py
+++ b/askbot/management/commands/subscribe_everyone.py
@@ -1,15 +1,10 @@
from django.core.management.base import NoArgsCommand
from django.db import connection
-from django.db.models import Q, F
-from forum.models import *
+from askbot.models import EmailFeedSetting, User
from django.core.mail import EmailMessage
-from django.utils.translation import ugettext as _
-from django.utils.translation import ungettext
-import datetime
-from django.conf import settings
class Command(NoArgsCommand):
- def handle_noargs(self,**options):
+ def handle_noargs(self, **options):
try:
try:
self.subscribe_everyone()
@@ -24,9 +19,15 @@ class Command(NoArgsCommand):
for user in User.objects.all():
for feed_type in feed_type_info:
try:
- feed_setting = EmailFeedSetting.objects.get(subscriber=user,feed_type = feed_type[0])
+ feed_setting = EmailFeedSetting.objects.get(
+ subscriber=user,
+ feed_type = feed_type[0]
+ )
except EmailFeedSetting.DoesNotExist:
- feed_setting = EmailFeedSetting(subscriber=user,feed_type=feed_type[0])
+ feed_setting = EmailFeedSetting(
+ subscriber=user,
+ feed_type=feed_type[0]
+ )
feed_setting.frequency = 'w'
feed_setting.reported_at = None
feed_setting.save()
diff --git a/forum/search/__init__.py b/askbot/middleware/__init__.py
index e69de29b..e69de29b 100644
--- a/forum/search/__init__.py
+++ b/askbot/middleware/__init__.py
diff --git a/forum/middleware/anon_user.py b/askbot/middleware/anon_user.py
index 866734da..06e9dfd0 100755..100644
--- a/forum/middleware/anon_user.py
+++ b/askbot/middleware/anon_user.py
@@ -1,16 +1,13 @@
-from django.http import HttpResponseRedirect
-from forum.utils.forms import get_next_url
from django.utils.translation import ugettext as _
-from forum.user_messages import create_message, get_and_delete_messages
-from django.conf import settings
-from django.core.urlresolvers import reverse
-import logging
+from askbot.user_messages import create_message, get_and_delete_messages
+from askbot.conf import settings as askbot_settings
+from askbot import const
class AnonymousMessageManager(object):
- def __init__(self,request):
+ def __init__(self, request):
self.request = request
- def create(self,message=''):
- create_message(self.request,message)
+ def create(self, message=''):
+ create_message(self.request, message)
def get_and_delete(self):
messages = get_and_delete_messages(self.request)
return messages
@@ -24,12 +21,16 @@ def dummy_deepcopy(*arg):
class ConnectToSessionMessagesMiddleware(object):
def process_request(self, request):
if not request.user.is_authenticated():
- request.user.__deepcopy__ = dummy_deepcopy #plug on deepcopy which may be called by django db "driver"
- request.user.message_set = AnonymousMessageManager(request) #here request is linked to anon user
- request.user.get_and_delete_messages = request.user.message_set.get_and_delete
+ #plug on deepcopy which may be called by django db "driver"
+ request.user.__deepcopy__ = dummy_deepcopy
+ #here request is linked to anon user
+ request.user.message_set = AnonymousMessageManager(request)
+ request.user.get_and_delete_messages = \
+ request.user.message_set.get_and_delete
#also set the first greeting one time per session only
if 'greeting_set' not in request.session:
request.session['greeting_set'] = True
- msg = _('First time here? Check out the <a href="%s">FAQ</a>!') % reverse('faq')
+ msg = _(const.GREETING_FOR_ANONYMOUS_USER) \
+ % askbot_settings.GREETING_URL
request.user.message_set.create(message=msg)
diff --git a/forum/middleware/cancel.py b/askbot/middleware/cancel.py
index 15a4371d..45764d82 100755..100644
--- a/forum/middleware/cancel.py
+++ b/askbot/middleware/cancel.py
@@ -1,5 +1,5 @@
from django.http import HttpResponseRedirect
-from forum.utils.forms import get_next_url
+from askbot.utils.forms import get_next_url
import logging
class CancelActionMiddleware(object):
def process_view(self, request, view_func, view_args, view_kwargs):
diff --git a/forum/middleware/pagesize.py b/askbot/middleware/pagesize.py
index 486193dc..20af6aa6 100755..100644
--- a/forum/middleware/pagesize.py
+++ b/askbot/middleware/pagesize.py
@@ -1,19 +1,23 @@
+import logging
+import traceback
+import sys
# used in questions
QUESTIONS_PAGE_SIZE = 10
class QuestionsPageSizeMiddleware(object):
def process_request(self, request):
- # Set flag to False by default. If it is equal to True, then need to be saved.
+ # Set flag to False by default. If it is True, then need to be saved.
page_size_changed = False
# get page_size from session, if failed then get default value
user_page_size = request.session.get("page_size", QUESTIONS_PAGE_SIZE)
# set page_size equal to logon user specified value in database
- if request.user.is_authenticated() and request.user.questions_per_page > 0:
+ if request.user.is_authenticated() \
+ and request.user.questions_per_page > 0:
user_page_size = request.user.questions_per_page
try:
# get new page_size from UI selection
page_size = int(request.GET.get('page_size', user_page_size))
- if page_size <> user_page_size:
+ if page_size != user_page_size:
page_size_changed = True
except ValueError:
@@ -28,6 +32,8 @@ class QuestionsPageSizeMiddleware(object):
# put page_size into session
request.session["page_size"] = page_size
- def process_exception(self,request,exception):
- import logging
- logging.debug('have exception %s' % str(exception))
+ def process_exception(self, request, exception):
+ exc_type, exc_value, exc_traceback = sys.exc_info()
+ logging.debug(''.join(traceback.format_tb(exc_traceback)))
+ logging.debug(exc_type)
+ logging.debug(exc_value)
diff --git a/askbot/middleware/spaceless.py b/askbot/middleware/spaceless.py
new file mode 100644
index 00000000..16b11522
--- /dev/null
+++ b/askbot/middleware/spaceless.py
@@ -0,0 +1,15 @@
+"""
+Middleware that strips whitespace between html tags
+copied from David Cramer's blog
+http://www.davidcramer.net/code/369/spaceless-html-in-django.html
+"""
+from django.utils.html import strip_spaces_between_tags as short
+
+class SpacelessMiddleware(object):
+ def process_response(self, request, response):
+ """strips whitespace from all documents
+ whose content type is text/html
+ """
+ if 'text/html' in response['Content-Type']:
+ response.content = short(response.content)
+ return response
diff --git a/forum/middleware/view_log.py b/askbot/middleware/view_log.py
index bf0b9fbb..fa38f29a 100644
--- a/forum/middleware/view_log.py
+++ b/askbot/middleware/view_log.py
@@ -1,10 +1,10 @@
import logging
from django.conf import settings
-from forum.views.readers import questions as questions_view
-from forum.views.commands import vote
+from askbot.views.readers import questions as questions_view
+from askbot.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
+from askbot.views.writers import delete_comment, question_comments, answer_comments
+from askbot.views.readers import question_revisions, answer_revisions
#todo: the list is getting bigger and bigger - maybe there is a better way to
#trigger reset of sarch state?
@@ -19,8 +19,6 @@ class ViewLog(object):
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:
diff --git a/askbot/migrations/0001_initial.py b/askbot/migrations/0001_initial.py
new file mode 100644
index 00000000..31f6827b
--- /dev/null
+++ b/askbot/migrations/0001_initial.py
@@ -0,0 +1,1550 @@
+# encoding: utf-8
+import os
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+app_dir_name = os.path.basename(os.path.dirname(os.path.dirname(__file__)))
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model 'Vote'
+ if app_dir_name == 'forum':
+ 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'])
+ else:
+ 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('askbot', ['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('askbot', ['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('askbot', ['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('askbot', ['Tag'])
+
+ # Adding model 'MarkedTag'
+ db.create_table('askbot_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['askbot.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('askbot', ['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('askbot', ['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['askbot.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['askbot.question'], null=False)),
+ ('tag', models.ForeignKey(orm['askbot.tag'], null=False))
+ ))
+ db.create_unique(u'question_tags', ['question_id', 'tag_id'])
+
+ # Adding model 'QuestionView'
+ db.create_table('askbot_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['askbot.Question'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('askbot', ['QuestionView'])
+
+ # Adding model 'FavoriteQuestion'
+ db.create_table(u'favorite_question', (
+ ('question', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['askbot.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('askbot', ['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['askbot.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('askbot', ['QuestionRevision'])
+
+ # Adding model 'AnonymousQuestion'
+ db.create_table('askbot_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('askbot', ['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['askbot.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('askbot', ['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['askbot.Answer'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('revision', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ))
+ db.send_create_signal('askbot', ['AnswerRevision'])
+
+ # Adding model 'AnonymousAnswer'
+ db.create_table('askbot_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['askbot.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('askbot', ['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('askbot', ['Activity'])
+
+ # Adding model 'EmailFeedSetting'
+ db.create_table('askbot_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('askbot', ['EmailFeedSetting'])
+
+ # Adding model 'ValidationHash'
+ db.create_table('askbot_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('askbot', ['ValidationHash'])
+
+ # Adding unique constraint on 'ValidationHash', fields ['user', 'type']
+ db.create_unique('askbot_validationhash', ['user_id', 'type'])
+
+ # Adding model 'AuthKeyUserAssociation'
+ db.create_table('askbot_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('askbot', ['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('askbot', ['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['askbot.Badge'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('askbot', ['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['askbot.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('askbot', ['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('askbot', ['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['askbot.book'], null=False)),
+ ('question', models.ForeignKey(orm['askbot.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['askbot.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('askbot', ['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['askbot.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('askbot', ['BookAuthorRss'])
+
+
+ def backwards(self, orm):
+
+ if app_dir_name == 'forum':
+ # 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')
+ else:
+ # 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('askbot_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('askbot_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('askbot_anonymousquestion')
+
+ # Deleting model 'Answer'
+ db.delete_table(u'answer')
+
+ # Deleting model 'AnswerRevision'
+ db.delete_table(u'answer_revision')
+
+ # Deleting model 'AnonymousAnswer'
+ db.delete_table('askbot_anonymousanswer')
+
+ # Deleting model 'Activity'
+ db.delete_table(u'activity')
+
+ # Deleting model 'EmailFeedSetting'
+ db.delete_table('askbot_emailfeedsetting')
+
+ # Deleting model 'ValidationHash'
+ db.delete_table('askbot_validationhash')
+
+ # Removing unique constraint on 'ValidationHash', fields ['user', 'type']
+ db.delete_unique('askbot_validationhash', ['user_id', 'type'])
+
+ # Deleting model 'AuthKeyUserAssociation'
+ db.delete_table('askbot_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')
+
+
+ if app_dir_name == 'forum':
+ 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'})
+ }
+ }
+ else:
+ 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'})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.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', [], {})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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', [], {})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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 = [app_dir_name]
diff --git a/askbot/migrations/0002_auto__add_field_answer_text__chg_field_answer_html__add_field_question.py b/askbot/migrations/0002_auto__add_field_answer_text__chg_field_answer_html__add_field_question.py
new file mode 100644
index 00000000..9b8cdab7
--- /dev/null
+++ b/askbot/migrations/0002_auto__add_field_answer_text__chg_field_answer_html__add_field_question.py
@@ -0,0 +1,700 @@
+# encoding: utf-8
+import os
+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')())
+
+ app_dir_name = os.path.basename(os.path.dirname(os.path.dirname(__file__)))
+
+ if app_dir_name == 'forum':
+ 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'})
+ }
+ }
+ else:
+ 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'})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.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', [], {})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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', [], {})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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 = [app_dir_name]
diff --git a/askbot/migrations/0003_copy_denorm_text_record_to_posts_for_fulltext_search.py b/askbot/migrations/0003_copy_denorm_text_record_to_posts_for_fulltext_search.py
new file mode 100644
index 00000000..3227a24f
--- /dev/null
+++ b/askbot/migrations/0003_copy_denorm_text_record_to_posts_for_fulltext_search.py
@@ -0,0 +1,687 @@
+# encoding: utf-8
+import datetime
+import os
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+
+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
+
+ forum_app_name = os.path.basename(os.path.dirname(os.path.dirname(__file__)))
+ if forum_app_name == 'forum':
+ 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']
+ else:
+ 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'})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.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', [], {})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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', [], {})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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 = ['askbot']
diff --git a/askbot/migrations/0004_install_full_text_indexes_for_mysql.py b/askbot/migrations/0004_install_full_text_indexes_for_mysql.py
new file mode 100644
index 00000000..ccf70fd2
--- /dev/null
+++ b/askbot/migrations/0004_install_full_text_indexes_for_mysql.py
@@ -0,0 +1,720 @@
+# encoding: utf-8
+import os
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+
+Q_INDEX_NAME = 'askbot_question_full_text_index'
+A_INDEX_NAME = 'askbot_answer_full_text_index'
+
+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,
+ orm.Question._meta.db_table,
+ ('title','text','tagnames',)
+ )
+ db.execute(question_index_sql)
+
+ answer_index_sql = get_create_full_text_index_sql(
+ A_INDEX_NAME,
+ orm.Answer._meta.db_table,
+ ('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,
+ orm.Question._meta.db_table,
+ )
+ )
+ db.execute(
+ get_drop_index_sql(
+ A_INDEX_NAME,
+ orm.Answer._meta.db_table,
+ )
+ )
+
+ forum_app_name = os.path.basename(os.path.dirname(os.path.dirname(__file__)))
+ if forum_app_name == 'forum':
+ 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']
+ else:
+ 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'})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.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', [], {})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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', [], {})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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 = ['askbot']
diff --git a/askbot/migrations/0005_install_badges.py b/askbot/migrations/0005_install_badges.py
new file mode 100644
index 00000000..c8efda9c
--- /dev/null
+++ b/askbot/migrations/0005_install_badges.py
@@ -0,0 +1,751 @@
+# encoding: utf-8
+import os
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+
+_ = lambda v:v #fake translation function so that badges are translated, but database takes keys
+
+INITIAL_BADGE_DATA = (
+ (_('Disciplined'), 3, _('disciplined'), _('Deleted own post with score of 3 or higher'), True, 0),
+ (_('Peer Pressure'), 3, _('peer-pressure'), _('Deleted own post with score of -3 or lower'), True, 0),
+ (_('Nice answer'), 3, _('nice-answer'), _('Answer voted up 10 times'), True, 0),
+ (_('Nice Question'), 3, _('nice-question'), _('Question voted up 10 times'), True, 0),
+ (_('Pundit'), 3, _('pundit'), _('Left 10 comments with score of 10 or more'), False, 0),
+ (_('Popular Question'), 3, _('popular-question'), _('Asked a question with 1,000 views'), True, 0),
+ (_('Citizen patrol'), 3, _('citizen-patrol'), _('First flagged post'), False, 0),
+ (_('Cleanup'), 3, _('cleanup'), _('First rollback'), False, 0),
+ (_('Critic'), 3, _('critic'), _('First down vote'), False, 0),
+ (_('Editor'), 3, _('editor'), _('First edit'), False, 0),
+ (_('Organizer'), 3, _('organizer'), _('First retag'), False, 0),
+ (_('Scholar'), 3, _('scholar'), _('First accepted answer on your own question'), False, 0),
+ (_('Student'), 3, _('student'), _('Asked first question with at least one up vote'), False, 0),
+ (_('Supporter'), 3, _('supporter'), _('First up vote'), False, 0),
+ (_('Teacher'), 3, _('teacher'), _('Answered first question with at least one up vote'), False, 0),
+ (_('Autobiographer'), 3, _('autobiographer'), _('Completed all user profile fields'), False, 0),
+ (_('Self-Learner'), 3, _('self-learner'), _('Answered your own question with at least 3 up votes'), True, 0),
+ (_('Great Answer'), 1, _('great-answer'), _('Answer voted up 100 times'), True, 0),
+ (_('Great Question'), 1, _('great-question'), _('Question voted up 100 times'), True, 0),
+ (_('Stellar Question'), 1, _('stellar-question'), _('Question favorited by 100 users'), True, 0),
+ (_('Famous question'), 1, _('famous-question'), _('Asked a question with 10,000 views'), True, 0),
+ (_('Alpha'), 2, _('alpha'), _('Actively participated in the private alpha'), False, 0),
+ (_('Good Answer'), 2, _('good-answer'), _('Answer voted up 25 times'), True, 0),
+ (_('Good Question'), 2, _('good-question'), _('Question voted up 25 times'), True, 0),
+ (_('Favorite Question'), 2, _('favorite-question'), _('Question favorited by 25 users'), True, 0),
+ (_('Civic duty'), 2, _('civic-duty'), _('Voted 300 times'), False, 0),
+ (_('Strunk & White'), 2, _('strunk-and-white'), _('Edited 100 entries'), False, 0),
+ (_('Generalist'), 2, _('generalist'), _('Active in many different tags'), False, 0),
+ (_('Expert'), 2, _('expert'), _('Very active in one tag'), False, 0),
+ (_('Yearling'), 2, _('yearling'), _('Active member for a year'), False, 0),
+ (_('Notable Question'), 2, _('notable-question'), _('Asked a question with 2,500 views'), True, 0),
+ (_('Enlightened'), 2, _('enlightened'), _('First answer was accepted with at least 10 up votes'), False, 0),
+ (_('Beta'), 2, _('beta'), _('Actively participated in the private beta'), False, 0),
+ (_('Guru'), 2, _('guru'), _('Accepted answer and voted up 40 times'), True, 0),
+ (_('Necromancer'), 2, _('necromancer'), _('Answered a question more than 60 days later with at least 5 votes'), True, 0),
+ (_('Taxonomist'), 2, _('taxonomist'), _('Created a tag used by 50 questions'), True, 0)
+)
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ "Write your forwards methods here."
+
+ for entry in INITIAL_BADGE_DATA:
+ name = entry[0]
+ type = entry[1]
+ slug = entry[2]
+ description = entry[3]
+ multiple = entry[4]
+
+ try:
+ badge = orm.Badge.objects.get(name=name)
+ print 'already have badge %s' % name
+ except orm.Badge.DoesNotExist:
+ print 'adding new badge %s' % name
+ badge = orm.Badge()
+ badge.name = name
+
+ badge.type = type
+ badge.slug = slug
+ badge.description = description
+ badge.multiple = multiple
+ badge.save()
+
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+ for entry in INITIAL_BADGE_DATA:
+ name = entry[0]
+ try:
+ badge = orm.Badge.objects.get(name = name)
+ badge.award_badge.clear()
+ badge.delete()
+ print 'deleted badge %s' % name
+ except orm.Badge.DoesNotExist:
+ print 'no such badge %s - so skipping' % name
+ pass
+
+ forum_app_name = os.path.basename(os.path.dirname(os.path.dirname(__file__)))
+ if forum_app_name == 'forum':
+ 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, 5, 2, 12, 29, 51, 920204)'}),
+ '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']
+ else:
+ 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'})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.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', [], {})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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', [], {})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 2, 12, 29, 51, 920204)'}),
+ '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']"})
+ },
+ 'askbot.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 = ['askbot']
diff --git a/askbot/migrations/0006_add_subscription_setting_for_comments_and_mentions.py b/askbot/migrations/0006_add_subscription_setting_for_comments_and_mentions.py
new file mode 100644
index 00000000..15c9111f
--- /dev/null
+++ b/askbot/migrations/0006_add_subscription_setting_for_comments_and_mentions.py
@@ -0,0 +1,719 @@
+# encoding: utf-8
+import os
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+try:
+ from forum import const
+except ImportError:
+ from askbot import const
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ "Write your forwards methods here."
+ print ''
+ print '**************'
+ print 'Adding subscription on comment responses and name mentions for each user. '
+ print 'frequency will be automatically set to the most frequent selection '
+ print 'that user made for any other types of subscriptions'
+ print ''
+
+ for user in orm['auth.User'].objects.all():
+
+ feeds = orm.EmailFeedSetting.objects.filter(subscriber=user)
+ freqs = set([f.frequency for f in feeds])
+
+ if 'i' in freqs:
+ frequency = 'i'
+ elif 'd' in freqs:
+ frequency = 'd'
+ elif 'w' in freqs:
+ frequency = 'w'
+ else:
+ frequency = 'n'
+
+ new_feed = orm.EmailFeedSetting(
+ subscriber = user,
+ frequency = frequency,
+ feed_type = 'm_and_c',
+ )
+ new_feed.save()
+ verbose_frequency = dict(const.NOTIFICATION_DELIVERY_SCHEDULE_CHOICES)[frequency]
+ print 'added \'%s\' subscription for %s (%d)' % (
+ verbose_frequency,
+ user.username,
+ user.id
+ )
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+ feeds = orm.EmailFeedSetting.objects.filter(feed_type = 'm_and_c')
+ n = len(feeds)
+ feeds.delete()
+ print 'deleted %d feeds' % n
+
+ forum_app_name = os.path.basename(os.path.dirname(os.path.dirname(__file__)))
+ if forum_app_name == 'forum':
+ 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, 5, 16, 15, 7, 19, 596607)'}),
+ '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']
+ else:
+ 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'})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.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', [], {})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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', [], {})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 16, 15, 7, 19, 596607)'}),
+ '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']"})
+ },
+ 'askbot.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 = ['askbot']
diff --git a/askbot/migrations/0007_install_mentions_model.py b/askbot/migrations/0007_install_mentions_model.py
new file mode 100644
index 00000000..f5a712ad
--- /dev/null
+++ b/askbot/migrations/0007_install_mentions_model.py
@@ -0,0 +1,708 @@
+# encoding: utf-8
+import os
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+app_dir_name = os.path.basename(os.path.dirname(os.path.dirname(__file__)))
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model 'Mention'
+ db.create_table(u'mention', (
+ ('mentioned_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='mentions_sent', to=orm['auth.User'])),
+ ('mentioned_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
+ ('mentioned_whom', self.gf('django.db.models.fields.related.ForeignKey')(related_name='mentions_received', to=orm['auth.User'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal(app_dir_name, ['Mention'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'Mention'
+ db.delete_table(u'mention')
+
+ if app_dir_name == 'forum':
+ 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', [], {'related_name': "'notification_subscriptions'", '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.mention': {
+ 'Meta': {'object_name': 'Mention', 'db_table': "u'mention'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mentioned_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'mentioned_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_sent'", 'to': "orm['auth.User']"}),
+ 'mentioned_whom': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_received'", 'to': "orm['auth.User']"}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ '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, 5, 17, 13, 4, 34, 910299)'}),
+ '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'})
+ }
+ }
+ else:
+ 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'})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.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', [], {})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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', [], {})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.mention': {
+ 'Meta': {'object_name': 'Mention', 'db_table': "u'mention'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mentioned_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'mentioned_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_sent'", 'to': "orm['auth.User']"}),
+ 'mentioned_whom': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_received'", 'to': "orm['auth.User']"}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 17, 13, 4, 34, 910299)'}),
+ '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']"})
+ },
+ 'askbot.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 = [app_dir_name]
diff --git a/askbot/migrations/0008_add_html_field_to_comments.py b/askbot/migrations/0008_add_html_field_to_comments.py
new file mode 100644
index 00000000..6da4b292
--- /dev/null
+++ b/askbot/migrations/0008_add_html_field_to_comments.py
@@ -0,0 +1,708 @@
+# encoding: utf-8
+import os
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+app_dir_name = os.path.basename(os.path.dirname(os.path.dirname(__file__)))
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding field 'Comment.html'
+ db.add_column(u'comment', 'html', self.gf('django.db.models.fields.CharField')(default='', max_length=2048), keep_default=False)
+
+ # Changing field 'Comment.comment'
+ db.alter_column(u'comment', 'comment', self.gf('django.db.models.fields.CharField')(max_length=2048))
+
+ def backwards(self, orm):
+
+ # Deleting field 'Comment.html'
+ db.delete_column(u'comment', 'html')
+
+ # Changing field 'Comment.comment'
+ db.alter_column(u'comment', 'comment', self.gf('django.db.models.fields.CharField')(max_length=300))
+
+
+ if app_dir_name == 'forum':
+ 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': '2048'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'html': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}),
+ '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', [], {'related_name': "'notification_subscriptions'", '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.mention': {
+ 'Meta': {'object_name': 'Mention', 'db_table': "u'mention'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mentioned_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'mentioned_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_sent'", 'to': "orm['auth.User']"}),
+ 'mentioned_whom': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_received'", 'to': "orm['auth.User']"}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ '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, 5, 17, 15, 29, 56, 802370)'}),
+ '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'})
+ }
+ }
+ else:
+ 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'})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.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', [], {})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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', [], {})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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': '2048'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'html': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}),
+ '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']"})
+ },
+ 'askbot.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', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.mention': {
+ 'Meta': {'object_name': 'Mention', 'db_table': "u'mention'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mentioned_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'mentioned_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_sent'", 'to': "orm['auth.User']"}),
+ 'mentioned_whom': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_received'", 'to': "orm['auth.User']"}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 17, 15, 29, 56, 802370)'}),
+ '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']"})
+ },
+ 'askbot.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 = [app_dir_name]
diff --git a/askbot/migrations/0009_calculate_html_field_for_comments.py b/askbot/migrations/0009_calculate_html_field_for_comments.py
new file mode 100644
index 00000000..a98447da
--- /dev/null
+++ b/askbot/migrations/0009_calculate_html_field_for_comments.py
@@ -0,0 +1,854 @@
+# encoding: utf-8
+import os
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from django.utils.html import urlize
+from django.template.defaultfilters import slugify
+from django.core.urlresolvers import reverse
+try:
+ from forum import const
+except ImportError:
+ from askbot import const
+import re
+
+def get_authors(question, orm = None):
+ authors = set()
+ for q_rev in orm.QuestionRevision.objects.filter(question=question):
+ authors.add(q_rev.author)
+
+ q_comments = orm.Comment.objects.filter(
+ content_type__model='question',
+ object_id = question.id
+ )
+ for q_c in q_comments:
+ authors.add(q_c.user)
+
+ answers = orm.Answer.objects.filter(
+ question = question,
+ deleted = False
+ )
+ for a in answers:
+ for a_rev in orm.AnswerRevision.objects.filter(answer = a):
+ authors.add(a_rev.author)
+ a_comments = orm.Comment.objects.filter(
+ content_type__model = 'answer',
+ object_id = a.id
+ )
+ for a_c in a_comments:
+ authors.add(a_c.user)
+ return authors
+
+def get_absolute_url(user):
+ url = reverse(
+ 'user_profile',
+ kwargs={
+ 'id':user.id,
+ 'slug': slugify(user.username)
+ }
+ )
+ return u'<a href="%s">@%s</a>' % (url, user.username)
+
+def get_comment_continuation(matching_author):
+ if matching_author:
+ return get_absolute_url(matching_author)
+ else:
+ return '@'
+
+def maybe_save_mention(
+ context = None,
+ mentioned_whom = None,
+ orm = None,
+ comment_content_type = None
+ ):
+ if mentioned_whom and mentioned_whom != context.user:
+ m = orm['forum.Mention'](
+ mentioned_by = context.user,
+ mentioned_whom = mentioned_whom,
+ mentioned_at = context.added_at,
+ object_id = context.id,
+ content_type = comment_content_type,
+ )
+ m.save()
+
+def extract_matching_author(text, ordered_authors):
+ for a in ordered_authors:
+ if text.startswith(a.username):
+ ulen = len(a.username)
+ if len(text) == ulen:
+ text = ''
+ elif text[ulen] in const.TWITTER_STYLE_MENTION_TERMINATION_CHARS:
+ text = text[ulen:]
+ else:
+ #near miss, here we could insert a warning that perhaps
+ #a termination character is needed
+ continue
+ return a, text
+ return None, text
+
+
+def mentionize(text, comment = None, all_users = None, orm = None):
+ if comment.content_type.model == 'answer':
+ answer = orm.Answer.objects.get(id = comment.object_id)
+ question = answer.question
+ else:
+ question = orm.Question.objects.get(id = comment.object_id)
+
+ #build ordered list of author names
+ authors = get_authors(question, orm = orm)
+ the_rest = all_users - authors
+ ordered_authors = list(authors) + list(the_rest)
+
+ comment_content_type = orm.ContentType.objects.get(model='comment')
+
+ output = ''
+ while '@' in text:
+ #the purpose of this loop is to convert any occurance of '@mention ' syntax
+ #to user account links leading space is required unless @ is the first
+ #character in whole text, also, either a punctuation or a ' ' char is required
+ #after the name
+ pos = text.index('@')
+
+ output += text[:pos]
+
+ if len(text) == pos + 1:
+ output += '@'
+ text = ''
+ break
+
+ if pos > 0:
+ if text[pos-1] in const.TWITTER_STYLE_MENTION_TERMINATION_CHARS:
+
+ text = text[pos+1:]
+ matching_author, text = extract_matching_author(text, ordered_authors)
+ output += get_comment_continuation(matching_author)
+ maybe_save_mention(
+ context = comment,
+ mentioned_whom = matching_author,
+ orm = orm,
+ comment_content_type = comment_content_type
+ )
+ else:
+ text = text[pos+1:]
+ output += '@'
+ else:
+ text = text[1:]
+ matching_author, text = extract_matching_author(text, ordered_authors)
+ output += get_comment_continuation(matching_author)
+ maybe_save_mention(
+ context = comment,
+ mentioned_whom = matching_author,
+ orm = orm,
+ comment_content_type = comment_content_type
+ )
+
+ #append the rest of text that did not have @ symbols
+ output += text
+ return output
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ "Write your forwards methods here."
+ all_users = set(orm['auth.User'].objects.all())
+ for comment in orm.Comment.objects.all():
+ comment.html = mentionize(
+ urlize(comment.comment, nofollow=True),
+ comment = comment,
+ all_users = all_users,
+ orm = orm
+ )
+ #print 'was %s' % comment.comment
+ #print 'now %s' % comment.html
+ comment.save()
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+ for comment in orm.Comment.objects.all():
+ comment.html = comment.comment
+ comment.save()
+
+ forum_app_name = os.path.basename(os.path.dirname(os.path.dirname(__file__)))
+ if forum_app_name == 'forum':
+ 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': '2048'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'html': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}),
+ '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', [], {'related_name': "'notification_subscriptions'", '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.mention': {
+ 'Meta': {'object_name': 'Mention', 'db_table': "u'mention'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mentioned_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'mentioned_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_sent'", 'to': "orm['auth.User']"}),
+ 'mentioned_whom': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_received'", 'to': "orm['auth.User']"}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ '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, 5, 17, 15, 33, 45, 429877)'}),
+ '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']
+ else:
+ 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'})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.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', [], {})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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', [], {})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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': '2048'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'html': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}),
+ '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']"})
+ },
+ 'askbot.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', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.mention': {
+ 'Meta': {'object_name': 'Mention', 'db_table': "u'mention'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mentioned_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'mentioned_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_sent'", 'to': "orm['auth.User']"}),
+ 'mentioned_whom': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_received'", 'to': "orm['auth.User']"}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 17, 15, 33, 45, 429877)'}),
+ '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']"})
+ },
+ 'askbot.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 = ['askbot']
diff --git a/forum/migrations/0002_auto__add_field_answer_text__chg_field_answer_html__add_field_question.py b/askbot/migrations/0010_add_receiving_user_to_activity_model.py
index d703c161..5fb6ebe0 100644
--- a/forum/migrations/0002_auto__add_field_answer_text__chg_field_answer_html__add_field_question.py
+++ b/askbot/migrations/0010_add_receiving_user_to_activity_model.py
@@ -8,32 +8,19 @@ 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))
+ # Adding M2M table for field receiving_user on 'Activity'
+ db.create_table(u'activity_receiving_users', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('activity', models.ForeignKey(orm['forum.activity'], null=False)),
+ ('user', models.ForeignKey(orm['auth.user'], null=False))
+ ))
+ db.create_unique(u'activity_receiving_users', ['activity_id', 'user_id'])
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')())
+ # Removing M2M table for field receiving_user on 'Activity'
+ db.delete_table('activity_receiving_users')
models = {
@@ -98,6 +85,7 @@ class Migration(SchemaMigration):
'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', [], {}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'to': "orm['auth.User']"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
},
'forum.anonymousanswer': {
@@ -229,8 +217,9 @@ class Migration(SchemaMigration):
'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'}),
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '2048'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'html': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}),
'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']"})
@@ -242,7 +231,7 @@ class Migration(SchemaMigration):
'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']"})
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
},
'forum.favoritequestion': {
'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
@@ -266,6 +255,15 @@ class Migration(SchemaMigration):
'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.mention': {
+ 'Meta': {'object_name': 'Mention', 'db_table': "u'mention'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mentioned_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'mentioned_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_sent'", 'to': "orm['auth.User']"}),
+ 'mentioned_whom': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_received'", 'to': "orm['auth.User']"}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
'forum.question': {
'Meta': {'object_name': 'Question', 'db_table': "u'question'"},
'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
@@ -347,7 +345,7 @@ class Migration(SchemaMigration):
},
'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)'}),
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 18, 11, 49, 24, 344026)'}),
'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'}),
diff --git a/askbot/migrations/0011_merge_mentions_into_activity.py b/askbot/migrations/0011_merge_mentions_into_activity.py
new file mode 100644
index 00000000..de19a5d2
--- /dev/null
+++ b/askbot/migrations/0011_merge_mentions_into_activity.py
@@ -0,0 +1,724 @@
+# encoding: utf-8
+import os
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+try:
+ from forum import const
+except:
+ from askbot import const
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ "Write your forwards methods here."
+ for m in orm.Mention.objects.all():
+ a = orm.Activity()
+ a.activity_type = const.TYPE_ACTIVITY_MENTION
+ a.user = m.mentioned_by
+ a.active_at = m.mentioned_at
+ a.object_id = m.object_id
+ a.content_type = m.content_type
+ a.save()
+ a.receiving_users.add(m.mentioned_whom)
+ m.delete()
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+ m_type = const.TYPE_ACTIVITY_MENTION
+ for a in orm.Activity.objects.filter(activity_type = m_type):
+ m = orm.Mention()
+ m.mentioned_by = a.user
+ m.mentioned_whom = a.receiving_users.all()[0]
+ m.mentioned_at = a.active_at
+ m.content_type = a.content_type
+ m.object_id = a.object_id
+ a.delete()
+ m.save()
+
+ forum_app_name = os.path.basename(os.path.dirname(os.path.dirname(__file__)))
+ if forum_app_name == 'forum':
+ 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', [], {}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'to': "orm['auth.User']"}),
+ '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': '2048'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'html': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}),
+ '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', [], {'related_name': "'notification_subscriptions'", '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.mention': {
+ 'Meta': {'object_name': 'Mention', 'db_table': "u'mention'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mentioned_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'mentioned_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_sent'", 'to': "orm['auth.User']"}),
+ 'mentioned_whom': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_received'", 'to': "orm['auth.User']"}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ '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, 5, 22, 21, 40, 30, 531379)'}),
+ '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']
+ else:
+ 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'})
+ },
+ 'askbot.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', [], {}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'to': "orm['auth.User']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.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', [], {})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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', [], {})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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': '2048'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'html': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}),
+ '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']"})
+ },
+ 'askbot.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', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.mention': {
+ 'Meta': {'object_name': 'Mention', 'db_table': "u'mention'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mentioned_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'mentioned_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_sent'", 'to': "orm['auth.User']"}),
+ 'mentioned_whom': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mentions_received'", 'to': "orm['auth.User']"}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 22, 21, 40, 30, 531379)'}),
+ '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']"})
+ },
+ 'askbot.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 = ['askbot']
diff --git a/askbot/migrations/0012_delete_some_unused_models.py b/askbot/migrations/0012_delete_some_unused_models.py
new file mode 100644
index 00000000..f34575e4
--- /dev/null
+++ b/askbot/migrations/0012_delete_some_unused_models.py
@@ -0,0 +1,755 @@
+# encoding: utf-8
+import os
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+from django.db import connection
+
+app_dir_name = os.path.basename(os.path.dirname(os.path.dirname(__file__)))
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Deleting model 'AuthKeyUserAssociation'
+ if app_dir_name == 'forum':
+ db.delete_table('forum_authkeyuserassociation')
+ else:
+ db.delete_table('askbot_authkeyuserassociation')
+
+ # Deleting model 'BookAuthorInfo'
+ db.delete_table(u'book_author_info')
+
+ # Deleting model 'Mention'
+ db.delete_table(u'mention')
+
+ # Deleting model 'Book'
+ db.delete_table(u'book')
+
+ # Removing M2M table for field questions on 'Book'
+ db.delete_table('book_question')
+
+ # Deleting model 'BookAuthorRss'
+ db.delete_table(u'book_author_rss')
+
+
+ def backwards(self, orm):
+
+ # Adding model 'AuthKeyUserAssociation'
+ if app_dir_name == 'forum':
+ db.create_table('forum_authkeyuserassociation', (
+ ('key', self.gf('django.db.models.fields.CharField')(max_length=255, unique=True)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='auth_keys', to=orm['auth.User'])),
+ ('added_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('provider', self.gf('django.db.models.fields.CharField')(max_length=64)),
+ ))
+ db.send_create_signal('forum', ['AuthKeyUserAssociation'])
+
+ # 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 'Mention'
+ db.create_table(u'mention', (
+ ('mentioned_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='mentions_sent', to=orm['auth.User'])),
+ ('mentioned_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
+ ('mentioned_whom', self.gf('django.db.models.fields.related.ForeignKey')(related_name='mentions_received', to=orm['auth.User'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('forum', ['Mention'])
+
+ # 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 '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'])
+ else:
+ db.create_table('askbot_authkeyuserassociation', (
+ ('key', self.gf('django.db.models.fields.CharField')(max_length=255, unique=True)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='auth_keys', to=orm['auth.User'])),
+ ('added_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('provider', self.gf('django.db.models.fields.CharField')(max_length=64)),
+ ))
+ db.send_create_signal('askbot', ['AuthKeyUserAssociation'])
+
+ # 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['askbot.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('askbot', ['BookAuthorInfo'])
+
+ # Adding model 'Mention'
+ db.create_table(u'mention', (
+ ('mentioned_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='mentions_sent', to=orm['auth.User'])),
+ ('mentioned_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
+ ('mentioned_whom', self.gf('django.db.models.fields.related.ForeignKey')(related_name='mentions_received', to=orm['auth.User'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('askbot', ['Mention'])
+
+ # 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('askbot', ['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['askbot.book'], null=False)),
+ ('question', models.ForeignKey(orm['askbot.question'], null=False))
+ ))
+ db.create_unique('book_question', ['book_id', 'question_id'])
+
+ # 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['askbot.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('askbot', ['BookAuthorRss'])
+
+
+ if app_dir_name == 'forum':
+ 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', [], {}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'to': "orm['auth.User']"}),
+ '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.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.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': '2048'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'html': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}),
+ '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', [], {'related_name': "'notification_subscriptions'", '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, 5, 29, 12, 2, 31, 449262)'}),
+ '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'})
+ }
+ }
+ else:
+ 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'})
+ },
+ 'askbot.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', [], {}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'to': "orm['auth.User']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.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', [], {})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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', [], {})
+ },
+ 'askbot.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': '2048'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'html': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}),
+ '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']"})
+ },
+ 'askbot.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', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 29, 12, 2, 31, 449262)'}),
+ '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']"})
+ },
+ 'askbot.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 = [app_dir_name]
diff --git a/forum/migrations/0003_copy_denorm_text_record_to_posts_for_fulltext_search.py b/askbot/migrations/0013_add_response_count__to_user.py
index 3e79b9d2..30ca164e 100644
--- a/forum/migrations/0003_copy_denorm_text_record_to_posts_for_fulltext_search.py
+++ b/askbot/migrations/0013_add_response_count__to_user.py
@@ -1,33 +1,42 @@
# encoding: utf-8
import datetime
from south.db import db
-from south.v2 import DataMigration
+from south.v2 import SchemaMigration
from django.db import models
-from forum.models import Question, Answer
-class Migration(DataMigration):
+class Migration(SchemaMigration):
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()
+ """adds integer field User.response_counter
+ if the field does not yet exist
+ this case checking is necessary to support syncdb of auth models
+ a bit hacky but we have to do it as long as we keep patching auth models
+ within the forum application
+ """
+ try:
+ db.add_column(
+ u'auth_user',
+ 'response_count',
+ self.gf('django.db.models.fields.IntegerField')(default=0, ),
+ keep_default=False
+ )
+ except:
+ print 'probably already have column User.response_count'
+ pass
+
def backwards(self, orm):
- "Write your backwards methods here."
- pass#there's no need to clean data here, just delete columns
+ """remove field User.respose_count
+ """
+ db.delete_column(u'auth_user', 'response_count')
+
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'})
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
@@ -48,7 +57,7 @@ class Migration(DataMigration):
'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'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', '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'}),
@@ -63,9 +72,10 @@ class Migration(DataMigration):
'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'}),
+ 'response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'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'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
},
@@ -84,6 +94,7 @@ class Migration(DataMigration):
'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', [], {}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
},
'forum.anonymousanswer': {
@@ -147,14 +158,6 @@ class Migration(DataMigration):
'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'}),
@@ -168,7 +171,7 @@ class Migration(DataMigration):
'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']"}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', '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'}),
@@ -176,47 +179,12 @@ class Migration(DataMigration):
'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'}),
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '2048'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'html': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}),
'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']"})
@@ -228,7 +196,7 @@ class Migration(DataMigration):
'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']"})
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
},
'forum.favoritequestion': {
'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
@@ -266,9 +234,9 @@ class Migration(DataMigration):
'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']"}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'symmetrical': 'False', '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']"}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_questions'", 'symmetrical': 'False', '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'}),
@@ -282,7 +250,7 @@ class Migration(DataMigration):
'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']"}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'questions'", 'symmetrical': 'False', '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'}),
@@ -333,7 +301,7 @@ class Migration(DataMigration):
},
'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)'}),
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 6, 6, 20, 9, 43, 480777)'}),
'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'}),
diff --git a/askbot/migrations/0014_rename_schema_from_forum_to_askbot.py b/askbot/migrations/0014_rename_schema_from_forum_to_askbot.py
new file mode 100644
index 00000000..8af0e9d6
--- /dev/null
+++ b/askbot/migrations/0014_rename_schema_from_forum_to_askbot.py
@@ -0,0 +1,611 @@
+# encoding: utf-8
+import os
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+app_dir_name = os.path.basename(os.path.dirname(os.path.dirname(__file__)))
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ try:
+ db.rename_table('forum_anonymousanswer', 'forum_anonymousanswer')
+ db.rename_table('forum_anonymousquestion', 'forum_anonymousquestion')
+ db.rename_table('forum_emailfeedsetting', 'forum_emailfeedsetting')
+ db.rename_table('forum_markedtag', 'forum_markedtag')
+ db.rename_table('forum_questionview', 'forum_questionview')
+ db.rename_table('forum_validationhash', 'forum_validationhash')
+ except:
+ pass
+
+
+ def backwards(self, orm):
+ if app_dirname == 'forum':
+ db.rename_table('forum_anonymousanswer', 'forum_anonymousanswer')
+ db.rename_table('forum_anonymousquestion', 'forum_anonymousquestion')
+ db.rename_table('forum_emailfeedsetting', 'forum_emailfeedsetting')
+ db.rename_table('forum_markedtag', 'forum_markedtag')
+ db.rename_table('forum_questionview', 'forum_questionview')
+ db.rename_table('forum_validationhash', 'forum_validationhash')
+
+
+ if app_dir_name == 'forum':
+ models = {
+ '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', [], {}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ '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.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'", 'symmetrical': 'False', '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.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': '2048'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'html': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}),
+ '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', [], {'related_name': "'notification_subscriptions'", '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'", 'symmetrical': 'False', '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'", 'symmetrical': 'False', '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'", 'symmetrical': 'False', '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, 6, 13, 23, 16, 4, 680070)'}),
+ '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'})
+ },
+ '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']", 'symmetrical': 'False', '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']", 'symmetrical': 'False', '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'}),
+ 'response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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']", 'symmetrical': 'False', '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'})
+ }
+ }
+ else:
+ models = {
+ 'askbot.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', [], {}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.answerrevision': {
+ 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.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', [], {})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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'", 'symmetrical': 'False', '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', [], {})
+ },
+ 'askbot.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': '2048'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'html': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}),
+ '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']"})
+ },
+ 'askbot.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', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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']"})
+ },
+ 'askbot.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['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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'", 'symmetrical': 'False', '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'", 'symmetrical': 'False', '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'", 'symmetrical': 'False', 'to': "orm['askbot.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'})
+ },
+ 'askbot.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['askbot.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'})
+ },
+ 'askbot.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['askbot.Question']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.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['askbot.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']"})
+ },
+ 'askbot.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'})
+ },
+ 'askbot.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 6, 13, 23, 16, 4, 680070)'}),
+ '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']"})
+ },
+ 'askbot.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'})
+ },
+ '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']", 'symmetrical': 'False', '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']", 'symmetrical': 'False', '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'}),
+ 'response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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']", 'symmetrical': 'False', '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'})
+ }
+ }
+
+ complete_apps = [app_dir_name]
diff --git a/forum/migrations/0004_install_full_text_indexes_for_mysql.py b/askbot/migrations/0015_rename_forum_contenttypes_to_askbot.py
index 0c52c442..854de75d 100644
--- a/forum/migrations/0004_install_full_text_indexes_for_mysql.py
+++ b/askbot/migrations/0015_rename_forum_contenttypes_to_askbot.py
@@ -3,115 +3,24 @@ 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)
+ "Write your forwards methods here."
+ content_types = orm['contenttypes.ContentType'].objects.filter(app_label='forum')
+ content_types.update(app_label='askbot')
+ pass
+
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,
- )
- )
+ "Write your backwards methods here."
+ content_types = orm['contenttypes.ContentType'].objects.filter(app_label='askbot')
+ content_types.update(app_label='forum')
+ pass
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': {
+ 'askbot.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', [], {}),
@@ -119,21 +28,22 @@ class Migration(DataMigration):
'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', [], {}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
},
- 'forum.anonymousanswer': {
+ 'askbot.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']"}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.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': {
+ 'askbot.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'}),
@@ -146,7 +56,7 @@ class Migration(DataMigration):
'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
},
- 'forum.answer': {
+ 'askbot.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'}),
@@ -164,7 +74,7 @@ class Migration(DataMigration):
'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']"}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['askbot.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'}),
@@ -172,9 +82,9 @@ class Migration(DataMigration):
'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
},
- 'forum.answerrevision': {
+ 'askbot.answerrevision': {
'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},
- 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Answer']"}),
+ 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.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', [], {}),
@@ -182,28 +92,20 @@ class Migration(DataMigration):
'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': {
+ 'askbot.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']"}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.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': {
+ 'askbot.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']"}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', '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'}),
@@ -211,68 +113,33 @@ class Migration(DataMigration):
'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': {
+ 'askbot.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'}),
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '2048'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'html': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}),
'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': {
+ 'askbot.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']"})
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
},
- 'forum.favoritequestion': {
+ 'askbot.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']"}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
},
- 'forum.flaggeditem': {
+ 'askbot.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'}),
@@ -280,14 +147,14 @@ class Migration(DataMigration):
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['auth.User']"})
},
- 'forum.markedtag': {
+ 'askbot.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']"}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
},
- 'forum.question': {
+ 'askbot.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'}),
@@ -301,9 +168,9 @@ class Migration(DataMigration):
'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']"}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'symmetrical': 'False', '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']"}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_questions'", 'symmetrical': 'False', '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'}),
@@ -317,7 +184,7 @@ class Migration(DataMigration):
'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']"}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'questions'", 'symmetrical': 'False', 'to': "orm['askbot.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'}),
@@ -326,11 +193,11 @@ class Migration(DataMigration):
'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
},
- 'forum.questionrevision': {
+ 'askbot.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']"}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.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'}),
@@ -338,25 +205,25 @@ class Migration(DataMigration):
'text': ('django.db.models.fields.TextField', [], {}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
},
- 'forum.questionview': {
+ 'askbot.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']"}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Question']"}),
'when': ('django.db.models.fields.DateTimeField', [], {}),
'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
},
- 'forum.repute': {
+ 'askbot.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']"}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.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': {
+ 'askbot.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'}),
@@ -366,16 +233,16 @@ class Migration(DataMigration):
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
},
- 'forum.validationhash': {
+ 'askbot.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)'}),
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 6, 13, 23, 48, 5, 784060)'}),
'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': {
+ 'askbot.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'}),
@@ -383,7 +250,61 @@ class Migration(DataMigration):
'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'})
+ },
+ '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']", 'symmetrical': 'False', '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']", 'symmetrical': 'False', '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'}),
+ 'response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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']", 'symmetrical': 'False', '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'})
}
}
- complete_apps = ['forum']
+ complete_apps = ['askbot']
diff --git a/forum/templatetags/__init__.py b/askbot/migrations/__init__.py
index e69de29b..e69de29b 100755..100644
--- a/forum/templatetags/__init__.py
+++ b/askbot/migrations/__init__.py
diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py
new file mode 100644
index 00000000..eb8d0185
--- /dev/null
+++ b/askbot/models/__init__.py
@@ -0,0 +1,696 @@
+import logging
+import re
+import hashlib
+import datetime
+from django.core.urlresolvers import reverse
+from django.core.mail import EmailMessage
+from askbot.search.indexer import create_fulltext_indexes
+from django.db.models import signals as django_signals
+from django.template import loader, Context
+from django.utils.translation import ugettext as _
+from django.contrib.auth.models import User
+from django.template.defaultfilters import slugify
+from django.utils.safestring import mark_safe
+from django.db import models
+from django.conf import settings as django_settings
+from django.contrib.contenttypes.models import ContentType
+from askbot import const
+from askbot.conf import settings as askbot_settings
+from askbot.models.question import Question, QuestionRevision
+from askbot.models.question import QuestionView, AnonymousQuestion
+from askbot.models.question import FavoriteQuestion
+from askbot.models.answer import Answer, AnonymousAnswer, AnswerRevision
+from askbot.models.tag import Tag, MarkedTag
+from askbot.models.meta import Vote, Comment, FlaggedItem
+from askbot.models.user import Activity, ValidationHash, EmailFeedSetting
+from askbot.models import signals
+#from user import AuthKeyUserAssociation
+from askbot.models.repute import Badge, Award, Repute
+from askbot import auth
+
+User.add_to_class('is_approved', models.BooleanField(default=False))
+User.add_to_class('email_isvalid', models.BooleanField(default=False))
+User.add_to_class('email_key', models.CharField(max_length=32, null=True))
+#hardcoded initial reputaion of 1, no setting for this one
+User.add_to_class('reputation', models.PositiveIntegerField(default=1))
+User.add_to_class('gravatar', models.CharField(max_length=32))
+User.add_to_class('gold', models.SmallIntegerField(default=0))
+User.add_to_class('silver', models.SmallIntegerField(default=0))
+User.add_to_class('bronze', models.SmallIntegerField(default=0))
+User.add_to_class('questions_per_page',
+ models.SmallIntegerField(
+ choices=const.QUESTIONS_PER_PAGE_USER_CHOICES,
+ default=10)
+ )
+User.add_to_class('last_seen',
+ models.DateTimeField(default=datetime.datetime.now))
+User.add_to_class('real_name', models.CharField(max_length=100, blank=True))
+User.add_to_class('website', models.URLField(max_length=200, blank=True))
+User.add_to_class('location', models.CharField(max_length=100, blank=True))
+User.add_to_class('date_of_birth', models.DateField(null=True, blank=True))
+User.add_to_class('about', models.TextField(blank=True))
+User.add_to_class('hide_ignored_questions', models.BooleanField(default=False))
+User.add_to_class('tag_filter_setting',
+ models.CharField(
+ max_length=16,
+ choices=const.TAG_EMAIL_FILTER_CHOICES,
+ default='ignored'
+ )
+ )
+User.add_to_class('response_count', models.IntegerField(default=0))
+
+def user_is_username_taken(cls,username):
+ try:
+ cls.objects.get(username=username)
+ return True
+ except cls.MultipleObjectsReturned:
+ return True
+ except cls.DoesNotExist:
+ return False
+
+def user_get_q_sel_email_feed_frequency(self):
+ #print 'looking for frequency for user %s' % self
+ try:
+ feed_setting = EmailFeedSetting.objects.get(
+ subscriber=self,
+ feed_type='q_sel'
+ )
+ except Exception, e:
+ #print 'have error %s' % e.message
+ raise e
+ #print 'have freq=%s' % feed_setting.frequency
+ return feed_setting.frequency
+
+def get_messages(self):
+ messages = []
+ for m in self.message_set.all():
+ messages.append(m.message)
+ return messages
+
+def delete_messages(self):
+ self.message_set.all().delete()
+
+#todo: find where this is used and replace with get_absolute_url
+def get_profile_url(self):
+ """Returns the URL for this User's profile."""
+ return reverse(
+ 'user_profile',
+ kwargs={'id':self.id, 'slug':slugify(self.username)}
+ )
+
+def user_get_absolute_url(self):
+ return self.get_profile_url()
+
+def get_profile_link(self):
+ profile_link = u'<a href="%s">%s</a>' \
+ % (self.get_profile_url(),self.username)
+
+ return mark_safe(profile_link)
+
+#series of methods for user vote-type commands
+#same call signature func(self, post, timestamp=None, cancel=None)
+#note that none of these have business logic checks internally
+#these functions are used by the askbot app and
+#by the data importer jobs from say stackexchange, where internal rules
+#may be different
+#maybe if we do use business rule checks here - we should add
+#some flag allowing to bypass them for things like the data importers
+def toggle_favorite_question(self, question, timestamp=None, cancel=False):
+ """cancel has no effect here, but is important for the SE loader
+ it is hoped that toggle will work and data will be consistent
+ but there is no guarantee, maybe it's better to be more strict
+ about processing the "cancel" option
+ another strange thing is that this function unlike others below
+ returns a value
+ """
+ try:
+ fave = FavoriteQuestion.objects.get(question=question, user=self)
+ fave.delete()
+ result = False
+ except FavoriteQuestion.DoesNotExist:
+ if timestamp is None:
+ timestamp = datetime.datetime.now()
+ fave = FavoriteQuestion(
+ question = question,
+ user = self,
+ added_at = timestamp,
+ )
+ fave.save()
+ result = True
+ Question.objects.update_favorite_count(question)
+ return result
+
+def _process_vote(user, post, timestamp=None, cancel=False, vote_type=None):
+ """"private" wrapper function that applies post upvotes/downvotes
+ and cancelations
+ """
+ post_type = ContentType.objects.get_for_model(post)
+ #get or create the vote object
+ #return with noop in some situations
+ try:
+ vote = Vote.objects.get(
+ user = user,
+ content_type = post_type,
+ object_id = post.id,
+ )
+ except Vote.DoesNotExist:
+ vote = None
+ if cancel:
+ if vote == None:
+ return
+ elif vote.is_opposite(vote_type):
+ return
+ else:
+ #we would call vote.delete() here
+ #but for now all that is handled by the
+ #legacy askbot.auth functions
+ #vote.delete()
+ pass
+ else:
+ if vote == None:
+ vote = Vote(
+ user = user,
+ content_object = post,
+ vote = vote_type,
+ voted_at = timestamp,
+ )
+ elif vote.is_opposite(vote_type):
+ vote.vote = vote_type
+ else:
+ return
+
+ #do the actual work
+ if vote_type == Vote.VOTE_UP:
+ if cancel:
+ auth.onUpVotedCanceled(vote, post, user, timestamp)
+ else:
+ auth.onUpVoted(vote, post, user, timestamp)
+ elif vote_type == Vote.VOTE_DOWN:
+ if cancel:
+ auth.onDownVotedCanceled(vote, post, user, timestamp)
+ else:
+ auth.onDownVoted(vote, post, user, timestamp)
+
+def upvote(self, post, timestamp=None, cancel=False):
+ _process_vote(
+ self,post,
+ timestamp=timestamp,
+ cancel=cancel,
+ vote_type=Vote.VOTE_UP
+ )
+
+def downvote(self, post, timestamp=None, cancel=False):
+ _process_vote(
+ self,post,
+ timestamp=timestamp,
+ cancel=cancel,
+ vote_type=Vote.VOTE_DOWN
+ )
+
+def accept_answer(self, answer, timestamp=None, cancel=False):
+ if cancel:
+ auth.onAnswerAcceptCanceled(answer, self, timestamp=timestamp)
+ else:
+ auth.onAnswerAccept(answer, self, timestamp=timestamp)
+
+def flag_post(user, post, timestamp=None, cancel=False):
+ if cancel:#todo: can't unflag?
+ return
+ if post.flagged_items.filter(user=user).count() > 0:
+ return
+ else:
+ flag = FlaggedItem(
+ user = user,
+ content_object = post,
+ flagged_at = timestamp,
+ )
+ auth.onFlaggedItem(flag, post, user, timestamp=timestamp)
+
+User.add_to_class('is_username_taken',classmethod(user_is_username_taken))
+User.add_to_class(
+ 'get_q_sel_email_feed_frequency',
+ user_get_q_sel_email_feed_frequency
+ )
+User.add_to_class('get_absolute_url', user_get_absolute_url)
+User.add_to_class('upvote', upvote)
+User.add_to_class('downvote', downvote)
+User.add_to_class('accept_answer', accept_answer)
+User.add_to_class('flag_post', flag_post)
+User.add_to_class('get_profile_url', get_profile_url)
+User.add_to_class('get_profile_link', get_profile_link)
+User.add_to_class('get_messages', get_messages)
+User.add_to_class('delete_messages', delete_messages)
+User.add_to_class('toggle_favorite_question', toggle_favorite_question)
+
+#todo: move this to askbot/utils ??
+def format_instant_notification_body(
+ to_user = None,
+ from_user = None,
+ post = None,
+ update_type = None,
+ template = None,
+ ):
+ """
+ returns text of the instant notification body
+ that is built when post is updated
+ only update_types in const.RESPONSE_ACTIVITY_TYPE_MAP_FOR_TEMPLATES
+ are supported
+ """
+
+ site_url = askbot_settings.APP_URL
+ origin_post = post.get_origin_post()
+ #todo: create a better method to access "sub-urls" in user views
+ user_subscriptions_url = site_url + to_user.get_absolute_url() + \
+ '?sort=email_subscriptions'
+
+ if update_type == 'question_comment':
+ assert(isinstance(post, Comment))
+ assert(isinstance(post.content_object, Question))
+ elif update_type == 'answer_comment':
+ assert(isinstance(post, Comment))
+ assert(isinstance(post.content_object, Answer))
+ elif update_type in ('answer_update', 'new_answer'):
+ assert(isinstance(post, Answer))
+ elif update_type in ('question_update', 'new_question'):
+ assert(isinstance(post, Question))
+
+ update_data = {
+ 'update_author_name': from_user.username,
+ 'post_url': site_url + post.get_absolute_url(),
+ 'origin_post_title': origin_post.title,
+ 'user_subscriptions_url': user_subscriptions_url
+ }
+ return template.render(Context(update_data))
+
+#todo: action
+def send_instant_notifications_about_activity_in_post(
+ update_activity = None,
+ post = None,
+ receiving_users = [],
+ ):
+ """
+ function called when posts are updated
+ newly mentioned users are carried through to reduce
+ database hits
+ """
+
+ acceptable_types = const.RESPONSE_ACTIVITY_TYPES_FOR_INSTANT_NOTIFICATIONS
+
+ if update_activity.activity_type not in acceptable_types:
+ return
+
+ template = loader.get_template('instant_notification.html')
+
+ update_type_map = const.RESPONSE_ACTIVITY_TYPE_MAP_FOR_TEMPLATES
+ update_type = update_type_map[update_activity.activity_type]
+
+ for user in receiving_users:
+
+ subject = _('email update message subject')
+ text = format_instant_notification_body(
+ to_user = user,
+ from_user = update_activity.user,
+ post = post,
+ update_type = update_type,
+ template = template,
+ )
+ #todo: this could be packaged as an "action" - a bundle
+ #of executive function with the activity log recording
+ msg = EmailMessage(
+ subject,
+ text,
+ django_settings.DEFAULT_FROM_EMAIL,
+ [user.email]
+ )
+ #msg.send()
+ print text
+ EMAIL_UPDATE_ACTIVITY = const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT
+ email_activity = Activity(
+ user = user,
+ content_object = post.get_origin_post(),
+ activity_type = EMAIL_UPDATE_ACTIVITY
+ )
+ email_activity.save()
+
+
+#todo: move to utils
+def calculate_gravatar_hash(instance, **kwargs):
+ """Calculates a User's gravatar hash from their email address."""
+ if kwargs.get('raw', False):
+ return
+ instance.gravatar = hashlib.md5(instance.email).hexdigest()
+
+
+def record_post_update_activity(
+ post,
+ newly_mentioned_users = list(),
+ updated_by = None,
+ timestamp = None,
+ created = False,
+ **kwargs
+ ):
+ """called upon signal askbot.models.signals.post_updated
+ which is sent at the end of save() method in posts
+ """
+ assert(timestamp != None)
+ assert(updated_by != None)
+
+ #todo: take into account created == True case
+ (activity_type, update_object) = post.get_updated_activity_data(created)
+
+ update_activity = Activity(
+ user = updated_by,
+ active_at = timestamp,
+ content_object = post,
+ activity_type = activity_type
+ )
+ update_activity.save()
+
+ #what users are included depends on the post type
+ #for example for question - all Q&A contributors
+ #are included, for comments only authors of comments and parent
+ #post are included
+ receiving_users = post.get_response_receivers(
+ exclude_list = [updated_by, ]
+ )
+
+ update_activity.receiving_users.add(*receiving_users)
+
+ assert(updated_by not in receiving_users)
+
+ for user in set(receiving_users) | set(newly_mentioned_users):
+ user.response_count += 1
+ user.save()
+
+ #todo: weird thing is that only comments need the receiving_users
+ #argument to this call
+ notification_subscribers = post.get_instant_notification_subscribers(
+ potential_subscribers = receiving_users,
+ mentioned_users = newly_mentioned_users,
+ exclude_list = [updated_by, ]
+ )
+
+ send_instant_notifications_about_activity_in_post(
+ update_activity = update_activity,
+ post = post,
+ receiving_users = notification_subscribers,
+ )
+
+
+def record_award_event(instance, created, **kwargs):
+ """
+ After we awarded a badge to user, we need to
+ record this activity and notify user.
+ We also recaculate awarded_count of this badge and user information.
+ """
+ if created:
+ #todo: change this to community user who gives the award
+ activity = Activity(
+ user=instance.user,
+ active_at=instance.awarded_at,
+ content_object=instance,
+ activity_type=const.TYPE_ACTIVITY_PRIZE
+ )
+ activity.save()
+ activity.receiving_users.add(instance.user)
+
+ instance.badge.awarded_count += 1
+ instance.badge.save()
+
+ if instance.badge.type == Badge.GOLD:
+ instance.user.gold += 1
+ if instance.badge.type == Badge.SILVER:
+ instance.user.silver += 1
+ if instance.badge.type == Badge.BRONZE:
+ instance.user.bronze += 1
+ instance.user.save()
+
+def notify_award_message(instance, created, **kwargs):
+ """
+ Notify users when they have been awarded badges by using Django message.
+ """
+ if created:
+ user = instance.user
+
+ msg = (u"Congratulations, you have received a badge '%s'. " \
+ + u"Check out <a href=\"%s\">your profile</a>.") \
+ % (instance.badge.name, user.get_profile_url())
+
+ user.message_set.create(message=msg)
+
+def record_answer_accepted(instance, created, **kwargs):
+ """
+ when answer is accepted, we record this for question author
+ - who accepted it.
+ """
+ if not created and instance.accepted:
+ activity = Activity(
+ user=instance.question.author,
+ active_at=datetime.datetime.now(),
+ content_object=instance,
+ activity_type=const.TYPE_ACTIVITY_MARK_ANSWER
+ )
+ activity.save()
+ receiving_users = instance.get_author_list(
+ exclude_list = [instance.question.author]
+ )
+ activity.receiving_users.add(*receiving_users)
+
+
+def update_last_seen(instance, created, **kwargs):
+ """
+ when user has activities, we update 'last_seen' time stamp for him
+ """
+ #todo: in reality author of this activity must not be the receiving user
+ #but for now just have this plug, so that last seen timestamp is not
+ #perturbed by the email update sender
+ if instance.activity_type == const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT:
+ return
+ user = instance.user
+ user.last_seen = datetime.datetime.now()
+ user.save()
+
+
+def record_vote(instance, created, **kwargs):
+ """
+ when user have voted
+ """
+ if created:
+ if instance.vote == 1:
+ vote_type = const.TYPE_ACTIVITY_VOTE_UP
+ else:
+ vote_type = const.TYPE_ACTIVITY_VOTE_DOWN
+
+ activity = Activity(
+ user=instance.user,
+ active_at=instance.voted_at,
+ content_object=instance,
+ activity_type=vote_type
+ )
+ #todo: problem cannot access receiving user here
+ activity.save()
+
+
+def record_cancel_vote(instance, **kwargs):
+ """
+ when user canceled vote, the vote will be deleted.
+ """
+ activity = Activity(
+ user=instance.user,
+ active_at=datetime.datetime.now(),
+ content_object=instance,
+ activity_type=const.TYPE_ACTIVITY_CANCEL_VOTE
+ )
+ #todo: same problem - cannot access receiving user here
+ activity.save()
+
+
+#todo: weird that there is no record delete answer or comment
+#is this even necessary to keep track of?
+def record_delete_question(instance, delete_by, **kwargs):
+ """
+ when user deleted the question
+ """
+ if instance.__class__ == "Question":
+ activity_type = const.TYPE_ACTIVITY_DELETE_QUESTION
+ else:
+ activity_type = const.TYPE_ACTIVITY_DELETE_ANSWER
+
+ activity = Activity(
+ user=delete_by,
+ active_at=datetime.datetime.now(),
+ content_object=instance,
+ activity_type=activity_type
+ )
+ #no need to set receiving user here
+ activity.save()
+
+def record_mark_offensive(instance, mark_by, **kwargs):
+ activity = Activity(
+ user=mark_by,
+ active_at=datetime.datetime.now(),
+ content_object=instance,
+ activity_type=const.TYPE_ACTIVITY_MARK_OFFENSIVE
+ )
+ activity.save()
+ receiving_users = instance.get_author_list(
+ exclude_list = [mark_by]
+ )
+ activity.receiving_users.add(*receiving_users)
+
+def record_update_tags(question, **kwargs):
+ """
+ when user updated tags of the question
+ """
+ activity = Activity(
+ user=question.author,
+ active_at=datetime.datetime.now(),
+ content_object=question,
+ activity_type=const.TYPE_ACTIVITY_UPDATE_TAGS
+ )
+ activity.save()
+
+def record_favorite_question(instance, created, **kwargs):
+ """
+ when user add the question in him favorite questions list.
+ """
+ if created:
+ activity = Activity(
+ user=instance.user,
+ active_at=datetime.datetime.now(),
+ content_object=instance,
+ activity_type=const.TYPE_ACTIVITY_FAVORITE
+ )
+ activity.save()
+ receiving_users = instance.question.get_author_list(
+ exclude_list = [instance.user]
+ )
+ activity.receiving_users.add(*receiving_users)
+
+def record_user_full_updated(instance, **kwargs):
+ activity = Activity(
+ user=instance,
+ active_at=datetime.datetime.now(),
+ content_object=instance,
+ activity_type=const.TYPE_ACTIVITY_USER_FULL_UPDATED
+ )
+ activity.save()
+
+def post_stored_anonymous_content(
+ sender,
+ user,
+ session_key,
+ signal,
+ *args,
+ **kwargs):
+
+ aq_list = AnonymousQuestion.objects.filter(session_key = session_key)
+ aa_list = AnonymousAnswer.objects.filter(session_key = session_key)
+ #from askbot.conf import settings as askbot_settings
+ if askbot_settings.EMAIL_VALIDATION == True:#add user to the record
+ for aq in aq_list:
+ aq.author = user
+ aq.save()
+ for aa in aa_list:
+ aa.author = user
+ aa.save()
+ #maybe add pending posts message?
+ else: #just publish the questions
+ for aq in aq_list:
+ aq.publish(user)
+ for aa in aa_list:
+ aa.publish(user)
+
+#signal for User model save changes
+django_signals.pre_save.connect(calculate_gravatar_hash, sender=User)
+django_signals.post_save.connect(record_award_event, sender=Award)
+django_signals.post_save.connect(notify_award_message, sender=Award)
+django_signals.post_save.connect(record_answer_accepted, sender=Answer)
+django_signals.post_save.connect(update_last_seen, sender=Activity)
+django_signals.post_save.connect(record_vote, sender=Vote)
+django_signals.post_save.connect(
+ record_favorite_question,
+ sender=FavoriteQuestion
+ )
+django_signals.post_delete.connect(record_cancel_vote, sender=Vote)
+
+#change this to real m2m_changed with Django1.2
+signals.delete_post_or_answer.connect(record_delete_question, sender=Question)
+signals.delete_post_or_answer.connect(record_delete_question, sender=Answer)
+signals.mark_offensive.connect(record_mark_offensive, sender=Question)
+signals.mark_offensive.connect(record_mark_offensive, sender=Answer)
+signals.tags_updated.connect(record_update_tags, sender=Question)
+signals.user_updated.connect(record_user_full_updated, sender=User)
+signals.user_logged_in.connect(post_stored_anonymous_content)
+signals.post_updated.connect(
+ record_post_update_activity,
+ sender=Comment
+ )
+signals.post_updated.connect(
+ record_post_update_activity,
+ sender=Answer
+ )
+signals.post_updated.connect(
+ record_post_update_activity,
+ sender=Question
+ )
+#post_syncdb.connect(create_fulltext_indexes)
+
+#todo: wtf??? what is x=x about?
+signals = signals
+
+Question = Question
+QuestionRevision = QuestionRevision
+QuestionView = QuestionView
+FavoriteQuestion = FavoriteQuestion
+AnonymousQuestion = AnonymousQuestion
+
+Answer = Answer
+AnswerRevision = AnswerRevision
+AnonymousAnswer = AnonymousAnswer
+
+Tag = Tag
+Comment = Comment
+Vote = Vote
+FlaggedItem = FlaggedItem
+MarkedTag = MarkedTag
+
+Badge = Badge
+Award = Award
+Repute = Repute
+
+Activity = Activity
+EmailFeedSetting = EmailFeedSetting
+ValidationHash = ValidationHash
+#AuthKeyUserAssociation = AuthKeyUserAssociation
+
+__all__ = [
+ 'signals',
+
+ 'Question',
+ 'QuestionRevision',
+ 'QuestionView',
+ 'FavoriteQuestion',
+ 'AnonymousQuestion',
+
+ 'Answer',
+ 'AnswerRevision',
+ 'AnonymousAnswer',
+
+ 'Tag',
+ 'Comment',
+ 'Vote',
+ 'FlaggedItem',
+ 'MarkedTag',
+
+ 'Badge',
+ 'Award',
+ 'Repute',
+
+ 'Activity',
+ 'EmailFeedSetting',
+ 'ValidationHash',
+ #'AuthKeyUserAssociation',
+
+ 'User',
+]
diff --git a/forum/models/answer.py b/askbot/models/answer.py
index 3de6cfc4..22951417 100755..100644
--- a/forum/models/answer.py
+++ b/askbot/models/answer.py
@@ -1,13 +1,15 @@
-from base import *
-#todo: take care of copy-paste markdowner stuff maybe make html automatic field?
-from forum.const import CONST
-from markdown2 import Markdown
-from django.utils.html import strip_tags
-from forum.utils.html import sanitize_html
import datetime
-markdowner = Markdown(html4tags=True)
+from django.db import models
+from django.utils.http import urlquote as django_urlquote
+from django.template.defaultfilters import slugify
+from django.core.urlresolvers import reverse
+from askbot.models.base import AnonymousContent, DeletableContent
+from askbot.models.base import ContentRevision
+from askbot.models.base import parse_post_text, parse_and_save_post
+from askbot.models import content
+from askbot.models.question import Question
+from askbot import const
-from question import Question
class AnswerManager(models.Manager):
def create_new(self, question=None, author=None, added_at=None, wiki=False, text='', email_notify=False):
@@ -17,20 +19,20 @@ class AnswerManager(models.Manager):
added_at = added_at,
wiki = wiki,
text = text,
- html = sanitize_html(markdowner.convert(text)),
+ #.html field is denormalized by the save() call
)
if answer.wiki:
answer.last_edited_by = answer.author
answer.last_edited_at = added_at
answer.wikified_at = added_at
- answer.save()
+ answer.parse_and_save(author = author)
answer.add_revision(
- revised_by=author,
- revised_at=added_at,
- text=text,
- comment=CONST['default_version'],
+ revised_by = author,
+ revised_at = added_at,
+ text = text,
+ comment = const.POST_STATUS['default_version'],
)
#update question data
@@ -51,6 +53,12 @@ class AnswerManager(models.Manager):
pass
return answer
+ def get_author_list(self, **kwargs):
+ authors = set()
+ for answer in self:
+ authors.update(answer.get_author_list(**kwargs))
+ return list(authors)
+
#GET_ANSWERS_FROM_USER_QUESTIONS = u'SELECT answer.* FROM answer INNER JOIN question ON answer.question_id = question.id WHERE question.author_id =%s AND answer.author_id <> %s'
def get_answers_from_question(self, question, user=None):
"""
@@ -73,16 +81,28 @@ class AnswerManager(models.Manager):
# cursor.execute(self.GET_ANSWERS_FROM_USER_QUESTIONS, [user_id, user_id])
# return cursor.fetchall()
-class Answer(Content, DeletableContent):
+class Answer(content.Content, DeletableContent):
question = models.ForeignKey('Question', related_name='answers')
accepted = models.BooleanField(default=False)
accepted_at = models.DateTimeField(null=True, blank=True)
objects = AnswerManager()
- class Meta(Content.Meta):
+ class Meta(content.Content.Meta):
db_table = u'answer'
+ parse = parse_post_text
+ parse_and_save = parse_and_save_post
+
+ def get_updated_activity_data(self, created = False):
+ #todo: simplify this to always return latest revision for the second
+ #part
+ if created:
+ return const.TYPE_ACTIVITY_ANSWER, self
+ else:
+ latest_revision = self.get_latest_revision()
+ return const.TYPE_ACTIVITY_UPDATE_ANSWER, latest_revision
+
def apply_edit(self, edited_at=None, edited_by=None, text=None, comment=None, wiki=False):
if text is None:
@@ -94,10 +114,10 @@ class Answer(Content, DeletableContent):
self.last_edited_at = edited_at
self.last_edited_by = edited_by
- self.html = sanitize_html(markdowner.convert(text))
+ #self.html is denormalized in save()
self.text = text
#todo: bug wiki has no effect here
- self.save()
+ self.parse_and_save(author = edited_by)
self.add_revision(
revised_by=edited_by,
@@ -116,7 +136,7 @@ class Answer(Content, DeletableContent):
rev_no = self.revisions.all().count() + 1
if comment in (None, ''):
if rev_no == 1:
- comment = CONST['default_version']
+ comment = const.POST_STATUS['default_version']
else:
comment = 'No.%s Revision' % rev_no
return AnswerRevision.objects.create(
@@ -128,6 +148,37 @@ class Answer(Content, DeletableContent):
revision=rev_no
)
+ def get_origin_post(self):
+ return self.question
+
+ def get_response_receivers(self, exclude_list = None):
+ """get list of users interested in this response
+ update based on their participation in the question
+ activity
+
+ exclude_list is required and normally should contain
+ author of the updated so that he/she is not notified of
+ the response
+ """
+ assert(exclude_list is not None)
+ receiving_users = set()
+ receiving_users.update(
+ self.get_author_list(
+ include_comments = True
+ )
+ )
+ receiving_users.update(
+ self.question.get_author_list(
+ include_comments = True
+ )
+ )
+ for answer in self.question.answers.all():
+ receiving_users.update(answer.get_author_list())
+
+ receiving_users -= set(exclude_list)
+
+ return list(receiving_users)
+
def get_user_vote(self, user):
if user.__class__.__name__ == "AnonymousUser":
return None
diff --git a/askbot/models/base.py b/askbot/models/base.py
new file mode 100644
index 00000000..8627b9e4
--- /dev/null
+++ b/askbot/models/base.py
@@ -0,0 +1,211 @@
+import datetime
+from django.db import models
+from django.utils.html import strip_tags
+from django.contrib.auth.models import User
+from django.contrib.contenttypes import generic
+from django.contrib.contenttypes.models import ContentType
+#todo: maybe merge askbot.utils.markup and forum.utils.html
+from askbot.utils import markup
+from askbot.utils.html import sanitize_html
+from django.utils import html
+import logging
+from markdown2 import Markdown
+
+markdowner = Markdown(html4tags=True)
+
+#todo: following methods belong to a future common post class
+def parse_post_text(post):
+ """typically post has a field to store raw source text
+ in comment it is called .comment, in Question and Answer it is
+ called .text
+ also there is another field called .html (consistent across models)
+ so the goal of this function is to render raw text into .html
+ and extract any metadata given stored in source (currently
+ this metadata is limited by twitter style @mentions
+ but there may be more in the future
+
+ function returns a dictionary with the following keys
+ html
+ newly_mentioned_users - list of <User> objects
+ removed_mentions - list of mention <Activity> objects - for removed ones
+ """
+
+ text = post.get_text()
+
+ if post._urlize:
+ text = html.urlize(text)
+
+ if post._use_markdown:
+ text = sanitize_html(markdowner.convert(text))
+
+ #todo, add markdown parser call conditional on
+ #post.use_markdown flag
+ post_html = text
+ mentioned_authors = list()
+ removed_mentions = list()
+ if '@' in text:
+ from askbot.models.user import Activity
+
+ op = post.get_origin_post()
+ anticipated_authors = op.get_author_list(
+ include_comments = True,
+ recursive = True
+ )
+
+ extra_name_seeds = markup.extract_mentioned_name_seeds(text)
+
+ extra_authors = set()
+ for name_seed in extra_name_seeds:
+ extra_authors.update(User.objects.filter(
+ username__startswith = name_seed
+ )
+ )
+
+ #it is important to preserve order here so that authors of post
+ #get mentioned first
+ anticipated_authors += list(extra_authors)
+
+ mentioned_authors, post_html = markup.mentionize_text(
+ text,
+ anticipated_authors
+ )
+
+ #find mentions that were removed and identify any previously
+ #entered mentions so that we can send alerts on only new ones
+ if post.pk is not None:
+ #only look for previous mentions if post was already saved before
+ prev_mention_qs = Activity.objects.get_mentions(
+ mentioned_in = post
+ )
+ new_set = set(mentioned_authors)
+ for prev_mention in prev_mention_qs:
+
+ user = prev_mention.get_mentioned_user()
+ if user in new_set:
+ #don't report mention twice
+ new_set.remove(user)
+ else:
+ removed_mentions.append(prev_mention)
+ mentioned_authors = list(new_set)
+
+ data = {
+ 'html': post_html,
+ 'newly_mentioned_users': mentioned_authors,
+ 'removed_mentions': removed_mentions,
+ }
+ return data
+
+#todo: when models are merged, it would be great to remove author parameter
+def parse_and_save_post(post, author = None, **kwargs):
+ """generic method to use with posts to be used prior to saving
+ post edit or addition
+ """
+
+ assert(author is not None)
+
+ data = post.parse()
+
+ post.html = data['html']
+ newly_mentioned_users = set(data['newly_mentioned_users']) - set([author])
+ removed_mentions = data['removed_mentions']
+
+ #a hack allowing to save denormalized .summary field for questions
+ if hasattr(post, 'summary'):
+ post.summary = strip_tags(post.html)[:120]
+
+ #delete removed mentions
+ for rm in removed_mentions:
+ rm.delete()
+
+ created = post.pk is None
+
+ #this save must precede saving the mention activity
+ #because generic relation needs primary key of the related object
+ super(post.__class__, post).save(**kwargs)
+
+ #create new mentions
+ for u in newly_mentioned_users:
+ from askbot.models.user import Activity
+ Activity.objects.create_new_mention(
+ mentioned_whom = u,
+ mentioned_in = post,
+ mentioned_by = author
+ )
+
+ #todo: this is handled in signal because models for posts
+ #are too spread out
+ from askbot.models import signals
+ signals.post_updated.send(
+ post = post,
+ updated_by = author,
+ newly_mentioned_users = newly_mentioned_users,
+ timestamp = post.get_time_of_last_edit(),
+ created = created,
+ sender = post.__class__
+ )
+
+ try:
+ ping_google()
+ except Exception:
+ logging.debug('cannot ping google - did you register with them?')
+
+class UserContent(models.Model):
+ user = models.ForeignKey(User, related_name='%(class)ss')
+
+ class Meta:
+ abstract = True
+ app_label = 'askbot'
+
+
+class MetaContent(models.Model):
+ """
+ Base class for Vote, Comment and FlaggedItem
+ """
+ content_type = models.ForeignKey(ContentType)
+ object_id = models.PositiveIntegerField()
+ content_object = generic.GenericForeignKey('content_type', 'object_id')
+
+ class Meta:
+ abstract = True
+ app_label = 'askbot'
+
+class DeletableContent(models.Model):
+ deleted = models.BooleanField(default=False)
+ deleted_at = models.DateTimeField(null=True, blank=True)
+ deleted_by = models.ForeignKey(User, null=True, blank=True, related_name='deleted_%(class)ss')
+
+ class Meta:
+ abstract = True
+ app_label = 'askbot'
+
+
+class ContentRevision(models.Model):
+ """
+ Base class for QuestionRevision and AnswerRevision
+ """
+ revision = models.PositiveIntegerField()
+ author = models.ForeignKey(User, related_name='%(class)ss')
+ revised_at = models.DateTimeField()
+ summary = models.CharField(max_length=300, blank=True)
+ text = models.TextField()
+
+ class Meta:
+ abstract = True
+ app_label = 'askbot'
+
+
+class AnonymousContent(models.Model):
+ """
+ Base class for AnonymousQuestion and AnonymousAnswer
+ """
+ session_key = models.CharField(max_length=40) #session id for anonymous questions
+ wiki = models.BooleanField(default=False)
+ added_at = models.DateTimeField(default=datetime.datetime.now)
+ ip_addr = models.IPAddressField(max_length=21) #allow high port numbers
+ author = models.ForeignKey(User,null=True)
+ text = models.TextField()
+ summary = models.CharField(max_length=180)
+
+ class Meta:
+ abstract = True
+ app_label = 'askbot'
diff --git a/askbot/models/content.py b/askbot/models/content.py
new file mode 100644
index 00000000..d3be3195
--- /dev/null
+++ b/askbot/models/content.py
@@ -0,0 +1,245 @@
+import datetime
+import logging
+from django.contrib.auth.models import User
+from django.contrib.contenttypes import generic
+from django.contrib.sitemaps import ping_google
+from django.db import models
+from askbot.models.meta import Comment, Vote, FlaggedItem
+from askbot.models.user import EmailFeedSetting
+
+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)
+
+ 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)
+
+ 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)
+ 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')
+
+ html = models.TextField(null=True)#html rendition of the latest revision
+ text = models.TextField(null=True)#denormalized copy of latest revision
+ comments = generic.GenericRelation(Comment)
+ votes = generic.GenericRelation(Vote)
+ flagged_items = generic.GenericRelation(FlaggedItem)
+
+ _use_markdown = True
+ _urlize = False
+
+ class Meta:
+ abstract = True
+ app_label = 'askbot'
+
+ def get_comments(self):
+ comments = self.comments.all().order_by('id')
+ return comments
+
+ #todo: maybe remove this wnen post models are unified
+ def get_text(self):
+ return self.text
+
+ def add_comment(self, comment=None, user=None, added_at=None):
+ if added_at is None:
+ added_at = datetime.datetime.now()
+ if None in (comment ,user):
+ raise Exception('arguments comment and user are required')
+
+ #Comment = models.get_model('askbot','Comment')#todo: forum hardcoded
+ comment = Comment(
+ content_object=self,
+ comment=comment,
+ user=user,
+ added_at=added_at
+ )
+ comment.parse_and_save(author = user)
+ self.comment_count = self.comment_count + 1
+ self.save()
+ return comment
+
+ def get_instant_notification_subscribers(
+ self,
+ potential_subscribers = None,
+ mentioned_users = None,
+ exclude_list = None,
+ ):
+ """get list of users who have subscribed to
+ receive instant notifications for a given post
+ this method works for questions and answers
+
+ parameter "potential_subscribers" is not used here,
+ but left for the uniformity of the interface (Comment method does use it)
+
+ comment class has it's own variant which does have quite a bit
+ of duplicated code at the moment
+ """
+ subscriber_set = set()
+
+ #1) mention subscribers - common to questions and answers
+ if mentioned_users:
+ mention_subscribers = EmailFeedSetting.objects.filter(
+ subscriber__in = mentioned_users,
+ feed_type = 'm_and_c',
+ frequency = 'i'
+ ).values_list(
+ 'subscriber',
+ flat=True
+ )
+ subscriber_set.update(mention_subscribers)
+
+ origin_post = self.get_origin_post()#handy to make generic method
+
+ #2) individually selected - make sure that users
+ #are individual subscribers to this question
+ selective_subscribers = origin_post.followed_by.all()
+ if selective_subscribers:
+ selective_subscribers = EmailFeedSetting.objects.filter(
+ subscriber__in = selective_subscribers,
+ feed_type = 'q_sel',
+ frequency = 'i'
+ ).values_list(
+ 'subscriber',
+ flat=True
+ )
+ for subscriber in selective_subscribers:
+ if origin_post.passes_tag_filter_for_user(subscriber):
+ subscriber_set.add(subscriber)
+
+ subscriber_set.update(selective_subscribers)
+
+ #3) whole askbot subscibers
+ global_subscribers = EmailFeedSetting.objects.filter(
+ feed_type = 'q_all',
+ frequency = 'i'
+ ).values_list(
+ 'subscriber',
+ flat=True
+ )
+ #todo: apply tag filters here
+ subscriber_set.update(global_subscribers)
+
+ #4) question asked by me
+ question_author = origin_post.author
+ if EmailFeedSetting.objects.filter(
+ subscriber = question_author,
+ frequency = 'i',
+ feed_type = 'q_ask'
+ ):
+ subscriber_set.add(question_author)
+
+ #4) questions answered by me -make sure is that people
+ #are authors of the answers to this question
+ #todo: replace this with a query set method
+ answer_authors = set()
+ for answer in origin_post.answers.all():
+ authors = answer.get_author_list()
+ answer_authors.update(authors)
+
+ if answer_authors:
+ answer_authors = EmailFeedSetting.objects.filter(
+ subscriber__in = answer_authors,
+ frequency = 'i',
+ feed_type = 'q_ans',
+ ).values_list(
+ 'subscriber',
+ flat=True
+ )
+ subscriber_set.update(answer_authors)
+ subscriber_set -= set(exclude_list)
+
+ return list(subscriber_set)
+
+ def passes_tag_filter_for_user(user):
+
+ post_tags = self.get_origin_post().tags.all()
+
+ if user.tag_filter_setting == 'ignored':
+ ignored_tags = user.tag_selections.filter(reason = 'bad')
+ if set(post_tags) & set(ignored_tags):
+ return False
+ else:
+ return True
+ else:
+ interesting_tags = user.tag_selections.filter(reason = 'good')
+ if set(post_tags) & set(interesting_tags):
+ return True
+ else:
+ return False
+
+ def get_latest_revision(self):
+ return self.revisions.all().order_by('-revised_at')[0]
+
+ def get_latest_revision_number(self):
+ return self.get_latest_revision().revision
+
+ def get_time_of_last_edit(self):
+ if self.last_edited_at:
+ return self.last_edited_at
+ else:
+ return self.added_at
+
+ def get_author_list(
+ self,
+ include_comments = False,
+ recursive = False,
+ exclude_list = None):
+
+ #todo: there may be a better way to do these queries
+ authors = set()
+ authors.update([r.author for r in self.revisions.all()])
+ if include_comments:
+ authors.update([c.user for c in self.comments.all()])
+ if recursive:
+ if hasattr(self, 'answers'):
+ for a in self.answers.exclude(deleted = True):
+ authors.update(a.get_author_list( include_comments = include_comments ) )
+ if exclude_list:
+ authors -= set(exclude_list)
+ return list(authors)
+
+ def passes_tag_filter_for_user(self, user):
+ tags = self.get_origin_post().tags.all()
+
+ if self.tag_filter_setting == 'interesting':
+ #at least some of the tags must be marked interesting
+ return self.tag_selections.exists(tag__in = tags, reason = 'good')
+
+ elif self.tag_filter_setting == 'ignored':
+ #at least one tag must be ignored
+ if self.tag_selections.exists(tag__in = tags, reason = 'bad'):
+ return False
+ else:
+ return True
+
+ else:
+ raise ValueError(
+ 'unexpected User.tag_filter_setting %s' \
+ % self.tag_filter_setting
+ )
+
+ 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:
+ when = self.last_edited_at
+ who = self.last_edited_by
+ comments = self.comments.all()
+ if len(comments) > 0:
+ for c in comments:
+ if c.added_at > when:
+ when = c.added_at
+ who = c.user
+ return when, who
diff --git a/askbot/models/meta.py b/askbot/models/meta.py
new file mode 100644
index 00000000..00ee60c7
--- /dev/null
+++ b/askbot/models/meta.py
@@ -0,0 +1,211 @@
+import datetime
+from django.db import models
+from askbot import const
+from askbot.models import base
+from askbot.models.user import EmailFeedSetting
+
+class VoteManager(models.Manager):
+ def get_up_vote_count_from_user(self, user):
+ if user is not None:
+ return self.filter(user=user, vote=1).count()
+ else:
+ return 0
+
+ def get_down_vote_count_from_user(self, user):
+ if user is not None:
+ return self.filter(user=user, vote=-1).count()
+ else:
+ return 0
+
+ def get_votes_count_today_from_user(self, user):
+ if user is not None:
+ today = datetime.date.today()
+ return self.filter(user=user, voted_at__range=(today, today + datetime.timedelta(1))).count()
+ else:
+ return 0
+
+
+class Vote(base.MetaContent, base.UserContent):
+ VOTE_UP = +1
+ VOTE_DOWN = -1
+ VOTE_CHOICES = (
+ (VOTE_UP, u'Up'),
+ (VOTE_DOWN, u'Down'),
+ )
+
+ vote = models.SmallIntegerField(choices=VOTE_CHOICES)
+ voted_at = models.DateTimeField(default=datetime.datetime.now)
+
+ objects = VoteManager()
+
+ class Meta(base.MetaContent.Meta):
+ unique_together = ('content_type', 'object_id', 'user')
+ db_table = u'vote'
+
+ def __unicode__(self):
+ return '[%s] voted at %s: %s' %(self.user, self.voted_at, self.vote)
+
+ def is_upvote(self):
+ return self.vote == self.VOTE_UP
+
+ def is_downvote(self):
+ return self.vote == self.VOTE_DOWN
+
+ def is_opposite(self, vote_type):
+ assert(vote_type in (self.VOTE_UP, self.VOTE_DOWN))
+ return self.vote != vote_type
+
+
+class FlaggedItemManager(models.Manager):
+ def get_flagged_items_count_today(self, user):
+ if user is not None:
+ today = datetime.date.today()
+ return self.filter(user=user, flagged_at__range=(today, today + datetime.timedelta(1))).count()
+ else:
+ return 0
+
+class FlaggedItem(base.MetaContent, base.UserContent):
+ """A flag on a Question or Answer indicating offensive content."""
+ flagged_at = models.DateTimeField(default=datetime.datetime.now)
+
+ objects = FlaggedItemManager()
+
+ class Meta(base.MetaContent.Meta):
+ unique_together = ('content_type', 'object_id', 'user')
+ db_table = u'flagged_item'
+
+ def __unicode__(self):
+ return '[%s] flagged at %s' %(self.user, self.flagged_at)
+
+class Comment(base.MetaContent, base.UserContent):
+ comment = models.CharField(max_length = const.COMMENT_HARD_MAX_LENGTH)
+ added_at = models.DateTimeField(default = datetime.datetime.now)
+ html = models.CharField(max_length = const.COMMENT_HARD_MAX_LENGTH, default='')
+
+ _urlize = True
+ _use_markdown = False
+
+ class Meta(base.MetaContent.Meta):
+ ordering = ('-added_at',)
+ db_table = u'comment'
+
+ #these two are methods
+ parse = base.parse_post_text
+ parse_and_save = base.parse_and_save_post
+
+ def get_origin_post(self):
+ return self.content_object.get_origin_post()
+
+ #todo: maybe remove this wnen post models are unified
+ def get_text(self):
+ return self.comment
+
+ def set_text(self, text):
+ self.comment = text
+
+ def get_updated_activity_data(self, created = False):
+ if self.content_object.__class__.__name__ == 'Question':
+ return const.TYPE_ACTIVITY_COMMENT_QUESTION, self
+ elif self.content_object.__class__.__name__ == 'Answer':
+ return const.TYPE_ACTIVITY_COMMENT_ANSWER, self
+
+ def get_response_receivers(self, exclude_list = None):
+ """get list of users who authored comments on a post
+ and the post itself
+ """
+ assert(exclude_list is not None)
+ users = set()
+ users.update(
+ #get authors of parent object and all associated comments
+ self.content_object.get_author_list(
+ include_comments = True,
+ )
+ )
+ users -= set(exclude_list)
+ return list(users)
+
+ def get_instant_notification_subscribers(
+ self,
+ potential_subscribers = None,
+ mentioned_users = None,
+ exclude_list = None
+ ):
+ """get list of users who want instant notifications
+ about this post
+
+ argument potential_subscribers is required as it saves on db hits
+ """
+
+ subscriber_set = set()
+
+ if potential_subscribers:
+ potential_subscribers = set(potential_subscribers)
+ else:
+ potential_subscribers = set()
+
+ if mentioned_users:
+ potential_subscribers.update(mentioned_users)
+
+ if potential_subscribers:
+ comment_subscribers = EmailFeedSetting.objects.filter(
+ subscriber__in = potential_subscribers,
+ feed_type = 'm_and_c',
+ frequency = 'i'
+ ).values_list(
+ 'subscriber',
+ flat=True
+ )
+ subscriber_set.update(comment_subscribers)
+
+ origin_post = self.get_origin_post()
+ selective_subscribers = origin_post.followed_by.all()
+ if selective_subscribers:
+ selective_subscribers = EmailFeedSetting.objects.filter(
+ subscriber__in = selective_subscribers,
+ feed_type = 'q_sel',
+ frequency = 'i'
+ ).values_list(
+ 'subscriber',
+ flat=True
+ )
+ for subscriber in selective_subscribers:
+ if origin_post.passes_tag_filter_for_user(subscriber):
+ subscriber_set.add(subscriber)
+
+ subscriber_set.update(selective_subscribers)
+
+ global_subscribers = EmailFeedSetting.objects.filter(
+ feed_type = 'q_all',
+ frequency = 'i'
+ ).values_list(
+ 'subscriber',
+ flat=True
+ )
+
+ subscriber_set.update(global_subscribers)
+ if exclude_list:
+ subscriber_set -= set(exclude_list)
+
+ return list(subscriber_set)
+
+ def get_time_of_last_edit(self):
+ return self.added_at
+
+ def delete(self, **kwargs):
+ #todo: not very good import in models of other models
+ #todo: potentially a circular import
+ from askbot.models.user import Activity
+ Activity.objects.get_mentions(
+ mentioned_in = self
+ ).delete()
+ super(Comment,self).delete(**kwargs)
+
+ def get_absolute_url(self):
+ origin_post = self.get_origin_post()
+ return '%s#comment-%d' % (origin_post.get_absolute_url(), self.id)
+
+ def get_latest_revision_number(self):
+ return 1
+
+ def __unicode__(self):
+ return self.comment
diff --git a/forum/models/question.py b/askbot/models/question.py
index e4a0dad7..31a82e0f 100755..100644
--- a/forum/models/question.py
+++ b/askbot/models/question.py
@@ -1,21 +1,22 @@
-from base import * #todo maybe remove *
import random
-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 logging
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
+from django.db import models
+from django.contrib.auth.models import User
+from django.utils.http import urlquote as django_urlquote
+from django.template.defaultfilters import slugify
+from django.core.urlresolvers import reverse
+from django.contrib.sitemaps import ping_google
+from django.utils.translation import ugettext as _
+from askbot.models.tag import Tag, MarkedTag
+from askbot.models import signals
+from askbot.models.base import AnonymousContent, DeletableContent, ContentRevision
+from askbot.models.base import parse_post_text, parse_and_save_post
+from askbot.models import content
+from askbot import const
+from askbot.utils.lists import LazyList
#todo: too bad keys are duplicated see const sort methods
QUESTION_ORDER_BY_MAP = {
@@ -32,8 +33,7 @@ QUESTION_ORDER_BY_MAP = {
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,
@@ -42,21 +42,25 @@ class QuestionManager(models.Manager):
last_activity_by = author,
wiki = wiki,
tagnames = tagnames,
- html = html,
+ #html field is denormalized in .save() call
text = text,
- summary = summary
+ #summary field is denormalized in .save() call
)
if question.wiki:
+ #todo: this is confusing - last_edited_at field
+ #is used as an indicator whether question has been edited
+ #in template askbot/skins/default/templates/post_contributor_info.html
+ #but in principle, post creation should count as edit as well
question.last_edited_by = question.author
question.last_edited_at = added_at
question.wikified_at = added_at
- question.save()
+ question.parse_and_save(author = author)
question.add_revision(
author=author,
text=text,
- comment=CONST['default_version'],
+ comment=const.POST_STATUS['default_version'],
revised_at=added_at,
)
return question
@@ -85,11 +89,12 @@ class QuestionManager(models.Manager):
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)
- )
+ qs = qs.filter(
+ models.Q(title__search = search_query) \
+ | models.Q(text__search = search_query) \
+ | models.Q(tagnames__search = search_query) \
+ | models.Q(answers__text__search = search_query)
+ )
except:
#fallback to dumb title match search
qs = qs.extra(
@@ -97,16 +102,19 @@ class QuestionManager(models.Manager):
params=['%' + search_query + '%']
)
+ #have to import this at run time, otherwise there
+ #a circular import dependency...
+ from askbot.conf import settings as askbot_settings
if scope_selector:
if scope_selector == 'unanswered':
- if const.UNANSWERED_MEANING == 'NO_ANSWERS':
+ if askbot_settings.UNANSWERED_QUESTION_MEANING == 'NO_ANSWERS':
qs = qs.filter(answer_count=0)#todo: expand for different meanings of this
- elif const.UNANSWERED_MEANING == 'NO_ACCEPTED_ANSWERS':
+ elif askbot_settings.UNANSWERED_QUESTION_MEANING == 'NO_ACCEPTED_ANSWERS':
qs = qs.filter(answer_accepted=False)
- elif const.UNANSWERED_MEANING == 'NO_UPVOTED_ANSWERS':
+ elif askbot_settings.UNANSWERED_QUESTION_MEANING == 'NO_UPVOTED_ANSWERS':
raise NotImplementedError()
else:
- raise Exception('UNANSWERED_MEANING setting is wrong')
+ raise Exception('UNANSWERED_QUESTION_MEANING setting is wrong')
elif scope_selector == 'favorite':
qs = qs.filter(favorited_by = request_user)
@@ -114,7 +122,10 @@ class QuestionManager(models.Manager):
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))
+ qs = qs.filter(
+ models.Q(author=u, deleted=False) \
+ | models.Q(answers__author=u, answers__deleted=False)
+ )
meta_data['author_name'] = u.username
except User.DoesNotExist:
meta_data['author_name'] = None
@@ -124,18 +135,18 @@ class QuestionManager(models.Manager):
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,),
- )
+ select = SortedDict([
+ (
+ 'interesting_score',
+ 'SELECT COUNT(1) FROM askbot_markedtag, question_tags '
+ + 'WHERE askbot_markedtag.user_id = %s '
+ + 'AND askbot_markedtag.tag_id = question_tags.tag_id '
+ + 'AND askbot_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',
@@ -147,10 +158,10 @@ class QuestionManager(models.Manager):
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\' '
+ 'SELECT COUNT(1) FROM askbot_markedtag, question_tags '
+ + 'WHERE askbot_markedtag.user_id = %s '
+ + 'AND askbot_markedtag.tag_id = question_tags.tag_id '
+ + 'AND askbot_markedtag.reason = \'bad\' '
+ 'AND question_tags.question_id = question.id'
)
]),
@@ -170,6 +181,9 @@ class QuestionManager(models.Manager):
qs = qs.distinct()
return qs, meta_data
+ #todo: this function is similar to get_response_receivers
+ #profile this function against the other one
+ #todo: maybe this must be a query set method, not manager method
def get_question_and_answer_contributors(self, question_list):
answer_list = []
question_list = list(question_list)#important for MySQL, b/c it does not support
@@ -177,13 +191,22 @@ class QuestionManager(models.Manager):
for q in question_list:
answer_list.extend(list(q.answers.all()))
contributors = User.objects.filter(
- Q(questions__in=question_list) \
- | Q(answers__in=answer_list)
+ models.Q(questions__in=question_list) \
+ | models.Q(answers__in=answer_list)
).distinct()
contributors = list(contributors)
random.shuffle(contributors)
return contributors
+ def get_author_list(self, **kwargs):
+ #todo: - this is duplication - answer manager also has this method
+ #will be gone when models are consolidated
+ #note that method get_question_and_answer_contributors is similar in function
+ authors = set()
+ for question in self:
+ authors.update(question.get_author_list(**kwargs))
+ return list(authors)
+
def update_tags(self, question, tagnames, user):
"""
Updates Tag associations for a question to match the given
@@ -217,7 +240,7 @@ class QuestionManager(models.Manager):
return False
- #todo: why not make this into a method of class Question?
+ #todo: why not make this into a method of Question class?
# also it is actually strange - why do we need the answer_count
# field if the count depends on who is requesting this?
def update_answer_count(self, question):
@@ -228,7 +251,7 @@ class QuestionManager(models.Manager):
# for some reasons, this Answer class failed to be imported,
# although we have imported all classes from models on top.
- from answer import Answer
+ from askbot.models.answer import Answer
self.filter(id=question.id).update(
answer_count=Answer.objects.get_answers_from_question(question).filter(deleted=False).count())
@@ -269,14 +292,18 @@ class QuestionManager(models.Manager):
return LazyList(get_data)
-class Question(Content, DeletableContent):
+class Question(content.Content, DeletableContent):
title = models.CharField(max_length=300)
tags = models.ManyToManyField('Tag', related_name='questions')
answer_accepted = models.BooleanField(default=False)
closed = models.BooleanField(default=False)
closed_by = models.ForeignKey(User, null=True, blank=True, related_name='closed_questions')
closed_at = models.DateTimeField(null=True, blank=True)
- close_reason = models.SmallIntegerField(choices=CLOSE_REASONS, null=True, blank=True)
+ close_reason = models.SmallIntegerField(
+ choices=const.CLOSE_REASONS,
+ null=True,
+ blank=True
+ )
followed_by = models.ManyToManyField(User, related_name='followed_questions')
# Denormalised data
@@ -292,9 +319,12 @@ class Question(Content, DeletableContent):
objects = QuestionManager()
- class Meta(Content.Meta):
+ class Meta(content.Content.Meta):
db_table = u'question'
+ parse = parse_post_text
+ parse_and_save = parse_and_save_post
+
def delete(self):
super(Question, self).delete()
try:
@@ -302,6 +332,35 @@ class Question(Content, DeletableContent):
except Exception:
logging.debug('problem pinging google did you register you sitemap with google?')
+ def get_updated_activity_data(self, created = False):
+ if created:
+ return const.TYPE_ACTIVITY_ASK_QUESTION, self
+ else:
+ latest_revision = self.get_latest_revision()
+ return const.TYPE_ACTIVITY_UPDATE_QUESTION, latest_revision
+
+ def get_response_receivers(self, exclude_list = None):
+ """returns list of users who might be interested
+ in the question update based on their participation
+ in the question activity
+
+ exclude_list is mandatory - it normally should have the
+ author of the update so the he/she is not notified about the update
+ """
+ assert(exclude_list != None)
+ receiving_users = set()
+ receiving_users.update(
+ self.get_author_list(
+ include_comments = True
+ )
+ )
+ #do not include answer commenters here
+ for a in self.answers.all():
+ receiving_users.update(a.get_author_list())
+
+ receiving_users -= set(exclude_list)
+ return receiving_users
+
def retag(self, retagged_by=None, retagged_at=None, tagnames=None):
if None in (retagged_by, retagged_at, tagnames):
raise Exception('arguments retagged_at, retagged_by and tagnames are required')
@@ -313,8 +372,11 @@ class Question(Content, DeletableContent):
self.last_activity_by = retagged_by
# Update the Question's tag associations
- tags_updated = self.objects.update_tags(self,
- form.cleaned_data['tags'], request.user)
+ signals.tags_updated = self.objects.update_tags(
+ self,
+ tagnames,
+ retagged_by
+ )
# Create a new revision
latest_revision = self.get_latest_revision()
@@ -324,11 +386,14 @@ class Question(Content, DeletableContent):
author = retagged_by,
revised_at = retagged_at,
tagnames = tagnames,
- summary = CONST['retagged'],
+ summary = const.POST_STATUS['retagged'],
text = latest_revision.text
)
# send tags updated singal
- tags_updated.send(sender=question.__class__, question=self)
+ signals.tags_updated.send(sender=Question, question=self)
+
+ def get_origin_post(self):
+ return self
def apply_edit(self, edited_at=None, edited_by=None, title=None,\
text=None, comment=None, tags=None, wiki=False):
@@ -348,10 +413,6 @@ class Question(Content, DeletableContent):
if edited_at is None:
edited_at = datetime.datetime.now()
- #todo: have this copy-paste in few places
- html = sanitize_html(markdowner.convert(text))
- question_summary = strip_tags(html)[:120]
-
# Update the Question itself
self.title = title
self.last_edited_at = edited_at
@@ -359,15 +420,13 @@ class Question(Content, DeletableContent):
self.last_edited_by = edited_by
self.last_activity_by = edited_by
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:
self.wiki = True
- self.save()
+ self.parse_and_save(author = edited_by)
# Update the Question tag associations
if latest_revision.tagnames != tags:
@@ -383,11 +442,11 @@ class Question(Content, DeletableContent):
def add_revision(self,author=None, text=None, comment=None, revised_at=None):
if None in (author, text, comment):
- raise Exception('author, text and revised_at are required arguments')
+ raise Exception('author, text and comment are required arguments')
rev_no = self.revisions.all().count() + 1
if comment in (None, ''):
if rev_no == 1:
- comment = CONST['default_version']
+ comment = const.POST_STATUS['default_version']
else:
comment = 'No.%s Revision' % rev_no
@@ -410,13 +469,15 @@ class Question(Content, DeletableContent):
This is required as we're using ``tagnames`` as the sole means of
adding and editing tags.
"""
- initial_addition = (self.id is None)
-
+ initial_addition = (self.pk is None)
+
super(Question, self).save(**kwargs)
if initial_addition:
- tags = Tag.objects.get_or_create_multiple(self.tagname_list(),
- self.author)
+ tags = Tag.objects.get_or_create_multiple(
+ self.tagname_list(),
+ self.author
+ )
self.tags.add(*tags)
Tag.objects.update_use_counts(tags)
@@ -428,7 +489,10 @@ class Question(Content, DeletableContent):
return u','.join([unicode(tag) for tag in self.tagname_list()])
def get_absolute_url(self):
- return '%s%s' % (reverse('question', args=[self.id]), django_urlquote(slugify(self.title)))
+ return '%s%s' % (
+ reverse('question', args=[self.id]),
+ django_urlquote(slugify(self.title))
+ )
def has_favorite_by_user(self, user):
if not user.is_authenticated():
@@ -437,15 +501,15 @@ class Question(Content, DeletableContent):
return FavoriteQuestion.objects.filter(question=self, user=user).count() > 0
def get_answer_count_by_user(self, user_id):
- from answer import Answer
+ from askbot.models.answer import Answer
query_set = Answer.objects.filter(author__id=user_id)
return query_set.filter(question=self).count()
def get_question_title(self):
if self.closed:
- attr = CONST['closed']
+ attr = const.POST_STATUS['closed']
elif self.deleted:
- attr = CONST['deleted']
+ attr = const.POST_STATUS['deleted']
else:
attr = None
if attr is not None:
@@ -497,6 +561,7 @@ class Question(Content, DeletableContent):
answer_comments.append(comment)
#create the report
+ from askbot.conf import settings as askbot_settings
if edited or new_answers or modified_answers or answer_comments:
out = []
if edited:
@@ -517,7 +582,7 @@ class Question(Content, DeletableContent):
out.append(_('%(people)s commented answers') % {'people':people})
else:
out.append(_('%(people)s commented an answer') % {'people':people})
- url = settings.APP_URL + self.get_absolute_url()
+ url = askbot_settings.APP_URL + self.get_absolute_url()
retval = '<a href="%s">%s</a>:<br>\n' % (url,self.title)
out = map(lambda x: '<li>' + x + '</li>',out)
retval += '<ul>' + '\n'.join(out) + '</ul><br>\n'
@@ -535,7 +600,7 @@ class QuestionView(models.Model):
when = models.DateTimeField()
class Meta:
- app_label = 'forum'
+ app_label = 'askbot'
class FavoriteQuestion(models.Model):
"""A favorite Question of a User."""
@@ -544,7 +609,7 @@ class FavoriteQuestion(models.Model):
added_at = models.DateTimeField(default=datetime.datetime.now)
class Meta:
- app_label = 'forum'
+ app_label = 'askbot'
db_table = u'favorite_question'
def __unicode__(self):
return '[%s] favorited at %s' %(self.user, self.added_at)
@@ -592,5 +657,3 @@ class AnonymousQuestion(AnonymousContent):
text=self.text,
)
self.delete()
-
-from answer import Answer, AnswerManager
diff --git a/forum/models/repute.py b/askbot/models/repute.py
index f71be4db..b7b379a2 100755..100644
--- a/forum/models/repute.py
+++ b/askbot/models/repute.py
@@ -1,8 +1,11 @@
-from base import *
from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes import generic
from django.contrib.auth.models import User
-
+from django.db import models
from django.utils.translation import ugettext as _
+import datetime
+from askbot import const
+from django.core.urlresolvers import reverse
class Badge(models.Model):
"""Awarded for notable actions performed on the site by Users."""
@@ -14,6 +17,12 @@ class Badge(models.Model):
(SILVER, _('silver')),
(BRONZE, _('bronze')),
)
+ CSS_CLASSES = {
+ GOLD: 'badge1',
+ SILVER: 'badge2',
+ BRONZE: 'badge3',
+ }
+ DISPLAY_SYMBOL = '&#9679;'
name = models.CharField(max_length=50)
type = models.SmallIntegerField(choices=TYPE_CHOICES)
@@ -26,7 +35,7 @@ class Badge(models.Model):
awarded_to = models.ManyToManyField(User, through='Award', related_name='badges')
class Meta:
- app_label = 'forum'
+ app_label = 'askbot'
db_table = u'badge'
ordering = ('name',)
unique_together = ('name', 'type')
@@ -71,7 +80,7 @@ class Award(models.Model):
return u'[%s] is awarded a badge [%s] at %s' % (self.user.username, self.badge.name, self.awarded_at)
class Meta:
- app_label = 'forum'
+ app_label = 'askbot'
db_table = u'award'
class ReputeManager(models.Manager):
@@ -109,7 +118,7 @@ class Repute(models.Model):
negative = models.SmallIntegerField(default=0)
question = models.ForeignKey('Question')
reputed_at = models.DateTimeField(default=datetime.datetime.now)
- reputation_type = models.SmallIntegerField(choices=TYPE_REPUTATION)
+ reputation_type = models.SmallIntegerField(choices=const.TYPE_REPUTATION)
reputation = models.IntegerField(default=1)
objects = ReputeManager()
@@ -118,5 +127,5 @@ class Repute(models.Model):
return u'[%s]\' reputation changed at %s' % (self.user.username, self.reputed_at)
class Meta:
- app_label = 'forum'
+ app_label = 'askbot'
db_table = u'repute'
diff --git a/askbot/models/signals.py b/askbot/models/signals.py
new file mode 100644
index 00000000..b4ed0d1b
--- /dev/null
+++ b/askbot/models/signals.py
@@ -0,0 +1,23 @@
+import django.dispatch
+
+tags_updated = django.dispatch.Signal(providing_args=['question'])
+
+#todo: this one seems to be unused
+edit_question_or_answer = django.dispatch.Signal(
+ providing_args=['instance', 'modified_by']
+ )
+delete_post_or_answer = django.dispatch.Signal(
+ providing_args=['instance', 'deleted_by']
+ )
+mark_offensive = django.dispatch.Signal(providing_args=['instance', 'mark_by'])
+user_updated = django.dispatch.Signal(providing_args=['instance', 'updated_by'])
+#todo: move this to authentication app
+user_logged_in = django.dispatch.Signal(providing_args=['session'])
+
+post_updated = django.dispatch.Signal(
+ providing_args=[
+ 'post',
+ 'updated_by',
+ 'newly_mentioned_users'
+ ]
+ )
diff --git a/forum/models/tag.py b/askbot/models/tag.py
index e13baf9b..5b1613b7 100755..100644
--- a/forum/models/tag.py
+++ b/askbot/models/tag.py
@@ -1,6 +1,9 @@
-from base import *
-
+from django.db import models
+from django.db import connection, transaction
+from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
+from askbot.models.base import DeletableContent
+
class TagManager(models.Manager):
UPDATE_USED_COUNTS_QUERY = (
@@ -84,4 +87,4 @@ class MarkedTag(models.Model):
reason = models.CharField(max_length=16, choices=TAG_MARK_REASONS)
class Meta:
- app_label = 'forum'
+ app_label = 'askbot'
diff --git a/askbot/models/user.py b/askbot/models/user.py
new file mode 100644
index 00000000..d06c4ed2
--- /dev/null
+++ b/askbot/models/user.py
@@ -0,0 +1,340 @@
+from hashlib import md5
+import string
+from random import Random
+import datetime
+import logging
+from django.db import models
+from django.db.backends.dummy.base import IntegrityError
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes import generic
+from django.contrib.auth.models import User
+from django.utils.translation import ugettext as _
+from askbot import const
+from askbot.utils import functions
+
+
+class ResponseAndMentionActivityManager(models.Manager):
+ def get_query_set(self):
+ response_types = const.RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY
+ response_types += (const.TYPE_ACTIVITY_MENTION, )
+ return super(
+ ResponseAndMentionActivityManager,
+ self
+ ).get_query_set().filter(
+ activity_type__in = response_types
+ )
+
+class ActivityManager(models.Manager):
+ def get_all_origin_posts(self):
+ #todo: redo this with query sets
+ origin_posts = set()
+ for m in self.all():
+ post = m.content_object
+ if post and hasattr(post, 'get_origin_post'):
+ origin_posts.add(post.get_origin_post())
+ else:
+ logging.debug(
+ 'method get_origin_post() not implemented for %s' \
+ % unicode(post)
+ )
+ return list(origin_posts)
+
+ def create_new_mention(
+ self,
+ mentioned_by = None,
+ mentioned_whom = None,
+ mentioned_at = None,
+ mentioned_in = None,
+ reported = None
+ ):
+
+ #todo: automate this using python inspect module
+ kwargs = dict()
+
+ kwargs['activity_type'] = const.TYPE_ACTIVITY_MENTION
+
+ if mentioned_at:
+ #todo: handle cases with rich lookups here like __lt
+ kwargs['active_at'] = mentioned_at
+
+ if mentioned_by:
+ kwargs['user'] = mentioned_by
+
+ if mentioned_in:
+ if functions.is_iterable(mentioned_in):
+ raise NotImplementedError('mentioned_in only works for single items')
+ else:
+ post_content_type = ContentType.objects.get_for_model(mentioned_in)
+ kwargs['content_type'] = post_content_type
+ kwargs['object_id'] = mentioned_in.id
+
+ if reported == True:
+ kwargs['is_auditted'] = True
+ else:
+ kwargs['is_auditted'] = False
+
+ mention_activity = Activity(**kwargs)
+ mention_activity.save()
+
+ if mentioned_whom:
+ if functions.is_iterable(mentioned_whom):
+ raise NotImplementedError('cannot yet mention multiple people at once')
+ else:
+ mention_activity.receiving_users.add(mentioned_whom)
+
+ return mention_activity
+
+ def get_mentions(
+ self,
+ mentioned_by = None,
+ mentioned_whom = None,
+ mentioned_at = None,
+ mentioned_in = None,
+ reported = None,
+ mentioned_at__gt = None,
+ ):
+ """extract mention-type activity objects
+ todo: implement better rich field lookups
+ """
+
+ kwargs = dict()
+
+ kwargs['activity_type'] = const.TYPE_ACTIVITY_MENTION
+
+ if mentioned_at:
+ #todo: handle cases with rich lookups here like __lt
+ kwargs['active_at'] = mentioned_at
+ elif mentioned_at__gt:
+ kwargs['active_at__gt'] = mentioned_at__gt
+
+ if mentioned_by:
+ kwargs['user'] = mentioned_by
+
+ if mentioned_whom:
+ if functions.is_iterable(mentioned_whom):
+ kwargs['receiving_users__in'] = mentioned_whom
+ else:
+ kwargs['receiving_users__in'] = (mentioned_whom,)
+
+ if mentioned_in:
+ if functions.is_iterable(mentioned_in):
+ it = iter(mentioned_in)
+ raise NotImplementedError('mentioned_in only works for single items')
+ else:
+ post_content_type = ContentType.objects.get_for_model(mentioned_in)
+ kwargs['content_type'] = post_content_type
+ kwargs['object_id'] = mentioned_in.id
+
+ if reported == True:
+ kwargs['is_auditted'] = True
+ else:
+ kwargs['is_auditted'] = False
+
+ return self.filter(**kwargs)
+
+
+class Activity(models.Model):
+ """
+ We keep some history data for user activities
+ """
+ user = models.ForeignKey(User)
+ receiving_users = models.ManyToManyField(User, related_name='received_activity')
+ activity_type = models.SmallIntegerField(choices = const.TYPE_ACTIVITY)
+ active_at = models.DateTimeField(default=datetime.datetime.now)
+ content_type = models.ForeignKey(ContentType)
+ object_id = models.PositiveIntegerField()
+ content_object = generic.GenericForeignKey('content_type', 'object_id')
+ is_auditted = models.BooleanField(default=False)
+
+ objects = ActivityManager()
+ responses_and_mentions = ResponseAndMentionActivityManager()
+
+ def __unicode__(self):
+ return u'[%s] was active at %s' % (self.user.username, self.active_at)
+
+ class Meta:
+ app_label = 'askbot'
+ db_table = u'activity'
+
+ def get_mentioned_user(self):
+ assert(self.activity_type == const.TYPE_ACTIVITY_MENTION)
+ user_qs = self.receiving_users.all()
+ assert(len(user_qs) == 1)
+ return user_qs[0]
+
+ def get_absolute_url(self):
+ return self.content_object.get_absolute_url()
+
+class EmailFeedSetting(models.Model):
+ DELTA_TABLE = {
+ 'i':datetime.timedelta(-1),#instant emails are processed separately
+ 'd':datetime.timedelta(1),
+ 'w':datetime.timedelta(7),
+ 'n':datetime.timedelta(-1),
+ }
+ FEED_TYPES = (
+ ('q_all',_('Entire askbot')),
+ ('q_ask',_('Questions that I asked')),
+ ('q_ans',_('Questions that I answered')),
+ ('q_sel',_('Individually selected questions')),
+ ('m_and_c',_('Mentions and comment responses')),
+ )
+ UPDATE_FREQUENCY = (
+ ('i',_('Instantly')),
+ ('d',_('Daily')),
+ ('w',_('Weekly')),
+ ('n',_('No email')),
+ )
+
+
+ subscriber = models.ForeignKey(User, related_name='notification_subscriptions')
+ feed_type = models.CharField(max_length=16,choices=FEED_TYPES)
+ frequency = models.CharField(
+ max_length=8,
+ choices=const.NOTIFICATION_DELIVERY_SCHEDULE_CHOICES,
+ default='n',
+ )
+ added_at = models.DateTimeField(auto_now_add=True)
+ reported_at = models.DateTimeField(null=True)
+
+ #functions for rich comparison
+ #PRECEDENCE = ('i','d','w','n')#the greater ones are first
+ #def __eq__(self, other):
+ # return self.id == other.id
+
+# def __eq__(self, other):
+# return self.id != other.id
+
+# def __gt__(self, other):
+# return PRECEDENCE.index(self.frequency) < PRECEDENCE.index(other.frequency)
+
+# def __lt__(self, other):
+# return PRECEDENCE.index(self.frequency) > PRECEDENCE.index(other.frequency)
+
+# def __gte__(self, other):
+# if self.__eq__(other):
+# return True
+# else:
+# return self.__gt__(other)
+
+# def __lte__(self, other):
+# if self.__eq__(other):
+# return True
+# else:
+# return self.__lt__(other)
+
+ def save(self,*args,**kwargs):
+ type = self.feed_type
+ subscriber = self.subscriber
+ similar = self.__class__.objects.filter(
+ feed_type=type,
+ subscriber=subscriber
+ ).exclude(pk=self.id)
+ if len(similar) > 0:
+ raise IntegrityError('email feed setting already exists')
+ super(EmailFeedSetting,self).save(*args,**kwargs)
+
+ def get_previous_report_cutoff_time(self):
+ now = datetime.datetime.now()
+ return now - self.DELTA_TABLE[self.frequency]
+
+ def should_send_now(self):
+ now = datetime.datetime.now()
+ cutoff_time = self.get_previous_report_cutoff_time()
+ if self.reported_at == None or self.reported_at <= cutoff_time:
+ return True
+ else:
+ return False
+
+ def mark_reported_now(self):
+ self.reported_at = datetime.datetime.now()
+ self.save()
+
+ class Meta:
+ app_label = 'askbot'
+
+from askbot.utils.time import one_day_from_now
+
+class ValidationHashManager(models.Manager):
+ def _generate_md5_hash(self, user, type, hash_data, seed):
+ return md5(
+ "%s%s%s%s" % (
+ seed,
+ "".join(map(str, hash_data)),
+ user.id,
+ type
+ )
+ ).hexdigest()
+
+ def create_new(self, user, type, hash_data=[], expiration=None):
+ seed = ''.join(Random().sample(string.letters+string.digits, 12))
+ hash = self._generate_md5_hash(user, type, hash_data, seed)
+
+ obj = ValidationHash(hash_code=hash, seed=seed, user=user, type=type)
+
+ if expiration is not None:
+ obj.expiration = expiration
+
+ try:
+ obj.save()
+ except:
+ return None
+
+ return obj
+
+ def validate(self, hash, user, type, hash_data=[]):
+ try:
+ obj = self.get(hash_code=hash)
+ except:
+ return False
+
+ if obj.type != type:
+ return False
+
+ if obj.user != user:
+ return False
+
+ valid = (obj.hash_code == self._generate_md5_hash(
+ obj.user,
+ type,
+ hash_data,
+ obj.seed
+ )
+ )
+
+ if valid:
+ if obj.expiration < datetime.datetime.now():
+ obj.delete()
+ return False
+ else:
+ obj.delete()
+ return True
+
+ return False
+
+class ValidationHash(models.Model):
+ #todo: was 256 chars - is that important?
+ #on mysql 255 is max for unique=True
+ hash_code = models.CharField(max_length=255,unique=True)
+ seed = models.CharField(max_length=12)
+ expiration = models.DateTimeField(default=one_day_from_now)
+ type = models.CharField(max_length=12)
+ user = models.ForeignKey(User)
+
+ objects = ValidationHashManager()
+
+ class Meta:
+ unique_together = ('user', 'type')
+ app_label = 'askbot'
+
+ def __str__(self):
+ return self.hash_code
+
+#class AuthKeyUserAssociation(models.Model):
+# key = models.CharField(max_length=255,null=False,unique=True)
+# provider = models.CharField(max_length=64)#string 'yahoo', 'google', etc.
+# user = models.ForeignKey(User, related_name="auth_keys")
+# added_at = models.DateTimeField(default=datetime.datetime.now)
+#
+# class Meta:
+# app_label = 'askbot'
diff --git a/forum/search/README b/askbot/search/README
index c15dc221..c15dc221 100644
--- a/forum/search/README
+++ b/askbot/search/README
diff --git a/forum/utils/__init__.py b/askbot/search/__init__.py
index e69de29b..e69de29b 100755..100644
--- a/forum/utils/__init__.py
+++ b/askbot/search/__init__.py
diff --git a/forum/search/indexer.py b/askbot/search/indexer.py
index c7c45c59..c7c45c59 100644
--- a/forum/search/indexer.py
+++ b/askbot/search/indexer.py
diff --git a/forum/search/sphinx/README b/askbot/search/sphinx/README
index 8c008a23..8c008a23 100644
--- a/forum/search/sphinx/README
+++ b/askbot/search/sphinx/README
diff --git a/forum/search/sphinx/sphinx.conf b/askbot/search/sphinx/sphinx.conf
index bf4bdc8b..bf4bdc8b 100644
--- a/forum/search/sphinx/sphinx.conf
+++ b/askbot/search/sphinx/sphinx.conf
diff --git a/forum/search/state_manager.py b/askbot/search/state_manager.py
index 6a38a7a2..f8643e31 100644
--- a/forum/search/state_manager.py
+++ b/askbot/search/state_manager.py
@@ -1,7 +1,8 @@
#search state manager object
#that lives in the session and takes care of the state
#persistece during the search session
-from forum import const
+from askbot import const
+from askbot.conf import settings as askbot_settings
import logging
ACTIVE_COMMANDS = (
@@ -19,12 +20,12 @@ def some_in(what, where):
class SearchState(object):
def __init__(self):
- self.scope= const.DEFAULT_POST_SCOPE
+ 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_size = int(askbot_settings.DEFAULT_QUESTIONS_PAGE_SIZE)
self.page = 1
self.logged_in = False
logging.debug('new search state initialized')
@@ -63,76 +64,76 @@ class SearchState(object):
setattr(self, key, new_value)
self.reset_page()
- def relax_stickiness(self, input, view_log):
+ def relax_stickiness(self, input_dict, view_log):
if view_log.get_previous(1) == 'questions':
- if not some_in(ACTIVE_COMMANDS, input):
+ if not some_in(ACTIVE_COMMANDS, input_dict):
self.reset()
#todo also relax if 'all' scope was clicked twice
- def update_from_user_input(self,input,raw_input = {}):
+ def update_from_user_input(self, input_dict, unprocessed_input = {}):
#todo: this function will probably not
#fit the case of multiple parameters entered at the same tiem
- if 'start_over' in input:
+ if 'start_over' in input_dict:
self.reset()
- if 'page' in input:
- self.page = input['page']
+ if 'page' in input_dict:
+ self.page = input_dict['page']
#special case - on page flip no other input is accepted
return
- if 'page_size' in input:
- self.update_value('page_size',input)
+ if 'page_size' in input_dict:
+ self.update_value('page_size', input_dict)
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:
+ if 'scope' in input_dict:
+ if input_dict['scope'] == 'favorite' and self.logged_in == False:
self.reset_scope()
else:
- self.update_value('scope',input)
+ self.update_value('scope', input_dict)
- if 'tags' in input:
+ if 'tags' in input_dict:
if self.tags:
old_tags = self.tags.copy()
- self.tags = self.tags.union(input['tags'])
+ self.tags = self.tags.union(input_dict['tags'])
if self.tags != old_tags:
self.reset_page()
else:
- self.tags = input['tags']
+ self.tags = input_dict['tags']
#all resets just return
- if 'reset_tags' in input:
+ if 'reset_tags' in input_dict:
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 'reset_author' in input_dict:
if self.author:
self.author = None
self.reset_page()
return
- if 'reset_query' in input:
+ if 'reset_query' in input_dict:
self.reset_query()
return
- self.update_value('author',input)
+ self.update_value('author', input_dict)
- if 'query' in input:
- self.update_value('query',input)
+ if 'query' in input_dict:
+ self.update_value('query', input_dict)
self.sort = 'relevant'
- elif 'search' in raw_input:#a case of use nulling search query by hand
+ elif 'search' in unprocessed_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:
+ if 'sort' in input_dict:
+ if input_dict['sort'] == 'relevant' and self.query is None:
self.reset_sort()
else:
- self.update_value('sort',input)
+ self.update_value('sort', input_dict)
#todo: plug - mysql has no relevance sort
if self.sort == 'relevant':
diff --git a/forum_modules/__init__.py b/askbot/setup_templates/__init__.py
index e69de29b..e69de29b 100755..100644
--- a/forum_modules/__init__.py
+++ b/askbot/setup_templates/__init__.py
diff --git a/django.wsgi b/askbot/setup_templates/django.wsgi
index 83274865..83274865 100644
--- a/django.wsgi
+++ b/askbot/setup_templates/django.wsgi
diff --git a/log/README b/askbot/setup_templates/log/README
index 28d3b6e9..28d3b6e9 100644
--- a/log/README
+++ b/askbot/setup_templates/log/README
diff --git a/manage.py b/askbot/setup_templates/manage.py
index 5e78ea97..5e78ea97 100644
--- a/manage.py
+++ b/askbot/setup_templates/manage.py
diff --git a/askbot/setup_templates/settings.py b/askbot/setup_templates/settings.py
new file mode 100644
index 00000000..aa6194aa
--- /dev/null
+++ b/askbot/setup_templates/settings.py
@@ -0,0 +1,194 @@
+# Django settings for ASKBOT enabled project.
+import os.path
+import logging
+
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+INTERNAL_IPS = ('127.0.0.1',)
+
+ADMINS = (
+ ('Your Name', 'your_email@domain.com'),
+)
+
+MANAGERS = ADMINS
+
+DATABASE_ENGINE = 'mysql' # only mysql is supported, more will be in the near future
+DATABASE_NAME = '' # Or path to database file if using sqlite3.
+DATABASE_USER = '' # Not used with sqlite3.
+DATABASE_PASSWORD = '' # Not used with sqlite3.
+DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
+DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
+
+#mail server settings
+SERVER_EMAIL = ''
+DEFAULT_FROM_EMAIL = ''
+EMAIL_HOST_USER = ''
+EMAIL_HOST_PASSWORD = ''
+EMAIL_SUBJECT_PREFIX = '[ASKBOT] '
+EMAIL_HOST='askbot.org'
+EMAIL_PORT='25'
+EMAIL_USE_TLS=False
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# On Unix systems, a value of None will cause Django to use the same
+# timezone as the operating system.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+TIME_ZONE = 'America/Chicago'
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'en-us'
+
+SITE_ID = 1
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+LANGUAGE_CODE = 'en'
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'askbot', 'upfiles')
+
+# URL that handles the media served from MEDIA_ROOT. Make sure to use a
+# trailing slash if there is a path component (optional in other cases).
+# Examples: "http://media.lawrence.com", "http://example.com/media/"
+MEDIA_URL = ''#set this to serve uploaded files correctly
+
+PROJECT_ROOT = os.path.dirname(__file__)
+
+# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
+# trailing slash.
+# Examples: "http://foo.com/media/", "/media/".
+ADMIN_MEDIA_PREFIX = '/admin/media/'
+
+# Make up some unique string, and don't share it with anybody.
+SECRET_KEY = 'sdljdfjkldsflsdjkhsjkldgjlsdgfs s '
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+ 'django.template.loaders.filesystem.load_template_source',
+ 'django.template.loaders.app_directories.load_template_source',
+ #below is askbot stuff for this tuple
+ 'askbot.skins.loaders.load_template_source',
+ #'django.template.loaders.eggs.load_template_source',
+)
+
+
+MIDDLEWARE_CLASSES = (
+ #'django.middleware.gzip.GZipMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ #'django.middleware.locale.LocaleMiddleware',
+ #'django.middleware.cache.UpdateCacheMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ #'django.middleware.cache.FetchFromCacheMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ #'django.middleware.sqlprint.SqlPrintingMiddleware',
+
+ #below is askbot stuff for this tuple
+ 'askbot.middleware.anon_user.ConnectToSessionMessagesMiddleware',
+ 'askbot.middleware.pagesize.QuestionsPageSizeMiddleware',
+ 'askbot.middleware.cancel.CancelActionMiddleware',
+ #'askbot.deps.recaptcha_django.middleware.ReCaptchaMiddleware',
+ 'django.middleware.transaction.TransactionMiddleware',
+ 'debug_toolbar.middleware.DebugToolbarMiddleware',
+ 'askbot.middleware.view_log.ViewLogMiddleware',
+ 'askbot.middleware.spaceless.SpacelessMiddleware',
+)
+
+
+ROOT_URLCONF = os.path.basename(os.path.dirname(__file__)) + '.urls'
+
+
+#UPLOAD SETTINGS
+FILE_UPLOAD_TEMP_DIR = os.path.join(
+ os.path.dirname(__file__),
+ 'tmp'
+ ).replace('\\','/')
+
+FILE_UPLOAD_HANDLERS = (
+ 'django.core.files.uploadhandler.MemoryFileUploadHandler',
+ 'django.core.files.uploadhandler.TemporaryFileUploadHandler',
+)
+ALLOW_FILE_TYPES = ('.jpg', '.jpeg', '.gif', '.bmp', '.png', '.tiff')
+ALLOW_MAX_FILE_SIZE = 1024 * 1024 #result in bytes
+DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
+
+
+TEMPLATE_DIRS = (
+ #specific to askbot
+ os.path.join(os.path.dirname(__file__),'askbot','skins').replace('\\','/'),
+)
+
+TEMPLATE_CONTEXT_PROCESSORS = (
+ 'django.core.context_processors.request',
+ 'askbot.context.application_settings',
+ #'django.core.context_processors.i18n',
+ 'askbot.user_messages.context_processors.user_messages',#must be before auth
+ 'django.core.context_processors.auth', #this is required for admin
+)
+
+
+INSTALLED_APPS = (
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.sites',
+
+ #all of these are needed for the askbot
+ 'django.contrib.admin',
+ 'django.contrib.humanize',
+ 'django.contrib.sitemaps',
+ 'debug_toolbar',
+ 'askbot',
+ 'askbot.deps.django_authopenid',
+ #'askbot.importers.stackexchange', #se loader
+ 'south',
+ 'askbot.deps.livesettings',
+ 'keyedcache',
+)
+
+
+#setup memcached for production use!
+#see http://docs.djangoproject.com/en/1.1/topics/cache/ for details
+CACHE_BACKEND = 'locmem://'
+#If you use memcache you may want to uncomment the following line to enable memcached based sessions
+#SESSION_ENGINE = 'django.contrib.sessions.backends.cache_db'
+
+AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',)
+
+#this needs to go
+USE_EXTERNAL_LEGACY_LOGIN = False #DO NOT USE, and do not delete this line, will be removed later
+if 'USE_EXTERNAL_LEGACY_LOGIN' in locals() and USE_EXTERNAL_LEGACY_LOGIN:
+ INSTALLED_APPS += (EXTERNAL_LEGACY_LOGIN_MODULE,)
+
+ if 'EXTERNAL_LEGACY_LOGIN_AUTHENTICATION_BACKEND' in locals():
+ AUTHENTICATION_BACKENDS += (EXTERNAL_LEGACY_LOGIN_AUTHENTICATION_BACKEND,)
+ if 'EXTERNAL_LEGACY_LOGIN_AUTHENTICATION_MIDDLEWARE' in locals():
+ MIDDLEWARE_CLASSES += (EXTERNAL_LEGACY_LOGIN_AUTHENTICATION_MIDDLEWARE,)
+ def LOAD_EXTERNAL_LOGIN_APP():
+ return __import__(EXTERNAL_LEGACY_LOGIN_MODULE, [], [], ['api','forms','views'])
+else:
+ LOAD_EXTERNAL_LOGIN_APP = lambda: None
+
+
+#logging settings
+LOG_FILENAME = 'askbot.log'
+logging.basicConfig(
+ filename=os.path.join(os.path.dirname(__file__), 'log', LOG_FILENAME),
+ level=logging.DEBUG,
+ format='%(pathname)s TIME: %(asctime)s MSG: %(filename)s:%(funcName)s:%(lineno)d %(message)s',
+)
+
+###########################
+#
+# this will allow running your forum with url like http://site.com/forum
+#
+# FORUM_SCRIPT_ALIAS = 'forum/'
+#
+FORUM_SCRIPT_ALIAS = '' #no leading slash, default = '' empty string
+_ = lambda v:v #fake translation function for the login url
+LOGIN_URL = '/%s%s%s' % (FORUM_SCRIPT_ALIAS,_('account/'),_('signin/'))
diff --git a/forum/upfiles/README b/askbot/setup_templates/upfiles/README
index 17bf8ecb..17bf8ecb 100755
--- a/forum/upfiles/README
+++ b/askbot/setup_templates/upfiles/README
diff --git a/urls.py b/askbot/setup_templates/urls.py
index 339791c9..31895b99 100644
--- a/urls.py
+++ b/askbot/setup_templates/urls.py
@@ -1,13 +1,17 @@
-from django.conf.urls.defaults import *
-from django.utils.translation import ugettext as _
+"""
+main url configuration file for the askbot site
+"""
+from django.conf.urls.defaults import patterns, include, handler404, handler500
from django.conf import settings
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
- (r'^%s' % settings.FORUM_SCRIPT_ALIAS, include('forum.urls')),
+ (r'^%s' % settings.FORUM_SCRIPT_ALIAS, include('askbot.urls')),
(r'^admin/', include(admin.site.urls)),
+ (r'^cache/', include('keyedcache.urls')),
+ (r'^settings/', include('askbot.deps.livesettings.urls')),
)
if 'rosetta' in settings.INSTALLED_APPS:
diff --git a/forum/sitemap.py b/askbot/sitemap.py
index c0c60b5e..0f8f7451 100755..100644
--- a/forum/sitemap.py
+++ b/askbot/sitemap.py
@@ -1,5 +1,5 @@
from django.contrib.sitemaps import Sitemap
-from forum.models import Question
+from askbot.models import Question
class QuestionsSitemap(Sitemap):
changefreq = 'daily'
diff --git a/forum/skins/README b/askbot/skins/README
index 01ef0a9d..01ef0a9d 100755
--- a/forum/skins/README
+++ b/askbot/skins/README
diff --git a/forum_modules/robotstxt/__init__.py b/askbot/skins/__init__.py
index e69de29b..e69de29b 100755..100644
--- a/forum_modules/robotstxt/__init__.py
+++ b/askbot/skins/__init__.py
diff --git a/forum/skins/common/media/README b/askbot/skins/common/media/README
index 3376e754..3376e754 100755
--- a/forum/skins/common/media/README
+++ b/askbot/skins/common/media/README
diff --git a/forum/skins/default/media/images/blue-up-arrow-h18px.png b/askbot/skins/default/media/images/blue-up-arrow-h18px.png
index e1f29e86..e1f29e86 100755
--- a/forum/skins/default/media/images/blue-up-arrow-h18px.png
+++ b/askbot/skins/default/media/images/blue-up-arrow-h18px.png
Binary files differ
diff --git a/forum/skins/default/media/images/box-arrow.gif b/askbot/skins/default/media/images/box-arrow.gif
index 89dcf5b3..89dcf5b3 100755
--- a/forum/skins/default/media/images/box-arrow.gif
+++ b/askbot/skins/default/media/images/box-arrow.gif
Binary files differ
diff --git a/forum/skins/default/media/images/bullet_green.gif b/askbot/skins/default/media/images/bullet_green.gif
index fa530910..fa530910 100755
--- a/forum/skins/default/media/images/bullet_green.gif
+++ b/askbot/skins/default/media/images/bullet_green.gif
Binary files differ
diff --git a/forum/skins/default/media/images/cc-88x31.png b/askbot/skins/default/media/images/cc-88x31.png
index 0f2a0f10..0f2a0f10 100755
--- a/forum/skins/default/media/images/cc-88x31.png
+++ b/askbot/skins/default/media/images/cc-88x31.png
Binary files differ
diff --git a/forum/skins/default/media/images/cc-wiki.png b/askbot/skins/default/media/images/cc-wiki.png
index 3e680538..3e680538 100755
--- a/forum/skins/default/media/images/cc-wiki.png
+++ b/askbot/skins/default/media/images/cc-wiki.png
Binary files differ
diff --git a/forum/skins/default/media/images/close-small-dark.png b/askbot/skins/default/media/images/close-small-dark.png
index 280c1fc7..280c1fc7 100755
--- a/forum/skins/default/media/images/close-small-dark.png
+++ b/askbot/skins/default/media/images/close-small-dark.png
Binary files differ
diff --git a/forum/skins/default/media/images/close-small-hover.png b/askbot/skins/default/media/images/close-small-hover.png
index 7899aec7..7899aec7 100755
--- a/forum/skins/default/media/images/close-small-hover.png
+++ b/askbot/skins/default/media/images/close-small-hover.png
Binary files differ
diff --git a/forum/skins/default/media/images/close-small.png b/askbot/skins/default/media/images/close-small.png
index 5a99d31f..5a99d31f 100755
--- a/forum/skins/default/media/images/close-small.png
+++ b/askbot/skins/default/media/images/close-small.png
Binary files differ
diff --git a/forum/skins/default/media/images/dash.gif b/askbot/skins/default/media/images/dash.gif
index d1ddc507..d1ddc507 100755
--- a/forum/skins/default/media/images/dash.gif
+++ b/askbot/skins/default/media/images/dash.gif
Binary files differ
diff --git a/forum/skins/default/media/images/djangomade124x25_grey.gif b/askbot/skins/default/media/images/djangomade124x25_grey.gif
index d34bb311..d34bb311 100755
--- a/forum/skins/default/media/images/djangomade124x25_grey.gif
+++ b/askbot/skins/default/media/images/djangomade124x25_grey.gif
Binary files differ
diff --git a/forum/skins/default/media/images/dot-g.gif b/askbot/skins/default/media/images/dot-g.gif
index 5d6bb28e..5d6bb28e 100755
--- a/forum/skins/default/media/images/dot-g.gif
+++ b/askbot/skins/default/media/images/dot-g.gif
Binary files differ
diff --git a/forum/skins/default/media/images/dot-list.gif b/askbot/skins/default/media/images/dot-list.gif
index f6a6b865..f6a6b865 100755
--- a/forum/skins/default/media/images/dot-list.gif
+++ b/askbot/skins/default/media/images/dot-list.gif
Binary files differ
diff --git a/forum/skins/default/media/images/edit.png b/askbot/skins/default/media/images/edit.png
index dcb09be0..dcb09be0 100755
--- a/forum/skins/default/media/images/edit.png
+++ b/askbot/skins/default/media/images/edit.png
Binary files differ
diff --git a/forum/skins/default/media/images/expander-arrow-hide.gif b/askbot/skins/default/media/images/expander-arrow-hide.gif
index feb6a618..feb6a618 100755
--- a/forum/skins/default/media/images/expander-arrow-hide.gif
+++ b/askbot/skins/default/media/images/expander-arrow-hide.gif
Binary files differ
diff --git a/forum/skins/default/media/images/expander-arrow-show.gif b/askbot/skins/default/media/images/expander-arrow-show.gif
index 6825c56e..6825c56e 100755
--- a/forum/skins/default/media/images/expander-arrow-show.gif
+++ b/askbot/skins/default/media/images/expander-arrow-show.gif
Binary files differ
diff --git a/forum/skins/default/media/images/favicon.gif b/askbot/skins/default/media/images/favicon.gif
index f7f9061b..f7f9061b 100644
--- a/forum/skins/default/media/images/favicon.gif
+++ b/askbot/skins/default/media/images/favicon.gif
Binary files differ
diff --git a/forum/skins/default/media/images/feed-icon-small.png b/askbot/skins/default/media/images/feed-icon-small.png
index b3c949d2..b3c949d2 100755
--- a/forum/skins/default/media/images/feed-icon-small.png
+++ b/askbot/skins/default/media/images/feed-icon-small.png
Binary files differ
diff --git a/forum/skins/default/media/images/gray-up-arrow-h18px.png b/askbot/skins/default/media/images/gray-up-arrow-h18px.png
index 78767445..78767445 100755
--- a/forum/skins/default/media/images/gray-up-arrow-h18px.png
+++ b/askbot/skins/default/media/images/gray-up-arrow-h18px.png
Binary files differ
diff --git a/forum/skins/default/media/images/grippie.png b/askbot/skins/default/media/images/grippie.png
index 6524d416..6524d416 100755
--- a/forum/skins/default/media/images/grippie.png
+++ b/askbot/skins/default/media/images/grippie.png
Binary files differ
diff --git a/forum/skins/default/media/images/indicator.gif b/askbot/skins/default/media/images/indicator.gif
index 1c72ebb5..1c72ebb5 100755
--- a/forum/skins/default/media/images/indicator.gif
+++ b/askbot/skins/default/media/images/indicator.gif
Binary files differ
diff --git a/forum/skins/default/media/images/logo.gif b/askbot/skins/default/media/images/logo.gif
index 03eb79f4..03eb79f4 100644
--- a/forum/skins/default/media/images/logo.gif
+++ b/askbot/skins/default/media/images/logo.gif
Binary files differ
diff --git a/forum/skins/default/media/images/logo.png b/askbot/skins/default/media/images/logo.png
index 10559161..10559161 100644
--- a/forum/skins/default/media/images/logo.png
+++ b/askbot/skins/default/media/images/logo.png
Binary files differ
diff --git a/forum/skins/default/media/images/logo1.png b/askbot/skins/default/media/images/logo1.png
index d79a6271..d79a6271 100755
--- a/forum/skins/default/media/images/logo1.png
+++ b/askbot/skins/default/media/images/logo1.png
Binary files differ
diff --git a/forum/skins/default/media/images/logo2.png b/askbot/skins/default/media/images/logo2.png
index bd3cccd9..bd3cccd9 100755
--- a/forum/skins/default/media/images/logo2.png
+++ b/askbot/skins/default/media/images/logo2.png
Binary files differ
diff --git a/askbot/skins/default/media/images/mail-envelope-empty.png b/askbot/skins/default/media/images/mail-envelope-empty.png
new file mode 100644
index 00000000..0fde87dc
--- /dev/null
+++ b/askbot/skins/default/media/images/mail-envelope-empty.png
Binary files differ
diff --git a/askbot/skins/default/media/images/mail-envelope-full.png b/askbot/skins/default/media/images/mail-envelope-full.png
new file mode 100644
index 00000000..2277e919
--- /dev/null
+++ b/askbot/skins/default/media/images/mail-envelope-full.png
Binary files differ
diff --git a/forum/skins/default/media/images/medala.gif b/askbot/skins/default/media/images/medala.gif
index 93dd1a39..93dd1a39 100755
--- a/forum/skins/default/media/images/medala.gif
+++ b/askbot/skins/default/media/images/medala.gif
Binary files differ
diff --git a/forum/skins/default/media/images/medala_on.gif b/askbot/skins/default/media/images/medala_on.gif
index a18f9e85..a18f9e85 100755
--- a/forum/skins/default/media/images/medala_on.gif
+++ b/askbot/skins/default/media/images/medala_on.gif
Binary files differ
diff --git a/forum/skins/default/media/images/new.gif b/askbot/skins/default/media/images/new.gif
index 8a220b53..8a220b53 100755
--- a/forum/skins/default/media/images/new.gif
+++ b/askbot/skins/default/media/images/new.gif
Binary files differ
diff --git a/forum/skins/default/media/images/nophoto.png b/askbot/skins/default/media/images/nophoto.png
index 2daf0ffd..2daf0ffd 100755
--- a/forum/skins/default/media/images/nophoto.png
+++ b/askbot/skins/default/media/images/nophoto.png
Binary files differ
diff --git a/forum/skins/default/media/images/openid.gif b/askbot/skins/default/media/images/openid.gif
index 8540e12b..8540e12b 100755
--- a/forum/skins/default/media/images/openid.gif
+++ b/askbot/skins/default/media/images/openid.gif
Binary files differ
diff --git a/forum/skins/default/media/images/openid/aol.gif b/askbot/skins/default/media/images/openid/aol.gif
index decc4f12..decc4f12 100755
--- a/forum/skins/default/media/images/openid/aol.gif
+++ b/askbot/skins/default/media/images/openid/aol.gif
Binary files differ
diff --git a/forum/skins/default/media/images/openid/blogger.ico b/askbot/skins/default/media/images/openid/blogger.ico
index 1b9730b0..1b9730b0 100755
--- a/forum/skins/default/media/images/openid/blogger.ico
+++ b/askbot/skins/default/media/images/openid/blogger.ico
Binary files differ
diff --git a/forum/skins/default/media/images/openid/claimid.ico b/askbot/skins/default/media/images/openid/claimid.ico
index 2b80f491..2b80f491 100755
--- a/forum/skins/default/media/images/openid/claimid.ico
+++ b/askbot/skins/default/media/images/openid/claimid.ico
Binary files differ
diff --git a/forum/skins/default/media/images/openid/facebook.gif b/askbot/skins/default/media/images/openid/facebook.gif
index b997b358..b997b358 100755
--- a/forum/skins/default/media/images/openid/facebook.gif
+++ b/askbot/skins/default/media/images/openid/facebook.gif
Binary files differ
diff --git a/forum/skins/default/media/images/openid/flickr.ico b/askbot/skins/default/media/images/openid/flickr.ico
index 11f6e07f..11f6e07f 100755
--- a/forum/skins/default/media/images/openid/flickr.ico
+++ b/askbot/skins/default/media/images/openid/flickr.ico
Binary files differ
diff --git a/forum/skins/default/media/images/openid/google.gif b/askbot/skins/default/media/images/openid/google.gif
index 1b6cd07b..1b6cd07b 100755
--- a/forum/skins/default/media/images/openid/google.gif
+++ b/askbot/skins/default/media/images/openid/google.gif
Binary files differ
diff --git a/forum/skins/default/media/images/openid/livejournal.ico b/askbot/skins/default/media/images/openid/livejournal.ico
index f3d21ec5..f3d21ec5 100755
--- a/forum/skins/default/media/images/openid/livejournal.ico
+++ b/askbot/skins/default/media/images/openid/livejournal.ico
Binary files differ
diff --git a/forum/skins/default/media/images/openid/myopenid.ico b/askbot/skins/default/media/images/openid/myopenid.ico
index ceb06e6a..ceb06e6a 100755
--- a/forum/skins/default/media/images/openid/myopenid.ico
+++ b/askbot/skins/default/media/images/openid/myopenid.ico
Binary files differ
diff --git a/forum/skins/default/media/images/openid/openid-inputicon.gif b/askbot/skins/default/media/images/openid/openid-inputicon.gif
index cde836c8..cde836c8 100755
--- a/forum/skins/default/media/images/openid/openid-inputicon.gif
+++ b/askbot/skins/default/media/images/openid/openid-inputicon.gif
Binary files differ
diff --git a/forum/skins/default/media/images/openid/openid.gif b/askbot/skins/default/media/images/openid/openid.gif
index c718b0e6..c718b0e6 100755
--- a/forum/skins/default/media/images/openid/openid.gif
+++ b/askbot/skins/default/media/images/openid/openid.gif
Binary files differ
diff --git a/forum/skins/default/media/images/openid/technorati.ico b/askbot/skins/default/media/images/openid/technorati.ico
index fa1083c1..fa1083c1 100755
--- a/forum/skins/default/media/images/openid/technorati.ico
+++ b/askbot/skins/default/media/images/openid/technorati.ico
Binary files differ
diff --git a/forum/skins/default/media/images/openid/twitter.png b/askbot/skins/default/media/images/openid/twitter.png
index 9a6552d1..9a6552d1 100755
--- a/forum/skins/default/media/images/openid/twitter.png
+++ b/askbot/skins/default/media/images/openid/twitter.png
Binary files differ
diff --git a/forum/skins/default/media/images/openid/verisign.ico b/askbot/skins/default/media/images/openid/verisign.ico
index 3953af93..3953af93 100755
--- a/forum/skins/default/media/images/openid/verisign.ico
+++ b/askbot/skins/default/media/images/openid/verisign.ico
Binary files differ
diff --git a/forum/skins/default/media/images/openid/vidoop.ico b/askbot/skins/default/media/images/openid/vidoop.ico
index bbd9a0d5..bbd9a0d5 100755
--- a/forum/skins/default/media/images/openid/vidoop.ico
+++ b/askbot/skins/default/media/images/openid/vidoop.ico
Binary files differ
diff --git a/forum/skins/default/media/images/openid/wordpress.ico b/askbot/skins/default/media/images/openid/wordpress.ico
index 31b7d2c2..31b7d2c2 100755
--- a/forum/skins/default/media/images/openid/wordpress.ico
+++ b/askbot/skins/default/media/images/openid/wordpress.ico
Binary files differ
diff --git a/forum/skins/default/media/images/openid/yahoo.gif b/askbot/skins/default/media/images/openid/yahoo.gif
index 0f0eb8ef..0f0eb8ef 100755
--- a/forum/skins/default/media/images/openid/yahoo.gif
+++ b/askbot/skins/default/media/images/openid/yahoo.gif
Binary files differ
diff --git a/forum/skins/default/media/images/quest-bg.gif b/askbot/skins/default/media/images/quest-bg.gif
index b7540238..b7540238 100755
--- a/forum/skins/default/media/images/quest-bg.gif
+++ b/askbot/skins/default/media/images/quest-bg.gif
Binary files differ
diff --git a/forum/skins/default/media/images/vote-accepted-on.png b/askbot/skins/default/media/images/vote-accepted-on.png
index 2026f3bc..2026f3bc 100755
--- a/forum/skins/default/media/images/vote-accepted-on.png
+++ b/askbot/skins/default/media/images/vote-accepted-on.png
Binary files differ
diff --git a/forum/skins/default/media/images/vote-accepted.png b/askbot/skins/default/media/images/vote-accepted.png
index ecd18551..ecd18551 100755
--- a/forum/skins/default/media/images/vote-accepted.png
+++ b/askbot/skins/default/media/images/vote-accepted.png
Binary files differ
diff --git a/forum/skins/default/media/images/vote-arrow-down-on.png b/askbot/skins/default/media/images/vote-arrow-down-on.png
index 048dbb44..048dbb44 100755
--- a/forum/skins/default/media/images/vote-arrow-down-on.png
+++ b/askbot/skins/default/media/images/vote-arrow-down-on.png
Binary files differ
diff --git a/forum/skins/default/media/images/vote-arrow-down.png b/askbot/skins/default/media/images/vote-arrow-down.png
index e4fdec0a..e4fdec0a 100755
--- a/forum/skins/default/media/images/vote-arrow-down.png
+++ b/askbot/skins/default/media/images/vote-arrow-down.png
Binary files differ
diff --git a/forum/skins/default/media/images/vote-arrow-up-on.png b/askbot/skins/default/media/images/vote-arrow-up-on.png
index 56ad0c25..56ad0c25 100755
--- a/forum/skins/default/media/images/vote-arrow-up-on.png
+++ b/askbot/skins/default/media/images/vote-arrow-up-on.png
Binary files differ
diff --git a/forum/skins/default/media/images/vote-arrow-up.png b/askbot/skins/default/media/images/vote-arrow-up.png
index 6e9a51c7..6e9a51c7 100755
--- a/forum/skins/default/media/images/vote-arrow-up.png
+++ b/askbot/skins/default/media/images/vote-arrow-up.png
Binary files differ
diff --git a/forum/skins/default/media/images/vote-favorite-off.png b/askbot/skins/default/media/images/vote-favorite-off.png
index c1bef074..c1bef074 100755
--- a/forum/skins/default/media/images/vote-favorite-off.png
+++ b/askbot/skins/default/media/images/vote-favorite-off.png
Binary files differ
diff --git a/forum/skins/default/media/images/vote-favorite-on.png b/askbot/skins/default/media/images/vote-favorite-on.png
index 1f9c14ab..1f9c14ab 100755
--- a/forum/skins/default/media/images/vote-favorite-on.png
+++ b/askbot/skins/default/media/images/vote-favorite-on.png
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/aol.gif b/askbot/skins/default/media/jquery-openid/images/aol.gif
index decc4f12..decc4f12 100755
--- a/forum/skins/default/media/jquery-openid/images/aol.gif
+++ b/askbot/skins/default/media/jquery-openid/images/aol.gif
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/blogger-1.png b/askbot/skins/default/media/jquery-openid/images/blogger-1.png
index 8b360ea5..8b360ea5 100755
--- a/forum/skins/default/media/jquery-openid/images/blogger-1.png
+++ b/askbot/skins/default/media/jquery-openid/images/blogger-1.png
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/blogger.ico b/askbot/skins/default/media/jquery-openid/images/blogger.ico
index 1b9730b0..1b9730b0 100755
--- a/forum/skins/default/media/jquery-openid/images/blogger.ico
+++ b/askbot/skins/default/media/jquery-openid/images/blogger.ico
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/claimid-0.png b/askbot/skins/default/media/jquery-openid/images/claimid-0.png
index 4a0ea1b3..4a0ea1b3 100755
--- a/forum/skins/default/media/jquery-openid/images/claimid-0.png
+++ b/askbot/skins/default/media/jquery-openid/images/claimid-0.png
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/claimid.ico b/askbot/skins/default/media/jquery-openid/images/claimid.ico
index 2b80f491..2b80f491 100755
--- a/forum/skins/default/media/jquery-openid/images/claimid.ico
+++ b/askbot/skins/default/media/jquery-openid/images/claimid.ico
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/facebook.gif b/askbot/skins/default/media/jquery-openid/images/facebook.gif
index b997b358..b997b358 100755
--- a/forum/skins/default/media/jquery-openid/images/facebook.gif
+++ b/askbot/skins/default/media/jquery-openid/images/facebook.gif
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/flickr.ico b/askbot/skins/default/media/jquery-openid/images/flickr.ico
index 11f6e07f..11f6e07f 100755
--- a/forum/skins/default/media/jquery-openid/images/flickr.ico
+++ b/askbot/skins/default/media/jquery-openid/images/flickr.ico
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/flickr.png b/askbot/skins/default/media/jquery-openid/images/flickr.png
index 142405a6..142405a6 100755
--- a/forum/skins/default/media/jquery-openid/images/flickr.png
+++ b/askbot/skins/default/media/jquery-openid/images/flickr.png
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/google.gif b/askbot/skins/default/media/jquery-openid/images/google.gif
index 1b6cd07b..1b6cd07b 100755
--- a/forum/skins/default/media/jquery-openid/images/google.gif
+++ b/askbot/skins/default/media/jquery-openid/images/google.gif
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/livejournal-1.png b/askbot/skins/default/media/jquery-openid/images/livejournal-1.png
index e6436081..e6436081 100755
--- a/forum/skins/default/media/jquery-openid/images/livejournal-1.png
+++ b/askbot/skins/default/media/jquery-openid/images/livejournal-1.png
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/livejournal.ico b/askbot/skins/default/media/jquery-openid/images/livejournal.ico
index f3d21ec5..f3d21ec5 100755
--- a/forum/skins/default/media/jquery-openid/images/livejournal.ico
+++ b/askbot/skins/default/media/jquery-openid/images/livejournal.ico
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/myopenid-2.png b/askbot/skins/default/media/jquery-openid/images/myopenid-2.png
index f64fb8e8..f64fb8e8 100755
--- a/forum/skins/default/media/jquery-openid/images/myopenid-2.png
+++ b/askbot/skins/default/media/jquery-openid/images/myopenid-2.png
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/myopenid.ico b/askbot/skins/default/media/jquery-openid/images/myopenid.ico
index ceb06e6a..ceb06e6a 100755
--- a/forum/skins/default/media/jquery-openid/images/myopenid.ico
+++ b/askbot/skins/default/media/jquery-openid/images/myopenid.ico
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/openid-inputicon.gif b/askbot/skins/default/media/jquery-openid/images/openid-inputicon.gif
index cde836c8..cde836c8 100755
--- a/forum/skins/default/media/jquery-openid/images/openid-inputicon.gif
+++ b/askbot/skins/default/media/jquery-openid/images/openid-inputicon.gif
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/openid.gif b/askbot/skins/default/media/jquery-openid/images/openid.gif
index c718b0e6..c718b0e6 100755
--- a/forum/skins/default/media/jquery-openid/images/openid.gif
+++ b/askbot/skins/default/media/jquery-openid/images/openid.gif
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/openidico.png b/askbot/skins/default/media/jquery-openid/images/openidico.png
index ab622669..ab622669 100755
--- a/forum/skins/default/media/jquery-openid/images/openidico.png
+++ b/askbot/skins/default/media/jquery-openid/images/openidico.png
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/openidico16.png b/askbot/skins/default/media/jquery-openid/images/openidico16.png
index ad718ac5..ad718ac5 100755
--- a/forum/skins/default/media/jquery-openid/images/openidico16.png
+++ b/askbot/skins/default/media/jquery-openid/images/openidico16.png
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/technorati-1.png b/askbot/skins/default/media/jquery-openid/images/technorati-1.png
index f7195240..f7195240 100755
--- a/forum/skins/default/media/jquery-openid/images/technorati-1.png
+++ b/askbot/skins/default/media/jquery-openid/images/technorati-1.png
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/technorati.ico b/askbot/skins/default/media/jquery-openid/images/technorati.ico
index fa1083c1..fa1083c1 100755
--- a/forum/skins/default/media/jquery-openid/images/technorati.ico
+++ b/askbot/skins/default/media/jquery-openid/images/technorati.ico
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/verisign-2.png b/askbot/skins/default/media/jquery-openid/images/verisign-2.png
index c1467008..c1467008 100755
--- a/forum/skins/default/media/jquery-openid/images/verisign-2.png
+++ b/askbot/skins/default/media/jquery-openid/images/verisign-2.png
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/verisign.ico b/askbot/skins/default/media/jquery-openid/images/verisign.ico
index 3953af93..3953af93 100755
--- a/forum/skins/default/media/jquery-openid/images/verisign.ico
+++ b/askbot/skins/default/media/jquery-openid/images/verisign.ico
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/vidoop.ico b/askbot/skins/default/media/jquery-openid/images/vidoop.ico
index bbd9a0d5..bbd9a0d5 100755
--- a/forum/skins/default/media/jquery-openid/images/vidoop.ico
+++ b/askbot/skins/default/media/jquery-openid/images/vidoop.ico
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/vidoop.png b/askbot/skins/default/media/jquery-openid/images/vidoop.png
index 032c9e98..032c9e98 100755
--- a/forum/skins/default/media/jquery-openid/images/vidoop.png
+++ b/askbot/skins/default/media/jquery-openid/images/vidoop.png
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/wordpress.ico b/askbot/skins/default/media/jquery-openid/images/wordpress.ico
index 31b7d2c2..31b7d2c2 100755
--- a/forum/skins/default/media/jquery-openid/images/wordpress.ico
+++ b/askbot/skins/default/media/jquery-openid/images/wordpress.ico
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/wordpress.png b/askbot/skins/default/media/jquery-openid/images/wordpress.png
index ee29f0cf..ee29f0cf 100755
--- a/forum/skins/default/media/jquery-openid/images/wordpress.png
+++ b/askbot/skins/default/media/jquery-openid/images/wordpress.png
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/images/yahoo.gif b/askbot/skins/default/media/jquery-openid/images/yahoo.gif
index 42adbfa5..42adbfa5 100755
--- a/forum/skins/default/media/jquery-openid/images/yahoo.gif
+++ b/askbot/skins/default/media/jquery-openid/images/yahoo.gif
Binary files differ
diff --git a/forum/skins/default/media/jquery-openid/jquery.openid.js b/askbot/skins/default/media/jquery-openid/jquery.openid.js
index eae7b3ea..eae7b3ea 100755
--- a/forum/skins/default/media/jquery-openid/jquery.openid.js
+++ b/askbot/skins/default/media/jquery-openid/jquery.openid.js
diff --git a/forum/skins/default/media/jquery-openid/openid.css b/askbot/skins/default/media/jquery-openid/openid.css
index 307d5624..307d5624 100755
--- a/forum/skins/default/media/jquery-openid/openid.css
+++ b/askbot/skins/default/media/jquery-openid/openid.css
diff --git a/forum/skins/default/media/js/com.cnprog.admin.js b/askbot/skins/default/media/js/com.cnprog.admin.js
index 39dff48c..39dff48c 100644
--- a/forum/skins/default/media/js/com.cnprog.admin.js
+++ b/askbot/skins/default/media/js/com.cnprog.admin.js
diff --git a/forum/skins/default/media/js/com.cnprog.editor.js b/askbot/skins/default/media/js/com.cnprog.editor.js
index 18cc5166..18cc5166 100644
--- a/forum/skins/default/media/js/com.cnprog.editor.js
+++ b/askbot/skins/default/media/js/com.cnprog.editor.js
diff --git a/forum/skins/default/media/js/com.cnprog.i18n.js b/askbot/skins/default/media/js/com.cnprog.i18n.js
index e8a78266..e8a78266 100644
--- a/forum/skins/default/media/js/com.cnprog.i18n.js
+++ b/askbot/skins/default/media/js/com.cnprog.i18n.js
diff --git a/forum/skins/default/media/js/com.cnprog.post.js b/askbot/skins/default/media/js/com.cnprog.post.js
index 7cc14e67..7cc14e67 100755
--- a/forum/skins/default/media/js/com.cnprog.post.js
+++ b/askbot/skins/default/media/js/com.cnprog.post.js
diff --git a/forum/skins/default/media/js/com.cnprog.tag_selector.js b/askbot/skins/default/media/js/com.cnprog.tag_selector.js
index a522f93a..a522f93a 100644
--- a/forum/skins/default/media/js/com.cnprog.tag_selector.js
+++ b/askbot/skins/default/media/js/com.cnprog.tag_selector.js
diff --git a/forum/skins/default/media/js/com.cnprog.utils.js b/askbot/skins/default/media/js/com.cnprog.utils.js
index 3b816ed7..3b816ed7 100644
--- a/forum/skins/default/media/js/com.cnprog.utils.js
+++ b/askbot/skins/default/media/js/com.cnprog.utils.js
diff --git a/forum/skins/default/media/js/compress.bat b/askbot/skins/default/media/js/compress.bat
index 5b2673cf..5b2673cf 100755
--- a/forum/skins/default/media/js/compress.bat
+++ b/askbot/skins/default/media/js/compress.bat
diff --git a/forum/skins/default/media/js/excanvas.min.js b/askbot/skins/default/media/js/excanvas.min.js
index 12c74f7b..12c74f7b 100644
--- a/forum/skins/default/media/js/excanvas.min.js
+++ b/askbot/skins/default/media/js/excanvas.min.js
diff --git a/forum/skins/default/media/js/flot-build.bat b/askbot/skins/default/media/js/flot-build.bat
index f9f32cb7..f9f32cb7 100755
--- a/forum/skins/default/media/js/flot-build.bat
+++ b/askbot/skins/default/media/js/flot-build.bat
diff --git a/forum/skins/default/media/js/jquery-1.2.6.js b/askbot/skins/default/media/js/jquery-1.2.6.js
index 88e661ee..88e661ee 100644
--- a/forum/skins/default/media/js/jquery-1.2.6.js
+++ b/askbot/skins/default/media/js/jquery-1.2.6.js
diff --git a/forum/skins/default/media/js/jquery-1.2.6.min.js b/askbot/skins/default/media/js/jquery-1.2.6.min.js
index 82b98e1d..82b98e1d 100644
--- a/forum/skins/default/media/js/jquery-1.2.6.min.js
+++ b/askbot/skins/default/media/js/jquery-1.2.6.min.js
diff --git a/forum/skins/default/media/js/jquery.ajaxfileupload.js b/askbot/skins/default/media/js/jquery.ajaxfileupload.js
index 75292776..75292776 100644
--- a/forum/skins/default/media/js/jquery.ajaxfileupload.js
+++ b/askbot/skins/default/media/js/jquery.ajaxfileupload.js
diff --git a/forum/skins/default/media/js/jquery.flot.js b/askbot/skins/default/media/js/jquery.flot.js
index 6534a468..6534a468 100644
--- a/forum/skins/default/media/js/jquery.flot.js
+++ b/askbot/skins/default/media/js/jquery.flot.js
diff --git a/forum/skins/default/media/js/jquery.flot.min.js b/askbot/skins/default/media/js/jquery.flot.min.js
index 31f465b8..31f465b8 100644
--- a/forum/skins/default/media/js/jquery.flot.min.js
+++ b/askbot/skins/default/media/js/jquery.flot.min.js
diff --git a/forum/skins/default/media/js/jquery.form.js b/askbot/skins/default/media/js/jquery.form.js
index 443114fd..443114fd 100644
--- a/forum/skins/default/media/js/jquery.form.js
+++ b/askbot/skins/default/media/js/jquery.form.js
diff --git a/forum/skins/default/media/js/jquery.i18n.js b/askbot/skins/default/media/js/jquery.i18n.js
index 0a155a31..0a155a31 100644
--- a/forum/skins/default/media/js/jquery.i18n.js
+++ b/askbot/skins/default/media/js/jquery.i18n.js
diff --git a/forum/skins/default/media/js/jquery.openid.js b/askbot/skins/default/media/js/jquery.openid.js
index af7d8cb9..af7d8cb9 100644
--- a/forum/skins/default/media/js/jquery.openid.js
+++ b/askbot/skins/default/media/js/jquery.openid.js
diff --git a/forum/skins/default/media/js/jquery.validate.pack.js b/askbot/skins/default/media/js/jquery.validate.pack.js
index 49134500..49134500 100644
--- a/forum/skins/default/media/js/jquery.validate.pack.js
+++ b/askbot/skins/default/media/js/jquery.validate.pack.js
diff --git a/forum/skins/default/media/js/org.askbot.output-words.html b/askbot/skins/default/media/js/org.askbot.output-words.html
index 6fc359e0..6fc359e0 100644
--- a/forum/skins/default/media/js/org.askbot.output-words.html
+++ b/askbot/skins/default/media/js/org.askbot.output-words.html
diff --git a/forum/skins/default/media/js/org.askbot.output-words.js b/askbot/skins/default/media/js/org.askbot.output-words.js
index 54eebba7..54eebba7 100644
--- a/forum/skins/default/media/js/org.askbot.output-words.js
+++ b/askbot/skins/default/media/js/org.askbot.output-words.js
diff --git a/forum/skins/default/media/js/se_hilite.js b/askbot/skins/default/media/js/se_hilite.js
index 42e99c8e..42e99c8e 100644
--- a/forum/skins/default/media/js/se_hilite.js
+++ b/askbot/skins/default/media/js/se_hilite.js
diff --git a/forum/skins/default/media/js/se_hilite_src.js b/askbot/skins/default/media/js/se_hilite_src.js
index b604f156..b604f156 100644
--- a/forum/skins/default/media/js/se_hilite_src.js
+++ b/askbot/skins/default/media/js/se_hilite_src.js
diff --git a/forum/skins/default/media/js/wmd/images/wmd-buttons.png b/askbot/skins/default/media/js/wmd/images/wmd-buttons.png
index 50b37090..50b37090 100755
--- a/forum/skins/default/media/js/wmd/images/wmd-buttons.png
+++ b/askbot/skins/default/media/js/wmd/images/wmd-buttons.png
Binary files differ
diff --git a/forum/skins/default/media/js/wmd/showdown-min.js b/askbot/skins/default/media/js/wmd/showdown-min.js
index 073613b1..073613b1 100755
--- a/forum/skins/default/media/js/wmd/showdown-min.js
+++ b/askbot/skins/default/media/js/wmd/showdown-min.js
diff --git a/forum/skins/default/media/js/wmd/showdown.js b/askbot/skins/default/media/js/wmd/showdown.js
index 3f4b9947..3f4b9947 100755
--- a/forum/skins/default/media/js/wmd/showdown.js
+++ b/askbot/skins/default/media/js/wmd/showdown.js
diff --git a/forum/skins/default/media/js/wmd/wmd-min.js b/askbot/skins/default/media/js/wmd/wmd-min.js
index aa643f1a..aa643f1a 100755
--- a/forum/skins/default/media/js/wmd/wmd-min.js
+++ b/askbot/skins/default/media/js/wmd/wmd-min.js
diff --git a/forum/skins/default/media/js/wmd/wmd-test.html b/askbot/skins/default/media/js/wmd/wmd-test.html
index d748501a..d748501a 100755
--- a/forum/skins/default/media/js/wmd/wmd-test.html
+++ b/askbot/skins/default/media/js/wmd/wmd-test.html
diff --git a/forum/skins/default/media/js/wmd/wmd.css b/askbot/skins/default/media/js/wmd/wmd.css
index 80c226c8..80c226c8 100755
--- a/forum/skins/default/media/js/wmd/wmd.css
+++ b/askbot/skins/default/media/js/wmd/wmd.css
diff --git a/forum/skins/default/media/js/wmd/wmd.js b/askbot/skins/default/media/js/wmd/wmd.js
index 70271d4d..70271d4d 100755
--- a/forum/skins/default/media/js/wmd/wmd.js
+++ b/askbot/skins/default/media/js/wmd/wmd.js
diff --git a/forum/skins/default/media/js/yuicompressor-2.4.2.jar b/askbot/skins/default/media/js/yuicompressor-2.4.2.jar
index c29470bd..c29470bd 100755
--- a/forum/skins/default/media/js/yuicompressor-2.4.2.jar
+++ b/askbot/skins/default/media/js/yuicompressor-2.4.2.jar
Binary files differ
diff --git a/forum/skins/default/media/style/auth.css b/askbot/skins/default/media/style/auth.css
index 33702758..33702758 100755
--- a/forum/skins/default/media/style/auth.css
+++ b/askbot/skins/default/media/style/auth.css
diff --git a/forum/skins/default/media/style/default.css b/askbot/skins/default/media/style/default.css
index 27da1dab..27da1dab 100755
--- a/forum/skins/default/media/style/default.css
+++ b/askbot/skins/default/media/style/default.css
diff --git a/forum/skins/default/media/style/jquery.autocomplete.css b/askbot/skins/default/media/style/jquery.autocomplete.css
index 3bf2c2d9..3bf2c2d9 100755
--- a/forum/skins/default/media/style/jquery.autocomplete.css
+++ b/askbot/skins/default/media/style/jquery.autocomplete.css
diff --git a/forum/skins/default/media/style/openid.css b/askbot/skins/default/media/style/openid.css
index 0d201df2..0d201df2 100755
--- a/forum/skins/default/media/style/openid.css
+++ b/askbot/skins/default/media/style/openid.css
diff --git a/forum/skins/default/media/style/prettify.css b/askbot/skins/default/media/style/prettify.css
index 10a37577..10a37577 100755
--- a/forum/skins/default/media/style/prettify.css
+++ b/askbot/skins/default/media/style/prettify.css
diff --git a/forum/skins/default/media/style/style.css b/askbot/skins/default/media/style/style.css
index 855dc75d..8471bdca 100755
--- a/forum/skins/default/media/style/style.css
+++ b/askbot/skins/default/media/style/style.css
@@ -229,7 +229,7 @@ blockquote {
}
#CARight {
- width: 240px;
+ width: 235px;
float: right;
}
@@ -271,6 +271,14 @@ blockquote {
color: #555555;
}
+#top a.ab-responses-envelope {
+ margin-left: 3px;
+}
+#top a img {
+ vertical-align:middle;
+ margin-bottom:2px;
+}
+
#logo {
padding: 0px 0px 0px 10px;
height: 90px;
@@ -280,7 +288,7 @@ blockquote {
#logoContainer {
}
#navTabContainer {
- width: 600px;
+ width: 610px;
padding-left: 10px;
text-align: left;
}
@@ -353,6 +361,7 @@ blockquote {
#searchBar {
display:inline-block;
background-color: #cccccc;/*888a85; /*#e9b96e;*/
+ width:700px;
border: 1px solid #aaaaaa;
padding: 4px 7px 5px 5px;
}
@@ -361,8 +370,8 @@ blockquote {
font-size: 24px;
line-height: 24px;
height: 36px;
- width: 598px;
- margin: 0px;
+ width: 605px;
+ margin: 0px 3px 0px 0px;
padding: 5px 0 0 5px;
}
@@ -370,18 +379,21 @@ blockquote {
font-size: 24px;
line-height: 24px;
height: 36px;
- width: 552px;
+ width: 561px;
padding: 5px 0 0 5px;
- margin: 0px;
+ margin: 0px 3px 0px 0px;
}
#searchBar .searchBtn {
font-size: 20px;
color: #666666;
height: 40px;
+ width: 80px;
+ width: 80px;
+ width: 80px;
line-height: 22px;
+ margin: 0px;
text-align: center;
- margin-top:1px;
padding-bottom: 4px;
}
@@ -391,8 +403,8 @@ blockquote {
height: 40px;
width: 40px;
line-height: 22px;
+ margin: 0px 3px 0px 0px;
padding-bottom: 4px;
- margin-top:1px;
text-align: center;
}
@@ -680,9 +692,8 @@ blockquote {
.boxC {
background: white /*#cacdc6; /*f9f7ed;*/
- padding: 10px;
+ padding: 10px 10px 10px 15px;
margin-bottom: 8px;
- margin-left: 10px;
/*
border-top: 1px solid #eeeeec;
border-left: 1px solid #eeeeec;
@@ -821,7 +832,7 @@ conflicts with WMD!
.tags a {
white-space: nowrap;
- font-size: 13px;
+ font-size: 11px;
font-weight: normal;
color: #333;
text-decoration: none;
@@ -831,6 +842,7 @@ conflicts with WMD!
border-bottom: 1px solid #CCC;
border-right: 1px solid #CCC;
padding: 1px 8px 1px 8px;
+ margin-right:3px;
}
.tags a:hover {
@@ -1333,6 +1345,12 @@ a.comments-link, a.comments-link-accepted, a.comments-link-owner, a.comments-lin
text-decoration: none;
}
+.comment a {
+ background-color: inherit;
+ color: blue;
+ padding: 0;
+}
+
a.comment-user, a.comment-user:hover {
background-color: inherit;
color: blue;
@@ -2630,3 +2648,17 @@ p.signup_p {
.search-tips a {
text-decoration: underline;
}
+
+.faq-rep-item {
+ text-align:right;
+ padding-right:5px;
+}
+
+#top a.ab-nav-karma, #top a.ab-nav-badges {
+ margin: 0;
+ text-decoration: none;
+}
+
+img.gravatar {
+ margin:2px;
+}
diff --git a/forum/skins/default/templates/404.html b/askbot/skins/default/templates/404.html
index 227de3ae..227de3ae 100644
--- a/forum/skins/default/templates/404.html
+++ b/askbot/skins/default/templates/404.html
diff --git a/forum/skins/default/templates/500.html b/askbot/skins/default/templates/500.html
index 51e73178..51e73178 100644
--- a/forum/skins/default/templates/500.html
+++ b/askbot/skins/default/templates/500.html
diff --git a/askbot/skins/default/templates/about.html b/askbot/skins/default/templates/about.html
new file mode 100644
index 00000000..d091725b
--- /dev/null
+++ b/askbot/skins/default/templates/about.html
@@ -0,0 +1,18 @@
+{% extends "base.html" %}
+<!-- template about.html -->
+{% load i18n %}
+{% load extra_tags %}
+{% load humanize %}
+{% block title %}{% spaceless %}{% trans "About" %}{% endspaceless %}{% endblock %}
+{% block forejs %}
+{% endblock %}
+{% block content %}
+<div class="headNormal">
+{% trans "About" %}
+</div>
+
+<div class="content">
+ {{settings.FORUM_ABOUT|safe}}
+</div>
+{% endblock %}
+<!-- end template about.html -->
diff --git a/forum/skins/default/templates/account_settings.html b/askbot/skins/default/templates/account_settings.html
index 91267d26..91267d26 100644
--- a/forum/skins/default/templates/account_settings.html
+++ b/askbot/skins/default/templates/account_settings.html
diff --git a/forum/skins/default/templates/answer_edit.html b/askbot/skins/default/templates/answer_edit.html
index 2d736f30..2d736f30 100644
--- a/forum/skins/default/templates/answer_edit.html
+++ b/askbot/skins/default/templates/answer_edit.html
diff --git a/forum/skins/default/templates/answer_edit_tips.html b/askbot/skins/default/templates/answer_edit_tips.html
index c390da06..c390da06 100644
--- a/forum/skins/default/templates/answer_edit_tips.html
+++ b/askbot/skins/default/templates/answer_edit_tips.html
diff --git a/forum/skins/default/templates/ask.html b/askbot/skins/default/templates/ask.html
index 4278f4cb..82828fe9 100644
--- a/forum/skins/default/templates/ask.html
+++ b/askbot/skins/default/templates/ask.html
@@ -69,7 +69,7 @@
<p>{% trans "login to post question info" %}</p>
</div>
{% else %}
- {% ifequal settings.EMAIL_VALIDATION 'on' %}
+ {% if settings.EMAIL_VALIDATION %}
{% if not request.user.email_isvalid %}
<div class="message">
{% blocktrans with request.user.email as email %}must have valid {{email}} to post,
@@ -77,7 +77,7 @@
{% endblocktrans %}
</div>
{% endif %}
- {% endifequal %}
+ {% endif %}
{% endif %}
<div class="form-item">
<label for="id_title" ><strong>{{ form.title.label_tag }}:</strong></label> <span class="form-error"></span><br/>
diff --git a/forum/skins/default/templates/ask_form.html b/askbot/skins/default/templates/ask_form.html
index 25e9fe6c..1bb3866b 100644
--- a/forum/skins/default/templates/ask_form.html
+++ b/askbot/skins/default/templates/ask_form.html
@@ -10,13 +10,13 @@
{% if not request.user.is_authenticated %}
<p>{% trans "login to post question info" %}</p>
{% else %}
- {% ifequal settings.EMAIL_VALIDATION 'on' %}
+ {% if settings.EMAIL_VALIDATION %}
{% 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 %}
{% endif %}
<input id="id_title" class="questionTitleInput" name="title"
value="{% if form.initial.title %}{{form.initial.title}}{% endif %}"/>
diff --git a/forum/skins/default/templates/authopenid/changeemail.html b/askbot/skins/default/templates/authopenid/changeemail.html
index 94d1881c..94d1881c 100644
--- a/forum/skins/default/templates/authopenid/changeemail.html
+++ b/askbot/skins/default/templates/authopenid/changeemail.html
diff --git a/forum/skins/default/templates/authopenid/changeopenid.html b/askbot/skins/default/templates/authopenid/changeopenid.html
index d01788fb..d01788fb 100644
--- a/forum/skins/default/templates/authopenid/changeopenid.html
+++ b/askbot/skins/default/templates/authopenid/changeopenid.html
diff --git a/forum/skins/default/templates/authopenid/changepw.html b/askbot/skins/default/templates/authopenid/changepw.html
index 8b059544..8b059544 100644
--- a/forum/skins/default/templates/authopenid/changepw.html
+++ b/askbot/skins/default/templates/authopenid/changepw.html
diff --git a/forum/skins/default/templates/authopenid/complete.html b/askbot/skins/default/templates/authopenid/complete.html
index 62970e38..62970e38 100644
--- a/forum/skins/default/templates/authopenid/complete.html
+++ b/askbot/skins/default/templates/authopenid/complete.html
diff --git a/forum/skins/default/templates/authopenid/confirm_email.txt b/askbot/skins/default/templates/authopenid/confirm_email.txt
index 3a01f146..3a01f146 100644
--- a/forum/skins/default/templates/authopenid/confirm_email.txt
+++ b/askbot/skins/default/templates/authopenid/confirm_email.txt
diff --git a/forum/skins/default/templates/authopenid/delete.html b/askbot/skins/default/templates/authopenid/delete.html
index 0f9f1c60..0f9f1c60 100644
--- a/forum/skins/default/templates/authopenid/delete.html
+++ b/askbot/skins/default/templates/authopenid/delete.html
diff --git a/forum/skins/default/templates/authopenid/email_validation.txt b/askbot/skins/default/templates/authopenid/email_validation.txt
index 5b166a9b..5b166a9b 100644
--- a/forum/skins/default/templates/authopenid/email_validation.txt
+++ b/askbot/skins/default/templates/authopenid/email_validation.txt
diff --git a/forum/skins/default/templates/authopenid/external_legacy_login_info.html b/askbot/skins/default/templates/authopenid/external_legacy_login_info.html
index 3318499c..3318499c 100644
--- a/forum/skins/default/templates/authopenid/external_legacy_login_info.html
+++ b/askbot/skins/default/templates/authopenid/external_legacy_login_info.html
diff --git a/forum/skins/default/templates/authopenid/failure.html b/askbot/skins/default/templates/authopenid/failure.html
index d075d6b0..d075d6b0 100644
--- a/forum/skins/default/templates/authopenid/failure.html
+++ b/askbot/skins/default/templates/authopenid/failure.html
diff --git a/forum/skins/default/templates/authopenid/sendpw.html b/askbot/skins/default/templates/authopenid/sendpw.html
index 6241c811..6241c811 100644
--- a/forum/skins/default/templates/authopenid/sendpw.html
+++ b/askbot/skins/default/templates/authopenid/sendpw.html
diff --git a/forum/skins/default/templates/authopenid/sendpw_email.txt b/askbot/skins/default/templates/authopenid/sendpw_email.txt
index f044ca45..f044ca45 100644
--- a/forum/skins/default/templates/authopenid/sendpw_email.txt
+++ b/askbot/skins/default/templates/authopenid/sendpw_email.txt
diff --git a/forum/skins/default/templates/authopenid/settings.html b/askbot/skins/default/templates/authopenid/settings.html
index 66ea5953..66ea5953 100644
--- a/forum/skins/default/templates/authopenid/settings.html
+++ b/askbot/skins/default/templates/authopenid/settings.html
diff --git a/forum/skins/default/templates/authopenid/signin.html b/askbot/skins/default/templates/authopenid/signin.html
index 66ef2f78..66ef2f78 100755
--- a/forum/skins/default/templates/authopenid/signin.html
+++ b/askbot/skins/default/templates/authopenid/signin.html
diff --git a/forum/skins/default/templates/authopenid/signup.html b/askbot/skins/default/templates/authopenid/signup.html
index fdb236c2..fdb236c2 100644
--- a/forum/skins/default/templates/authopenid/signup.html
+++ b/askbot/skins/default/templates/authopenid/signup.html
diff --git a/forum/skins/default/templates/authopenid/yadis.xrdf b/askbot/skins/default/templates/authopenid/yadis.xrdf
index a9ed44fe..a9ed44fe 100644
--- a/forum/skins/default/templates/authopenid/yadis.xrdf
+++ b/askbot/skins/default/templates/authopenid/yadis.xrdf
diff --git a/forum/skins/default/templates/badge.html b/askbot/skins/default/templates/badge.html
index 99d74e1b..99d74e1b 100644
--- a/forum/skins/default/templates/badge.html
+++ b/askbot/skins/default/templates/badge.html
diff --git a/forum/skins/default/templates/badges.html b/askbot/skins/default/templates/badges.html
index 9fbd6395..9fbd6395 100644
--- a/forum/skins/default/templates/badges.html
+++ b/askbot/skins/default/templates/badges.html
diff --git a/forum/skins/default/templates/base.html b/askbot/skins/default/templates/base.html
index a4e4ceed..dd7c6083 100644
--- a/forum/skins/default/templates/base.html
+++ b/askbot/skins/default/templates/base.html
@@ -9,8 +9,12 @@
<title>{% block title %}{% endblock %} - {{ settings.APP_TITLE }}</title>
{% spaceless %}
{% block meta %}{% endblock %}
+ {% block meta_description %}
+ <meta name="description" content="{{settings.APP_DESCRIPTION}}" />
+ {% endblock %}
{% endspaceless %}
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta name="keywords" content="{%block keywords%}{%endblock%},{{settings.APP_KEYWORDS}}" />
{% if settings.GOOGLE_SITEMAP_CODE %}
<meta name="google-site-verification" content="{{settings.GOOGLE_SITEMAP_CODE}}" />
{% endif %}
@@ -21,7 +25,7 @@
<script type="text/javascript">
var i18nLang = '{{settings.LANGUAGE_CODE}}';
var scriptUrl = '/{{settings.FORUM_SCRIPT_ALIAS}}'
- var askbotSkin = '{{settings.ASKBOT_SKIN}}';
+ var askbotSkin = '{{settings.ASKBOT_DEFAULT_SKIN}}';
</script>
<script type='text/javascript' src='{% media "/media/js/com.cnprog.i18n.js" %}'></script>
<script type='text/javascript' src='{% media "/media/js/jquery.i18n.js" %}'></script>
diff --git a/forum/skins/default/templates/base_content.html b/askbot/skins/default/templates/base_content.html
index 284007d8..000b5358 100644
--- a/forum/skins/default/templates/base_content.html
+++ b/askbot/skins/default/templates/base_content.html
@@ -6,6 +6,10 @@
<head>
<title>{% block title %}{% endblock %} - {{ settings.APP_TITLE }}</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta name="keywords" content="{%block keywords%}{%endblock%},{{settings.APP_KEYWORDS}}" />
+ {% block meta_description %}
+ <meta name="description" content="{{settings.APP_DESCRIPTION}}" />
+ {% endblock %}
{% if settings.GOOGLE_SITEMAP_CODE %}
<meta name="google-site-verification" content="{{ settings.GOOGLE_SITEMAP_CODE }}" />
{% endif %}
@@ -19,7 +23,7 @@
<script type="text/javascript">
var i18nLang = '{{ settings.LANGUAGE_CODE }}';
var scriptUrl = '/{{settings.FORUM_SCRIPT_ALIAS}}'
- var askbotSkin = '{{settings.ASKBOT_SKIN}}';
+ var askbotSkin = '{{settings.ASKBOT_DEFAULT_SKIN}}';
</script>
<script type='text/javascript' src='{% media "/media/js/com.cnprog.i18n.js" %}'></script>
<script type='text/javascript' src='{% media "/media/js/jquery.i18n.js" %}'></script>
diff --git a/forum/skins/default/templates/book.html b/askbot/skins/default/templates/book.html
index 528b800d..528b800d 100644
--- a/forum/skins/default/templates/book.html
+++ b/askbot/skins/default/templates/book.html
diff --git a/forum/skins/default/templates/close.html b/askbot/skins/default/templates/close.html
index d9e73507..d9e73507 100644
--- a/forum/skins/default/templates/close.html
+++ b/askbot/skins/default/templates/close.html
diff --git a/forum/skins/default/templates/edit_user_email_feeds_form.html b/askbot/skins/default/templates/edit_user_email_feeds_form.html
index 65902e7e..65902e7e 100644
--- a/forum/skins/default/templates/edit_user_email_feeds_form.html
+++ b/askbot/skins/default/templates/edit_user_email_feeds_form.html
diff --git a/forum/skins/default/templates/email_base.html b/askbot/skins/default/templates/email_base.html
index b74741e3..b74741e3 100644
--- a/forum/skins/default/templates/email_base.html
+++ b/askbot/skins/default/templates/email_base.html
diff --git a/forum/skins/default/templates/faq.html b/askbot/skins/default/templates/faq.html
index cc790ccc..83a24d68 100644
--- a/forum/skins/default/templates/faq.html
+++ b/askbot/skins/default/templates/faq.html
@@ -1,6 +1,7 @@
{% extends "base.html" %}
<!-- template faq.html -->
{% load extra_tags %}
+{% load extra_filters %}
{% load humanize %}
{% load i18n %}
{% block title %}{% spaceless %}FAQ{% endspaceless %}{% endblock %}
@@ -39,7 +40,7 @@
<div>
<h3 class="subtitle">{% trans "How does reputation system work?" %}</h3>
<p>{% trans "Rep system summary" %}</p>
- <p>{% blocktrans %}For example, if you ask an interesting question or give a helpful answer, your input will be upvoted. On the other hand if the answer is misleading - it will be downvoted. Each vote in favor will generate <strong>10</strong> points, each vote against will subtract <strong>2</strong> points. There is a limit of <strong>200</strong> points that can be accumulated per question or answer. The table below explains reputation point requirements for each type of moderation task.{% endblocktrans %}
+ <p>{% blocktrans with settings.MAX_REP_GAIN_PER_USER_PER_DAY as MAX_REP_GAIN_PER_USER_PER_DAY and settings.REP_GAIN_FOR_RECEIVING_UPVOTE as REP_GAIN_FOR_RECEIVING_UPVOTE and settings.REP_LOSS_FOR_RECEIVING_DOWNVOTE|absolute_value as REP_LOSS_FOR_RECEIVING_DOWNVOTE%}For example, if you ask an interesting question or give a helpful answer, your input will be upvoted. On the other hand if the answer is misleading - it will be downvoted. Each vote in favor will generate <strong>{{REP_GAIN_FOR_RECEIVING_UPVOTE}}</strong> points, each vote against will subtract <strong>{{REP_LOSS_FOR_RECEIVING_DOWNVOTE}}</strong> points. There is a limit of <strong>{{MAX_REP_GAIN_PER_USER_PER_DAY}}</strong> points that can be accumulated for a question or answer per day. The table below explains reputation point requirements for each type of moderation task.{% endblocktrans %}
</p>
<table style="font-family:arial;" cellspacing="3" cellpadding="3">
@@ -47,64 +48,55 @@
<th width="40px" style="text-align:right"></th>
<th width="300px"></th>
</tr>
- <!--
<tr>
- <td style="text-align:right;padding-right:5px"><strong>15</strong></td>
+ <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_VOTE_UP}}</strong></td>
<td>{% trans "upvote" %}</td>
</tr>
+ <!--
<tr>
- <td style="text-align:right;padding-right:5px"><strong>15</strong></td>
+ <td class="faq-rep-item"><strong>15</strong></td>
<td>{% trans "use tags" %}</td>
</tr>
-->
<tr>
- <td style="text-align:right;padding-right:5px"><strong>50</strong></td>
+ <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_LEAVE_COMMENTS}}</strong></td>
<td>{% trans "add comments" %}</td>
</tr>
<tr>
- <td style="text-align:right;padding-right:5px"><strong>100</strong></td>
+ <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_VOTE_DOWN}}</strong></td>
<td>{% trans "downvote" %}</td>
</tr><tr>
- <td style="text-align:right;padding-right:5px"><strong>250</strong></td>
+ <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_CLOSE_OWN_QUESTIONS}}</strong></td>
<td>{% trans "open and close own questions" %}</td>
</tr>
<tr>
- <td style="text-align:right;padding-right:5px"><strong>500</strong></td>
+ <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_RETAG_OTHERS_QUESTIONS}}</strong></td>
<td>{% trans "retag questions" %}</td>
</tr>
{% if settings.WIKI_ON %}
<tr>
- <td style="text-align:right;padding-right:5px"><strong>750</strong></td>
+ <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_EDIT_WIKI}}</strong></td>
<td>{% trans "edit community wiki questions" %}</td>
</tr>
{% endif %}
<tr>
- <td style="text-align:right;padding-right:5px"><strong>2000</strong></td>
+ <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_EDIT_OTHERS_POSTS}}</strong></td>
<td>{% trans "edit any answer" %}</td>
</tr>
<tr>
- <td style="text-align:right;padding-right:5px"><strong>3000</strong></td>
- <td>{% trans "open any closed question" %}</td>
- </tr>
- <tr>
- <td style="text-align:right;padding-right:5px"><strong>5000</strong></td>
+ <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_DELETE_OTHERS_COMMENTS}}</strong></td>
<td>{% trans "delete any comment" %}</td>
</tr>
- <tr>
- <td style="text-align:right;padding-right:5px"><strong>10000</strong></td>
- <td>{% trans "delete any questions and answers and perform other moderation tasks" %}</td>
- </tr>
-
</table>
</div>
{% comment %}
- {% ifequal settings.EMAIL_VALIDATION 'on' %}
+ {% if settings.EMAIL_VALIDATION %}
<div>
<a id='validate'></a><h3 class="subtitle">{% trans "how to validate email title" %}</h3>
<!--special case here message must contain paragraphs-->
{% blocktrans %}how to validate email info with {{send_email_key_url}} {{gravatar_faq_url}}{% endblocktrans %}
</div>
- {% endifequal %}
+ {% endif %}
{% endcomment %}
<div>
<a id='gravatar'></a><h3 class="subtitle">{% trans "what is gravatar" %}</h3>
diff --git a/forum/skins/default/templates/fbconnect/xd_receiver.html b/askbot/skins/default/templates/fbconnect/xd_receiver.html
index a03c61bc..60c02a22 100755
--- a/forum/skins/default/templates/fbconnect/xd_receiver.html
+++ b/askbot/skins/default/templates/fbconnect/xd_receiver.html
@@ -2,7 +2,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" >
{% load i18n %}
<head>
- <title>{% blocktrans %}Connect to {{APP_SHORT_NAME}} with Facebook!{% endblocktrans %}
+ <title>{% blocktrans %}Connect to {{settings.APP_SHORT_NAME}} with Facebook!{% endblocktrans %}
</head>
<body>
<script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.js" type="text/javascript"></script>
diff --git a/forum/skins/default/templates/feedback.html b/askbot/skins/default/templates/feedback.html
index af4f635f..af4f635f 100644
--- a/forum/skins/default/templates/feedback.html
+++ b/askbot/skins/default/templates/feedback.html
diff --git a/forum/skins/default/templates/feedback_email.txt b/askbot/skins/default/templates/feedback_email.txt
index df768180..df768180 100644
--- a/forum/skins/default/templates/feedback_email.txt
+++ b/askbot/skins/default/templates/feedback_email.txt
diff --git a/forum/skins/default/templates/feeds/rss_description.html b/askbot/skins/default/templates/feeds/rss_description.html
index fa781907..fa781907 100755
--- a/forum/skins/default/templates/feeds/rss_description.html
+++ b/askbot/skins/default/templates/feeds/rss_description.html
diff --git a/forum/skins/default/templates/feeds/rss_title.html b/askbot/skins/default/templates/feeds/rss_title.html
index 7899fce3..7899fce3 100755
--- a/forum/skins/default/templates/feeds/rss_title.html
+++ b/askbot/skins/default/templates/feeds/rss_title.html
diff --git a/forum/skins/default/templates/footer.html b/askbot/skins/default/templates/footer.html
index 9b7c5d98..a28a1980 100644
--- a/forum/skins/default/templates/footer.html
+++ b/askbot/skins/default/templates/footer.html
@@ -23,7 +23,7 @@
<p>
<a href="http://askbot.org" target="_blank">
powered by ASKBOT
- </a>
+ </a><br/>{{settings.APP_COPYRIGHT}}
</p>
</div>
<div id="licenseLogo">
diff --git a/askbot/skins/default/templates/header.html b/askbot/skins/default/templates/header.html
new file mode 100644
index 00000000..49811fde
--- /dev/null
+++ b/askbot/skins/default/templates/header.html
@@ -0,0 +1,53 @@
+<!-- template header.html -->
+{% load extra_tags %}
+{% load smart_if %}
+{% load i18n %}
+<div id="roof">
+ <div id="navBar">
+ <div id="top">
+ {% if request.user.is_authenticated %}
+ <a href="{% url user_profile id=request.user.id,slug=request.user.username|slugify %}">{{ request.user.username }}</a>
+ {% spaceless %}
+ <a class='ab-responses-envelope' href="{{request.user.get_absolute_url}}?sort=responses">
+ <img
+ alt="{%blocktrans with request.user.username as username %}responses for {{username}}{% endblocktrans %}"
+ {% if request.user.response_count > 0 %}
+ src="{% media "/media/images/mail-envelope-full.png" %}"
+ title="{% blocktrans count request.user.response_count as response_count %}you have a new response{% plural %}you nave {{response_count}} new responses{% endblocktrans %}"
+ {% else %}
+ src="{% media "/media/images/mail-envelope-empty.png" %}"
+ title="{% trans "no new responses yet" %}"
+ {% endif %}
+ />
+ </a>
+ {% endspaceless %}
+ ({% get_long_score_and_badge_report user %})
+ <a href="{% url logout %}">{% trans "logout" %}</a>
+ {% else %}
+ <a href="{% url user_signin %}">{% trans "login" %}</a>
+ {% endif %}
+ <a href="{% url about %}">{% trans "about" %}</a>
+ <a href="{% url faq %}">{% trans "faq" %}</a>
+ </div>
+ <table border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <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>
+ <a id="nav_badges" href="{% url badges %}">{% trans "badges" %}</a>
+ <a id="nav_ask" href="{% url ask %}" class="special">{% trans "ask a question" %}</a>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </div>
+</div>
+<!-- end template header.html -->
diff --git a/forum/skins/default/templates/input_bar.html b/askbot/skins/default/templates/input_bar.html
index 59236350..66e6ed94 100644
--- a/forum/skins/default/templates/input_bar.html
+++ b/askbot/skins/default/templates/input_bar.html
@@ -30,7 +30,7 @@
value="true"
class="cancelSearchBtn"/>
{% endif %}
- <input type="submit" value="{% trans "search" %}" name="search" class="searchBtn" default />
+ <input type="submit" value="{% trans "search" %}" name="search" class="searchBtn" />
{% if active_tab == "tags" %}
<input type="hidden" name="t" value="tag"/>
{% else %}
diff --git a/askbot/skins/default/templates/instant_notification.html b/askbot/skins/default/templates/instant_notification.html
new file mode 100644
index 00000000..db2f5a05
--- /dev/null
+++ b/askbot/skins/default/templates/instant_notification.html
@@ -0,0 +1,46 @@
+{% load i18n %}
+{% load smart_if %}
+{% blocktrans %}<p>Dear {{receiving_user_name}},</p>{% endblocktrans %}
+<p></p>
+ {% if update_type == 'question_comment' %}
+{% blocktrans %}
+<p>{{update_author_name}} left a <a href="%{{post_url}}">new comment</a>
+for question "{{origin_post_title}}"</p>
+{% endblocktrans %}
+ {% endif %}
+ {% if update_type == 'answer_comment' %}
+{% blocktrans %}
+<p>{{update_author_name}} left a <a href="{{post_url}}">new comment</a>
+ for an answer to question "{{origin_post_title}}"</p>
+{% endblocktrans %}
+ {% endif %}
+ {% if update_type == 'new_answer' %}
+{% blocktrans %}
+<p>{{update_author_name}} answered a question
+<a href="{{post_url}}">{{origin_post_title}}</a></p>
+{% endblocktrans %}
+ {% endif %}
+ {% if update_type == 'new_question' %}
+{% blocktrans %}
+<p>{{update_author_name}} asked a question
+<a href="{{post_url}}">{{origin_post_title}}</a></p>
+{% endblocktrans %}
+ {% endif %}
+ {%if update_type == 'answer_update' %}
+{% blocktrans %}
+<p>{{update_author_name}} updated an answer to the question
+<a href="{{post_url}}">{{origin_post_title}}</a></p>
+{% endblocktrans %}
+ {% endif %}
+ {% if update_type == 'question_update' %}
+{% blocktrans %}
+<p>{{update_author_name}} updated a question
+<a href="{{post_url}}">{{origin_post_title}}</a></p>
+{% endblocktrans %}
+ {% endif %}
+<p></p>
+{% blocktrans %}
+<p>Please note - you can easily <a href="{{user_subscriptions_url}}">change</a>
+how often you receive these notifications.</p>
+{% endblocktrans %}
+{% trans "<p>Sincerely,<br/>Forum Administrator</p>" %}
diff --git a/forum/skins/default/templates/logout.html b/askbot/skins/default/templates/logout.html
index 650ba044..650ba044 100644
--- a/forum/skins/default/templates/logout.html
+++ b/askbot/skins/default/templates/logout.html
diff --git a/forum/skins/default/templates/notarobot.html b/askbot/skins/default/templates/notarobot.html
index 698c5696..698c5696 100644
--- a/forum/skins/default/templates/notarobot.html
+++ b/askbot/skins/default/templates/notarobot.html
diff --git a/forum/skins/default/templates/pagesize.html b/askbot/skins/default/templates/pagesize.html
index 5fb28e20..5fb28e20 100644
--- a/forum/skins/default/templates/pagesize.html
+++ b/askbot/skins/default/templates/pagesize.html
diff --git a/forum/skins/default/templates/paginator.html b/askbot/skins/default/templates/paginator.html
index 4c1f55b0..4c1f55b0 100644
--- a/forum/skins/default/templates/paginator.html
+++ b/askbot/skins/default/templates/paginator.html
diff --git a/forum/skins/default/templates/post_contributor_info.html b/askbot/skins/default/templates/post_contributor_info.html
index 260a0590..260a0590 100644
--- a/forum/skins/default/templates/post_contributor_info.html
+++ b/askbot/skins/default/templates/post_contributor_info.html
diff --git a/askbot/skins/default/templates/privacy.html b/askbot/skins/default/templates/privacy.html
new file mode 100644
index 00000000..fe074491
--- /dev/null
+++ b/askbot/skins/default/templates/privacy.html
@@ -0,0 +1,17 @@
+{% extends "base_content.html" %}
+<!-- privacy.html -->
+{% load extra_tags %}
+{% load i18n %}
+{% load humanize %}
+{% block title %}{% spaceless %}{% trans "Privacy policy" %}{% endspaceless %}{% endblock %}
+{% block forejs %}
+{% endblock %}
+{% block content %}
+<div class="headNormal">
+ {% trans "Privacy policy" %}
+</div>
+<div id="main-body" style="width:100%">
+ {{settings.FORUM_PRIVACY|safe}}
+</div>
+{% endblock %}
+<!-- end privacy.html -->
diff --git a/forum/skins/default/templates/question.html b/askbot/skins/default/templates/question.html
index f0619ab8..566f7762 100644
--- a/forum/skins/default/templates/question.html
+++ b/askbot/skins/default/templates/question.html
@@ -7,9 +7,11 @@
{% load i18n %}
{% load cache %}
{% block title %}{% spaceless %}{{ question.get_question_title }}{% endspaceless %}{% endblock %}
-{% block forejs %}
+{% block meta_description %}
<meta name="description" content="{{question.summary}}" />
- <meta name="keywords" content="{{question.tagname_meta_generator}}" />
+{% endblock %}
+{% block keywords %}{{question.tagname_meta_generator}}{% endblock %}
+{% block forejs %}
<link rel="canonical" href="{{settings.APP_URL}}{{question.get_absolute_url}}" />
{% if not question.closed %}
<script type='text/javascript' src='{% media "/media/js/com.cnprog.editor.js" %}'></script>
@@ -173,7 +175,7 @@
<div class="comments-container" id="comments-container-question-{{question.id}}">
{% for comment in question.get_comments|slice:":5" %}
<p class="comment" id="comment-{{comment.id}}">
- {{comment.comment}}
+ {{comment.html|safe}}
- <a class="comment-user" href="{{comment.user.get_profile_url}}">{{comment.user}}</a>
{% spaceless %}
<span class="comment-age">({% diff_date comment.added_at %})</span>
@@ -315,7 +317,7 @@
<div class="comments-container" id="comments-container-answer-{{answer.id}}">
{% for comment in answer.get_comments|slice:":5" %}
<p id="comment-{{comment.id}}" class="comment">
- {{comment.comment}}
+ {{comment.html|safe}}
- <a class="comment-user" href="{{comment.user.get_profile_url}}">{{comment.user}}</a>
{% spaceless %}
<span class="comment-age">({% diff_date comment.added_at %})</span>
diff --git a/forum/skins/default/templates/question_counter_widget.html b/askbot/skins/default/templates/question_counter_widget.html
index 5b35651f..5b35651f 100644
--- a/forum/skins/default/templates/question_counter_widget.html
+++ b/askbot/skins/default/templates/question_counter_widget.html
diff --git a/forum/skins/default/templates/question_edit.html b/askbot/skins/default/templates/question_edit.html
index fe711849..fe711849 100644
--- a/forum/skins/default/templates/question_edit.html
+++ b/askbot/skins/default/templates/question_edit.html
diff --git a/forum/skins/default/templates/question_edit_tips.html b/askbot/skins/default/templates/question_edit_tips.html
index 4cabea79..4cabea79 100644
--- a/forum/skins/default/templates/question_edit_tips.html
+++ b/askbot/skins/default/templates/question_edit_tips.html
diff --git a/forum/skins/default/templates/question_list.html b/askbot/skins/default/templates/question_list.html
index 38ac254a..c9fc1f96 100644
--- a/forum/skins/default/templates/question_list.html
+++ b/askbot/skins/default/templates/question_list.html
@@ -11,7 +11,7 @@
<div class="userinfo">
<span class="relativetime" title="{{question.last_activity_at}}">{% diff_date question.last_activity_at %}</span>
{% if question.last_activity_by %}
- <a href="{% url user_profile question.last_activity_by.id question.last_activity_by.username|slugify %}">{{ question.last_activity_by }}</a> {% get_score_badge question.last_activity_by %}
+ &nbsp;<a href="{% url user_profile question.last_activity_by.id question.last_activity_by.username|slugify %}">{{ question.last_activity_by }}</a>&nbsp;{% get_score_badge question.last_activity_by %}
{% endif %}
</div>
<div class="tags">
diff --git a/forum/skins/default/templates/question_retag.html b/askbot/skins/default/templates/question_retag.html
index 03f3da04..03f3da04 100644
--- a/forum/skins/default/templates/question_retag.html
+++ b/askbot/skins/default/templates/question_retag.html
diff --git a/forum/skins/default/templates/question_summary_list_roll.html b/askbot/skins/default/templates/question_summary_list_roll.html
index f2432a24..f2432a24 100644
--- a/forum/skins/default/templates/question_summary_list_roll.html
+++ b/askbot/skins/default/templates/question_summary_list_roll.html
diff --git a/forum/skins/default/templates/questions.html b/askbot/skins/default/templates/questions.html
index f7863208..1988f0cb 100644
--- a/forum/skins/default/templates/questions.html
+++ b/askbot/skins/default/templates/questions.html
@@ -50,7 +50,7 @@
<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>
+ <a id="unanswered" class="off" href="?scope=unanswered&amp;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 %}
@@ -138,7 +138,11 @@
<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 %} {{q_num}} question found{% plural %}{{q_num}} questions found{% endblocktrans %}
+ {% blocktrans count questions_count as cnt with questions_count|intcomma as q_num %}
+ {{q_num}} 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 %}
diff --git a/forum/skins/default/templates/reopen.html b/askbot/skins/default/templates/reopen.html
index 37fb69c1..37fb69c1 100644
--- a/forum/skins/default/templates/reopen.html
+++ b/askbot/skins/default/templates/reopen.html
diff --git a/forum/skins/default/templates/revisions_answer.html b/askbot/skins/default/templates/revisions_answer.html
index b2e33dfe..5c37e386 100644
--- a/forum/skins/default/templates/revisions_answer.html
+++ b/askbot/skins/default/templates/revisions_answer.html
@@ -25,7 +25,7 @@
var visible = arrow.attr("src").indexOf("hide") > -1;
var path = $.i18n._('/') + "media/images/expander-arrow-" +
- (visible ? "show" : "hide") + ".gif" + "?v={{settings.RESOURCE_REVISION}}";
+ (visible ? "show" : "hide") + ".gif" + "?v={{settings.MEDIA_RESOURCE_REVISION}}";
arrow.attr("src", path);
$("#rev-body-" + id).slideToggle("fast");
}
diff --git a/forum/skins/default/templates/revisions_question.html b/askbot/skins/default/templates/revisions_question.html
index 86d52a36..a227071f 100644
--- a/forum/skins/default/templates/revisions_question.html
+++ b/askbot/skins/default/templates/revisions_question.html
@@ -26,7 +26,7 @@
var visible = arrow.attr("src").indexOf("hide") > -1;
var path = $.i18n._('/') + "media/images/expander-arrow-" +
- (visible ? "show" : "hide") + ".gif" + "?v={{settings.RESOURCE_REVISION}}";
+ (visible ? "show" : "hide") + ".gif" + "?v={{settings.MEDIA_RESOURCE_REVISION}}";
arrow.attr("src", path);
$("#rev-body-" + id).slideToggle("fast");
}
diff --git a/forum/skins/default/templates/tag_selector.html b/askbot/skins/default/templates/tag_selector.html
index 85b858d2..85b858d2 100644
--- a/forum/skins/default/templates/tag_selector.html
+++ b/askbot/skins/default/templates/tag_selector.html
diff --git a/forum/skins/default/templates/tags.html b/askbot/skins/default/templates/tags.html
index 6627db32..6627db32 100644
--- a/forum/skins/default/templates/tags.html
+++ b/askbot/skins/default/templates/tags.html
diff --git a/forum/skins/default/templates/user.html b/askbot/skins/default/templates/user.html
index 833c2058..dee52cd7 100644
--- a/forum/skins/default/templates/user.html
+++ b/askbot/skins/default/templates/user.html
@@ -3,6 +3,7 @@
{% load extra_tags %}
{% load extra_filters %}
{% load humanize %}
+{% load i18n %}
{% block title %}{% spaceless %}{{ page_title }}{% endspaceless %}{% endblock %}
{% block forestyle%}
<style type="text/css">
@@ -26,7 +27,13 @@
{% endblock %}
{% block content %}
<div id="mainbar-full">
- {% include "user_info.html" %}
+ <div id="subheader" class="headUser">
+ {% spaceless %}
+ <a href="{% url user_profile view_user.id view_user.username|slugify %}">
+ {% blocktrans with view_user.username as username %}{{username}}'s profile{% endblocktrans %}
+ </a>
+ {% endspaceless %}
+ </div>
{% include "user_tabs.html" %}
{% block usercontent %}
{% endblock %}
diff --git a/forum/skins/default/templates/user_edit.html b/askbot/skins/default/templates/user_edit.html
index abbce58a..abbce58a 100644
--- a/forum/skins/default/templates/user_edit.html
+++ b/askbot/skins/default/templates/user_edit.html
diff --git a/forum/skins/default/templates/user_email_subscriptions.html b/askbot/skins/default/templates/user_email_subscriptions.html
index 9578046a..9578046a 100644
--- a/forum/skins/default/templates/user_email_subscriptions.html
+++ b/askbot/skins/default/templates/user_email_subscriptions.html
diff --git a/forum/skins/default/templates/user_favorites.html b/askbot/skins/default/templates/user_favorites.html
index 9db01e9a..9db01e9a 100644
--- a/forum/skins/default/templates/user_favorites.html
+++ b/askbot/skins/default/templates/user_favorites.html
diff --git a/forum/skins/default/templates/user_footer.html b/askbot/skins/default/templates/user_footer.html
index ee347742..ee347742 100644
--- a/forum/skins/default/templates/user_footer.html
+++ b/askbot/skins/default/templates/user_footer.html
diff --git a/forum/skins/default/templates/user_info.html b/askbot/skins/default/templates/user_info.html
index fda7133c..c99dd2c1 100644
--- a/forum/skins/default/templates/user_info.html
+++ b/askbot/skins/default/templates/user_info.html
@@ -4,9 +4,6 @@
{% load humanize %}
{% load smart_if %}
{% load i18n %}
-<div id="subheader" class="headUser">
- <a href="{% url user_profile view_user.id view_user.username|slugify %}">{{view_user.username}}</a>
-</div>
<table class="user-info-table">
<tr>
<td width="180" style="vertical-align:middle;text-align:center;">
diff --git a/forum/skins/default/templates/user_recent.html b/askbot/skins/default/templates/user_recent.html
index 78347993..78347993 100644
--- a/forum/skins/default/templates/user_recent.html
+++ b/askbot/skins/default/templates/user_recent.html
diff --git a/forum/skins/default/templates/user_reputation.html b/askbot/skins/default/templates/user_reputation.html
index f6a33d93..f6a33d93 100644
--- a/forum/skins/default/templates/user_reputation.html
+++ b/askbot/skins/default/templates/user_reputation.html
diff --git a/askbot/skins/default/templates/user_responses.html b/askbot/skins/default/templates/user_responses.html
new file mode 100644
index 00000000..2d96112b
--- /dev/null
+++ b/askbot/skins/default/templates/user_responses.html
@@ -0,0 +1,41 @@
+{% extends "user.html" %}
+<!-- user_responses.html -->
+
+{% comment %}
+This template accepts a list of response list
+they are a generalized form of any response and
+
+The following properties of response object are used:
+timestamp - when it happened
+user - user who gave response (database object)
+response_type - type of response
+response_url - link to the question
+response_title - title of the question
+response_snippet - abbreviated content of the response
+{% endcomment %}
+
+{% load extra_tags %}
+{% load humanize %}
+{% load i18n %}
+
+{% block usercontent %}
+ <div style="padding-top:5px;font-size:13px;">
+ {% for response in responses %}
+ <div style="clear:both;line-height:18px;margin-bottom:15px;">
+ <div>
+ <div style="float:left; display:inline-block; text-align: center; width: 54px; padding: 3px;overflow:hidden;">
+ {% gravatar response.user 48 %}
+ </div>
+ <a style="font-size:12px" href="{{ response.user.get_absolute_url }}">{{ response.user.username }}</a>
+ <a style="text-decoration:none;" href="{{ response.response_url }}">
+ {{ response.response_type }}
+ ({% diff_date response.timestamp 3 "True" %}):<br/>
+ <strong>"{{ response.response_title }}"</strong>&nbsp;
+ {{ response.response_snippet|safe }}
+ </a>
+ </div>
+ </div>
+ {% endfor %}
+ </div>
+{% endblock %}
+<!-- end user_responses.html -->
diff --git a/forum/skins/default/templates/user_stats.html b/askbot/skins/default/templates/user_stats.html
index f5dcf4f5..0e0f4d36 100644
--- a/forum/skins/default/templates/user_stats.html
+++ b/askbot/skins/default/templates/user_stats.html
@@ -5,7 +5,7 @@
{% load extra_filters %}
{% load humanize %}
{% block usercontent %}
-
+ {% include "user_info.html" %}
<a name="questions"></a>
{% spaceless %}
<h2>{% blocktrans count questions|length as counter %}<span class="count">{{counter}}</span> Question{% plural %}<span class="count">{{counter}}</span> Questions{% endblocktrans %}</h2>
diff --git a/forum/skins/default/templates/user_tabs.html b/askbot/skins/default/templates/user_tabs.html
index d0d52930..d0d52930 100644
--- a/forum/skins/default/templates/user_tabs.html
+++ b/askbot/skins/default/templates/user_tabs.html
diff --git a/forum/skins/default/templates/user_votes.html b/askbot/skins/default/templates/user_votes.html
index b56aab01..b56aab01 100644
--- a/forum/skins/default/templates/user_votes.html
+++ b/askbot/skins/default/templates/user_votes.html
diff --git a/forum/skins/default/templates/users.html b/askbot/skins/default/templates/users.html
index f3ccd6e9..f3ccd6e9 100644
--- a/forum/skins/default/templates/users.html
+++ b/askbot/skins/default/templates/users.html
diff --git a/forum/skins/default/templates/users_questions.html b/askbot/skins/default/templates/users_questions.html
index 99a7f90c..99a7f90c 100644
--- a/forum/skins/default/templates/users_questions.html
+++ b/askbot/skins/default/templates/users_questions.html
diff --git a/forum/skins/__init__.py b/askbot/skins/loaders.py
index 10b6a340..b95f7f1f 100755..100644
--- a/forum/skins/__init__.py
+++ b/askbot/skins/loaders.py
@@ -1,24 +1,32 @@
-from django.conf import settings
from django.template import loader
-from django.template.loaders import filesystem
-from django.http import HttpResponse
+from django.template.loaders import filesystem
import os.path
+import os
import logging
+from askbot.skins import utils
+from askbot.conf import settings as askbot_settings
#module for skinning askbot
-#at this point skin can be changed only in settings file
-#via ASKBOT_DEFAULT_SKIN variable
+#via ASKBOT_DEFAULT_SKIN configureation variable (not django setting)
#note - Django template loaders use method django.utils._os.safe_join
#to work on unicode file paths
#here it is ignored because it is assumed that we won't use unicode paths
+ASKBOT_SKIN_COLLECTION_DIR = os.path.dirname(__file__)
def load_template_source(name, dirs=None):
+ if dirs is None:
+ dirs = (ASKBOT_SKIN_COLLECTION_DIR, )
+ else:
+ dirs += (ASKBOT_SKIN_COLLECTION_DIR, )
+
try:
- tname = os.path.join(settings.ASKBOT_DEFAULT_SKIN,'templates',name)
+ #todo: move this to top after splitting out get_skin_dirs()
+ tname = os.path.join(askbot_settings.ASKBOT_DEFAULT_SKIN,'templates',name)
return filesystem.load_template_source(tname,dirs)
except:
tname = os.path.join('default','templates',name)
+ print tname
return filesystem.load_template_source(tname,dirs)
load_template_source.is_usable = True
@@ -26,7 +34,7 @@ def find_media_source(url):
"""returns url prefixed with the skin name
of the first skin that contains the file
directories are searched in this order:
- settings.ASKBOT_DEFAULT_SKIN, then 'default', then 'commmon'
+ askbot_settings.ASKBOT_DEFAULT_SKIN, then 'default', then 'commmon'
if file is not found - returns None
and logs an error message
"""
@@ -35,11 +43,12 @@ def find_media_source(url):
n = os.path.normpath
j = os.path.join
f = os.path.isfile
- skins = n(j(d(d(__file__)),'skins'))
+ #todo: handles case of multiple skin directories
+ skins = utils.get_skin_dirs()[0]
try:
- media = os.path.join(skins, settings.ASKBOT_DEFAULT_SKIN, url)
+ use_skin = askbot_settings.ASKBOT_DEFAULT_SKIN
+ media = os.path.join(skins, use_skin, url)
assert(f(media))
- use_skin = settings.ASKBOT_DEFAULT_SKIN
except:
try:
media = j(skins, 'default', url)
diff --git a/askbot/skins/utils.py b/askbot/skins/utils.py
new file mode 100644
index 00000000..e3f2ddc5
--- /dev/null
+++ b/askbot/skins/utils.py
@@ -0,0 +1,29 @@
+import os
+
+def get_skin_dirs():
+ #todo: handle case of multiple skin directories
+ d = os.path.dirname
+ n = os.path.normpath
+ j = os.path.join
+ f = os.path.isfile
+ skin_dirs = []
+ skin_dirs.append( n(j(d(d(__file__)), 'skins')) )
+ return skin_dirs
+
+def get_skin_choices():
+ #todo: expand this to handle custom skin directories
+ dirs = get_skin_dirs()
+ default_dir = dirs[0]
+ items = os.listdir(default_dir)
+ skin_list = ['default']
+ for i in items:
+ item_path = os.path.join(default_dir,i)
+ if not os.path.isdir(item_path):
+ continue
+ if i == 'common':
+ continue
+ if i not in skin_list:
+ skin_list.append(i)
+
+ return [(i,i) for i in skin_list]
+
diff --git a/forum/sql_scripts/091111_upgrade_evgeny.sql b/askbot/sql_scripts/091111_upgrade_evgeny.sql
index cb76ec3c..cb76ec3c 100644
--- a/forum/sql_scripts/091111_upgrade_evgeny.sql
+++ b/askbot/sql_scripts/091111_upgrade_evgeny.sql
diff --git a/forum/sql_scripts/091208_upgrade_evgeny.sql b/askbot/sql_scripts/091208_upgrade_evgeny.sql
index d9c4289a..d9c4289a 100644
--- a/forum/sql_scripts/091208_upgrade_evgeny.sql
+++ b/askbot/sql_scripts/091208_upgrade_evgeny.sql
diff --git a/forum/sql_scripts/091208_upgrade_evgeny_1.sql b/askbot/sql_scripts/091208_upgrade_evgeny_1.sql
index b1b4107f..b1b4107f 100644
--- a/forum/sql_scripts/091208_upgrade_evgeny_1.sql
+++ b/askbot/sql_scripts/091208_upgrade_evgeny_1.sql
diff --git a/forum/sql_scripts/100108_upgrade_ef.sql b/askbot/sql_scripts/100108_upgrade_ef.sql
index 1c9a5c1c..1c9a5c1c 100644
--- a/forum/sql_scripts/100108_upgrade_ef.sql
+++ b/askbot/sql_scripts/100108_upgrade_ef.sql
diff --git a/forum/sql_scripts/badges.sql b/askbot/sql_scripts/badges.sql
index 5fd03d18..5fd03d18 100644
--- a/forum/sql_scripts/badges.sql
+++ b/askbot/sql_scripts/badges.sql
diff --git a/forum/sql_scripts/cnprog.xml b/askbot/sql_scripts/cnprog.xml
index 95f9b362..95f9b362 100644
--- a/forum/sql_scripts/cnprog.xml
+++ b/askbot/sql_scripts/cnprog.xml
diff --git a/forum/sql_scripts/cnprog_new_install.sql b/askbot/sql_scripts/cnprog_new_install.sql
index ac33a6ba..ac33a6ba 100644
--- a/forum/sql_scripts/cnprog_new_install.sql
+++ b/askbot/sql_scripts/cnprog_new_install.sql
diff --git a/forum/sql_scripts/cnprog_new_install_2009_02_28.sql b/askbot/sql_scripts/cnprog_new_install_2009_02_28.sql
index 80b9fced..80b9fced 100644
--- a/forum/sql_scripts/cnprog_new_install_2009_02_28.sql
+++ b/askbot/sql_scripts/cnprog_new_install_2009_02_28.sql
diff --git a/forum/sql_scripts/cnprog_new_install_2009_03_31.sql b/askbot/sql_scripts/cnprog_new_install_2009_03_31.sql
index c2c69f36..c2c69f36 100644
--- a/forum/sql_scripts/cnprog_new_install_2009_03_31.sql
+++ b/askbot/sql_scripts/cnprog_new_install_2009_03_31.sql
diff --git a/forum/sql_scripts/cnprog_new_install_2009_04_07.sql b/askbot/sql_scripts/cnprog_new_install_2009_04_07.sql
index ff9016fa..ff9016fa 100644
--- a/forum/sql_scripts/cnprog_new_install_2009_04_07.sql
+++ b/askbot/sql_scripts/cnprog_new_install_2009_04_07.sql
diff --git a/forum/sql_scripts/cnprog_new_install_2009_04_09.sql b/askbot/sql_scripts/cnprog_new_install_2009_04_09.sql
index f4424852..f4424852 100644
--- a/forum/sql_scripts/cnprog_new_install_2009_04_09.sql
+++ b/askbot/sql_scripts/cnprog_new_install_2009_04_09.sql
diff --git a/forum/sql_scripts/drop-all-tables.sh b/askbot/sql_scripts/drop-all-tables.sh
index 1e55cb1f..1e55cb1f 100644
--- a/forum/sql_scripts/drop-all-tables.sh
+++ b/askbot/sql_scripts/drop-all-tables.sh
diff --git a/forum/sql_scripts/drop-auth.sql b/askbot/sql_scripts/drop-auth.sql
index bc17dce3..bc17dce3 100644
--- a/forum/sql_scripts/drop-auth.sql
+++ b/askbot/sql_scripts/drop-auth.sql
diff --git a/forum/sql_scripts/pg_fts_install.sql b/askbot/sql_scripts/pg_fts_install.sql
index d0655134..d0655134 100644
--- a/forum/sql_scripts/pg_fts_install.sql
+++ b/askbot/sql_scripts/pg_fts_install.sql
diff --git a/forum/sql_scripts/update_2009_01_13_001.sql b/askbot/sql_scripts/update_2009_01_13_001.sql
index 165d1125..165d1125 100644
--- a/forum/sql_scripts/update_2009_01_13_001.sql
+++ b/askbot/sql_scripts/update_2009_01_13_001.sql
diff --git a/forum/sql_scripts/update_2009_01_13_002.sql b/askbot/sql_scripts/update_2009_01_13_002.sql
index c223cb8c..c223cb8c 100644
--- a/forum/sql_scripts/update_2009_01_13_002.sql
+++ b/askbot/sql_scripts/update_2009_01_13_002.sql
diff --git a/forum/sql_scripts/update_2009_01_18_001.sql b/askbot/sql_scripts/update_2009_01_18_001.sql
index 6f29fa32..6f29fa32 100644
--- a/forum/sql_scripts/update_2009_01_18_001.sql
+++ b/askbot/sql_scripts/update_2009_01_18_001.sql
diff --git a/forum/sql_scripts/update_2009_01_24.sql b/askbot/sql_scripts/update_2009_01_24.sql
index 45b83935..45b83935 100644
--- a/forum/sql_scripts/update_2009_01_24.sql
+++ b/askbot/sql_scripts/update_2009_01_24.sql
diff --git a/forum/sql_scripts/update_2009_01_25_001.sql b/askbot/sql_scripts/update_2009_01_25_001.sql
index 16c3487b..16c3487b 100644
--- a/forum/sql_scripts/update_2009_01_25_001.sql
+++ b/askbot/sql_scripts/update_2009_01_25_001.sql
diff --git a/forum/sql_scripts/update_2009_02_26_001.sql b/askbot/sql_scripts/update_2009_02_26_001.sql
index a6af5931..a6af5931 100644
--- a/forum/sql_scripts/update_2009_02_26_001.sql
+++ b/askbot/sql_scripts/update_2009_02_26_001.sql
diff --git a/forum/sql_scripts/update_2009_04_10_001.sql b/askbot/sql_scripts/update_2009_04_10_001.sql
index 8148632a..8148632a 100644
--- a/forum/sql_scripts/update_2009_04_10_001.sql
+++ b/askbot/sql_scripts/update_2009_04_10_001.sql
diff --git a/forum/sql_scripts/update_2009_07_05_EF.sql b/askbot/sql_scripts/update_2009_07_05_EF.sql
index 43c7c2f0..43c7c2f0 100644
--- a/forum/sql_scripts/update_2009_07_05_EF.sql
+++ b/askbot/sql_scripts/update_2009_07_05_EF.sql
diff --git a/forum/sql_scripts/update_2009_12_24_001.sql b/askbot/sql_scripts/update_2009_12_24_001.sql
index 3d082c2f..3d082c2f 100644
--- a/forum/sql_scripts/update_2009_12_24_001.sql
+++ b/askbot/sql_scripts/update_2009_12_24_001.sql
diff --git a/forum/sql_scripts/update_2009_12_27_001.sql b/askbot/sql_scripts/update_2009_12_27_001.sql
index e2da7d4d..e2da7d4d 100644
--- a/forum/sql_scripts/update_2009_12_27_001.sql
+++ b/askbot/sql_scripts/update_2009_12_27_001.sql
diff --git a/forum/sql_scripts/update_2009_12_27_002.sql b/askbot/sql_scripts/update_2009_12_27_002.sql
index a36470bf..a36470bf 100644
--- a/forum/sql_scripts/update_2009_12_27_002.sql
+++ b/askbot/sql_scripts/update_2009_12_27_002.sql
diff --git a/forum/sql_scripts/update_2010_02_22.sql b/askbot/sql_scripts/update_2010_02_22.sql
index 2778885a..2778885a 100644
--- a/forum/sql_scripts/update_2010_02_22.sql
+++ b/askbot/sql_scripts/update_2010_02_22.sql
diff --git a/forum_modules/sphinxfulltext/__init__.py b/askbot/templatetags/__init__.py
index e69de29b..e69de29b 100644
--- a/forum_modules/sphinxfulltext/__init__.py
+++ b/askbot/templatetags/__init__.py
diff --git a/forum/templatetags/extra_filters.py b/askbot/templatetags/extra_filters.py
index d600c23e..df47ed9a 100755..100644
--- a/forum/templatetags/extra_filters.py
+++ b/askbot/templatetags/extra_filters.py
@@ -1,6 +1,6 @@
from django import template
-from forum import auth
-from forum_modules.grapefruit import Color
+from askbot import auth
+from askbot.deps.grapefruit import Color
from django.utils.translation import ugettext as _
import logging
@@ -107,3 +107,7 @@ def humanize_counter(number):
return s + 'k'
else:
return str(number)
+
+@register.filter
+def absolute_value(number):
+ return abs(number)
diff --git a/forum/templatetags/extra_tags.py b/askbot/templatetags/extra_tags.py
index 86f2e9df..4a7367bc 100755..100644
--- a/forum/templatetags/extra_tags.py
+++ b/askbot/templatetags/extra_tags.py
@@ -1,6 +1,5 @@
import time
import os
-import posixpath
import datetime
import math
import re
@@ -8,17 +7,19 @@ import logging
from django import template
from django.utils.encoding import smart_unicode
from django.utils.safestring import mark_safe
-from forum.const import *
-from forum.models import Question, Answer, QuestionRevision, AnswerRevision
+from askbot.const import *
+from askbot.models import Question, Answer, QuestionRevision, AnswerRevision
+from askbot.models import Badge
from django.utils.translation import ugettext as _
from django.utils.translation import ungettext
from django.conf import settings
+from askbot.conf import settings as askbot_settings
from django.template.defaulttags import url as default_url
from django.template.defaultfilters import slugify
from django.core.urlresolvers import reverse
-from forum import skins
-from forum.utils import colors
-from forum.utils.functions import get_from_dict_or_object
+from askbot import skins
+from askbot.utils import colors
+from askbot.utils.functions import get_from_dict_or_object
register = template.Library()
@@ -146,66 +147,117 @@ def post_contributor_info(post,contributor_type='original_author'):
return {
'post':post,
'post_type':post_type,
- 'wiki_on':settings.WIKI_ON,
+ 'wiki_on':askbot_settings.WIKI_ON,
'contributor_type':contributor_type
}
-
+
+
+BADGE_TEMPLATE = '<span title="%(pluralized_badge_count)s">' \
+ + '<span class="%(badge_css_class)s">%(badge_symbol)s</span>' \
+ + '<span class="badgecount">%(badge_count)s</span>' \
+ + '</span>'
+BADGE_LEVELS = dict(Badge.TYPE_CHOICES)
+
+def render_badge_counter(badge_level = None, badge_count = None):
+
+ pluralized_badge_count = ungettext(
+ '%(badge_count)d %(badge_level)s badge',
+ '%(badge_count)d %(badge_level)s badges',
+ badge_count
+ ) % {
+ 'badge_count': badge_count,
+ 'badge_level': BADGE_LEVELS[badge_level]
+ }
+
+ output = BADGE_TEMPLATE % \
+ {
+ 'pluralized_badge_count': pluralized_badge_count,
+ 'badge_css_class': Badge.CSS_CLASSES[badge_level],
+ 'badge_symbol': Badge.DISPLAY_SYMBOL,
+ 'badge_count': badge_count,
+ }
+ return output
+
+
+REP_TEMPLATE = '<span class="reputation-score" ' \
+ + 'title="%(reputation)s %(repword)s">%(reputation)s</span>'
@register.simple_tag
-def get_score_badge(user):
- BADGE_TEMPLATE = '<span class="score" title="%(reputation)s %(reputationword)s">%(reputation)s</span>'
- if user.gold > 0 :
- BADGE_TEMPLATE = '%s%s' % (BADGE_TEMPLATE, '<span title="%(gold)s %(badgesword)s">'
- '<span class="badge1">&#9679;</span>'
- '<span class="badgecount">%(gold)s</span>'
- '</span>')
- if user.silver > 0:
- BADGE_TEMPLATE = '%s%s' % (BADGE_TEMPLATE, '<span title="%(silver)s %(badgesword)s">'
- '<span class="silver">&#9679;</span>'
- '<span class="badgecount">%(silver)s</span>'
- '</span>')
- if user.bronze > 0:
- BADGE_TEMPLATE = '%s%s' % (BADGE_TEMPLATE, '<span title="%(bronze)s %(badgesword)s">'
- '<span class="bronze">&#9679;</span>'
- '<span class="badgecount">%(bronze)s</span>'
- '</span>')
- BADGE_TEMPLATE = smart_unicode(BADGE_TEMPLATE, encoding='utf-8', strings_only=False, errors='strict')
- return mark_safe(BADGE_TEMPLATE % {
- 'reputation' : user.reputation,
- 'gold' : user.gold,
- 'silver' : user.silver,
- 'bronze' : user.bronze,
- 'badgesword' : _('badges'),
- 'reputationword' : _('reputation points'),
- })
-
+def render_reputation_counter(rep):
+ return REP_TEMPLATE % {
+ 'repword': _('reputation points'),
+ 'reputation': rep
+ }
+
+
@register.simple_tag
-def get_score_badge_by_details(rep, gold, silver, bronze):
- BADGE_TEMPLATE = '<span class="reputation-score" title="%(reputation)s %(repword)s">%(reputation)s</span>'
- if gold > 0 :
- BADGE_TEMPLATE = '%s%s' % (BADGE_TEMPLATE, '<span title="%(gold)s %(badgeword)s">'
- '<span class="badge1">&#9679;</span>'
- '<span class="badgecount">%(gold)s</span>'
- '</span>')
- if silver > 0:
- BADGE_TEMPLATE = '%s%s' % (BADGE_TEMPLATE, '<span title="%(silver)s %(badgeword)s">'
- '<span class="badge2">&#9679;</span>'
- '<span class="badgecount">%(silver)s</span>'
- '</span>')
- if bronze > 0:
- BADGE_TEMPLATE = '%s%s' % (BADGE_TEMPLATE, '<span title="%(bronze)s %(badgeword)s">'
- '<span class="badge3">&#9679;</span>'
- '<span class="badgecount">%(bronze)s</span>'
- '</span>')
- BADGE_TEMPLATE = smart_unicode(BADGE_TEMPLATE, encoding='utf-8', strings_only=False, errors='strict')
- return mark_safe(BADGE_TEMPLATE % {
- 'reputation' : rep,
- 'gold' : gold,
- 'silver' : silver,
- 'bronze' : bronze,
- 'repword' : _('reputation points'),
- 'badgeword' : _('badges'),
- })
-
+def render_badge_counters(gold_count, silver_count, bronze_count):
+ output = ''
+ if gold_count > 0 :
+ output += render_badge_counter(
+ badge_level = Badge.GOLD,
+ badge_count = gold_count
+ )
+ if silver_count > 0:
+ output += render_badge_counter(
+ badge_level = Badge.SILVER,
+ badge_count = silver_count
+ )
+ if bronze_count > 0:
+ output += render_badge_counter(
+ badge_level = Badge.BRONZE,
+ badge_count = bronze_count
+ )
+ return output
+
+
+@register.simple_tag
+def get_score_badge_by_details(rep, gold_count, silver_count, bronze_count):
+ output = render_reputation_counter(rep)
+ output += render_badge_counters(gold_count, silver_count, bronze_count)
+ return output
+
+
+#this one is used for the header next to user profile and logout links
+REP_TEMPLATE2 = '<a class="ab-nav-karma" href="%(karma_graph_url)s" ' \
+ + ' title="%(karma_phrase)s">' \
+ + '%(rep_word)s: %(reputation)s</a>&nbsp;'
+BADGE_TEMPLATE2 = '<a class="ab-nav-badges" href="%(user_badges_url)s">' \
+ + '%(badge_counters)s</a>'
+@register.simple_tag
+def get_long_score_and_badge_report(user):
+ profile_url = user.get_absolute_url()
+ karma_graph_url = profile_url + '?sort=reputation'
+ karma_phrase = _('your karma is %(reputation)s') \
+ % { 'reputation': user.reputation }
+
+ output = REP_TEMPLATE2 % {
+ 'repword': _('reputation points'),
+ 'karma_graph_url': karma_graph_url,
+ 'reputation': user.reputation,
+ 'karma_phrase': karma_phrase,
+ 'rep_word': _('reputation points'),
+ }
+
+ badge_counters = render_badge_counters(user.gold, user.silver, user.bronze)
+
+ if badge_counters != '':
+ output += ' ' + BADGE_TEMPLATE2 % {
+ 'user_badges_url': profile_url + '#badges',
+ 'badge_counters': _('badges: ') + badge_counters
+ }
+ return output
+
+
+@register.simple_tag
+def get_score_badge(user):
+ return get_score_badge_by_details(
+ user.reputation,
+ user.gold,
+ user.silver,
+ user.bronze
+ )
+
+
@register.simple_tag
def get_user_vote_image(dic, key, arrow):
if dic.has_key(key):
@@ -249,7 +301,7 @@ def convert2tagname_list(question):
return ''
@register.simple_tag
-def diff_date(date, limen=2):
+def diff_date(date, limen=2, use_on_prefix = False):
now = datetime.datetime.now()#datetime(*time.localtime()[0:6])#???
diff = now - date
days = diff.days
@@ -258,9 +310,13 @@ def diff_date(date, limen=2):
if days > 2:
if date.year == now.year:
- return date.strftime("%b %d")# at %H:%M")
+ date_token = date.strftime("%b %d")
else:
- return date.strftime("%b %d '%y")# at %H:%M")
+ date_token = date.strftime("%b %d '%y")
+ if use_on_prefix:
+ return _('on %(date)s') % { 'date': date_token }
+ else:
+ return date_token
elif days == 2:
return _('2 days ago')
elif days == 1:
@@ -278,7 +334,7 @@ def get_latest_changed_timestamp():
root = settings.SITE_SRC_ROOT
dir = (
root,
- '%s/forum' % root,
+ '%s/askbot' % root,
'%s/templates' % root,
)
stamp = (path.getmtime(d) for d in dir)
@@ -290,10 +346,13 @@ def get_latest_changed_timestamp():
@register.simple_tag
def media(url):
- url = skins.find_media_source(url)
+ url = skins.loaders.find_media_source(url)
if url:
url = '///' + settings.FORUM_SCRIPT_ALIAS + '/m/' + url
- return posixpath.normpath(url) + '?v=%d' % settings.RESOURCE_REVISION
+ return os.path.normpath(url) + '?v=%d' \
+ % askbot_settings.MEDIA_RESOURCE_REVISION
+ else:
+ return '' #todo: raise exception here?
class ItemSeparatorNode(template.Node):
def __init__(self,separator):
@@ -371,9 +430,9 @@ class BlockMediaUrlNode(template.Node):
for item in self.items:
url += item.render(context)
- url = skins.find_media_source(url)
+ url = skins.loaders.find_media_source(url)
url = prefix + url
- out = posixpath.normpath(url) + '?v=%d' % settings.RESOURCE_REVISION
+ out = os.path.normpath(url) + '?v=%d' % askbot_settings.MEDIA_RESOURCE_REVISION
return out.replace(' ','')
@register.tag(name='blockmedia')
@@ -395,7 +454,7 @@ class FullUrlNode(template.Node):
self.default_node = default_node
def render(self, context):
- domain = settings.APP_URL
+ domain = askbot_settings.APP_URL
#protocol = getattr(settings, "PROTOCOL", "http")
path = self.default_node.render(context)
return "%s%s" % (domain, path)
@@ -407,7 +466,7 @@ def fullurl(parser, token):
@register.simple_tag
def fullmedia(url):
- domain = settings.APP_URL
+ domain = askbot_settings.APP_URL
#protocol = getattr(settings, "PROTOCOL", "http")
path = media(url)
return "%s%s" % (domain, path)
@@ -422,41 +481,41 @@ def question_counter_widget(question):
#background and foreground colors for each item
(views_fg, views_bg) = colors.get_counter_colors(
- view_count,
- max = settings.VIEW_COUNTER_EXPECTED_MAXIMUM,
- zero_bg = settings.COLORS_VIEW_COUNTER_EMPTY_BG,
- zero_fg = settings.COLORS_VIEW_COUNTER_EMPTY_FG,
- min_bg = settings.COLORS_VIEW_COUNTER_MIN_BG,
- min_fg = settings.COLORS_VIEW_COUNTER_MIN_FG,
- max_bg = settings.COLORS_VIEW_COUNTER_MAX_BG,
- max_fg = settings.COLORS_VIEW_COUNTER_MAX_FG,
- )
+ view_count,
+ counter_max = askbot_settings.VIEW_COUNTER_EXPECTED_MAXIMUM,
+ zero_bg = askbot_settings.COLORS_VIEW_COUNTER_EMPTY_BG,
+ zero_fg = askbot_settings.COLORS_VIEW_COUNTER_EMPTY_FG,
+ min_bg = askbot_settings.COLORS_VIEW_COUNTER_MIN_BG,
+ min_fg = askbot_settings.COLORS_VIEW_COUNTER_MIN_FG,
+ max_bg = askbot_settings.COLORS_VIEW_COUNTER_MAX_BG,
+ max_fg = askbot_settings.COLORS_VIEW_COUNTER_MAX_FG,
+ )
(answers_fg, answers_bg) = colors.get_counter_colors(
- answer_count,
- max = settings.ANSWER_COUNTER_EXPECTED_MAXIMUM,
- zero_bg = settings.COLORS_ANSWER_COUNTER_EMPTY_BG,
- zero_fg = settings.COLORS_ANSWER_COUNTER_EMPTY_FG,
- min_bg = settings.COLORS_ANSWER_COUNTER_MIN_BG,
- min_fg = settings.COLORS_ANSWER_COUNTER_MIN_FG,
- max_bg = settings.COLORS_ANSWER_COUNTER_MAX_BG,
- max_fg = settings.COLORS_ANSWER_COUNTER_MAX_FG,
- )
+ answer_count,
+ counter_max = askbot_settings.ANSWER_COUNTER_EXPECTED_MAXIMUM,
+ zero_bg = askbot_settings.COLORS_ANSWER_COUNTER_EMPTY_BG,
+ zero_fg = askbot_settings.COLORS_ANSWER_COUNTER_EMPTY_FG,
+ min_bg = askbot_settings.COLORS_ANSWER_COUNTER_MIN_BG,
+ min_fg = askbot_settings.COLORS_ANSWER_COUNTER_MIN_FG,
+ max_bg = askbot_settings.COLORS_ANSWER_COUNTER_MAX_BG,
+ max_fg = askbot_settings.COLORS_ANSWER_COUNTER_MAX_FG,
+ )
if answer_accepted:
#todo: maybe recalculate the foreground color too
- answers_bg = settings.COLORS_ANSWER_COUNTER_ACCEPTED_BG
- answers_fg = settings.COLORS_ANSWER_COUNTER_ACCEPTED_FG
+ answers_bg = askbot_settings.COLORS_ANSWER_COUNTER_ACCEPTED_BG
+ answers_fg = askbot_settings.COLORS_ANSWER_COUNTER_ACCEPTED_FG
(votes_fg, votes_bg) = colors.get_counter_colors(
- vote_count,
- max = settings.VOTE_COUNTER_EXPECTED_MAXIMUM,
- zero_bg = settings.COLORS_VOTE_COUNTER_EMPTY_BG,
- zero_fg = settings.COLORS_VOTE_COUNTER_EMPTY_FG,
- min_bg = settings.COLORS_VOTE_COUNTER_MIN_BG,
- min_fg = settings.COLORS_VOTE_COUNTER_MIN_FG,
- max_bg = settings.COLORS_VOTE_COUNTER_MAX_BG,
- max_fg = settings.COLORS_VOTE_COUNTER_MAX_FG,
- )
+ vote_count,
+ counter_max = askbot_settings.VOTE_COUNTER_EXPECTED_MAXIMUM,
+ zero_bg = askbot_settings.COLORS_VOTE_COUNTER_EMPTY_BG,
+ zero_fg = askbot_settings.COLORS_VOTE_COUNTER_EMPTY_FG,
+ min_bg = askbot_settings.COLORS_VOTE_COUNTER_MIN_BG,
+ min_fg = askbot_settings.COLORS_VOTE_COUNTER_MIN_FG,
+ max_bg = askbot_settings.COLORS_VOTE_COUNTER_MAX_BG,
+ max_fg = askbot_settings.COLORS_VOTE_COUNTER_MAX_FG,
+ )
#returns a dictionary with keys like 'votes_bg', etc
return locals()
@@ -502,5 +561,4 @@ def ifmany(parser,token):
else:
false_nodelist = template.NodeList()
-
return IsManyNode(test_items, true_nodelist, false_nodelist)
diff --git a/forum/templatetags/smart_if.py b/askbot/templatetags/smart_if.py
index ca3b43fe..ca3b43fe 100755..100644
--- a/forum/templatetags/smart_if.py
+++ b/askbot/templatetags/smart_if.py
diff --git a/askbot/tests.py b/askbot/tests.py
new file mode 100644
index 00000000..12eb03a3
--- /dev/null
+++ b/askbot/tests.py
@@ -0,0 +1,870 @@
+import datetime
+import time
+from django.test import TestCase
+from django.template import defaultfilters
+from django.core.urlresolvers import reverse
+from askbot.models import User, Question, Answer, Activity
+from askbot.models import EmailFeedSetting
+from askbot import const
+
+def create_user(username = None, email = None):
+ user = User.objects.create_user(username, email)
+ for feed_type in EmailFeedSetting.FEED_TYPES:
+ feed = EmailFeedSetting(
+ feed_type = feed_type[0],
+ frequency = 'n',
+ subscriber = user
+ )
+ feed.save()
+ return user
+
+def get_re_notif_after(timestamp):
+ notifications = Activity.objects.filter(
+ activity_type__in = const.RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY,
+ active_at__gte = timestamp
+ )
+ return notifications
+
+class UpdateNotificationTests(TestCase):
+
+ def reset_response_counts(self):
+ self.reload_users()
+ for user in self.users:
+ user.response_count = 0
+ user.save()
+
+ def reload_users(self):
+ self.u11 = User.objects.get(id=self.u11.id)
+ self.u12 = User.objects.get(id=self.u12.id)
+ self.u13 = User.objects.get(id=self.u13.id)
+ self.u14 = User.objects.get(id=self.u14.id)
+ self.u21 = User.objects.get(id=self.u21.id)
+ self.u22 = User.objects.get(id=self.u22.id)
+ self.u23 = User.objects.get(id=self.u23.id)
+ self.u24 = User.objects.get(id=self.u24.id)
+ self.u31 = User.objects.get(id=self.u31.id)
+ self.u32 = User.objects.get(id=self.u32.id)
+ self.u33 = User.objects.get(id=self.u33.id)
+ self.u34 = User.objects.get(id=self.u34.id)
+ self.users = [
+ self.u11,
+ self.u12,
+ self.u13,
+ self.u14,
+ self.u21,
+ self.u22,
+ self.u23,
+ self.u24,
+ self.u31,
+ self.u32,
+ self.u33,
+ self.u34,
+ ]
+
+ def setUp(self):
+ #users for the question
+ self.u11 = create_user('user11', 'user11@example.com')
+ self.u12 = create_user('user12', 'user12@example.com')
+ self.u13 = create_user('user13', 'user13@example.com')
+ self.u14 = create_user('user14', 'user14@example.com')
+
+ #users for first answer
+ self.u21 = create_user('user21', 'user21@example.com')#post answer
+ self.u22 = create_user('user22', 'user22@example.com')#edit answer
+ self.u23 = create_user('user23', 'user23@example.com')
+ self.u24 = create_user('user24', 'user24@example.com')
+
+ #users for second answer
+ self.u31 = create_user('user31', 'user31@example.com')#post answer
+ self.u32 = create_user('user32', 'user32@example.com')#edit answer
+ self.u33 = create_user('user33', 'user33@example.com')
+ self.u34 = create_user('user34', 'user34@example.com')
+
+ #a hack to initialize .users list
+ self.reload_users()
+
+ #pre-populate askbot with some content
+ self.question = Question.objects.create_new(
+ title = 'test question',
+ author = self.u11,
+ added_at = datetime.datetime.now(),
+ wiki = False,
+ tagnames = 'test',
+ text = 'hey listen up',
+ )
+ self.comment12 = self.question.add_comment(
+ user = self.u12,
+ comment = 'comment12'
+ )
+ self.comment13 = self.question.add_comment(
+ user = self.u13,
+ comment = 'comment13'
+ )
+ self.answer1 = Answer.objects.create_new(
+ question = self.question,
+ author = self.u21,
+ added_at = datetime.datetime.now(),
+ text = 'answer1'
+ )
+ self.comment22 = self.answer1.add_comment(
+ user = self.u22,
+ comment = 'comment22'
+ )
+ self.comment23 = self.answer1.add_comment(
+ user = self.u23,
+ comment = 'comment23'
+ )
+ self.answer2 = Answer.objects.create_new(
+ question = self.question,
+ author = self.u31,
+ added_at = datetime.datetime.now(),
+ text = 'answer2'
+ )
+ self.comment32 = self.answer2.add_comment(
+ user = self.u32,
+ comment = 'comment32'
+ )
+ self.comment33 = self.answer2.add_comment(
+ user = self.u33,
+ comment = 'comment33'
+ )
+
+ def test_self_comments(self):
+ self.reset_response_counts()
+ time.sleep(1)
+ timestamp = datetime.datetime.now()
+ self.question.add_comment(
+ user = self.u11,
+ comment = 'self-comment',
+ added_at = timestamp
+ )
+ notifications = get_re_notif_after(timestamp)
+ self.assertEqual(len(notifications), 1)
+ self.assertEqual(
+ set(notifications[0].receiving_users.all()),
+ set([self.u12, self.u13]),
+ )
+ self.reload_users()
+ self.assertEqual(
+ [
+ self.u11.response_count,
+ self.u12.response_count,
+ self.u13.response_count,
+ self.u14.response_count,
+ self.u21.response_count,
+ self.u22.response_count,
+ self.u23.response_count,
+ self.u24.response_count,
+ self.u31.response_count,
+ self.u32.response_count,
+ self.u33.response_count,
+ self.u34.response_count,
+ ],
+ [
+ 0, 1, 1, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ ]
+ )
+ self.reset_response_counts()
+ time.sleep(1)
+ timestamp = datetime.datetime.now()
+ self.answer1.add_comment(
+ user = self.u21,
+ comment = 'self-comment 2',
+ added_at = timestamp
+ )
+ notifications = get_re_notif_after(timestamp)
+ self.assertEqual(len(notifications), 1)
+ self.assertEqual(
+ set(notifications[0].receiving_users.all()),
+ set([self.u22, self.u23]),
+ )
+ self.reload_users()
+ self.assertEqual(
+ [
+ self.u11.response_count,
+ self.u12.response_count,
+ self.u13.response_count,
+ self.u14.response_count,
+ self.u21.response_count,
+ self.u22.response_count,
+ self.u23.response_count,
+ self.u24.response_count,
+ self.u31.response_count,
+ self.u32.response_count,
+ self.u33.response_count,
+ self.u34.response_count,
+ ],
+ [
+ 0, 0, 0, 0,
+ 0, 1, 1, 0,
+ 0, 0, 0, 0,
+ ]
+ )
+
+ def test_self_mention_not_posting_in_comment_to_question1(self):
+ self.reset_response_counts()
+ time.sleep(1)
+ timestamp = datetime.datetime.now()
+ self.question.add_comment(
+ user = self.u11,
+ comment = 'self-comment @user11',
+ added_at = timestamp
+ )
+ notifications = get_re_notif_after(timestamp)
+ self.assertEqual(len(notifications), 1)
+ self.assertEqual(
+ set(notifications[0].receiving_users.all()),
+ set([self.u12, self.u13]),
+ )
+ self.reload_users()
+ self.assertEqual(
+ [
+ self.u11.response_count,
+ self.u12.response_count,
+ self.u13.response_count,
+ self.u14.response_count,
+ self.u21.response_count,
+ self.u22.response_count,
+ self.u23.response_count,
+ self.u24.response_count,
+ self.u31.response_count,
+ self.u32.response_count,
+ self.u33.response_count,
+ self.u34.response_count,
+ ],
+ [
+ 0, 1, 1, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ ]
+ )
+
+ def test_self_mention_not_posting_in_comment_to_question2(self):
+ self.reset_response_counts()
+ time.sleep(1)
+ timestamp = datetime.datetime.now()
+ self.question.add_comment(
+ user = self.u11,
+ comment = 'self-comment @user11 blah',
+ added_at = timestamp
+ )
+ notifications = get_re_notif_after(timestamp)
+ self.assertEqual(len(notifications), 1)
+ self.assertEqual(
+ set(notifications[0].receiving_users.all()),
+ set([self.u12, self.u13]),
+ )
+ self.reload_users()
+ self.assertEqual(
+ [
+ self.u11.response_count,
+ self.u12.response_count,
+ self.u13.response_count,
+ self.u14.response_count,
+ self.u21.response_count,
+ self.u22.response_count,
+ self.u23.response_count,
+ self.u24.response_count,
+ self.u31.response_count,
+ self.u32.response_count,
+ self.u33.response_count,
+ self.u34.response_count,
+ ],
+ [
+ 0, 1, 1, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ ]
+ )
+
+ def test_self_mention_not_posting_in_comment_to_answer(self):
+ self.reset_response_counts()
+ time.sleep(1)
+ timestamp = datetime.datetime.now()
+ self.answer1.add_comment(
+ user = self.u21,
+ comment = 'self-comment 1 @user21',
+ added_at = timestamp
+ )
+ notifications = get_re_notif_after(timestamp)
+ self.assertEqual(len(notifications), 1)
+ self.assertEqual(
+ set(notifications[0].receiving_users.all()),
+ set([self.u22, self.u23]),
+ )
+ self.reload_users()
+ self.assertEqual(
+ [
+ self.u11.response_count,
+ self.u12.response_count,
+ self.u13.response_count,
+ self.u14.response_count,
+ self.u21.response_count,
+ self.u22.response_count,
+ self.u23.response_count,
+ self.u24.response_count,
+ self.u31.response_count,
+ self.u32.response_count,
+ self.u33.response_count,
+ self.u34.response_count,
+ ],
+ [
+ 0, 0, 0, 0,
+ 0, 1, 1, 0,
+ 0, 0, 0, 0,
+ ]
+ )
+
+ def test_comments_to_post_authors(self):
+ self.question.apply_edit(
+ edited_by = self.u14,
+ text = 'now much better',
+ comment = 'improved text'
+ )
+ self.reset_response_counts()
+ time.sleep(1)
+ timestamp = datetime.datetime.now()
+ self.question.add_comment(
+ user = self.u12,
+ comment = 'self-comment 1',
+ added_at = timestamp
+ )
+ notifications = get_re_notif_after(timestamp)
+ self.assertEqual(len(notifications), 1)
+ self.assertEqual(
+ set(notifications[0].receiving_users.all()),
+ set([self.u11, self.u13, self.u14]),
+ )
+ self.reload_users()
+ self.assertEqual(
+ [
+ self.u11.response_count,
+ self.u12.response_count,
+ self.u13.response_count,
+ self.u14.response_count,
+ self.u21.response_count,
+ self.u22.response_count,
+ self.u23.response_count,
+ self.u24.response_count,
+ self.u31.response_count,
+ self.u32.response_count,
+ self.u33.response_count,
+ self.u34.response_count,
+ ],
+ [
+ 1, 0, 1, 1,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ ]
+ )
+ self.answer1.apply_edit(
+ edited_by = self.u24,
+ text = 'now much better',
+ comment = 'improved text'
+ )
+ self.reset_response_counts()
+ time.sleep(1)
+ timestamp = datetime.datetime.now()
+ self.answer1.add_comment(
+ user = self.u22,
+ comment = 'self-comment 1',
+ added_at = timestamp
+ )
+ notifications = get_re_notif_after(timestamp)
+ self.assertEqual(len(notifications), 1)
+ self.assertEqual(
+ set(notifications[0].receiving_users.all()),
+ set([self.u21, self.u23, self.u24]),
+ )
+ self.reload_users()
+ self.assertEqual(
+ [
+ self.u11.response_count,
+ self.u12.response_count,
+ self.u13.response_count,
+ self.u14.response_count,
+ self.u21.response_count,
+ self.u22.response_count,
+ self.u23.response_count,
+ self.u24.response_count,
+ self.u31.response_count,
+ self.u32.response_count,
+ self.u33.response_count,
+ self.u34.response_count,
+ ],
+ [
+ 0, 0, 0, 0,
+ 1, 0, 1, 1,
+ 0, 0, 0, 0,
+ ]
+ )
+
+ def test_question_edit(self):
+ """when question is edited
+ response receivers are question authors, commenters
+ and answer authors, but not answer commenters
+ """
+ self.reset_response_counts()
+ time.sleep(1)
+ timestamp = datetime.datetime.now()
+ self.question.apply_edit(
+ edited_by = self.u14,
+ text = 'waaay better question!',
+ comment = 'improved question',
+ )
+ notifications = get_re_notif_after(timestamp)
+ self.assertEqual(len(notifications), 1)
+ self.assertEqual(
+ set(notifications[0].receiving_users.all()),
+ set([self.u11, self.u12, self.u13, self.u21, self.u31])
+ )
+ self.reload_users()
+ self.assertEqual(
+ [
+ self.u11.response_count,
+ self.u12.response_count,
+ self.u13.response_count,
+ self.u14.response_count,
+ self.u21.response_count,
+ self.u22.response_count,
+ self.u23.response_count,
+ self.u24.response_count,
+ self.u31.response_count,
+ self.u32.response_count,
+ self.u33.response_count,
+ self.u34.response_count,
+ ],
+ [
+ 1, 1, 1, 0,
+ 1, 0, 0, 0,
+ 1, 0, 0, 0,
+ ]
+ )
+ self.reset_response_counts()
+ time.sleep(1)
+ timestamp = datetime.datetime.now()
+ self.question.apply_edit(
+ edited_by = self.u31,
+ text = 'waaay even better question!',
+ comment = 'improved question',
+ )
+ notifications = get_re_notif_after(timestamp)
+ self.assertEqual(len(notifications), 1)
+ self.assertEqual(
+ set(notifications[0].receiving_users.all()),
+ set([self.u11, self.u12, self.u13, self.u14, self.u21])
+ )
+ self.reload_users()
+ self.assertEqual(
+ [
+ self.u11.response_count,
+ self.u12.response_count,
+ self.u13.response_count,
+ self.u14.response_count,
+ self.u21.response_count,
+ self.u22.response_count,
+ self.u23.response_count,
+ self.u24.response_count,
+ self.u31.response_count,
+ self.u32.response_count,
+ self.u33.response_count,
+ self.u34.response_count,
+ ],
+ [
+ 1, 1, 1, 1,
+ 1, 0, 0, 0,
+ 0, 0, 0, 0,
+ ]
+ )
+
+ def test_answer_edit(self):
+ """
+ """
+ self.reset_response_counts()
+ time.sleep(1)
+ timestamp = datetime.datetime.now()
+ self.answer1.apply_edit(
+ edited_by = self.u24,
+ text = 'waaay better answer!',
+ comment = 'improved answer1',
+ )
+ notifications = get_re_notif_after(timestamp)
+ self.assertEqual(len(notifications), 1)
+ self.assertEqual(
+ set(notifications[0].receiving_users.all()),
+ set(
+ [
+ self.u11, self.u12, self.u13,
+ self.u21, self.u22, self.u23,
+ self.u31
+ ]
+ )
+ )
+ self.reload_users()
+ self.assertEqual(
+ [
+ self.u11.response_count,
+ self.u12.response_count,
+ self.u13.response_count,
+ self.u14.response_count,
+ self.u21.response_count,
+ self.u22.response_count,
+ self.u23.response_count,
+ self.u24.response_count,
+ self.u31.response_count,
+ self.u32.response_count,
+ self.u33.response_count,
+ self.u34.response_count,
+ ],
+ [
+ 1, 1, 1, 0,
+ 1, 1, 1, 0,
+ 1, 0, 0, 0,
+ ]
+ )
+
+ def test_new_answer(self):
+ self.reset_response_counts()
+ time.sleep(1)
+ timestamp = datetime.datetime.now()
+ self.answer3 = Answer.objects.create_new(
+ question = self.question,
+ author = self.u11,
+ added_at = timestamp,
+ text = 'answer3'
+ )
+ time_end = datetime.datetime.now()
+ notifications = get_re_notif_after(timestamp)
+ self.assertEqual(len(notifications), 1)
+ self.assertEqual(
+ set(notifications[0].receiving_users.all()),
+ set(
+ [
+ self.u12, self.u13,
+ self.u21, self.u31
+ ]
+ )
+ )
+ self.reload_users()
+ self.assertEqual(
+ [
+ self.u11.response_count,
+ self.u12.response_count,
+ self.u13.response_count,
+ self.u14.response_count,
+ self.u21.response_count,
+ self.u22.response_count,
+ self.u23.response_count,
+ self.u24.response_count,
+ self.u31.response_count,
+ self.u32.response_count,
+ self.u33.response_count,
+ self.u34.response_count,
+ ],
+ [
+ 0, 1, 1, 0,
+ 1, 0, 0, 0,
+ 1, 0, 0, 0,
+ ]
+ )
+ self.reset_response_counts()
+ time.sleep(1)
+ timestamp = datetime.datetime.now()
+ self.answer3 = Answer.objects.create_new(
+ question = self.question,
+ author = self.u31,
+ added_at = timestamp,
+ text = 'answer4'
+ )
+ notifications = get_re_notif_after(timestamp)
+ self.assertEqual(len(notifications), 1)
+ self.assertEqual(
+ set(notifications[0].receiving_users.all()),
+ set(
+ [
+ self.u11, self.u12, self.u13,
+ self.u21
+ ]
+ )
+ )
+ self.reload_users()
+ self.assertEqual(
+ [
+ self.u11.response_count,
+ self.u12.response_count,
+ self.u13.response_count,
+ self.u14.response_count,
+ self.u21.response_count,
+ self.u22.response_count,
+ self.u23.response_count,
+ self.u24.response_count,
+ self.u31.response_count,
+ self.u32.response_count,
+ self.u33.response_count,
+ self.u34.response_count,
+ ],
+ [
+ 1, 1, 1, 0,
+ 1, 0, 0, 0,
+ 0, 0, 0, 0,
+ ]
+ )
+
+
+class AnonymousVisitorTests(TestCase):
+ fixtures = ['tmp/fixture1.json', ]
+
+ def test_index(self):
+ #todo: merge this with all reader url tests
+ print 'trying to reverse index'
+ response = self.client.get(reverse('index'), follow=True)
+ self.assertEqual(response.status_code, 200)
+ self.failUnless(len(response.redirect_chain) == 1)
+ self.failUnless(response.redirect_chain[0][0].endswith('/questions/'))
+ c = response.context[0]
+ t = response.template[0]
+ self.assertEqual(t.name, 'questions.html')
+ print 'index works'
+
+ def test_reader_urls(self):
+ """test all reader views thoroughly
+ on non-crashiness (no correcteness tests here)
+ """
+
+ def try_url(
+ url_name, status_code=200, template=None,
+ kwargs={}, redirect_url=None, follow=False,
+ data = {}
+ ):
+ url = reverse(url_name, kwargs = kwargs)
+ url_info = 'getting url %s' % url
+ if data:
+ url_info += '?' + '&'.join(['%s=%s' % (k, v) for k, v in data.iteritems()])
+ print url_info
+
+ r = self.client.get(url, data=data, follow=follow)
+ if hasattr(self.client, 'redirect_chain'):
+ print 'redirect chain: %s' % ','.join(self.client.redirect_chain)
+
+ self.assertEqual(r.status_code, status_code)
+
+ if template:
+ #asuming that there is more than one template
+ print 'templates are %s' % ','.join([t.name for t in r.template])
+ self.assertEqual(r.template[0].name, template)
+
+ try_url('sitemap')
+ try_url('about', template='about.html')
+ try_url('privacy', template='privacy.html')
+ try_url('logout', template='logout.html')
+ try_url('user_signin', template='authopenid/signin.html')
+ #todo: test different tabs
+ try_url('tags', template='tags.html')
+ try_url('tags', data={'sort':'name'}, template='tags.html')
+ try_url('tags', data={'sort':'used'}, template='tags.html')
+ try_url('badges', template='badges.html')
+ try_url(
+ 'answer_revisions',
+ template='revisions_answer.html',
+ kwargs={'id':38}
+ )
+ #todo: test different sort methods and scopes
+ try_url(
+ 'questions',
+ template='questions.html'
+ )
+ try_url(
+ 'questions',
+ data={'start_over':'true'},
+ template='questions.html'
+ )
+ try_url(
+ 'questions',
+ data={'scope':'unanswered'},
+ template='questions.html'
+ )
+ try_url(
+ 'questions',
+ data={'scope':'all'},
+ template='questions.html'
+ )
+ try_url(
+ 'questions',
+ data={'scope':'favorite'},
+ template='questions.html'
+ )
+ try_url(
+ 'questions',
+ data={'scope':'unanswered', 'sort':'latest'},
+ template='questions.html'
+ )
+ try_url(
+ 'questions',
+ data={'scope':'unanswered', 'sort':'oldest'},
+ template='questions.html'
+ )
+ try_url(
+ 'questions',
+ data={'scope':'unanswered', 'sort':'active'},
+ template='questions.html'
+ )
+ try_url(
+ 'questions',
+ data={'scope':'unanswered', 'sort':'inactive'},
+ template='questions.html'
+ )
+ try_url(
+ 'questions',
+ data={'sort':'hottest'},
+ template='questions.html'
+ )
+ try_url(
+ 'questions',
+ data={'sort':'coldest'},
+ template='questions.html'
+ )
+ try_url(
+ 'questions',
+ data={'sort':'mostvoted'},
+ template='questions.html'
+ )
+ try_url(
+ 'questions',
+ data={'sort':'leastvoted'},
+ template='questions.html'
+ )
+ try_url(
+ 'question',
+ kwargs={'id':1},
+ )
+ try_url(
+ 'question',
+ kwargs={'id':2},
+ )
+ try_url(
+ 'question',
+ kwargs={'id':3},
+ )
+ try_url(
+ 'question_revisions',
+ kwargs={'id':17},
+ template='revisions_question.html'
+ )
+ try_url('users', template='users.html')
+ #todo: really odd naming conventions for sort methods
+ try_url(
+ 'users',
+ template='users.html',
+ data={'sort':'reputation'},
+ )
+ try_url(
+ 'users',
+ template='users.html',
+ data={'sort':'newest'},
+ )
+ try_url(
+ 'users',
+ template='users.html',
+ data={'sort':'last'},
+ )
+ try_url(
+ 'users',
+ template='users.html',
+ data={'sort':'user'},
+ )
+ try_url(
+ 'users',
+ template='users.html',
+ data={'sort':'reputation', 'page':2},
+ )
+ try_url(
+ 'users',
+ template='users.html',
+ data={'sort':'newest', 'page':2},
+ )
+ try_url(
+ 'users',
+ template='users.html',
+ data={'sort':'last', 'page':2},
+ )
+ try_url(
+ 'users',
+ template='users.html',
+ data={'sort':'user', 'page':2},
+ )
+ try_url(
+ 'users',
+ template='users.html',
+ data={'sort':'reputation', 'page':1},
+ )
+ try_url(
+ 'users',
+ template='users.html',
+ data={'sort':'newest', 'page':1},
+ )
+ try_url(
+ 'users',
+ template='users.html',
+ data={'sort':'last', 'page':1},
+ )
+ try_url(
+ 'users',
+ template='users.html',
+ data={'sort':'user', 'page':1},
+ )
+ try_url(
+ 'edit_user',
+ template='authopenid/signin.html',
+ kwargs={'id':4},
+ status_code=200,
+ follow=True,
+ )
+ user = User.objects.get(id=2)
+ name_slug = defaultfilters.slugify(user.username)
+ try_url(
+ 'user_profile',
+ kwargs={'id': 2, 'slug': name_slug},
+ data={'sort':'stats'},
+ template='user_stats.html'
+ )
+ try_url(
+ 'user_profile',
+ kwargs={'id': 2, 'slug': name_slug},
+ data={'sort':'recent'},
+ template='user_recent.html'
+ )
+ try_url(
+ 'user_profile',
+ kwargs={'id': 2, 'slug': name_slug},
+ data={'sort':'responses'},
+ status_code=404,
+ template='404.html'
+ )
+ try_url(
+ 'user_profile',
+ kwargs={'id': 2, 'slug': name_slug},
+ data={'sort':'reputation'},
+ template='user_reputation.html'
+ )
+ try_url(
+ 'user_profile',
+ kwargs={'id': 2, 'slug': name_slug},
+ data={'sort':'votes'},
+ status_code=404,
+ template='404.html'
+ )
+ try_url(
+ 'user_profile',
+ kwargs={'id': 2, 'slug': name_slug},
+ data={'sort':'favorites'},
+ template='user_favorites.html'
+ )
+ try_url(
+ 'user_profile',
+ kwargs={'id': 2, 'slug': name_slug},
+ data={'sort':'email_subscriptions'},
+ status_code=404,
+ template='404.html'
+ )
diff --git a/askbot/upfiles/README b/askbot/upfiles/README
new file mode 100644
index 00000000..097ee8a5
--- /dev/null
+++ b/askbot/upfiles/README
@@ -0,0 +1,3 @@
+this directory is empty
+it is copied at deployment time to some other
+location where it will hold user uploaded files
diff --git a/askbot/urls.py b/askbot/urls.py
new file mode 100644
index 00000000..c538df3b
--- /dev/null
+++ b/askbot/urls.py
@@ -0,0 +1,204 @@
+"""
+askbot askbot url configuraion file
+"""
+import os.path
+from django.conf.urls.defaults import url, patterns, include
+from django.conf.urls.defaults import handler500, handler404
+from django.contrib import admin
+from askbot import views as app
+from askbot.feed import RssLastestQuestionsFeed
+from askbot.sitemap import QuestionsSitemap
+from django.utils.translation import ugettext as _
+from django.conf import settings
+
+admin.autodiscover()
+feeds = {
+ 'rss': RssLastestQuestionsFeed
+}
+sitemaps = {
+ 'questions': QuestionsSitemap
+}
+
+APP_PATH = os.path.dirname(__file__)
+urlpatterns = patterns('',
+ url(r'^$', app.readers.index, name='index'),
+ url(
+ r'^sitemap.xml$',
+ 'django.contrib.sitemaps.views.sitemap',
+ {'sitemaps': sitemaps},
+ name='sitemap'
+ ),
+ url(
+ r'^m/(?P<path>.*)$',
+ 'django.views.static.serve',
+ {'document_root': os.path.join(APP_PATH,'skins').replace('\\','/')},
+ name='askbot_media',
+ ),
+ url(
+ r'^%s(?P<path>.*)$' % _('upfiles/'),
+ 'django.views.static.serve',
+ {'document_root': os.path.join(settings.PROJECT_ROOT, 'askbot', 'upfiles').replace('\\','/')},
+ name='uploaded_file',
+ ),
+ url(r'^%s$' % _('about/'), app.meta.about, name='about'),
+ url(r'^%s$' % _('faq/'), app.meta.faq, name='faq'),
+ url(r'^%s$' % _('privacy/'), app.meta.privacy, name='privacy'),
+ url(r'^%s$' % _('logout/'), app.meta.logout, name='logout'),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('comments/')),
+ app.writers.answer_comments,
+ name='answer_comments'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('edit/')),
+ app.writers.edit_answer,
+ name='edit_answer'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('revisions/')),
+ app.readers.answer_revisions,
+ name='answer_revisions'
+ ),
+ url(
+ r'^%s$' % _('questions/'),
+ app.readers.questions,
+ name='questions'
+ ),
+ url(
+ r'^%s%s$' % (_('questions/'), _('ask/')),
+ app.writers.ask,
+ name='ask'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('edit/')),
+ app.writers.edit_question,
+ name='edit_question'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('close/')),
+ app.commands.close,
+ name='close'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('reopen/')),
+ app.commands.reopen,
+ name='reopen'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('answer/')),
+ app.writers.answer,
+ name='answer'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('vote/')),
+ app.commands.vote,
+ name='vote'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('revisions/')),
+ app.readers.question_revisions,
+ name='question_revisions'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('comments/')),
+ app.writers.question_comments,
+ name='question_comments'
+ ),
+ url(
+ r'^%s$' % _('command/'),
+ app.commands.ajax_command,
+ name='call_ajax'
+ ),
+ url(
+ r'^%s(?P<object_id>\d+)/%s(?P<comment_id>\d+)/%s$'\
+ % (_('questions/'), _('comments/'),_('delete/')),
+ app.writers.delete_comment,
+ kwargs={'commented_object_type':'question'},
+ name='delete_question_comment'
+ ),
+ url(
+ r'^%s(?P<object_id>\d+)/%s(?P<comment_id>\d+)/%s$'\
+ % (_('answers/'), _('comments/'),_('delete/')),
+ app.writers.delete_comment,
+ kwargs={'commented_object_type':'answer'},
+ name='delete_answer_comment'
+ ),
+ #place general question item in the end of other operations
+ url(
+ r'^%s(?P<id>\d+)/' % _('question/'),
+ app.readers.question,
+ name='question'
+ ),
+ url(
+ r'^%s$' % _('tags/'),
+ app.readers.tags,
+ name='tags'
+ ),
+ url(
+ r'^%s%s(?P<tag>[^/]+)/$' % (_('mark-tag/'),_('interesting/')),
+ app.commands.mark_tag,
+ kwargs={'reason':'good','action':'add'},
+ name='mark_interesting_tag'
+ ),
+ url(
+ r'^%s%s(?P<tag>[^/]+)/$' % (_('mark-tag/'),_('ignored/')),
+ app.commands.mark_tag,
+ kwargs={'reason':'bad','action':'add'},
+ name='mark_ignored_tag'
+ ),
+ url(
+ r'^%s(?P<tag>[^/]+)/$' % _('unmark-tag/'),
+ app.commands.mark_tag,
+ kwargs={'action':'remove'},
+ name='mark_ignored_tag'
+ ),
+ url(
+ r'^%s$' % _('users/'),
+ app.users.users,
+ name='users'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/$' % _('moderate-user/'),
+ app.users.moderate_user,
+ name='moderate_user'
+ ),
+ #todo: rename as user_edit, b/c that's how template is named
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('users/'), _('edit/')),
+ app.users.edit_user,
+ name='edit_user'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/(?P<slug>.+)/$' % _('users/'),
+ app.users.user,
+ name='user_profile'
+ ),
+ url(
+ r'^%s$' % _('badges/'),
+ app.meta.badges,
+ name='badges'
+ ),
+ url(
+ r'^%s(?P<id>\d+)//*' % _('badges/'),
+ app.meta.badge,
+ name='badge'
+ ),
+ url(
+ r'^%s%s$' % (_('messages/'), _('markread/')),
+ app.commands.read_message,
+ name='read_message'
+ ),
+ #(r'^admin/doc/' % _('admin/doc'),include('django.contrib.admindocs.urls')),
+ url(
+ r'^feeds/(?P<url>.*)/$',
+ 'django.contrib.syndication.views.feed',
+ {'feed_dict': feeds},
+ name='feeds'
+ ),
+ url( r'^%s$' % _('upload/'), app.writers.upload, name='upload'),
+ url(r'^%s$' % _('search/'), app.readers.search, name='search'),
+ url(r'^%s$' % _('feedback/'), app.meta.feedback, name='feedback'),
+ (r'^%s' % _('account/'), include('askbot.deps.django_authopenid.urls')),
+ (r'^i18n/', include('django.conf.urls.i18n')),
+ url(r'^feeds/rss/$', RssLastestQuestionsFeed, name="latest_questions_feed"),
+)
diff --git a/forum/user_messages/__init__.py b/askbot/user_messages/__init__.py
index 0136c888..0136c888 100755..100644
--- a/forum/user_messages/__init__.py
+++ b/askbot/user_messages/__init__.py
diff --git a/forum/user_messages/context_processors.py b/askbot/user_messages/context_processors.py
index 5f7b857c..f4c5e3ac 100755..100644
--- a/forum/user_messages/context_processors.py
+++ b/askbot/user_messages/context_processors.py
@@ -6,7 +6,7 @@ Time-stamp: <2008-07-19 23:16:19 carljm context_processors.py>
"""
from django.utils.encoding import StrAndUnicode
-from forum.user_messages import get_and_delete_messages
+from askbot.user_messages import get_and_delete_messages
def user_messages (request):
"""
@@ -52,4 +52,3 @@ class LazyMessages (StrAndUnicode):
self._messages = get_and_delete_messages(self.request)
return self._messages
messages = property(_get_messages)
-
diff --git a/forum_modules/pgfulltext/DISABLED b/askbot/utils/__init__.py
index e69de29b..e69de29b 100644
--- a/forum_modules/pgfulltext/DISABLED
+++ b/askbot/utils/__init__.py
diff --git a/forum/utils/cache.py b/askbot/utils/cache.py
index 6341392e..805cfe11 100755..100644
--- a/forum/utils/cache.py
+++ b/askbot/utils/cache.py
@@ -3,7 +3,7 @@ import itertools
from django.contrib.contenttypes.models import ContentType
-from forum.utils.lists import flatten
+from askbot.utils.lists import flatten
def fetch_model_dict(model, ids, fields=None):
"""
diff --git a/forum/utils/colors.py b/askbot/utils/colors.py
index 8ab092d7..7385d06c 100644
--- a/forum/utils/colors.py
+++ b/askbot/utils/colors.py
@@ -1,7 +1,7 @@
-from forum_modules.grapefruit import Color
+from askbot.deps.grapefruit import Color
import math
-def get_counter_colors(count, max=10, empty_bg='white', empty_fg='black',
+def get_counter_colors(count, counter_max=10, empty_bg='white', empty_fg='black',
zero_bg='white', zero_fg='black',
min_bg='white', min_fg='black',
max_bg='white', max_fg='black'
@@ -9,11 +9,11 @@ def get_counter_colors(count, max=10, empty_bg='white', empty_fg='black',
if count == 0:
return zero_fg, zero_bg
- if count > max:
+ if count > counter_max:
blend_factor = 0
else:
#todo deal with negative counts properly
- blend_factor = 1 - math.fabs(float(count)/float(max))
+ blend_factor = 1 - math.fabs(float(count)/float(counter_max))
max_fg_color = Color.NewFromHtml(max_fg)
fg = Color.NewFromHtml(min_fg).Blend(max_fg_color, blend_factor)
diff --git a/forum/utils/decorators.py b/askbot/utils/decorators.py
index 440e8312..440e8312 100755..100644
--- a/forum/utils/decorators.py
+++ b/askbot/utils/decorators.py
diff --git a/forum/utils/diff.py b/askbot/utils/diff.py
index d741d788..d741d788 100755..100644
--- a/forum/utils/diff.py
+++ b/askbot/utils/diff.py
diff --git a/forum/utils/email.py b/askbot/utils/email.py
index dc712572..8f719e82 100755..100644
--- a/forum/utils/email.py
+++ b/askbot/utils/email.py
@@ -1,4 +1,4 @@
-from django.core.mail import send_mail, EmailMultiAlternatives
+from django.core.mail import EmailMultiAlternatives
from django.conf import settings
from django.template import loader, Context
from django.utils.html import strip_tags
diff --git a/forum/utils/forms.py b/askbot/utils/forms.py
index d8d04d05..a480419e 100755..100644
--- a/forum/utils/forms.py
+++ b/askbot/utils/forms.py
@@ -3,8 +3,10 @@ import re
from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe
from django.conf import settings
+from askbot.conf import settings as askbot_settings
from django.http import str_to_unicode
from django.contrib.auth.models import User
+from askbot import const
import logging
import urllib
@@ -37,7 +39,6 @@ class NextUrlField(forms.CharField):
return clean_next(value)
login_form_widget_attrs = { 'class': 'required login' }
-username_re = re.compile(r'^[\w ]+$')
class UserNameField(StrippedNonEmptyCharField):
RESERVED_NAMES = (u'fuck', u'shit', u'ass', u'sex', u'add',
@@ -47,6 +48,7 @@ class UserNameField(StrippedNonEmptyCharField):
self.skip_clean = skip_clean
self.db_model = db_model
self.db_field = db_field
+ self.user_instance = None
error_messages={'required':_('user name is required'),
'taken':_('sorry, this name is taken, please choose another'),
'forbidden':_('sorry, this name is not allowed, please choose another'),
@@ -69,15 +71,22 @@ class UserNameField(StrippedNonEmptyCharField):
if self.skip_clean == True:
logging.debug('username accepted with no validation')
return username
- if hasattr(self, 'user_instance') and isinstance(self.user_instance, User):
+ if self.user_instance is None:
+ pass
+ elif isinstance(self.user_instance, User):
if username == self.user_instance.username:
logging.debug('username valid')
return username
+ else:
+ raise TypeError('user instance must be of type User')
+
try:
username = super(UserNameField, self).clean(username)
except forms.ValidationError:
raise forms.ValidationError(self.error_messages['required'])
- if self.required and not username_re.search(username):
+
+ username_regex = re.compile(const.USERNAME_REGEX_STRING)
+ if self.required and not username_regex.search(username):
raise forms.ValidationError(self.error_messages['invalid'])
if username in self.RESERVED_NAMES:
raise forms.ValidationError(self.error_messages['forbidden'])
@@ -121,7 +130,7 @@ class UserEmailField(forms.EmailField):
email = super(UserEmailField,self).clean(email.strip())
if self.skip_clean:
return email
- if settings.EMAIL_UNIQUE == True:
+ if askbot_settings.EMAIL_UNIQUE == True:
try:
user = User.objects.get(email = email)
logging.debug('email taken')
diff --git a/askbot/utils/functions.py b/askbot/utils/functions.py
new file mode 100644
index 00000000..7d886a2a
--- /dev/null
+++ b/askbot/utils/functions.py
@@ -0,0 +1,45 @@
+import re
+
+def get_from_dict_or_object(source, key):
+ try:
+ return source[key]
+ except:
+ return getattr(source,key)
+
+
+def is_iterable(thing):
+ if hasattr(thing, '__iter__'):
+ return True
+ else:
+ return isinstance(thing, basestring)
+
+BOT_REGEX = re.compile(
+ r'bot|http|\.com|crawl|spider|python|curl|yandex'
+)
+BROWSER_REGEX = re.compile(
+ r'^(Mozilla.*(Gecko|KHTML|MSIE|Presto|Trident)|Opera).*$'
+)
+MOBILE_REGEX = re.compile(
+ r'(BlackBerry|HTC|LG|MOT|Nokia|NOKIAN|PLAYSTATION|PSP|SAMSUNG|SonyEricsson)'
+)
+
+
+def not_a_robot_request(request):
+
+ if 'HTTP_ACCEPT_LANGUAGE' not in request.META:
+ return False
+
+ user_agent = request.META.get('HTTP_USER_AGENT', None)
+ if user_agent is None:
+ return False
+
+ if BOT_REGEX.match(user_agent, re.IGNORECASE):
+ return False
+
+ if MOBILE_REGEX.match(user_agent):
+ return True
+
+ if BROWSER_REGEX.search(user_agent):
+ return True
+
+ return False
diff --git a/forum/utils/html.py b/askbot/utils/html.py
index 25a74a4a..25a74a4a 100755..100644
--- a/forum/utils/html.py
+++ b/askbot/utils/html.py
diff --git a/forum/utils/lists.py b/askbot/utils/lists.py
index f69c8f20..f69c8f20 100755..100644
--- a/forum/utils/lists.py
+++ b/askbot/utils/lists.py
diff --git a/askbot/utils/markup.py b/askbot/utils/markup.py
new file mode 100644
index 00000000..85e37393
--- /dev/null
+++ b/askbot/utils/markup.py
@@ -0,0 +1,112 @@
+from askbot import const
+
+def format_mention_in_html(mentioned_user):
+ url = mentioned_user.get_profile_url()
+ username = mentioned_user.username
+ return '<a href="%s">@%s</a>' % (url, username)
+
+def extract_first_matching_mentioned_author(text, anticipated_authors):
+
+ if len(text) == 0:
+ return None, ''
+
+ for a in anticipated_authors:
+ if text.startswith(a.username):
+ ulen = len(a.username)
+ if len(text) == ulen:
+ text = ''
+ elif text[ulen] in const.TWITTER_STYLE_MENTION_TERMINATION_CHARS:
+ text = text[ulen:]
+ else:
+ #near miss, here we could insert a warning that perhaps
+ #a termination character is needed
+ continue
+ return a, text
+ return None, text
+
+def extract_mentioned_name_seeds(text):
+ extra_name_seeds = set()
+ while '@' in text:
+ pos = text.index('@')
+ text = text[pos+1:]#chop off prefix
+ name_seed = ''
+ for c in text:
+ if c in const.TWITTER_STYLE_MENTION_TERMINATION_CHARS:
+ extra_name_seeds.add(name_seed)
+ name_seed = ''
+ break
+ if len(name_seed) > 10:
+ extra_name_seeds.add(name_seed)
+ name_seed = ''
+ break
+ if c == '@':
+ if len(name_seed) > 0:
+ extra_name_seeds.add(name_seed)
+ name_seed = ''
+ break
+ name_seed += c
+ if len(name_seed) > 0:
+ #in case we run off the end of text
+ extra_name_seeds.add(name_seed)
+
+ return extra_name_seeds
+
+def mentionize_text(text, anticipated_authors):
+ output = ''
+ mentioned_authors = list()
+ while '@' in text:
+ #the purpose of this loop is to convert any occurance of
+ #'@mention ' syntax
+ #to user account links leading space is required unless @ is the first
+ #character in whole text, also, either a punctuation or
+ #a ' ' char is required after the name
+ pos = text.index('@')
+
+ #save stuff before @mention to the output
+ output += text[:pos]#this works for pos == 0 too
+
+ if len(text) == pos + 1:
+ #finish up if the found @ is the last symbol
+ output += '@'
+ text = ''
+ break
+
+ if pos > 0:
+
+ if text[pos-1] in const.TWITTER_STYLE_MENTION_TERMINATION_CHARS:
+ #if there is a termination character before @mention
+ #indeed try to find a matching person
+ text = text[pos+1:]
+ mentioned_author, text = \
+ extract_first_matching_mentioned_author(
+ text,
+ anticipated_authors
+ )
+ if mentioned_author:
+ mentioned_authors.append(mentioned_author)
+ output += format_mention_in_html(mentioned_author)
+ else:
+ output += '@'
+
+ else:
+ #if there isn't, i.e. text goes like something@mention,
+ #do not look up people
+ output += '@'
+ text = text[pos+1:]
+ else:
+ #do this if @ is the first character
+ text = text[1:]
+ mentioned_author, text = \
+ extract_first_matching_mentioned_author(
+ text,
+ anticipated_authors
+ )
+ if mentioned_author:
+ mentioned_authors.append(mentioned_author)
+ output += format_mention_in_html(mentioned_author)
+ else:
+ output += '@'
+
+ #append the rest of text that did not have @ symbols
+ output += text
+ return mentioned_authors, output
diff --git a/forum/utils/time.py b/askbot/utils/time.py
index 39e01d0f..39e01d0f 100755..100644
--- a/forum/utils/time.py
+++ b/askbot/utils/time.py
diff --git a/forum/views/README b/askbot/views/README
index 5416f88c..5416f88c 100755
--- a/forum/views/README
+++ b/askbot/views/README
diff --git a/askbot/views/__init__.py b/askbot/views/__init__.py
new file mode 100644
index 00000000..35b2acba
--- /dev/null
+++ b/askbot/views/__init__.py
@@ -0,0 +1,8 @@
+"""
+Forum views module
+"""
+from askbot.views import readers
+from askbot.views import writers
+from askbot.views import commands
+from askbot.views import users
+from askbot.views import meta
diff --git a/forum/views/commands.py b/askbot/views/commands.py
index 39b34d13..4e4347f2 100755..100644
--- a/forum/views/commands.py
+++ b/askbot/views/commands.py
@@ -1,16 +1,19 @@
import datetime
+#todo: maybe eliminate usage of django.settings
from django.conf import settings
+from askbot.conf import settings as askbot_settings
from django.utils import simplejson
from django.http import HttpResponse, HttpResponseRedirect
+from django.http import HttpResponseForbidden
from django.shortcuts import get_object_or_404, render_to_response
from django.utils.translation import ugettext as _
from django.template import RequestContext
-from forum.models import *
-from forum.forms import CloseForm
-from forum import auth
+from askbot.models import *
+from askbot.forms import CloseForm
+from askbot import auth
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
-from forum.utils.decorators import ajax_method, ajax_login_required
+from askbot.utils.decorators import ajax_method, ajax_login_required
import logging
def vote(request, id):#todo: pretty incomprehensible view used by various ajax calls
@@ -138,7 +141,8 @@ def vote(request, id):#todo: pretty incomprehensible view used by various ajax c
vote = post.votes.filter(user=request.user)[0]
# get latest vote by the current user
# unvote should be less than certain time
- if (datetime.datetime.now().day - vote.voted_at.day) >= auth.VOTE_RULES['scope_deny_unvote_days']:
+ if (datetime.datetime.now().day - vote.voted_at.day) \
+ >= askbot_settings.MAX_DAYS_TO_CANCEL_VOTE:
response_data['status'] = 2
else:
voted = vote.vote
@@ -152,7 +156,8 @@ def vote(request, id):#todo: pretty incomprehensible view used by various ajax c
response_data['status'] = 1
response_data['count'] = post.score
- elif Vote.objects.get_votes_count_today_from_user(request.user) >= auth.VOTE_RULES['scope_votes_per_user_per_day']:
+ elif Vote.objects.get_votes_count_today_from_user(request.user)\
+ >= askbot_settings.MAX_VOTES_PER_USER_PER_DAY:
response_data['allowed'] = -3
else:
vote = Vote(user=request.user, content_object=post, vote=vote_score, voted_at=datetime.datetime.now())
@@ -163,8 +168,10 @@ def vote(request, id):#todo: pretty incomprehensible view used by various ajax c
# downvote
auth.onDownVoted(vote, post, request.user)
- votes_left = auth.VOTE_RULES['scope_votes_per_user_per_day'] - Vote.objects.get_votes_count_today_from_user(request.user)
- if votes_left <= auth.VOTE_RULES['scope_warn_votes_left']:
+ votes_left = askbot_settings.MAX_VOTES_PER_USER_PER_DAY \
+ - Vote.objects.get_votes_count_today_from_user(request.user)
+ if votes_left <= \
+ askbot_settings.VOTES_LEFT_WARNING_THRESHOLD:
response_data['message'] = u'%s votes left' % votes_left
response_data['count'] = post.score
elif vote_type in ['7', '8']:
@@ -174,7 +181,7 @@ def vote(request, id):#todo: pretty incomprehensible view used by various ajax c
post_id = request.POST.get('postId')
post = get_object_or_404(Answer, id=post_id)
- if FlaggedItem.objects.get_flagged_items_count_today(request.user) >= auth.VOTE_RULES['scope_flags_per_user_per_day']:
+ if FlaggedItem.objects.get_flagged_items_count_today(request.user) >= askbot_settings.MAX_FLAGS_PER_USER_PER_DAY:
response_data['allowed'] = -3
elif not auth.can_flag_offensive(request.user):
response_data['allowed'] = -2
@@ -204,7 +211,9 @@ def vote(request, id):#todo: pretty incomprehensible view used by various ajax c
if user.is_authenticated():
if user not in question.followed_by.all():
question.followed_by.add(user)
- if settings.EMAIL_VALIDATION == 'on' and user.email_isvalid == False:
+ if askbot_settings.EMAIL_VALIDATION == True \
+ and user.email_isvalid == False:
+
response_data['message'] = \
_('subscription saved, %(email)s needs validation, see %(details_url)s') \
% {'email':user.email,'details_url':reverse('faq') + '#validate'}
@@ -268,7 +277,9 @@ def ajax_toggle_ignored_questions(request):#ajax tagging and tag-filtering syste
request.user.save()
@ajax_method
-def ajax_command(request):#refactor? view processing ajax commands - note "vote" and view others do it too
+def ajax_command(request):
+ """view processing ajax commands - note "vote" and view others do it too
+ """
if 'command' not in request.POST:
return HttpResponseForbidden(mimetype="application/json")
if request.POST['command'] == 'toggle-ignored-questions':
diff --git a/forum/views/meta.py b/askbot/views/meta.py
index af5fe6df..564b11e6 100755..100644
--- a/forum/views/meta.py
+++ b/askbot/views/meta.py
@@ -2,12 +2,12 @@ from django.shortcuts import render_to_response, get_object_or_404
from django.core.urlresolvers import reverse
from django.template import RequestContext
from django.http import HttpResponseRedirect, HttpResponse
-from forum.forms import FeedbackForm
+from askbot.forms import FeedbackForm
from django.core.urlresolvers import reverse
from django.core.mail import mail_admins
from django.utils.translation import ugettext as _
-from forum.utils.forms import get_next_url
-from forum.models import Badge, Award
+from askbot.utils.forms import get_next_url
+from askbot.models import Badge, Award
def about(request):
return render_to_response('about.html', context_instance=RequestContext(request))
@@ -52,7 +52,7 @@ def logout(request):#refactor/change behavior?
#I guess rationale was to tell the user that s/he may be still logged in
#through their external login sytem and we'd want to remind them about it
#however it might be a little annoying
-#why not just show a message: you are logged out of askbot, but
+#why not just show a message: you are logged out of forum, but
#if you really want to log out -> go to your openid provider
return render_to_response('logout.html', {
'view_name':'logout',
diff --git a/forum/views/readers.py b/askbot/views/readers.py
index cd3832d3..f719fd4f 100644
--- a/forum/views/readers.py
+++ b/askbot/views/readers.py
@@ -15,20 +15,20 @@ from django.template.defaultfilters import slugify
from django.core.urlresolvers import reverse
from django.views.decorators.cache import cache_page
-from forum.utils.html import sanitize_html
+from askbot.utils.html import sanitize_html
from markdown2 import Markdown
#from lxml.html.diff import htmldiff
-from forum.utils.diff import textDiff as htmldiff
-from forum.forms import *
-from forum.models import *
-from forum.auth import *
-from forum import const
-from forum import auth
-from forum.utils.forms import get_next_url
-from forum.search.state_manager import SearchState
+from askbot.utils.diff import textDiff as htmldiff
+from askbot.forms import *
+from askbot.models import *
+from askbot import const
+from askbot import auth
+from askbot.utils.forms import get_next_url
+from askbot.utils.functions import not_a_robot_request
+from askbot.search.state_manager import SearchState
# used in index page
-#refactor - move these numbers somewhere?
+#todo: - take these out of const or settings
INDEX_PAGE_SIZE = 30
INDEX_AWARD_SIZE = 15
INDEX_TAGS_SIZE = 25
@@ -64,13 +64,10 @@ def index(request):#generates front page - shows listing of questions sorted in
"""
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):#a view generating listing of questions, used by 'unanswered' too
+def questions(request):
"""
List of Questions, Tagged questions, and Unanswered questions.
+ matching search query or user selection
"""
#don't allow to post to this view
@@ -183,11 +180,6 @@ def search(request): #generates listing of questions matching a search query - i
else:
raise Http404
-#todo: eliminate this - need to go through templates to make sure
-#that there are no urls pointing here
-def tag(request, tag):#stub generates listing of questions tagged with a single tag
- return questions(request, tagname=tag)
-
def tags(request):#view showing a listing of available tags - plain list
stag = ""
is_paginated = True
@@ -313,36 +305,91 @@ def question(request, id):#refactor - long subroutine. display question body, an
objects_list = Paginator(filtered_answers, ANSWERS_PAGE_SIZE)
page_objects = objects_list.page(page)
- #todo: merge view counts per user and per session
- #1) view count per session
- update_view_count = False
- if 'question_view_times' not in request.session:
- request.session['question_view_times'] = {}
-
- last_seen = request.session['question_view_times'].get(question.id,None)
- updated_when, updated_who = question.get_last_update_info()
-
- if updated_who != request.user:
- if last_seen:
- if last_seen < updated_when:
- update_view_count = True
- else:
- update_view_count = True
-
- request.session['question_view_times'][question.id] = datetime.datetime.now()
-
- if update_view_count:
- question.view_count += 1
- question.save()
+ if not_a_robot_request(request):
+ #todo: split this out into a subroutine
+ #todo: merge view counts per user and per session
+ #1) view count per session
+ update_view_count = False
+ if 'question_view_times' not in request.session:
+ request.session['question_view_times'] = {}
+
+ last_seen = request.session['question_view_times'].get(question.id,None)
+ updated_when, updated_who = question.get_last_update_info()
+
+ if updated_who != request.user:
+ if last_seen:
+ if last_seen < updated_when:
+ update_view_count = True
+ else:
+ update_view_count = True
+
+ request.session['question_view_times'][question.id] = \
+ datetime.datetime.now()
+ if update_view_count:
+ question.view_count += 1
+ question.save()
+
+ #2) question view count per user
+ if request.user.is_authenticated():
+ try:
+ question_view = QuestionView.objects.get(
+ who=request.user,
+ question=question
+ )
+ #another task - remove the response alert if it exists
+ ACTIVITY_TYPES = const.RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY
+ ACTIVITY_TYPES += (const.TYPE_ACTIVITY_MENTION,)
+ response_activities = Activity.objects.filter(
+ receiving_users = request.user,
+ activity_type__in = ACTIVITY_TYPES,
+ active_at__gt = question_view.when
+ )
+
+ for activity in response_activities:
+ post = activity.content_object
+ if hasattr(post, 'get_origin_post'):
+ if question == post.get_origin_post():
+ activity.receiving_users.remove(request.user)
+ if request.user.response_count > 0:
+ request.user.response_count -= 1
+ request.user.save()
+ else:
+ logging.critical(
+ 'response count wanted to go below zero'
+ )
+ else:
+ logging.critical(
+ 'activity content object has no get_origin_post method'
+ )
- #2) question view count per user
- if request.user.is_authenticated():
- try:
- question_view = QuestionView.objects.get(who=request.user, question=question)
- except QuestionView.DoesNotExist:
- question_view = QuestionView(who=request.user, question=question)
- question_view.when = datetime.datetime.now()
- question_view.save()
+ except QuestionView.DoesNotExist:
+ question_view = QuestionView(who=request.user, question=question)
+ #todo: cleanup this cut/paste
+ ACTIVITY_TYPES = const.RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY
+ ACTIVITY_TYPES += (const.TYPE_ACTIVITY_MENTION,)
+ response_activities = Activity.objects.filter(
+ receiving_users = request.user,
+ activity_type__in = ACTIVITY_TYPES,
+ )
+
+ for activity in response_activities:
+ post = activity.content_object
+ if hasattr(post, 'get_origin_post'):
+ if question == post.get_origin_post():
+ activity.receiving_users.remove(request.user)
+ if request.user.response_count > 0:
+ request.user.response_count -= 1
+ request.user.save()
+ else:
+ logging.critical(
+ 'response count wanted to go below zero'
+ )
+ else:
+ logging.critical(
+ 'activity content object has no get_origin_post method'
+ )
+ question_view.when = datetime.datetime.now()
+ question_view.save()
return render_to_response('question.html', {
'view_name': 'question',
diff --git a/forum/views/users.py b/askbot/views/users.py
index ed9b7992..3709ee78 100755..100644
--- a/forum/views/users.py
+++ b/askbot/views/users.py
@@ -1,32 +1,36 @@
from django.contrib.auth.decorators import login_required
-from django.contrib.auth.models import User
from django.core.paginator import Paginator, EmptyPage, InvalidPage
from django.template.defaultfilters import slugify
from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
-from django.http import HttpResponse, HttpResponseForbidden, HttpResponseRedirect, Http404
+from django.http import HttpResponse, HttpResponseForbidden
+from django.http import HttpResponseRedirect, Http404
from django.utils.translation import ugettext as _
-from django.utils.http import urlquote_plus
from django.utils.html import strip_tags
from django.utils import simplejson
-from django.core.urlresolvers import reverse
-from forum.forms import *#incomplete list is EditUserForm, ModerateUserForm, TagFilterSelectionForm,
-from forum.utils.html import sanitize_html
-from forum import auth
+from askbot.utils.html import sanitize_html
+from askbot import auth
+from askbot import forms
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)
-answer_type = ContentType.objects.get_for_model(Answer)
-comment_type = ContentType.objects.get_for_model(Comment)
-question_revision_type = ContentType.objects.get_for_model(QuestionRevision)
-answer_revision_type = ContentType.objects.get_for_model(AnswerRevision)
-repute_type = ContentType.objects.get_for_model(Repute)
+from askbot import const
+from askbot.conf import settings as askbot_settings
+from askbot import models
+from askbot.models import signals
+import logging
+
+question_type = ContentType.objects.get_for_model(models.Question)
+answer_type = ContentType.objects.get_for_model(models.Answer)
+comment_type = ContentType.objects.get_for_model(models.Comment)
+question_revision_type = ContentType.objects.get_for_model(
+ models.QuestionRevision
+ )
+
+answer_revision_type = ContentType.objects.get_for_model(
+ models.AnswerRevision
+ )
+repute_type = ContentType.objects.get_for_model(models.Repute)
question_type_id = question_type.id
answer_type_id = answer_type.id
comment_type_id = comment_type.id
@@ -45,43 +49,61 @@ def users(request):
if suser == "":
if sortby == "newest":
- objects_list = Paginator(User.objects.all().order_by('-date_joined'), USERS_PAGE_SIZE)
+ order_by_parameter = '-date_joined'
elif sortby == "last":
- objects_list = Paginator(User.objects.all().order_by('date_joined'), USERS_PAGE_SIZE)
+ order_by_parameter = 'date_joined'
elif sortby == "user":
- objects_list = Paginator(User.objects.all().order_by('username'), USERS_PAGE_SIZE)
- # default
+ order_by_parameter = 'username'
else:
- objects_list = Paginator(User.objects.all().order_by('-reputation'), USERS_PAGE_SIZE)
+ # default
+ order_by_parameter = '-reputation'
+
+ objects_list = Paginator(
+ models.User.objects.all().order_by(
+ order_by_parameter
+ ),
+ const.USERS_PAGE_SIZE
+ )
base_url = reverse('users') + '?sort=%s&' % sortby
else:
sortby = "reputation"
- objects_list = Paginator(User.objects.extra(where=['username like %s'], params=['%' + suser + '%']).order_by('-reputation'), USERS_PAGE_SIZE)
+ objects_list = Paginator(
+ models.User.objects.extra(
+ where=['username like %s'],
+ params=['%' + suser + '%']
+ ).order_by(
+ '-reputation'
+ ),
+ const.USERS_PAGE_SIZE
+ )
base_url = reverse('users') + '?name=%s&sort=%s&' % (suser, sortby)
try:
- users = objects_list.page(page)
+ users_page = objects_list.page(page)
except (EmptyPage, InvalidPage):
- users = objects_list.page(objects_list.num_pages)
-
- return render_to_response('users.html', {
- 'active_tab': 'users',
- 'users' : users,
- 'suser' : suser,
- 'keywords' : suser,
- 'tab_id' : sortby,
- 'context' : {
- 'is_paginated' : is_paginated,
- 'pages': objects_list.num_pages,
- 'page': page,
- 'has_previous': users.has_previous(),
- 'has_next': users.has_next(),
- 'previous': users.previous_page_number(),
- 'next': users.next_page_number(),
- 'base_url' : base_url
- }
-
- }, context_instance=RequestContext(request))
+ users_page = objects_list.page(objects_list.num_pages)
+
+ return render_to_response(
+ 'users.html',
+ {
+ 'active_tab': 'users',
+ 'users' : users_page,
+ 'suser' : suser,
+ 'keywords' : suser,
+ 'tab_id' : sortby,
+ 'context' : {
+ 'is_paginated' : is_paginated,
+ 'pages': objects_list.num_pages,
+ 'page': page,
+ 'has_previous': users_page.has_previous(),
+ 'has_next': users_page.has_next(),
+ 'previous': users_page.previous_page_number(),
+ 'next': users_page.next_page_number(),
+ 'base_url' : base_url
+ }
+ },
+ context_instance=RequestContext(request)
+ )
@login_required
def moderate_user(request, id):
@@ -92,13 +114,16 @@ def moderate_user(request, id):
if not request.is_ajax():
return HttpResponseForbidden(mimetype="application/json")
- user = get_object_or_404(User, id=id)
- form = ModerateUserForm(request.POST, instance=user)
+ user = get_object_or_404(models.User, id=id)
+ form = forms.ModerateUserForm(request.POST, instance=user)
if form.is_valid():
form.save()
logging.debug('data saved')
- response = HttpResponse(simplejson.dumps(''), mimetype="application/json")
+ response = HttpResponse(
+ simplejson.dumps(''),
+ mimetype="application/json"
+ )
else:
response = HttpResponseForbidden(mimetype="application/json")
return response
@@ -109,49 +134,59 @@ def set_new_email(user, new_email, nomessage=False):
user.email = new_email
user.email_isvalid = False
user.save()
- #if settings.EMAIL_VALIDATION == 'on':
+ #if askbot_settings.EMAIL_VALIDATION == True:
# send_new_email_key(user,nomessage=nomessage)
@login_required
def edit_user(request, id):
- user = get_object_or_404(User, id=id)
+ user = get_object_or_404(models.User, id=id)
if request.user != user:
raise Http404
if request.method == "POST":
- form = EditUserForm(user, request.POST)
+ form = forms.EditUserForm(user, request.POST)
if form.is_valid():
new_email = sanitize_html(form.cleaned_data['email'])
set_new_email(user, new_email)
- if settings.EDITABLE_SCREEN_NAME:
+ if askbot_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'])
user.date_of_birth = sanitize_html(form.cleaned_data['birthday'])
+
if len(user.date_of_birth) == 0:
user.date_of_birth = '1900-01-01'
+
user.about = sanitize_html(form.cleaned_data['about'])
user.save()
# send user updated singal if full fields have been updated
- if user.email and user.real_name and user.website and user.location and \
- user.date_of_birth and user.about:
- user_updated.send(sender=user.__class__, instance=user, updated_by=user)
+ if user.email and user.real_name and user.website \
+ and user.location and user.date_of_birth and user.about:
+ signals.user_updated.send(
+ sender=user.__class__,
+ instance=user,
+ updated_by=user
+ )
return HttpResponseRedirect(user.get_profile_url())
else:
- form = EditUserForm(user)
- return render_to_response('user_edit.html', {
- 'active_tab': 'users',
- 'form' : form,
- 'gravatar_faq_url' : reverse('faq') + '#gravatar',
- }, context_instance=RequestContext(request))
+ form = forms.EditUserForm(user)
+ return render_to_response(
+ 'user_edit.html',
+ {
+ 'active_tab': 'users',
+ 'form' : form,
+ 'gravatar_faq_url' : reverse('faq') + '#gravatar',
+ },
+ context_instance=RequestContext(request)
+ )
def user_stats(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
- questions = Question.objects.extra(
+ user = get_object_or_404(models.User, id=user_id)
+ questions = models.Question.objects.extra(
select={
'score' : 'question.score',
'favorited_myself' : 'SELECT count(*) FROM favorite_question f WHERE f.user_id = %s AND f.question_id = question.id',
@@ -191,7 +226,7 @@ def user_stats(request, user_id, user_view):
'la_user_reputation')[:100]
#this is meant for the questions answered by the user (or where answers were edited by him/her?)
- answered_questions = Question.objects.extra(
+ answered_questions = models.Question.objects.extra(
select={
'vote_up_count' : 'answer.vote_up_count',
'vote_down_count' : 'answer.vote_down_count',
@@ -216,46 +251,49 @@ def user_stats(request, user_id, user_view):
'vote_up_count',
'vote_down_count')[:100]
- up_votes = Vote.objects.get_up_vote_count_from_user(user)
- down_votes = Vote.objects.get_down_vote_count_from_user(user)
- votes_today = Vote.objects.get_votes_count_today_from_user(user)
- votes_total = auth.VOTE_RULES['scope_votes_per_user_per_day']
+ up_votes = models.Vote.objects.get_up_vote_count_from_user(user)
+ down_votes = models.Vote.objects.get_down_vote_count_from_user(user)
+ votes_today = models.Vote.objects.get_votes_count_today_from_user(user)
+ votes_total = askbot_settings.MAX_VOTES_PER_USER_PER_DAY
- question_id_set = set(map(lambda v: v['id'], list(questions))) \
- | set(map(lambda v: v['id'], list(answered_questions)))
-
- user_tags = Tag.objects.filter(questions__id__in = question_id_set)
+ question_id_set = set()
+ #todo: there may be a better way to do these queries
+ question_id_set.update([q['id'] for q in questions])
+ question_id_set.update([q['id'] for q in answered_questions])
+ user_tags = models.Tag.objects.filter(questions__id__in = question_id_set)
try:
from django.db.models import Count
#todo - rewrite template to do the table joins within standard ORM
- #awards = Award.objects.filter(user=user).order_by('-awarded_at')
- awards = Award.objects.extra(
- select={'id': 'badge.id',
- 'name':'badge.name',
- 'description': 'badge.description',
- 'type': 'badge.type'},
- tables=['award', 'badge'],
- order_by=['-awarded_at'],
- where=['user_id=%s AND badge_id=badge.id'],
- params=[user.id]
- ).values('id', 'name', 'description', 'type')
+ #awards = models.Award.objects.filter(user=user).order_by('-awarded_at')
+ awards = models.Award.objects.extra(
+ select={'id': 'badge.id',
+ 'name':'badge.name',
+ 'description': 'badge.description',
+ 'type': 'badge.type'},
+ tables=['award', 'badge'],
+ order_by=['-awarded_at'],
+ where=['user_id=%s AND badge_id=badge.id'],
+ params=[user.id]
+ ).values('id', 'name', 'description', 'type')
+
total_awards = awards.count()
awards = awards.annotate(count = Count('badge__id'))
user_tags = user_tags.annotate(user_tag_usage_count=Count('name'))
except ImportError:
#todo: remove all old django stuff, e.g. with '.group_by = ' pattern
- awards = Award.objects.extra(
- select={'id': 'badge.id',
- 'count': 'count(badge_id)',
- 'name':'badge.name',
- 'description': 'badge.description',
- 'type': 'badge.type'},
- tables=['award', 'badge'],
- order_by=['-awarded_at'],
- where=['user_id=%s AND badge_id=badge.id'],
- params=[user.id]
- ).values('id', 'count', 'name', 'description', 'type')
+ awards = models.Award.objects.extra(
+ select={'id': 'badge.id',
+ 'count': 'count(badge_id)',
+ 'name':'badge.name',
+ 'description': 'badge.description',
+ 'type': 'badge.type'},
+ tables=['award', 'badge'],
+ order_by=['-awarded_at'],
+ where=['user_id=%s AND badge_id=badge.id'],
+ params=[user.id]
+ ).values('id', 'count', 'name', 'description', 'type')
+
total_awards = awards.count()
awards.query.group_by = ['badge_id']
@@ -266,33 +304,37 @@ def user_stats(request, user_id, user_view):
user_tags.query.group_by = ['name']
if auth.can_moderate_users(request.user):
- moderate_user_form = ModerateUserForm(instance=user)
+ moderate_user_form = forms.ModerateUserForm(instance=user)
else:
moderate_user_form = None
- return render_to_response(user_view.template_file,{
- 'active_tab':'users',
- 'moderate_user_form': moderate_user_form,
- "tab_name" : user_view.id,
- "tab_description" : user_view.tab_description,
- "page_title" : user_view.page_title,
- "view_user" : user,
- "questions" : questions,
- "answered_questions" : answered_questions,
- "up_votes" : up_votes,
- "down_votes" : down_votes,
- "total_votes": up_votes + down_votes,
- "votes_today_left": votes_total-votes_today,
- "votes_total_per_day": votes_total,
- "user_tags" : user_tags[:50],
- "awards": awards,
- "total_awards" : total_awards,
- }, context_instance=RequestContext(request))
+ return render_to_response(
+ user_view.template_file,
+ {
+ 'active_tab':'users',
+ 'moderate_user_form': moderate_user_form,
+ "tab_name" : user_view.id,
+ "tab_description" : user_view.tab_description,
+ "page_title" : user_view.page_title,
+ "view_user" : user,
+ "questions" : questions,
+ "answered_questions" : answered_questions,
+ "up_votes" : up_votes,
+ "down_votes" : down_votes,
+ "total_votes": up_votes + down_votes,
+ "votes_today_left": votes_total-votes_today,
+ "votes_total_per_day": votes_total,
+ "user_tags" : user_tags[:50],
+ "awards": awards,
+ "total_awards" : total_awards,
+ },
+ context_instance=RequestContext(request)
+ )
def user_recent(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
+ user = get_object_or_404(models.User, id=user_id)
def get_type_name(type_id):
- for item in TYPE_ACTIVITY:
+ for item in const.TYPE_ACTIVITY:
if type_id in item:
return item[1]
@@ -304,7 +346,10 @@ def user_recent(request, user_id, user_view):
self.title = title
self.summary = summary
slug_title = slugify(title)
- self.title_link = reverse('question', kwargs={'id':question_id}) + u'%s' % slug_title
+ self.title_link = reverse(
+ 'question',
+ kwargs={'id':question_id}
+ ) + u'%s' % slug_title
if int(answer_id) > 0:
self.title_link += '#%s' % answer_id
@@ -313,11 +358,11 @@ def user_recent(request, user_id, user_view):
self.time = time
self.type = get_type_name(type)
self.type_id = type
- self.badge = get_object_or_404(Badge, id=id)
+ self.badge = get_object_or_404(models.Badge, id=id)
activities = []
# ask questions
- questions = Activity.objects.extra(
+ questions = models.Activity.objects.extra(
select={
'title' : 'question.title',
'question_id' : 'question.id',
@@ -327,7 +372,7 @@ def user_recent(request, user_id, user_view):
tables=['activity', 'question'],
where=['activity.content_type_id = %s AND activity.object_id = ' +
'question.id AND question.deleted=False AND activity.user_id = %s AND activity.activity_type = %s'],
- params=[question_type_id, user_id, TYPE_ACTIVITY_ASK_QUESTION],
+ params=[question_type_id, user_id, const.TYPE_ACTIVITY_ASK_QUESTION],
order_by=['-activity.active_at']
).values(
'title',
@@ -336,12 +381,23 @@ def user_recent(request, user_id, user_view):
'activity_type'
)
if len(questions) > 0:
- questions = [(Event(q['active_at'], q['activity_type'], q['title'], '', '0', \
- q['question_id'])) for q in questions]
- activities.extend(questions)
+
+ question_activities = []
+ for q in questions:
+ q_event = Event(
+ q['active_at'],
+ q['activity_type'],
+ q['title'],
+ '',
+ '0',
+ q['question_id']
+ )
+ question_activities.append(q_event)
+
+ activities.extend(question_activities)
# answers
- answers = Activity.objects.extra(
+ answers = models.Activity.objects.extra(
select={
'title' : 'question.title',
'question_id' : 'question.id',
@@ -353,7 +409,7 @@ def user_recent(request, user_id, user_view):
where=['activity.content_type_id = %s AND activity.object_id = answer.id AND ' +
'answer.question_id=question.id AND answer.deleted=False AND activity.user_id=%s AND '+
'activity.activity_type=%s AND question.deleted=False'],
- params=[answer_type_id, user_id, TYPE_ACTIVITY_ANSWER],
+ params=[answer_type_id, user_id, const.TYPE_ACTIVITY_ANSWER],
order_by=['-activity.active_at']
).values(
'title',
@@ -368,7 +424,7 @@ def user_recent(request, user_id, user_view):
activities.extend(answers)
# question comments
- comments = Activity.objects.extra(
+ comments = models.Activity.objects.extra(
select={
'title' : 'question.title',
'question_id' : 'comment.object_id',
@@ -381,7 +437,7 @@ def user_recent(request, user_id, user_view):
'activity.user_id = comment.user_id AND comment.object_id=question.id AND '+
'comment.content_type_id=%s AND activity.user_id = %s AND activity.activity_type=%s AND ' +
'question.deleted=False'],
- params=[comment_type_id, question_type_id, user_id, TYPE_ACTIVITY_COMMENT_QUESTION],
+ params=[comment_type_id, question_type_id, user_id, const.TYPE_ACTIVITY_COMMENT_QUESTION],
order_by=['-comment.added_at']
).values(
'title',
@@ -396,7 +452,7 @@ def user_recent(request, user_id, user_view):
activities.extend(comments)
# answer comments
- comments = Activity.objects.extra(
+ comments = models.Activity.objects.extra(
select={
'title' : 'question.title',
'question_id' : 'question.id',
@@ -411,7 +467,7 @@ def user_recent(request, user_id, user_view):
'comment.content_type_id=%s AND question.id = answer.question_id AND '+
'activity.user_id = %s AND activity.activity_type=%s AND '+
'answer.deleted=False AND question.deleted=False'],
- params=[comment_type_id, answer_type_id, user_id, TYPE_ACTIVITY_COMMENT_ANSWER],
+ params=[comment_type_id, answer_type_id, user_id, const.TYPE_ACTIVITY_COMMENT_ANSWER],
order_by=['-comment.added_at']
).values(
'title',
@@ -427,7 +483,7 @@ def user_recent(request, user_id, user_view):
activities.extend(comments)
# question revisions
- revisions = Activity.objects.extra(
+ revisions = models.Activity.objects.extra(
select={
'title' : 'question_revision.title',
'question_id' : 'question_revision.question_id',
@@ -440,7 +496,7 @@ def user_recent(request, user_id, user_view):
'question_revision.id=question.id AND question.deleted=False AND '+
'activity.user_id = question_revision.author_id AND activity.user_id = %s AND '+
'activity.activity_type=%s'],
- params=[question_revision_type_id, user_id, TYPE_ACTIVITY_UPDATE_QUESTION],
+ params=[question_revision_type_id, user_id, const.TYPE_ACTIVITY_UPDATE_QUESTION],
order_by=['-activity.active_at']
).values(
'title',
@@ -456,7 +512,7 @@ def user_recent(request, user_id, user_view):
activities.extend(revisions)
# answer revisions
- revisions = Activity.objects.extra(
+ revisions = models.Activity.objects.extra(
select={
'title' : 'question.title',
'question_id' : 'question.id',
@@ -472,7 +528,7 @@ def user_recent(request, user_id, user_view):
'answer_revision.answer_id=answer.id AND answer.question_id = question.id AND '+
'question.deleted=False AND answer.deleted=False AND '+
'activity.activity_type=%s'],
- params=[answer_revision_type_id, user_id, TYPE_ACTIVITY_UPDATE_ANSWER],
+ params=[answer_revision_type_id, user_id, const.TYPE_ACTIVITY_UPDATE_ANSWER],
order_by=['-activity.active_at']
).values(
'title',
@@ -489,7 +545,7 @@ def user_recent(request, user_id, user_view):
activities.extend(revisions)
# accepted answers
- accept_answers = Activity.objects.extra(
+ accept_answers = models.Activity.objects.extra(
select={
'title' : 'question.title',
'question_id' : 'question.id',
@@ -501,7 +557,7 @@ def user_recent(request, user_id, user_view):
'activity.user_id = question.author_id AND activity.user_id = %s AND '+
'answer.deleted=False AND question.deleted=False AND '+
'answer.question_id=question.id AND activity.activity_type=%s'],
- params=[answer_type_id, user_id, TYPE_ACTIVITY_MARK_ANSWER],
+ params=[answer_type_id, user_id, const.TYPE_ACTIVITY_MARK_ANSWER],
order_by=['-activity.active_at']
).values(
'title',
@@ -514,7 +570,7 @@ def user_recent(request, user_id, user_view):
q['question_id'])) for q in accept_answers]
activities.extend(accept_answers)
#award history
- awards = Activity.objects.extra(
+ awards = models.Activity.objects.extra(
select={
'badge_id' : 'badge.id',
'awarded_at': 'award.awarded_at',
@@ -523,7 +579,7 @@ def user_recent(request, user_id, user_view):
tables=['activity', 'award', 'badge'],
where=['activity.user_id = award.user_id AND activity.user_id = %s AND '+
'award.badge_id=badge.id AND activity.object_id=award.id AND activity.activity_type=%s'],
- params=[user_id, TYPE_ACTIVITY_PRIZE],
+ params=[user_id, const.TYPE_ACTIVITY_PRIZE],
order_by=['-activity.active_at']
).values(
'badge_id',
@@ -545,167 +601,86 @@ def user_recent(request, user_id, user_view):
"activities" : activities[:user_view.data_size]
}, context_instance=RequestContext(request))
-def user_responses(request, user_id, user_view):
+class Response:
+ """class that abstracts any kind of response
+ answer, comment, mention, post edits, etc.
"""
- We list answers for question, comments, and answer accepted by others for this user.
- """
- class Response:
- def __init__(self, type, title, question_id, answer_id, time, username, user_id, content):
- self.type = type
- self.title = title
- self.titlelink = reverse('question', args=[question_id]) + u'%s#%s' % (slugify(title), answer_id)
- self.time = time
- self.userlink = reverse('users') + u'%s/%s/' % (user_id, username)
- self.username = username
- self.content = u'%s ...' % strip_tags(content)[:300]
-
- def __unicode__(self):
- return u'%s %s' % (self.type, self.titlelink)
-
- user = get_object_or_404(User, id=user_id)
- responses = []
- answers = Answer.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'added_at' : 'answer.added_at',
- 'html' : 'answer.html',
- 'username' : 'auth_user.username',
- 'user_id' : 'auth_user.id'
- },
- select_params=[user_id],
- tables=['answer', 'question', 'auth_user'],
- where=['answer.question_id = question.id AND answer.deleted=False AND question.deleted=False AND '+
- 'question.author_id = %s AND answer.author_id <> %s AND answer.author_id=auth_user.id'],
- params=[user_id, user_id],
- order_by=['-answer.id']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'added_at',
- 'html',
- 'username',
- 'user_id'
- )
- if len(answers) > 0:
- answers = [(Response(TYPE_RESPONSE['QUESTION_ANSWERED'], a['title'], a['question_id'],
- a['answer_id'], a['added_at'], a['username'], a['user_id'], a['html'])) for a in answers]
- responses.extend(answers)
-
-
- # question comments
- comments = Comment.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'comment.object_id',
- 'added_at' : 'comment.added_at',
- 'comment' : 'comment.comment',
- 'username' : 'auth_user.username',
- 'user_id' : 'auth_user.id'
- },
- tables=['question', 'auth_user', 'comment'],
- where=['question.deleted=False AND question.author_id = %s AND comment.object_id=question.id AND '+
- 'comment.content_type_id=%s AND comment.user_id <> %s AND comment.user_id = auth_user.id'],
- params=[user_id, question_type_id, user_id],
- order_by=['-comment.added_at']
- ).values(
- 'title',
- 'question_id',
- 'added_at',
- 'comment',
- 'username',
- 'user_id'
- )
-
- if len(comments) > 0:
- comments = [(Response(TYPE_RESPONSE['QUESTION_COMMENTED'], c['title'], c['question_id'],
- '', c['added_at'], c['username'], c['user_id'], c['comment'])) for c in comments]
- responses.extend(comments)
-
- # answer comments
- comments = Comment.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'added_at' : 'comment.added_at',
- 'comment' : 'comment.comment',
- 'username' : 'auth_user.username',
- 'user_id' : 'auth_user.id'
- },
- tables=['answer', 'auth_user', 'comment', 'question'],
- where=['answer.deleted=False AND answer.author_id = %s AND comment.object_id=answer.id AND '+
- 'comment.content_type_id=%s AND comment.user_id <> %s AND comment.user_id = auth_user.id '+
- 'AND question.id = answer.question_id'],
- params=[user_id, answer_type_id, user_id],
- order_by=['-comment.added_at']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'added_at',
- 'comment',
- 'username',
- 'user_id'
- )
+ def __init__(
+ self, type, title, question_id,
+ answer_id, time, username,
+ user_id, content):
+
+ self.type = type
+ self.title = title
+ self.titlelink = reverse(
+ 'question',
+ args=[question_id]) \
+ + u'%s#%s' % (slugify(title),
+ answer_id
+ )
+ self.time = time
+ self.userlink = reverse('users') + u'%s/%s/' % (user_id, username)
+ self.username = username
+ self.content = u'%s ...' % strip_tags(content)[:300]
+
+ def __unicode__(self):
+ return u'%s %s' % (self.type, self.titlelink)
- if len(comments) > 0:
- comments = [(Response(TYPE_RESPONSE['ANSWER_COMMENTED'], c['title'], c['question_id'],
- c['answer_id'], c['added_at'], c['username'], c['user_id'], c['comment'])) for c in comments]
- responses.extend(comments)
-
- # answer has been accepted
- answers = Answer.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'added_at' : 'answer.accepted_at',
- 'html' : 'answer.html',
- 'username' : 'auth_user.username',
- 'user_id' : 'auth_user.id'
- },
- select_params=[user_id],
- tables=['answer', 'question', 'auth_user'],
- where=['answer.question_id = question.id AND answer.deleted=False AND question.deleted=False AND '+
- 'answer.author_id = %s AND answer.accepted=True AND question.author_id=auth_user.id'],
- params=[user_id],
- order_by=['-answer.id']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'added_at',
- 'html',
- 'username',
- 'user_id'
- )
- if len(answers) > 0:
- answers = [(Response(TYPE_RESPONSE['ANSWER_ACCEPTED'], a['title'], a['question_id'],
- a['answer_id'], a['added_at'], a['username'], a['user_id'], a['html'])) for a in answers]
- responses.extend(answers)
-
- # sort posts by time
- responses.sort(lambda x,y: cmp(y.time, x.time))
+def user_responses(request, user_id, user_view):
+ """
+ We list answers for question, comments, and
+ answer accepted by others for this user.
+ as well as mentions of the user
- return render_to_response(user_view.template_file,{
- 'active_tab':'users',
- "tab_name" : user_view.id,
- "tab_description" : user_view.tab_description,
- "page_title" : user_view.page_title,
- "view_user" : user,
- "responses" : responses[:user_view.data_size],
+ user_id - id of the profile owner
+ user_view - id of the user who is looking at the
+ page
+ """
+ user = get_object_or_404(models.User, id=user_id)
+ if request.user != user:
+ raise Http404
- }, context_instance=RequestContext(request))
+ user = get_object_or_404(models.User, id=user_id)
+ response_list = []
+
+ activities = list()
+ activities = models.Activity.responses_and_mentions.filter(
+ receiving_users = user
+ )
+
+ for act in activities:
+ origin_post = act.content_object.get_origin_post()
+ response = {
+ 'timestamp': act.active_at,
+ 'user': act.user,
+ 'response_url': act.get_absolute_url(),
+ 'response_snippet': strip_tags(act.content_object.html)[:300],
+ 'response_title': origin_post.title,
+ 'response_type': act.get_activity_type_display(),
+ }
+ response_list.append(response)
+
+ response_list.sort(lambda x,y: cmp(y['timestamp'], x['timestamp']))
+
+ return render_to_response(
+ user_view.template_file,
+ {
+ 'active_tab':'users',
+ 'tab_name' : user_view.id,
+ 'tab_description' : user_view.tab_description,
+ 'page_title' : user_view.page_title,
+ 'view_user' : user,
+ 'responses' : response_list[:user_view.data_size],
+ },
+ context_instance=RequestContext(request)
+ )
def user_votes(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
+ user = get_object_or_404(models.User, id=user_id)
if not auth.can_view_user_votes(request.user, user):
raise Http404
votes = []
- question_votes = Vote.objects.extra(
+ question_votes = models.Vote.objects.extra(
select={
'title' : 'question.title',
'question_id' : 'question.id',
@@ -729,7 +704,7 @@ def user_votes(request, user_id, user_view):
if(len(question_votes) > 0):
votes.extend(question_votes)
- answer_votes = Vote.objects.extra(
+ answer_votes = models.Vote.objects.extra(
select={
'title' : 'question.title',
'question_id' : 'question.id',
@@ -764,10 +739,10 @@ def user_votes(request, user_id, user_view):
}, context_instance=RequestContext(request))
def user_reputation(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
+ user = get_object_or_404(models.User, id=user_id)
try:
from django.db.models import Sum
- reputation = Repute.objects.extra(
+ reputation = models.Repute.objects.extra(
select={'question_id':'question_id',
'title': 'question.title'},
tables=['repute', 'question'],
@@ -777,7 +752,7 @@ def user_reputation(request, user_id, user_view):
).values('question_id', 'title', 'reputed_at', 'reputation')
reputation = reputation.annotate(positive=Sum("positive"), negative=Sum("negative"))
except ImportError:
- reputation = Repute.objects.extra(
+ reputation = models.Repute.objects.extra(
select={'positive':'sum(positive)', 'negative':'sum(negative)', 'question_id':'question_id',
'title': 'question.title'},
tables=['repute', 'question'],
@@ -788,7 +763,7 @@ def user_reputation(request, user_id, user_view):
reputation.query.group_by = ['question_id']
rep_list = []
- for rep in Repute.objects.filter(user=user).order_by('reputed_at'):
+ for rep in models.Repute.objects.filter(user=user).order_by('reputed_at'):
dic = '[%s,%s]' % (calendar.timegm(rep.reputed_at.timetuple()) * 1000, rep.reputation)
rep_list.append(dic)
reps = ','.join(rep_list)
@@ -805,8 +780,8 @@ def user_reputation(request, user_id, user_view):
}, context_instance=RequestContext(request))
def user_favorites(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
- questions = Question.objects.extra(
+ user = get_object_or_404(models.User, id=user_id)
+ questions = models.Question.objects.extra(
select={
'score' : 'question.vote_up_count + question.vote_down_count',
'favorited_myself' : 'SELECT count(*) FROM favorite_question f WHERE f.user_id = %s '+
@@ -856,10 +831,12 @@ def user_favorites(request, user_id, user_view):
}, context_instance=RequestContext(request))
def user_email_subscriptions(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
+ user = get_object_or_404(models.User, id=user_id)
+ if request.user != user:
+ raise Http404
if request.method == 'POST':
- email_feeds_form = EditUserEmailFeedsForm(request.POST)
- tag_filter_form = TagFilterSelectionForm(request.POST, instance=user)
+ email_feeds_form = forms.EditUserEmailFeedsForm(request.POST)
+ tag_filter_form = forms.TagFilterSelectionForm(request.POST, instance=user)
if email_feeds_form.is_valid() and tag_filter_form.is_valid():
action_status = None
@@ -872,14 +849,14 @@ def user_email_subscriptions(request, user_id, user_view):
action_status = _('changes saved')
elif 'stop_email' in request.POST:
email_stopped = email_feeds_form.reset().save(user)
- initial_values = EditUserEmailFeedsForm.NO_EMAIL_INITIAL
- email_feeds_form = EditUserEmailFeedsForm(initial=initial_values)
+ initial_values = forms.EditUserEmailFeedsForm.NO_EMAIL_INITIAL
+ email_feeds_form = forms.EditUserEmailFeedsForm(initial=initial_values)
if email_stopped:
action_status = _('email updates canceled')
else:
- email_feeds_form = EditUserEmailFeedsForm()
+ email_feeds_form = forms.EditUserEmailFeedsForm()
email_feeds_form.set_initial_values(user)
- tag_filter_form = TagFilterSelectionForm(instance=user)
+ tag_filter_form = forms.TagFilterSelectionForm(instance=user)
action_status = None
return render_to_response(user_view.template_file,{
'active_tab':'users',
@@ -965,10 +942,14 @@ USER_TEMPLATE_VIEWS = (
)
)
+#todo: rename this function - variable named user is everywhere
def user(request, id, slug=None):
sort = request.GET.get('sort', 'stats')
- user_view = dict((v.id, v) for v in USER_TEMPLATE_VIEWS).get(sort, USER_TEMPLATE_VIEWS[0])
- from forum.views import users
+ user_view = dict(
+ (v.id, v) for v in USER_TEMPLATE_VIEWS
+ ).get(
+ sort, USER_TEMPLATE_VIEWS[0]
+ )
func = user_view.view_func
return func(request, id, user_view)
diff --git a/forum/views/writers.py b/askbot/views/writers.py
index 603ddde7..4063e19a 100755..100644
--- a/forum/views/writers.py
+++ b/askbot/views/writers.py
@@ -1,25 +1,22 @@
# encoding:utf-8
import os.path
import time, datetime, random
-import logging
from django.core.files.storage import default_storage
from django.shortcuts import render_to_response, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden, Http404
from django.template import RequestContext
-from django.utils.html import * #todo: remove import * in favor of explicit imports
from django.utils import simplejson
+from django.utils.html import strip_tags
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
from django.core.exceptions import PermissionDenied
+from django.conf import settings
-from forum.forms import *
-from forum.models import *
-from forum.auth import *
-from forum.const import *
-from forum import auth
-from forum.utils.forms import get_next_url
-from forum.views.readers import _get_tags_cache_json
+from askbot import auth
+from askbot.views.readers import _get_tags_cache_json
+from askbot import forms
+from askbot import models
# used in index page
INDEX_PAGE_SIZE = 20
@@ -86,7 +83,7 @@ def ask(request):#view used to ask a new question
must login/register in order for the question go be shown
"""
if request.method == "POST":
- form = AskForm(request.POST)
+ form = forms.AskForm(request.POST)
if form.is_valid():
added_at = datetime.datetime.now()
@@ -104,7 +101,7 @@ def ask(request):#view used to ask a new question
if request.user.is_authenticated():
author = request.user
- question = Question.objects.create_new(
+ question = models.Question.objects.create_new(
title = title,
author = author,
added_at = added_at,
@@ -118,7 +115,7 @@ def ask(request):#view used to ask a new question
request.session.flush()
session_key = request.session.session_key
summary = strip_tags(text)[:120]
- question = AnonymousQuestion(
+ question = models.AnonymousQuestion(
session_key = session_key,
title = title,
tagnames = tagnames,
@@ -132,7 +129,7 @@ def ask(request):#view used to ask a new question
return HttpResponseRedirect(reverse('user_signin_new_question'))
else:
#this branch is for the initial load of ask form
- form = AskForm()
+ form = forms.AskForm()
if 'title' in request.GET:
#normally this title is inherited from search query
#but it is possible to ask with a parameter title in the url query
@@ -156,7 +153,7 @@ def ask(request):#view used to ask a new question
def edit_question(request, id):#edit or retag a question
"""view to edit question
"""
- question = get_object_or_404(Question, id=id)
+ question = get_object_or_404(models.Question, id=id)
if question.deleted and not auth.can_view_deleted_post(request.user, question):
raise Http404
if auth.can_edit_post(request.user, question):
@@ -171,7 +168,7 @@ def _retag_question(request, question):#non-url subview of edit question - just
view "edit_question"
"""
if request.method == 'POST':
- form = RetagQuestionForm(question, request.POST)
+ form = forms.RetagQuestionForm(question, request.POST)
if form.is_valid():
if form.has_changed():
question.retag(
@@ -181,7 +178,7 @@ def _retag_question(request, question):#non-url subview of edit question - just
)
return HttpResponseRedirect(question.get_absolute_url())
else:
- form = RetagQuestionForm(question)
+ form = forms.RetagQuestionForm(question)
return render_to_response('question_retag.html', {
'active_tab': 'questions',
'question': question,
@@ -195,17 +192,17 @@ def _edit_question(request, question):#non-url subview of edit_question - just e
if request.method == 'POST':
if 'select_revision' in request.POST:#revert-type edit
# user has changed revistion number
- revision_form = RevisionForm(question, latest_revision, request.POST)
+ revision_form = forms.RevisionForm(question, latest_revision, request.POST)
if revision_form.is_valid():
# Replace with those from the selected revision
- form = EditQuestionForm(question,
- QuestionRevision.objects.get(question=question,
+ form = forms.EditQuestionForm(question,
+ models.QuestionRevision.objects.get(question=question,
revision=revision_form.cleaned_data['revision']))
else:
- form = EditQuestionForm(question, latest_revision, request.POST)
+ form = forms.EditQuestionForm(question, latest_revision, request.POST)
else:#new content edit
# Always check modifications against the latest revision
- form = EditQuestionForm(question, latest_revision, request.POST)
+ form = forms.EditQuestionForm(question, latest_revision, request.POST)
if form.is_valid():
if form.has_changed():
edited_at = datetime.datetime.now()
@@ -223,8 +220,8 @@ def _edit_question(request, question):#non-url subview of edit_question - just e
return HttpResponseRedirect(question.get_absolute_url())
else:
- revision_form = RevisionForm(question, latest_revision)
- form = EditQuestionForm(question, latest_revision)
+ revision_form = forms.RevisionForm(question, latest_revision)
+ form = forms.EditQuestionForm(question, latest_revision)
return render_to_response('question_edit.html', {
'active_tab': 'questions',
'question': question,
@@ -235,7 +232,7 @@ def _edit_question(request, question):#non-url subview of edit_question - just e
@login_required
def edit_answer(request, id):
- answer = get_object_or_404(Answer, id=id)
+ answer = get_object_or_404(models.Answer, id=id)
if answer.deleted and not auth.can_view_deleted_post(request.user, answer):
raise Http404
elif not auth.can_edit_post(request.user, answer):
@@ -245,16 +242,16 @@ def edit_answer(request, id):
if request.method == "POST":
if 'select_revision' in request.POST:
# user has changed revistion number
- revision_form = RevisionForm(answer, latest_revision, request.POST)
+ revision_form = forms.RevisionForm(answer, latest_revision, request.POST)
if revision_form.is_valid():
# Replace with those from the selected revision
- form = EditAnswerForm(answer,
- AnswerRevision.objects.get(answer=answer,
+ form = forms.EditAnswerForm(answer,
+ models.AnswerRevision.objects.get(answer=answer,
revision=revision_form.cleaned_data['revision']))
else:
- form = EditAnswerForm(answer, latest_revision, request.POST)
+ form = forms.EditAnswerForm(answer, latest_revision, request.POST)
else:
- form = EditAnswerForm(answer, latest_revision, request.POST)
+ form = forms.EditAnswerForm(answer, latest_revision, request.POST)
if form.is_valid():
if form.has_changed():
edited_at = datetime.datetime.now()
@@ -267,8 +264,8 @@ def edit_answer(request, id):
)
return HttpResponseRedirect(answer.get_absolute_url())
else:
- revision_form = RevisionForm(answer, latest_revision)
- form = EditAnswerForm(answer, latest_revision)
+ revision_form = forms.RevisionForm(answer, latest_revision)
+ form = forms.EditAnswerForm(answer, latest_revision)
return render_to_response('answer_edit.html', {
'active_tab': 'questions',
'answer': answer,
@@ -276,17 +273,18 @@ def edit_answer(request, id):
'form': form,
}, context_instance=RequestContext(request))
+#todo: rename this function to post_new_answer
def answer(request, id):#process a new answer
- question = get_object_or_404(Question, id=id)
+ question = get_object_or_404(models.Question, id=id)
if request.method == "POST":
- form = AnswerForm(question, request.user, request.POST)
+ form = forms.AnswerForm(question, request.user, request.POST)
if form.is_valid():
wiki = form.cleaned_data['wiki']
text = form.cleaned_data['text']
update_time = datetime.datetime.now()
if request.user.is_authenticated():
- Answer.objects.create_new(
+ models.Answer.objects.create_new(
question=question,
author=request.user,
added_at=update_time,
@@ -296,7 +294,7 @@ def answer(request, id):#process a new answer
)
else:
request.session.flush()
- anon = AnonymousAnswer(
+ anon = models.AnonymousAnswer(
question=question,
wiki=wiki,
text=text,
@@ -310,19 +308,21 @@ def answer(request, id):#process a new answer
return HttpResponseRedirect(question.get_absolute_url())
def __generate_comments_json(obj, user):#non-view generates json data for the post comments
+ """non-view generates json data for the post comments
+ """
comments = obj.comments.all().order_by('id')
# {"Id":6,"PostId":38589,"CreationDate":"an hour ago","Text":"hello there!","UserDisplayName":"Jarrod Dixon","UserUrl":"/users/3/jarrod-dixon","DeleteUrl":null}
json_comments = []
- from forum.templatetags.extra_tags import diff_date
+ from askbot.templatetags.extra_tags import diff_date
for comment in comments:
comment_user = comment.user
delete_url = ""
if user != None and auth.can_delete_comment(user, comment):
#/posts/392845/comments/219852/delete
#todo translate this url
- if isinstance(comment.content_object, Answer):
+ if isinstance(comment.content_object, models.Answer):
delete_comment_view = 'delete_answer_comment'
- elif isinstance(comment.content_object, Question):
+ elif isinstance(comment.content_object, models.Question):
delete_comment_view = 'delete_question_comment'
delete_url = reverse(
delete_comment_view,
@@ -334,7 +334,7 @@ def __generate_comments_json(obj, user):#non-view generates json data for the po
json_comments.append({"id" : comment.id,
"object_id" : obj.id,
"comment_age" : diff_date(comment.added_at),
- "text" : comment.comment,
+ "text" : comment.html,
"user_display_name" : comment_user.username,
"user_url" : comment_user.get_profile_url(),
"delete_url" : delete_url
@@ -344,12 +344,12 @@ def __generate_comments_json(obj, user):#non-view generates json data for the po
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)
+ question = get_object_or_404(models.Question, id=id)
user = request.user
return __comments(request, question)
def answer_comments(request, id):#ajax handler for loading comments on answer
- answer = get_object_or_404(Answer, id=id)
+ answer = get_object_or_404(models.Answer, id=id)
user = request.user
return __comments(request, answer)
@@ -360,7 +360,7 @@ def __comments(request, obj):#non-view generic ajax handler to load comments to
if request.method == "GET":
response = __generate_comments_json(obj, user)
elif request.method == "POST":
- if auth.can_add_comments(user,obj):
+ if auth.can_add_comments(user, obj):
obj.add_comment(
comment = request.POST.get('comment'),
user = request.user,
@@ -371,15 +371,14 @@ def __comments(request, obj):#non-view generic ajax handler to load comments to
return response
def delete_comment(request, object_id='', comment_id='', commented_object_type=None):#ajax handler to delete comment
- response = None
commented_object = None
if commented_object_type == 'question':
- commented_object = Question
+ commented_object = models.Question
elif commented_object_type == 'answer':
- commented_object = Answer
+ commented_object = models.Answer
if request.is_ajax():
- comment = get_object_or_404(Comment, id=comment_id)
+ comment = get_object_or_404(models.Comment, id=comment_id)
if auth.can_delete_comment(request.user, comment):
obj = get_object_or_404(commented_object, id=object_id)
obj.comments.remove(comment)
diff --git a/cache/README.TXT b/cache/README.TXT
deleted file mode 100755
index 54247a82..00000000
--- a/cache/README.TXT
+++ /dev/null
@@ -1 +0,0 @@
-this file is just a placeholder so the empty directory is not ignored by version control \ No newline at end of file
diff --git a/ez_setup.py b/ez_setup.py
new file mode 100644
index 00000000..1ff1d3e7
--- /dev/null
+++ b/ez_setup.py
@@ -0,0 +1,284 @@
+#!python
+"""Bootstrap setuptools installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+ from ez_setup import use_setuptools
+ use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import sys
+DEFAULT_VERSION = "0.6c11"
+DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
+
+md5_data = {
+ 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
+ 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
+ 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
+ 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
+ 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
+ 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
+ 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
+ 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
+ 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
+ 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
+ 'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090',
+ 'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4',
+ 'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7',
+ 'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5',
+ 'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de',
+ 'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b',
+ 'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2',
+ 'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086',
+ 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
+ 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
+ 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
+ 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
+ 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
+ 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
+ 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
+ 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
+ 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
+ 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
+ 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
+ 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
+ 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
+ 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
+ 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
+ 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
+ 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
+ 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
+ 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
+ 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
+ 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
+ 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
+ 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
+ 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
+}
+
+import sys, os
+try: from hashlib import md5
+except ImportError: from md5 import md5
+
+def _validate_md5(egg_name, data):
+ if egg_name in md5_data:
+ digest = md5(data).hexdigest()
+ if digest != md5_data[egg_name]:
+ print >>sys.stderr, (
+ "md5 validation of %s failed! (Possible download problem?)"
+ % egg_name
+ )
+ sys.exit(2)
+ return data
+
+def use_setuptools(
+ version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+ download_delay=15
+):
+ """Automatically find/download setuptools and make it available on sys.path
+
+ `version` should be a valid setuptools version number that is available
+ as an egg for download under the `download_base` URL (which should end with
+ a '/'). `to_dir` is the directory where setuptools will be downloaded, if
+ it is not already available. If `download_delay` is specified, it should
+ be the number of seconds that will be paused before initiating a download,
+ should one be required. If an older version of setuptools is installed,
+ this routine will print a message to ``sys.stderr`` and raise SystemExit in
+ an attempt to abort the calling script.
+ """
+ was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
+ def do_download():
+ egg = download_setuptools(version, download_base, to_dir, download_delay)
+ sys.path.insert(0, egg)
+ import setuptools; setuptools.bootstrap_install_from = egg
+ try:
+ import pkg_resources
+ except ImportError:
+ return do_download()
+ try:
+ pkg_resources.require("setuptools>="+version); return
+ except pkg_resources.VersionConflict, e:
+ if was_imported:
+ print >>sys.stderr, (
+ "The required version of setuptools (>=%s) is not available, and\n"
+ "can't be installed while this script is running. Please install\n"
+ " a more recent version first, using 'easy_install -U setuptools'."
+ "\n\n(Currently using %r)"
+ ) % (version, e.args[0])
+ sys.exit(2)
+ else:
+ del pkg_resources, sys.modules['pkg_resources'] # reload ok
+ return do_download()
+ except pkg_resources.DistributionNotFound:
+ return do_download()
+
+def download_setuptools(
+ version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+ delay = 15
+):
+ """Download setuptools from a specified location and return its filename
+
+ `version` should be a valid setuptools version number that is available
+ as an egg for download under the `download_base` URL (which should end
+ with a '/'). `to_dir` is the directory where the egg will be downloaded.
+ `delay` is the number of seconds to pause before an actual download attempt.
+ """
+ import urllib2, shutil
+ egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
+ url = download_base + egg_name
+ saveto = os.path.join(to_dir, egg_name)
+ src = dst = None
+ if not os.path.exists(saveto): # Avoid repeated downloads
+ try:
+ from distutils import log
+ if delay:
+ log.warn("""
+---------------------------------------------------------------------------
+This script requires setuptools version %s to run (even to display
+help). I will attempt to download it for you (from
+%s), but
+you may need to enable firewall access for this script first.
+I will start the download in %d seconds.
+
+(Note: if this machine does not have network access, please obtain the file
+
+ %s
+
+and place it in this directory before rerunning this script.)
+---------------------------------------------------------------------------""",
+ version, download_base, delay, url
+ ); from time import sleep; sleep(delay)
+ log.warn("Downloading %s", url)
+ src = urllib2.urlopen(url)
+ # Read/write all in one block, so we don't create a corrupt file
+ # if the download is interrupted.
+ data = _validate_md5(egg_name, src.read())
+ dst = open(saveto,"wb"); dst.write(data)
+ finally:
+ if src: src.close()
+ if dst: dst.close()
+ return os.path.realpath(saveto)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+def main(argv, version=DEFAULT_VERSION):
+ """Install or upgrade setuptools and EasyInstall"""
+ try:
+ import setuptools
+ except ImportError:
+ egg = None
+ try:
+ egg = download_setuptools(version, delay=0)
+ sys.path.insert(0,egg)
+ from setuptools.command.easy_install import main
+ return main(list(argv)+[egg]) # we're done here
+ finally:
+ if egg and os.path.exists(egg):
+ os.unlink(egg)
+ else:
+ if setuptools.__version__ == '0.0.1':
+ print >>sys.stderr, (
+ "You have an obsolete version of setuptools installed. Please\n"
+ "remove it from your system entirely before rerunning this script."
+ )
+ sys.exit(2)
+
+ req = "setuptools>="+version
+ import pkg_resources
+ try:
+ pkg_resources.require(req)
+ except pkg_resources.VersionConflict:
+ try:
+ from setuptools.command.easy_install import main
+ except ImportError:
+ from easy_install import main
+ main(list(argv)+[download_setuptools(delay=0)])
+ sys.exit(0) # try to force an exit
+ else:
+ if argv:
+ from setuptools.command.easy_install import main
+ main(argv)
+ else:
+ print "Setuptools version",version,"or greater has been installed."
+ print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
+
+def update_md5(filenames):
+ """Update our built-in md5 registry"""
+
+ import re
+
+ for name in filenames:
+ base = os.path.basename(name)
+ f = open(name,'rb')
+ md5_data[base] = md5(f.read()).hexdigest()
+ f.close()
+
+ data = [" %r: %r,\n" % it for it in md5_data.items()]
+ data.sort()
+ repl = "".join(data)
+
+ import inspect
+ srcfile = inspect.getsourcefile(sys.modules[__name__])
+ f = open(srcfile, 'rb'); src = f.read(); f.close()
+
+ match = re.search("\nmd5_data = {\n([^}]+)}", src)
+ if not match:
+ print >>sys.stderr, "Internal error!"
+ sys.exit(2)
+
+ src = src[:match.start(1)] + repl + src[match.end(1):]
+ f = open(srcfile,'w')
+ f.write(src)
+ f.close()
+
+
+if __name__=='__main__':
+ if len(sys.argv)>2 and sys.argv[1]=='--md5update':
+ update_md5(sys.argv[2:])
+ else:
+ main(sys.argv[1:])
+
+
+
+
+
+
diff --git a/fbconnect/fb.py b/fbconnect/fb.py
deleted file mode 100755
index afcd8210..00000000
--- a/fbconnect/fb.py
+++ /dev/null
@@ -1,96 +0,0 @@
-from django.conf import settings
-from time import time
-from datetime import datetime
-from urllib import urlopen, urlencode
-
-try:
- from json import load as load_json
-except:
- from pjson import fread as load_json
-
-from models import FBAssociation
-import hashlib
-import logging
-
-REST_SERVER = 'http://api.facebook.com/restserver.php'
-
-def generate_sig(values):
- keys = []
-
- for key in sorted(values.keys()):
- keys.append(key)
-
- signature = ''.join(['%s=%s' % (key, values[key]) for key in keys]) + settings.FB_SECRET
- return hashlib.md5(signature).hexdigest()
-
-def check_cookies_signature(cookies):
- API_KEY = settings.FB_API_KEY
-
- values = {}
-
- for key in cookies.keys():
- if (key.startswith(API_KEY + '_')):
- values[key.replace(API_KEY + '_', '')] = cookies[key]
-
- return generate_sig(values) == cookies[API_KEY]
-
-def get_user_data(cookies):
- request_data = {
- 'method': 'Users.getInfo',
- 'api_key': settings.FB_API_KEY,
- 'call_id': time(),
- 'v': '1.0',
- 'uids': cookies[settings.FB_API_KEY + '_user'],
- 'fields': 'name,first_name,last_name',
- 'format': 'json',
- }
-
- request_data['sig'] = generate_sig(request_data)
- fb_response = urlopen(REST_SERVER, urlencode(request_data))
- #print(fb_response)
- return load_json(fb_response)[0]
-
-
-def delete_cookies(response):
- API_KEY = settings.FB_API_KEY
-
- response.delete_cookie(API_KEY + '_user')
- response.delete_cookie(API_KEY + '_session_key')
- response.delete_cookie(API_KEY + '_expires')
- response.delete_cookie(API_KEY + '_ss')
- response.delete_cookie(API_KEY)
- response.delete_cookie('fbsetting_' + API_KEY)
-
-def check_session_expiry(cookies):
- return datetime.fromtimestamp(float(cookies[settings.FB_API_KEY+'_expires'])) > datetime.now()
-
-STATES = {
- 'FIRSTTIMER': 1,
- 'SESSIONEXPIRED': 2,
- 'RETURNINGUSER': 3,
- 'INVALIDSTATE': 4,
-}
-
-def get_user_state(request):
- API_KEY = settings.FB_API_KEY
- logging.debug('')
-
- if API_KEY in request.COOKIES:
- logging.debug('FB API key is in request cookies')
- if check_cookies_signature(request.COOKIES):
- logging.debug('FB cookie signature is fine')
- if check_session_expiry(request.COOKIES):
- logging.debug('FB session is not expired')
- try:
- uassoc = FBAssociation.objects.get(fbuid=request.COOKIES[API_KEY + '_user'])
- logging.debug('found existing FB user association')
- return (STATES['RETURNINGUSER'], uassoc.user)
- except:
- logging.debug('dont have FB association for this user')
- return (STATES['FIRSTTIMER'], get_user_data(request.COOKIES))
- else:
- logging.debug('FB session expired')
- return (STATES['SESSIONEXPIRED'], None)
- logging.debug('FB state is INVALID')
-
- return (STATES['INVALIDSTATE'], None)
diff --git a/fbconnect/forms.py b/fbconnect/forms.py
deleted file mode 100755
index 94f86816..00000000
--- a/fbconnect/forms.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from django_authopenid.forms import NextUrlField, UserNameField, UserEmailField
-
-from django import forms
-
-class FBConnectRegisterForm(forms.Form):
- next = NextUrlField()
- username = UserNameField()
- email = UserEmailField()
diff --git a/fbconnect/models.py b/fbconnect/models.py
deleted file mode 100755
index 2172217d..00000000
--- a/fbconnect/models.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from django.db import models
-from django.contrib.auth.models import User
-
-class FBAssociation(models.Model):
- user = models.ForeignKey(User)
- fbuid = models.CharField(max_length=12, unique=True)
diff --git a/fbconnect/pjson.py b/fbconnect/pjson.py
deleted file mode 100755
index 273b684e..00000000
--- a/fbconnect/pjson.py
+++ /dev/null
@@ -1,313 +0,0 @@
-import string
-import types
-
-## json.py implements a JSON (http://json.org) reader and writer.
-## Copyright (C) 2005 Patrick D. Logan
-## Contact mailto:patrickdlogan@stardecisions.com
-##
-## This library is free software; you can redistribute it and/or
-## modify it under the terms of the GNU Lesser General Public
-## License as published by the Free Software Foundation; either
-## version 2.1 of the License, or (at your option) any later version.
-##
-## This library 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
-## Lesser General Public License for more details.
-##
-## You should have received a copy of the GNU Lesser General Public
-## License along with this library; if not, write to the Free Software
-## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-
-class _StringGenerator(object):
- def __init__(self, string):
- self.string = string
- self.index = -1
- def peek(self):
- i = self.index + 1
- if i < len(self.string):
- return self.string[i]
- else:
- return None
- def next(self):
- self.index += 1
- if self.index < len(self.string):
- return self.string[self.index]
- else:
- raise StopIteration
- def all(self):
- return self.string
-
-class WriteException(Exception):
- pass
-
-class ReadException(Exception):
- pass
-
-class JsonReader(object):
- hex_digits = {'A': 10,'B': 11,'C': 12,'D': 13,'E': 14,'F':15}
- escapes = {'t':'\t','n':'\n','f':'\f','r':'\r','b':'\b'}
-
- def read(self, s):
- self._generator = _StringGenerator(s)
- result = self._read()
- return result
-
- def _read(self):
- self._eatWhitespace()
- peek = self._peek()
- if peek is None:
- raise ReadException, "Nothing to read: '%s'" % self._generator.all()
- if peek == '{':
- return self._readObject()
- elif peek == '[':
- return self._readArray()
- elif peek == '"':
- return self._readString()
- elif peek == '-' or peek.isdigit():
- return self._readNumber()
- elif peek == 't':
- return self._readTrue()
- elif peek == 'f':
- return self._readFalse()
- elif peek == 'n':
- return self._readNull()
- elif peek == '/':
- self._readComment()
- return self._read()
- else:
- raise ReadException, "Input is not valid JSON: '%s'" % self._generator.all()
-
- def _readTrue(self):
- self._assertNext('t', "true")
- self._assertNext('r', "true")
- self._assertNext('u', "true")
- self._assertNext('e', "true")
- return True
-
- def _readFalse(self):
- self._assertNext('f', "false")
- self._assertNext('a', "false")
- self._assertNext('l', "false")
- self._assertNext('s', "false")
- self._assertNext('e', "false")
- return False
-
- def _readNull(self):
- self._assertNext('n', "null")
- self._assertNext('u', "null")
- self._assertNext('l', "null")
- self._assertNext('l', "null")
- return None
-
- def _assertNext(self, ch, target):
- if self._next() != ch:
- raise ReadException, "Trying to read %s: '%s'" % (target, self._generator.all())
-
- def _readNumber(self):
- isfloat = False
- result = self._next()
- peek = self._peek()
- while peek is not None and (peek.isdigit() or peek == "."):
- isfloat = isfloat or peek == "."
- result = result + self._next()
- peek = self._peek()
- try:
- if isfloat:
- return float(result)
- else:
- return int(result)
- except ValueError:
- raise ReadException, "Not a valid JSON number: '%s'" % result
-
- def _readString(self):
- result = ""
- assert self._next() == '"'
- try:
- while self._peek() != '"':
- ch = self._next()
- if ch == "\\":
- ch = self._next()
- if ch in 'brnft':
- ch = self.escapes[ch]
- elif ch == "u":
- ch4096 = self._next()
- ch256 = self._next()
- ch16 = self._next()
- ch1 = self._next()
- n = 4096 * self._hexDigitToInt(ch4096)
- n += 256 * self._hexDigitToInt(ch256)
- n += 16 * self._hexDigitToInt(ch16)
- n += self._hexDigitToInt(ch1)
- ch = unichr(n)
- elif ch not in '"/\\':
- raise ReadException, "Not a valid escaped JSON character: '%s' in %s" % (ch, self._generator.all())
- result = result + ch
- except StopIteration:
- raise ReadException, "Not a valid JSON string: '%s'" % self._generator.all()
- assert self._next() == '"'
- return result
-
- def _hexDigitToInt(self, ch):
- try:
- result = self.hex_digits[ch.upper()]
- except KeyError:
- try:
- result = int(ch)
- except ValueError:
- raise ReadException, "The character %s is not a hex digit." % ch
- return result
-
- def _readComment(self):
- assert self._next() == "/"
- second = self._next()
- if second == "/":
- self._readDoubleSolidusComment()
- elif second == '*':
- self._readCStyleComment()
- else:
- raise ReadException, "Not a valid JSON comment: %s" % self._generator.all()
-
- def _readCStyleComment(self):
- try:
- done = False
- while not done:
- ch = self._next()
- done = (ch == "*" and self._peek() == "/")
- if not done and ch == "/" and self._peek() == "*":
- raise ReadException, "Not a valid JSON comment: %s, '/*' cannot be embedded in the comment." % self._generator.all()
- self._next()
- except StopIteration:
- raise ReadException, "Not a valid JSON comment: %s, expected */" % self._generator.all()
-
- def _readDoubleSolidusComment(self):
- try:
- ch = self._next()
- while ch != "\r" and ch != "\n":
- ch = self._next()
- except StopIteration:
- pass
-
- def _readArray(self):
- result = []
- assert self._next() == '['
- done = self._peek() == ']'
- while not done:
- item = self._read()
- result.append(item)
- self._eatWhitespace()
- done = self._peek() == ']'
- if not done:
- ch = self._next()
- if ch != ",":
- raise ReadException, "Not a valid JSON array: '%s' due to: '%s'" % (self._generator.all(), ch)
- assert ']' == self._next()
- return result
-
- def _readObject(self):
- result = {}
- assert self._next() == '{'
- done = self._peek() == '}'
- while not done:
- key = self._read()
- if type(key) is not types.StringType:
- raise ReadException, "Not a valid JSON object key (should be a string): %s" % key
- self._eatWhitespace()
- ch = self._next()
- if ch != ":":
- raise ReadException, "Not a valid JSON object: '%s' due to: '%s'" % (self._generator.all(), ch)
- self._eatWhitespace()
- val = self._read()
- result[key] = val
- self._eatWhitespace()
- done = self._peek() == '}'
- if not done:
- ch = self._next()
- if ch != ",":
- raise ReadException, "Not a valid JSON array: '%s' due to: '%s'" % (self._generator.all(), ch)
- assert self._next() == "}"
- return result
-
- def _eatWhitespace(self):
- p = self._peek()
- while p is not None and p in string.whitespace or p == '/':
- if p == '/':
- self._readComment()
- else:
- self._next()
- p = self._peek()
-
- def _peek(self):
- return self._generator.peek()
-
- def _next(self):
- return self._generator.next()
-
-class JsonWriter(object):
-
- def _append(self, s):
- self._results.append(s)
-
- def write(self, obj, escaped_forward_slash=False):
- self._escaped_forward_slash = escaped_forward_slash
- self._results = []
- self._write(obj)
- return "".join(self._results)
-
- def _write(self, obj):
- ty = type(obj)
- if ty is types.DictType:
- n = len(obj)
- self._append("{")
- for k, v in obj.items():
- self._write(k)
- self._append(":")
- self._write(v)
- n = n - 1
- if n > 0:
- self._append(",")
- self._append("}")
- elif ty is types.ListType or ty is types.TupleType:
- n = len(obj)
- self._append("[")
- for item in obj:
- self._write(item)
- n = n - 1
- if n > 0:
- self._append(",")
- self._append("]")
- elif ty is types.StringType or ty is types.UnicodeType:
- self._append('"')
- obj = obj.replace('\\', r'\\')
- if self._escaped_forward_slash:
- obj = obj.replace('/', r'\/')
- obj = obj.replace('"', r'\"')
- obj = obj.replace('\b', r'\b')
- obj = obj.replace('\f', r'\f')
- obj = obj.replace('\n', r'\n')
- obj = obj.replace('\r', r'\r')
- obj = obj.replace('\t', r'\t')
- self._append(obj)
- self._append('"')
- elif ty is types.IntType or ty is types.LongType:
- self._append(str(obj))
- elif ty is types.FloatType:
- self._append("%f" % obj)
- elif obj is True:
- self._append("true")
- elif obj is False:
- self._append("false")
- elif obj is None:
- self._append("null")
- else:
- raise WriteException, "Cannot write in JSON: %s" % repr(obj)
-
-def write(obj, escaped_forward_slash=False):
- return JsonWriter().write(obj, escaped_forward_slash)
-
-def read(s):
- return JsonReader().read(s)
-
-def fread(f):
- return read(f.read())
diff --git a/fbconnect/tests.py b/fbconnect/tests.py
deleted file mode 100755
index 2247054b..00000000
--- a/fbconnect/tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
-
-Replace these with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
-
diff --git a/fbconnect/urls.py b/fbconnect/urls.py
deleted file mode 100755
index bf2d4364..00000000
--- a/fbconnect/urls.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from django.conf.urls.defaults import *
-from django.utils.translation import ugettext as _
-from django.views.generic.simple import direct_to_template
-from django.conf import settings
-from views import signin, register
-
-urlpatterns = patterns('',
- url(r'^xd_receiver$', direct_to_template, {'template': 'fbconnect/xd_receiver.html',\
- 'extra_context': {'APP_SHORT_NAME':settings.APP_SHORT_NAME}},\
- name='xd_receiver'),
-
- url(r'^%s$' % _('signin/'), signin, name="fb_signin"),
- url(r'^%s%s$' % (_('signin/'), _('newquestion/')), signin, {'newquestion': True}, name="fb_signin_new_question"),
- url(r'^%s%s$' % (_('signin/'), _('newanswer/')), signin, {'newanswer': True}, name="fb_signin_new_answer"),
-
- url(r'^%s$' % _('register/'), register, name="fb_user_register"),
- url(r'^%s%s$' % (_('register/'), _('newquestion/')), register, {'newquestion': True}, name="fb_user_register_new_question"),
- url(r'^%s%s$' % (_('register/'), _('newanswer/')), register, {'newanswer': True}, name="fb_user_register_new_answer"),
-)
diff --git a/fbconnect/views.py b/fbconnect/views.py
deleted file mode 100755
index 1781f6bf..00000000
--- a/fbconnect/views.py
+++ /dev/null
@@ -1,112 +0,0 @@
-from django.shortcuts import render_to_response as render
-from django.template import RequestContext
-from django.http import HttpResponseRedirect
-from django.utils.safestring import mark_safe
-from django.core.urlresolvers import reverse
-from django.contrib.auth.models import User
-from django.contrib.auth import login, logout
-from models import FBAssociation
-from forum.forms import SimpleEmailSubscribeForm
-from django.conf import settings
-
-import fb
-import forms
-
-import logging
-
-def signin(request, newquestion = False, newanswer = False):
- logging.debug('')
- state, context = fb.get_user_state(request)
-
- if state == fb.STATES['FIRSTTIMER']:
- logging.debug('FB state = FIRSTTIMER')
- if newquestion:
- register_url = 'fb_user_register_new_question'
- elif newanswer:
- register_url = 'fb_user_register_new_answer'
- else:
- register_url = 'fb_user_register'
- return HttpResponseRedirect(reverse(register_url))
- elif state == fb.STATES['RETURNINGUSER']:
- logging.debug('FB state = RETURNINGUSER')
- return login_and_forward(request, context, newquestion, newanswer)
- elif state == fb.STATES['SESSIONEXPIRED']:
- logging.debug('FB state = SESSIONEXPIRED')
- response = logout(request, next_page=reverse('index'))
- fb.delete_cookies(response)
- return response
-
- return HttpResponseRedirect(reverse('index'))
-
-def register(request, newquestion = False, newanswer = False):
- logging.debug('')
- state, context = fb.get_user_state(request)
-
- if state == fb.STATES['FIRSTTIMER']:
- logging.debug('FB FIRSTTIMER - try to register locally')
- logging.debug('request method is %s' % request.method)
- if request.method == 'POST' and 'bnewaccount' in request.POST:
- form1 = forms.FBConnectRegisterForm(request.POST)
- email_feeds_form = SimpleEmailSubscribeForm(request.POST)
-
- if (form1.is_valid() and email_feeds_form.is_valid()):
- tmp_pwd = User.objects.make_random_password()
- user_ = User.objects.create_user(form1.cleaned_data['username'],
- form1.cleaned_data['email'], tmp_pwd)
-
- user_.set_unusable_password()
- logging.debug('created new internal user %s' % form1.cleaned_data['username'])
-
- uassoc = FBAssociation(user=user_, fbuid=context['uid'])
- uassoc.save()
- logging.debug('created new user association')
-
- email_feeds_form.save(user_)
-
- return login_and_forward(request, user_, newquestion, newanswer)
- else:
- logging.debug('form user input is invalid')
- else:
- form1 = forms.FBConnectRegisterForm(initial={
- 'next': '/',
- 'username': context['name'],
- 'email': '',
- })
- email_feeds_form = SimpleEmailSubscribeForm()
-
- return render('authopenid/complete.html', {
- 'form1': form1,
- 'email_feeds_form': email_feeds_form,
- 'provider':mark_safe('facebook'),
- 'login_type':'facebook',
- 'gravatar_faq_url':reverse('faq') + '#gravatar',
- }, context_instance=RequestContext(request))
- else:
- logging.debug('not a FIRSTTIMER --> redirect to index view')
- return HttpResponseRedirect(reverse('index'))
-
-def login_and_forward(request, user, newquestion = False, newanswer = False):
- old_session = request.session.session_key
- user.backend = "django.contrib.auth.backends.ModelBackend"
- logging.debug('attached auth.backends.ModelBackend to this FB user')
- login(request, user)
- logging.debug('user logged in!')
-
- from forum.models import user_logged_in
- user_logged_in.send(user=user,session_key=old_session,sender=None)
- logging.debug('user_logged_in signal sent')
-
- if (newquestion):
- from forum.models import Question
- question = Question.objects.filter(author=user).order_by('-added_at')[0]
- logging.debug('redirecting to newly posted question')
- return HttpResponseRedirect(question.get_absolute_url())
-
- if (newanswer):
- from forum.models import Answer
- answer = Answer.objects.filter(author=user).order_by('-added_at')[0]
- logging.debug('redirecting to newly posted answer')
- return HttpResponseRedirect(answer.get_absolute_url())
-
- logging.debug('redirecting to front page')
- return HttpResponseRedirect('/')
diff --git a/forum/__init__.py b/forum/__init__.py
deleted file mode 100755
index 85cd5d26..00000000
--- a/forum/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-__all__ = ['admin','auth','const','feed','forms','managers','models','sitemap','urls','views']
diff --git a/forum/badges/__init__.py b/forum/badges/__init__.py
deleted file mode 100755
index 8d7cd097..00000000
--- a/forum/badges/__init__.py
+++ /dev/null
@@ -1,10 +0,0 @@
-import re
-
-from forum.badges.base import BadgeImplementation
-from forum.modules import get_modules_script_classes
-
-ALL_BADGES = dict([
- (re.sub('BadgeImpl', '', name).lower(), cls) for name, cls
- in get_modules_script_classes('badges', BadgeImplementation).items()
- if not re.search('AbstractBadgeImpl$', name)
- ]) \ No newline at end of file
diff --git a/forum/badges/base.py b/forum/badges/base.py
deleted file mode 100755
index 03ef3565..00000000
--- a/forum/badges/base.py
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-class BadgeImplementation(object):
- name = ""
- description = ""
-
- def install(self):
- pass
-
- def process_job(self):
- raise NotImplementedError \ No newline at end of file
diff --git a/forum/context.py b/forum/context.py
deleted file mode 100644
index 043af81d..00000000
--- a/forum/context.py
+++ /dev/null
@@ -1,47 +0,0 @@
-from django.conf import settings
-def application_settings(context):
- my_settings = {
- 'APP_TITLE' : settings.APP_TITLE,
- 'APP_SHORT_NAME' : settings.APP_SHORT_NAME,
- 'APP_URL' : settings.APP_URL,
- 'APP_KEYWORDS' : settings.APP_KEYWORDS,
- 'APP_DESCRIPTION' : settings.APP_DESCRIPTION,
- 'APP_INTRO' : settings.APP_INTRO,
- 'EMAIL_VALIDATION': settings.EMAIL_VALIDATION,
- 'FEEDBACK_SITE_URL': settings.FEEDBACK_SITE_URL,
- 'FORUM_SCRIPT_ALIAS': settings.FORUM_SCRIPT_ALIAS,
- 'LANGUAGE_CODE': settings.LANGUAGE_CODE,
- 'GOOGLE_SITEMAP_CODE':settings.GOOGLE_SITEMAP_CODE,
- 'GOOGLE_ANALYTICS_KEY':settings.GOOGLE_ANALYTICS_KEY,
- 'WIKI_ON':settings.WIKI_ON,
- 'RESOURCE_REVISION':settings.RESOURCE_REVISION,
- 'ASKBOT_SKIN':settings.ASKBOT_DEFAULT_SKIN,
- 'EDITABLE_SCREEN_NAME':settings.EDITABLE_SCREEN_NAME,
- }
- return {'settings':my_settings}
-
-def auth_processor(request):
- """
- Returns context variables required by apps that use Django's authentication
- system.
-
- If there is no 'user' attribute in the request, uses AnonymousUser (from
- django.contrib.auth).
- """
- if hasattr(request, 'user'):
- user = request.user
- if user.is_authenticated():
- messages = user.message_set.all()
- else:
- messages = None
- else:
- from django.contrib.auth.models import AnonymousUser
- user = AnonymousUser()
- messages = None
-
- from django.core.context_processors import PermWrapper
- return {
- 'user': user,
- 'messages': messages,
- 'perms': PermWrapper(user),
- }
diff --git a/forum/cron/multi_award_badges b/forum/cron/multi_award_badges
deleted file mode 100755
index 3d768772..00000000
--- a/forum/cron/multi_award_badges
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/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
deleted file mode 100755
index 4230fb22..00000000
--- a/forum/cron/multi_award_badges_virtualenv
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/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
deleted file mode 100755
index 069656ca..00000000
--- a/forum/cron/once_award_badges
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/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
deleted file mode 100755
index 0011981c..00000000
--- a/forum/cron/once_award_badges_virtualenv
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/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
deleted file mode 100644
index 7581a88c..00000000
--- a/forum/cron/send_email_alerts
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/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
deleted file mode 100644
index 2f1b64d0..00000000
--- a/forum/cron/send_email_alerts_virtualenv
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/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/feed.py b/forum/feed.py
deleted file mode 100755
index e4b929e9..00000000
--- a/forum/feed.py
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env python
-#encoding:utf-8
-#-------------------------------------------------------------------------------
-# Name: Syndication feed class for subsribtion
-# Purpose:
-#
-# Author: Mike
-#
-# Created: 29/01/2009
-# Copyright: (c) CNPROG.COM 2009
-# Licence: GPL V2
-#-------------------------------------------------------------------------------
-from django.contrib.syndication.feeds import Feed, FeedDoesNotExist
-from django.utils.translation import ugettext as _
-from models import Question
-from django.conf import settings
-class RssLastestQuestionsFeed(Feed):
- title = settings.APP_TITLE + _(' - ')+ _('latest questions')
- link = settings.APP_URL #+ '/' + _('question/')
- description = settings.APP_DESCRIPTION
- #ttl = 10
- copyright = settings.APP_COPYRIGHT
-
- def item_link(self, item):
- return self.link + item.get_absolute_url()
-
- def item_author_name(self, item):
- return item.author.username
-
- def item_author_link(self, item):
- return item.author.get_profile_url()
-
- def item_pubdate(self, item):
- return item.added_at
-
- def items(self, item):
- return Question.objects.filter(deleted=False).order_by('-last_activity_at')[:30]
-
-def main():
- pass
-
-if __name__ == '__main__':
- main()
diff --git a/forum/management/__init__.py b/forum/management/__init__.py
deleted file mode 100755
index b654caaa..00000000
--- a/forum/management/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from forum.modules import get_modules_script
-
-get_modules_script('management') \ No newline at end of file
diff --git a/forum/management/commands/send_email_alerts.py b/forum/management/commands/send_email_alerts.py
deleted file mode 100755
index 5204a81e..00000000
--- a/forum/management/commands/send_email_alerts.py
+++ /dev/null
@@ -1,320 +0,0 @@
-from django.core.management.base import NoArgsCommand
-from django.db import connection
-from django.db.models import Q, F
-from forum.models import *
-from forum import const
-from django.core.mail import EmailMessage
-from django.utils.translation import ugettext as _
-from django.utils.translation import ungettext
-import datetime
-from django.conf import settings
-import logging
-from forum.utils.odict import OrderedDict
-from django.contrib.contenttypes.models import ContentType
-from forum import const
-
-def extend_question_list(src, dst, limit=False):
- """src is a query set with questions
- or None
- dst - is an ordered dictionary
- """
- if limit and len(dst.keys()) >= const.MAX_ALERTS_PER_EMAIL:
- return
- if src is None:#is not QuerySet
- return #will not do anything if subscription of this type is not used
- cutoff_time = src.cutoff_time
- for q in src:
- if q in dst:
- #the latest cutoff time wins for a given question
- #if the question falls into several subscription groups
- if cutoff_time > dst[q]['cutoff_time']:
- dst[q]['cutoff_time'] = cutoff_time
- else:
- #initialise a questions metadata dictionary to use for email reporting
- dst[q] = {'cutoff_time':cutoff_time}
-
-class Command(NoArgsCommand):
- def handle_noargs(self,**options):
- try:
- try:
- self.send_email_alerts()
- except Exception, e:
- print e
- finally:
- connection.close()
-
- def get_updated_questions_for_user(self,user):
-
- #these are placeholders for separate query sets per question group
- #there are four groups - one for each EmailFeedSetting.feed_type
- #and each group has subtypes A and B
- #that's because of the strange thing commented below
- #see note on Q and F objects marked with todo tag
- q_sel_A = None
- q_sel_B = None
-
- q_ask_A = None
- q_ask_B = None
-
- q_ans_A = None
- q_ans_B = None
-
- q_all_A = None
- q_all_B = None
-
- now = datetime.datetime.now()
- #Q_set1 - base questionquery set for this user
- Q_set1 = Question.objects.exclude(
- last_activity_by=user
- ).exclude(
- last_activity_at__lt=user.date_joined#exclude old stuff
- ).exclude(
- deleted=True
- ).exclude(
- closed=True
- ).order_by('-last_activity_at')
- #todo: for some reason filter on did not work as expected ~Q(viewed__who=user) |
- # Q(viewed__who=user,viewed__when__lt=F('last_activity_at'))
- #returns way more questions than you might think it should
- #so because of that I've created separate query sets Q_set2 and Q_set3
- #plus two separate queries run faster!
-
- #questions that are not seen by the user
- Q_set2 = Q_set1.filter(~Q(viewed__who=user))
- #questions seen before the last modification
- Q_set3 = Q_set1.filter(Q(viewed__who=user,viewed__when__lt=F('last_activity_at')))
-
- #todo may shortcirquit here is len(user_feeds) == 0
- user_feeds = EmailFeedSetting.objects.filter(subscriber=user).exclude(frequency='n')
- if len(user_feeds) == 0:
- return {};#short cirquit
- for feed in user_feeds:
- #each group of updates has it's own cutoff time
- #to be saved as a new parameter for each query set
- #won't send email for a given question if it has been done
- #after the cutoff_time
- cutoff_time = now - EmailFeedSetting.DELTA_TABLE[feed.frequency]
- if feed.reported_at == None or feed.reported_at <= cutoff_time:
- Q_set_A = Q_set2#.exclude(last_activity_at__gt=cutoff_time)#report these excluded later
- Q_set_B = Q_set3#.exclude(last_activity_at__gt=cutoff_time)
- feed.reported_at = now
- feed.save()#may not actually report anything, depending on filters below
- if feed.feed_type == 'q_sel':
- q_sel_A = Q_set_A.filter(followed_by=user)
- q_sel_A.cutoff_time = cutoff_time #store cutoff time per query set
- q_sel_B = Q_set_B.filter(followed_by=user)
- q_sel_B.cutoff_time = cutoff_time #store cutoff time per query set
- elif feed.feed_type == 'q_ask':
- q_ask_A = Q_set_A.filter(author=user)
- q_ask_A.cutoff_time = cutoff_time
- q_ask_B = Q_set_B.filter(author=user)
- q_ask_B.cutoff_time = cutoff_time
- elif feed.feed_type == 'q_ans':
- q_ans_A = Q_set_A.filter(answers__author=user)[:const.MAX_ALERTS_PER_EMAIL]
- q_ans_A.cutoff_time = cutoff_time
- q_ans_B = Q_set_B.filter(answers__author=user)[:const.MAX_ALERTS_PER_EMAIL]
- q_ans_B.cutoff_time = cutoff_time
- elif feed.feed_type == 'q_all':
- if user.tag_filter_setting == 'ignored':
- ignored_tags = Tag.objects.filter(user_selections__reason='bad', \
- user_selections__user=user)
- q_all_A = Q_set_A.exclude( tags__in=ignored_tags )[:const.MAX_ALERTS_PER_EMAIL]
- q_all_B = Q_set_B.exclude( tags__in=ignored_tags )[:const.MAX_ALERTS_PER_EMAIL]
- else:
- selected_tags = Tag.objects.filter(user_selections__reason='good', \
- user_selections__user=user)
- q_all_A = Q_set_A.filter( tags__in=selected_tags )
- q_all_B = Q_set_B.filter( tags__in=selected_tags )
- q_all_A.cutoff_time = cutoff_time
- q_all_B.cutoff_time = cutoff_time
- #build list in this order
- q_list = OrderedDict()
-
- extend_question_list(q_sel_A, q_list)
- extend_question_list(q_sel_B, q_list)
-
- if user.tag_filter_setting == 'interesting':
- extend_question_list(q_all_A, q_list)
- extend_question_list(q_all_B, q_list)
-
- extend_question_list(q_ask_A, q_list, limit=True)
- extend_question_list(q_ask_B, q_list, limit=True)
-
- extend_question_list(q_ans_A, q_list, limit=True)
- extend_question_list(q_ans_B, q_list, limit=True)
-
- if user.tag_filter_setting == 'ignored':
- extend_question_list(q_all_A, q_list, limit=True)
- extend_question_list(q_all_B, q_list, limit=True)
-
- ctype = ContentType.objects.get_for_model(Question)
- EMAIL_UPDATE_ACTIVITY = const.TYPE_ACTIVITY_QUESTION_EMAIL_UPDATE_SENT
- for q, meta_data in q_list.items():
- #this loop edits meta_data for each question
- #so that user will receive counts on new edits new answers, etc
- #maybe not so important actually??
-
- #keeps email activity per question per user
- try:
- update_info = Activity.objects.get(
- user=user,
- content_type=ctype,
- object_id=q.id,
- activity_type=EMAIL_UPDATE_ACTIVITY
- )
- emailed_at = update_info.active_at
- except Activity.DoesNotExist:
- update_info = Activity(user=user, content_object=q, activity_type=EMAIL_UPDATE_ACTIVITY)
- emailed_at = datetime.datetime(1970,1,1)#long time ago
- except Activity.MultipleObjectsReturned:
- raise Exception('server error - multiple question email activities found per user-question pair')
-
- cutoff_time = meta_data['cutoff_time']#cutoff time for the question
-
- #wait some more time before emailing about this question
- if emailed_at > cutoff_time:
- #here we are maybe losing opportunity to record the finding
- #of yet unseen version of a question
- meta_data['skip'] = True
- continue
-
- #collect info on all sorts of news that happened after
- #the most recent emailing to the user about this question
- q_rev = QuestionRevision.objects.filter(question=q,\
- revised_at__gt=emailed_at)
- q_rev = q_rev.exclude(author=user)
-
- #now update all sorts of metadata per question
- meta_data['q_rev'] = len(q_rev)
- if len(q_rev) > 0 and q.added_at == q_rev[0].revised_at:
- meta_data['q_rev'] = 0
- meta_data['new_q'] = True
- else:
- meta_data['new_q'] = False
-
- new_ans = Answer.objects.filter(question=q,\
- added_at__gt=emailed_at)
- new_ans = new_ans.exclude(author=user)
- meta_data['new_ans'] = len(new_ans)
- ans_rev = AnswerRevision.objects.filter(answer__question=q,\
- revised_at__gt=emailed_at)
- ans_rev = ans_rev.exclude(author=user)
- meta_data['ans_rev'] = len(ans_rev)
-
- if len(q_rev) + len(new_ans) + len(ans_rev) == 0:
- meta_data['skip'] = True
- else:
- meta_data['skip'] = False
- update_info.active_at = now
- update_info.save() #save question email update activity
- #q_list is actually a ordered dictionary
- #print 'user %s gets %d' % (user.username, len(q_list.keys()))
- #todo: sort question list by update time
- return q_list
-
- def __action_count(self,string,number,output):
- if number > 0:
- output.append(_(string) % {'num':number})
-
- def send_email_alerts(self):
- #does not change the database, only sends the email
- #todo: move this to template
- for user in User.objects.all():
- #todo: q_list is a dictionary, not a list
- q_list = self.get_updated_questions_for_user(user)
- if len(q_list.keys()) == 0:
- continue
- num_q = 0
- num_moot = 0
- for meta_data in q_list.values():
- if meta_data['skip']:
- num_moot = True
- else:
- num_q += 1
- if num_q > 0:
- url_prefix = settings.APP_URL
- subject = _('email update message subject')
- print 'have %d updated questions for %s' % (num_q, user.username)
- text = ungettext('%(name)s, this is an update message header for %(num)d question',
- '%(name)s, this is an update message header for %(num)d questions',num_q) \
- % {'num':num_q, 'name':user.username}
-
- text += '<ul>'
- items_added = 0
- items_unreported = 0
- for q, meta_data in q_list.items():
- act_list = []
- if meta_data['skip']:
- continue
- if items_added >= const.MAX_ALERTS_PER_EMAIL:
- items_unreported = num_q - items_added #may be inaccurate actually, but it's ok
-
- else:
- items_added += 1
- if meta_data['new_q']:
- act_list.append(_('new question'))
- self.__action_count('%(num)d rev', meta_data['q_rev'],act_list)
- self.__action_count('%(num)d ans', meta_data['new_ans'],act_list)
- self.__action_count('%(num)d ans rev',meta_data['ans_rev'],act_list)
- act_token = ', '.join(act_list)
- text += '<li><a href="%s?sort=latest">%s</a> <font color="#777777">(%s)</font></li>' \
- % (url_prefix + q.get_absolute_url(), q.title, act_token)
- text += '</ul>'
- text += '<p></p>'
- #if len(q_list.keys()) >= const.MAX_ALERTS_PER_EMAIL:
- # text += _('There may be more questions updated since '
- # 'you have logged in last time as this list is '
- # 'abridged for your convinience. Please visit '
- # 'the forum and see what\'s new!<br>'
- # )
-
- text += _(
- 'Please visit the forum and see what\'s new! '
- 'Could you spread the word about it - '
- 'can somebody you know help answering those questions or '
- 'benefit from posting one?'
- )
-
- feeds = EmailFeedSetting.objects.filter(
- subscriber=user,
- )
- feed_freq = [feed.frequency for feed in feeds]
- text += '<p></p>'
- if 'd' in feed_freq:
- text += _('Your most frequent subscription setting is \'daily\' '
- 'on selected questions. If you are receiving more than one '
- 'email per day'
- 'please tell about this issue to the forum administrator.'
- )
- elif 'w' in feed_freq:
- text += _('Your most frequent subscription setting is \'weekly\' '
- 'if you are receiving this email more than once a week '
- 'please report this issue to the forum administrator.'
- )
- text += ' '
- text += _(
- 'There is a chance that you may be receiving links seen '
- 'before - due to a technicality that will eventually go away. '
- )
- # text += '</p>'
- #if num_moot > 0:
- # text += '<p></p>'
- # text += ungettext('There is also one question which was recently '\
- # +'updated but you might not have seen its latest version.',
- # 'There are also %(num)d more questions which were recently updated '\
- # +'but you might not have seen their latest version.',num_moot) \
- # % {'num':num_moot,}
- # text += _('Perhaps you could look up previously sent forum reminders in your mailbox.')
- # text += '</p>'
-
- link = url_prefix + user.get_profile_url() + '?sort=email_subscriptions'
- text += _('go to %(link)s to change frequency of email updates or %(email)s administrator') \
- % {'link':link, 'email':settings.ADMINS[0][1]}
- msg = EmailMessage(subject, text, settings.DEFAULT_FROM_EMAIL, [user.email])
- msg.content_subtype = 'html'
- msg.send()
- #uncomment lines below to get copies of emails sent to others
- #todo: maybe some debug setting would be appropriate here
- #msg2 = EmailMessage(subject, text, settings.DEFAULT_FROM_EMAIL, ['your@email.com'])
- #msg2.content_subtype = 'html'
- #msg2.send()
diff --git a/forum/migrations/0001_initial.py b/forum/migrations/0001_initial.py
deleted file mode 100644
index e6350446..00000000
--- a/forum/migrations/0001_initial.py
+++ /dev/null
@@ -1,780 +0,0 @@
-# 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/0005_install_badges.py b/forum/migrations/0005_install_badges.py
deleted file mode 100644
index 5c05ecdd..00000000
--- a/forum/migrations/0005_install_badges.py
+++ /dev/null
@@ -1,417 +0,0 @@
-# encoding: utf-8
-import datetime
-from south.db import db
-from south.v2 import DataMigration
-from django.db import models
-
-_ = lambda v:v #fake translation function so that badges are translated, but database takes keys
-
-INITIAL_BADGE_DATA = (
- (_('Disciplined'), 3, _('disciplined'), _('Deleted own post with score of 3 or higher'), True, 0),
- (_('Peer Pressure'), 3, _('peer-pressure'), _('Deleted own post with score of -3 or lower'), True, 0),
- (_('Nice answer'), 3, _('nice-answer'), _('Answer voted up 10 times'), True, 0),
- (_('Nice Question'), 3, _('nice-question'), _('Question voted up 10 times'), True, 0),
- (_('Pundit'), 3, _('pundit'), _('Left 10 comments with score of 10 or more'), False, 0),
- (_('Popular Question'), 3, _('popular-question'), _('Asked a question with 1,000 views'), True, 0),
- (_('Citizen patrol'), 3, _('citizen-patrol'), _('First flagged post'), False, 0),
- (_('Cleanup'), 3, _('cleanup'), _('First rollback'), False, 0),
- (_('Critic'), 3, _('critic'), _('First down vote'), False, 0),
- (_('Editor'), 3, _('editor'), _('First edit'), False, 0),
- (_('Organizer'), 3, _('organizer'), _('First retag'), False, 0),
- (_('Scholar'), 3, _('scholar'), _('First accepted answer on your own question'), False, 0),
- (_('Student'), 3, _('student'), _('Asked first question with at least one up vote'), False, 0),
- (_('Supporter'), 3, _('supporter'), _('First up vote'), False, 0),
- (_('Teacher'), 3, _('teacher'), _('Answered first question with at least one up vote'), False, 0),
- (_('Autobiographer'), 3, _('autobiographer'), _('Completed all user profile fields'), False, 0),
- (_('Self-Learner'), 3, _('self-learner'), _('Answered your own question with at least 3 up votes'), True, 0),
- (_('Great Answer'), 1, _('great-answer'), _('Answer voted up 100 times'), True, 0),
- (_('Great Question'), 1, _('great-question'), _('Question voted up 100 times'), True, 0),
- (_('Stellar Question'), 1, _('stellar-question'), _('Question favorited by 100 users'), True, 0),
- (_('Famous question'), 1, _('famous-question'), _('Asked a question with 10,000 views'), True, 0),
- (_('Alpha'), 2, _('alpha'), _('Actively participated in the private alpha'), False, 0),
- (_('Good Answer'), 2, _('good-answer'), _('Answer voted up 25 times'), True, 0),
- (_('Good Question'), 2, _('good-question'), _('Question voted up 25 times'), True, 0),
- (_('Favorite Question'), 2, _('favorite-question'), _('Question favorited by 25 users'), True, 0),
- (_('Civic duty'), 2, _('civic-duty'), _('Voted 300 times'), False, 0),
- (_('Strunk & White'), 2, _('strunk-and-white'), _('Edited 100 entries'), False, 0),
- (_('Generalist'), 2, _('generalist'), _('Active in many different tags'), False, 0),
- (_('Expert'), 2, _('expert'), _('Very active in one tag'), False, 0),
- (_('Yearling'), 2, _('yearling'), _('Active member for a year'), False, 0),
- (_('Notable Question'), 2, _('notable-question'), _('Asked a question with 2,500 views'), True, 0),
- (_('Enlightened'), 2, _('enlightened'), _('First answer was accepted with at least 10 up votes'), False, 0),
- (_('Beta'), 2, _('beta'), _('Actively participated in the private beta'), False, 0),
- (_('Guru'), 2, _('guru'), _('Accepted answer and voted up 40 times'), True, 0),
- (_('Necromancer'), 2, _('necromancer'), _('Answered a question more than 60 days later with at least 5 votes'), True, 0),
- (_('Taxonomist'), 2, _('taxonomist'), _('Created a tag used by 50 questions'), True, 0)
-)
-
-class Migration(DataMigration):
-
- def forwards(self, orm):
- "Write your forwards methods here."
-
- for entry in INITIAL_BADGE_DATA:
- name = entry[0]
- type = entry[1]
- slug = entry[2]
- description = entry[3]
- multiple = entry[4]
-
- try:
- badge = orm.Badge.objects.get(name=name)
- print 'already have badge %s' % name
- except orm.Badge.DoesNotExist:
- print 'adding new badge %s' % name
- badge = orm.Badge()
- badge.name = name
-
- badge.type = type
- badge.slug = slug
- badge.description = description
- badge.multiple = multiple
- badge.save()
-
-
- def backwards(self, orm):
- "Write your backwards methods here."
- for entry in INITIAL_BADGE_DATA:
- name = entry[0]
- try:
- badge = orm.Badge.objects.get(name = name)
- badge.award_badge.clear()
- badge.delete()
- print 'deleted badge %s' % name
- except orm.Badge.DoesNotExist:
- print 'no such badge %s - so skipping' % name
- pass
-
- 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, 5, 2, 12, 29, 51, 920204)'}),
- '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/models/__init__.py b/forum/models/__init__.py
deleted file mode 100755
index d0d2d4a7..00000000
--- a/forum/models/__init__.py
+++ /dev/null
@@ -1,507 +0,0 @@
-from question import Question ,QuestionRevision, QuestionView, AnonymousQuestion, FavoriteQuestion
-from answer import Answer, AnonymousAnswer, AnswerRevision
-from tag import Tag, MarkedTag
-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 *
-import datetime
-from django.contrib.contenttypes.models import ContentType
-
-#todo: move to a separate file?
-# custom signals
-tags_updated = django.dispatch.Signal(providing_args=["question"])
-edit_question_or_answer = django.dispatch.Signal(providing_args=["instance", "modified_by"])
-delete_post_or_answer = django.dispatch.Signal(providing_args=["instance", "deleted_by"])
-mark_offensive = django.dispatch.Signal(providing_args=["instance", "mark_by"])
-user_updated = django.dispatch.Signal(providing_args=["instance", "updated_by"])
-user_logged_in = django.dispatch.Signal(providing_args=["session"])
-
-#todo: must go after signals
-from forum import auth
-
-# User extend properties
-QUESTIONS_PER_PAGE_CHOICES = (
- (10, u'10'),
- (30, u'30'),
- (50, u'50'),
-)
-
-def user_is_username_taken(cls,username):
- try:
- cls.objects.get(username=username)
- return True
- except cls.MultipleObjectsReturned:
- return True
- except cls.DoesNotExist:
- return False
-
-def user_get_q_sel_email_feed_frequency(self):
- #print 'looking for frequency for user %s' % self
- try:
- feed_setting = EmailFeedSetting.objects.get(subscriber=self,feed_type='q_sel')
- except Exception, e:
- #print 'have error %s' % e.message
- raise e
- #print 'have freq=%s' % feed_setting.frequency
- return feed_setting.frequency
-
-def user_get_absolute_url(self):
- return "/users/%d/%s/" % (self.id, (self.username))
-
-User.add_to_class('is_approved', models.BooleanField(default=False))
-User.add_to_class('email_isvalid', models.BooleanField(default=False))
-User.add_to_class('email_key', models.CharField(max_length=32, null=True))
-User.add_to_class('reputation', models.PositiveIntegerField(default=1))
-User.add_to_class('gravatar', models.CharField(max_length=32))
-
-#User.add_to_class('favorite_questions',
-# models.ManyToManyField(Question, through=FavoriteQuestion,
-# related_name='favorited_by'))
-
-#User.add_to_class('badges', models.ManyToManyField(Badge, through=Award,
-# related_name='awarded_to'))
-User.add_to_class('gold', models.SmallIntegerField(default=0))
-User.add_to_class('silver', models.SmallIntegerField(default=0))
-User.add_to_class('bronze', models.SmallIntegerField(default=0))
-User.add_to_class('questions_per_page',
- models.SmallIntegerField(choices=QUESTIONS_PER_PAGE_CHOICES, default=10))
-User.add_to_class('last_seen',
- models.DateTimeField(default=datetime.datetime.now))
-User.add_to_class('real_name', models.CharField(max_length=100, blank=True))
-User.add_to_class('website', models.URLField(max_length=200, blank=True))
-User.add_to_class('location', models.CharField(max_length=100, blank=True))
-User.add_to_class('date_of_birth', models.DateField(null=True, blank=True))
-User.add_to_class('about', models.TextField(blank=True))
-User.add_to_class('is_username_taken',classmethod(user_is_username_taken))
-User.add_to_class('get_q_sel_email_feed_frequency',user_get_q_sel_email_feed_frequency)
-User.add_to_class('hide_ignored_questions', models.BooleanField(default=False))
-User.add_to_class('tag_filter_setting',
- models.CharField(
- max_length=16,
- choices=TAG_EMAIL_FILTER_CHOICES,
- default='ignored'
- )
- )
-User.add_to_class('get_absolute_url', user_get_absolute_url)
-
-def get_messages(self):
- messages = []
- for m in self.message_set.all():
- messages.append(m.message)
- return messages
-
-def delete_messages(self):
- self.message_set.all().delete()
-
-def get_profile_url(self):
- """Returns the URL for this User's profile."""
- return reverse('user_profile', kwargs={'id':self.id, 'slug':slugify(self.username)})
-
-def get_profile_link(self):
- profile_link = u'<a href="%s">%s</a>' % (self.get_profile_url(),self.username)
- logging.debug('in get profile link %s' % profile_link)
- return mark_safe(profile_link)
-
-#series of methods for user vote-type commands
-#same call signature func(self, post, timestamp=None, cancel=None)
-#note that none of these have business logic checks internally
-#these functions are used by the forum app and
-#by the data importer jobs from say stackexchange, where internal rules
-#may be different
-#maybe if we do use business rule checks here - we should add
-#some flag allowing to bypass them for things like the data importers
-def toggle_favorite_question(self, question, timestamp=None, cancel=False):
- """cancel has no effect here, but is important for the SE loader
- it is hoped that toggle will work and data will be consistent
- but there is no guarantee, maybe it's better to be more strict
- about processing the "cancel" option
- another strange thing is that this function unlike others below
- returns a value
- """
- try:
- fave = FavoriteQuestion.objects.get(question=question, user=self)
- fave.delete()
- result = False
- except FavoriteQuestion.DoesNotExist:
- if timestamp is None:
- timestamp = datetime.datetime.now()
- fave = FavoriteQuestion(
- question = question,
- user = self,
- added_at = timestamp,
- )
- fave.save()
- result = True
- Question.objects.update_favorite_count(question)
- return result
-
-#"private" wrapper function that applies post upvotes/downvotes and cancelations
-def _process_vote(user, post, timestamp=None, cancel=False, vote_type=None):
- post_type = ContentType.objects.get_for_model(post)
- #get or create the vote object
- #return with noop in some situations
- try:
- vote = Vote.objects.get(
- user = user,
- content_type = post_type,
- object_id = post.id,
- )
- except Vote.DoesNotExist:
- vote = None
- if cancel:
- if vote == None:
- return
- elif vote.is_opposite(vote_type):
- return
- else:
- #we would call vote.delete() here
- #but for now all that is handled by the
- #legacy forum.auth functions
- #vote.delete()
- pass
- else:
- if vote == None:
- vote = Vote(
- user = user,
- content_object = post,
- vote = vote_type,
- voted_at = timestamp,
- )
- elif vote.is_opposite(vote_type):
- vote.vote = vote_type
- else:
- return
-
- #do the actual work
- if vote_type == Vote.VOTE_UP:
- if cancel:
- auth.onUpVotedCanceled(vote, post, user, timestamp)
- else:
- auth.onUpVoted(vote, post, user, timestamp)
- elif vote_type == Vote.VOTE_DOWN:
- if cancel:
- auth.onDownVotedCanceled(vote, post, user, timestamp)
- else:
- auth.onDonwVoted(vote, post, user, timestamp)
-
-def upvote(self, post, timestamp=None, cancel=False):
- _process_vote(
- self,post,
- timestamp=timestamp,
- cancel=cancel,
- vote_type=Vote.VOTE_UP
- )
-
-def downvote(self, post, timestamp=None, cancel=False):
- _process_vote(
- self,post,
- timestamp=timestamp,
- cancel=cancel,
- vote_type=Vote.VOTE_DOWN
- )
-
-def accept_answer(self, answer, timestamp=None, cancel=False):
- if cancel:
- auth.onAnswerAcceptCanceled(answer, self, timestamp=timestamp)
- else:
- auth.onAnswerAccept(answer, self, timestamp=timestamp)
-
-def flag_post(self, post, timestamp=None, cancel=False):
- if cancel:#todo: can't unflag?
- return
- if post.flagged_items.filter(user=user).count() > 0:
- return
- else:
- flag = FlaggedItem(
- user = self,
- content_object = post,
- flagged_at = timestamp,
- )
- auth.onFlaggedItem(flag, post, user, timestamp=timestamp)
-
-User.add_to_class('upvote', upvote)
-User.add_to_class('downvote', downvote)
-User.add_to_class('accept_answer', accept_answer)
-User.add_to_class('flag_post', flag_post)
-User.add_to_class('get_profile_url', get_profile_url)
-User.add_to_class('get_profile_link', get_profile_link)
-User.add_to_class('get_messages', get_messages)
-User.add_to_class('delete_messages', delete_messages)
-User.add_to_class('toggle_favorite_question', toggle_favorite_question)
-
-def calculate_gravatar_hash(instance, **kwargs):
- """Calculates a User's gravatar hash from their email address."""
- if kwargs.get('raw', False):
- return
- instance.gravatar = hashlib.md5(instance.email).hexdigest()
-
-def record_ask_event(instance, created, **kwargs):
- if created:
- activity = Activity(user=instance.author, active_at=instance.added_at, content_object=instance, activity_type=TYPE_ACTIVITY_ASK_QUESTION)
- activity.save()
-
-#todo: translate this
-record_answer_event_re = re.compile("You have received (a|\d+) .*new response.*")
-def record_answer_event(instance, created, **kwargs):
- if created:
- q_author = instance.question.author
- found_match = False
- for m in q_author.message_set.all():
- match = record_answer_event_re.search(m.message)
- if match:
- found_match = True
- try:
- cnt = int(match.group(1))
- except:
- cnt = 1
- m.message = u"You have received %d <a href=\"%s?sort=responses\">new responses</a>."\
- % (cnt+1, q_author.get_profile_url())
- m.save()
- break
- if not found_match:
- msg = u"You have received a <a href=\"%s?sort=responses\">new response</a>."\
- % q_author.get_profile_url()
- q_author.message_set.create(message=msg)
-
- activity = Activity(user=instance.author, \
- active_at=instance.added_at,\
- content_object=instance, \
- activity_type=TYPE_ACTIVITY_ANSWER)
- activity.save()
-
-def record_comment_event(instance, created, **kwargs):
- if created:
- from django.contrib.contenttypes.models import ContentType
- question_type = ContentType.objects.get_for_model(Question)
- question_type_id = question_type.id
- if (instance.content_type_id == question_type_id):
- type = TYPE_ACTIVITY_COMMENT_QUESTION
- else:
- type = TYPE_ACTIVITY_COMMENT_ANSWER
- activity = Activity(user=instance.user, active_at=instance.added_at, content_object=instance, activity_type=type)
- activity.save()
-
-def record_revision_question_event(instance, created, **kwargs):
- if created and instance.revision <> 1:
- activity = Activity(user=instance.author, active_at=instance.revised_at, content_object=instance, activity_type=TYPE_ACTIVITY_UPDATE_QUESTION)
- activity.save()
-
-def record_revision_answer_event(instance, created, **kwargs):
- if created and instance.revision <> 1:
- activity = Activity(user=instance.author, active_at=instance.revised_at, content_object=instance, activity_type=TYPE_ACTIVITY_UPDATE_ANSWER)
- activity.save()
-
-def record_award_event(instance, created, **kwargs):
- """
- After we awarded a badge to user, we need to record this activity and notify user.
- We also recaculate awarded_count of this badge and user information.
- """
- if created:
- activity = Activity(user=instance.user, active_at=instance.awarded_at, content_object=instance,
- activity_type=TYPE_ACTIVITY_PRIZE)
- activity.save()
-
- instance.badge.awarded_count += 1
- instance.badge.save()
-
- if instance.badge.type == Badge.GOLD:
- instance.user.gold += 1
- if instance.badge.type == Badge.SILVER:
- instance.user.silver += 1
- if instance.badge.type == Badge.BRONZE:
- instance.user.bronze += 1
- instance.user.save()
-
-def notify_award_message(instance, created, **kwargs):
- """
- Notify users when they have been awarded badges by using Django message.
- """
- if created:
- user = instance.user
-
- msg = (u"Congratulations, you have received a badge '%s'. " \
- + u"Check out <a href=\"%s\">your profile</a>.") \
- % (instance.badge.name, user.get_profile_url())
-
- user.message_set.create(message=msg)
-
-def record_answer_accepted(instance, created, **kwargs):
- """
- when answer is accepted, we record this for question author - who accepted it.
- """
- if not created and instance.accepted:
- activity = Activity(user=instance.question.author, active_at=datetime.datetime.now(), \
- content_object=instance, activity_type=TYPE_ACTIVITY_MARK_ANSWER)
- activity.save()
-
-def update_last_seen(instance, created, **kwargs):
- """
- when user has activities, we update 'last_seen' time stamp for him
- """
- user = instance.user
- user.last_seen = datetime.datetime.now()
- user.save()
-
-def record_vote(instance, created, **kwargs):
- """
- when user have voted
- """
- if created:
- if instance.vote == 1:
- vote_type = TYPE_ACTIVITY_VOTE_UP
- else:
- vote_type = TYPE_ACTIVITY_VOTE_DOWN
-
- activity = Activity(user=instance.user, active_at=instance.voted_at, content_object=instance, activity_type=vote_type)
- activity.save()
-
-def record_cancel_vote(instance, **kwargs):
- """
- when user canceled vote, the vote will be deleted.
- """
- activity = Activity(user=instance.user, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_CANCEL_VOTE)
- activity.save()
-
-def record_delete_question(instance, delete_by, **kwargs):
- """
- when user deleted the question
- """
- if instance.__class__ == "Question":
- activity_type = TYPE_ACTIVITY_DELETE_QUESTION
- else:
- activity_type = TYPE_ACTIVITY_DELETE_ANSWER
-
- activity = Activity(user=delete_by, active_at=datetime.datetime.now(), content_object=instance, activity_type=activity_type)
- activity.save()
-
-def record_mark_offensive(instance, mark_by, **kwargs):
- activity = Activity(user=mark_by, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_MARK_OFFENSIVE)
- activity.save()
-
-def record_update_tags(question, **kwargs):
- """
- when user updated tags of the question
- """
- activity = Activity(user=question.author, active_at=datetime.datetime.now(), content_object=question, activity_type=TYPE_ACTIVITY_UPDATE_TAGS)
- activity.save()
-
-def record_favorite_question(instance, created, **kwargs):
- """
- when user add the question in him favorite questions list.
- """
- if created:
- activity = Activity(user=instance.user, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_FAVORITE)
- activity.save()
-
-def record_user_full_updated(instance, **kwargs):
- activity = Activity(user=instance, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_USER_FULL_UPDATED)
- activity.save()
-
-def post_stored_anonymous_content(sender,user,session_key,signal,*args,**kwargs):
- aq_list = AnonymousQuestion.objects.filter(session_key = session_key)
- aa_list = AnonymousAnswer.objects.filter(session_key = session_key)
- import settings
- if settings.EMAIL_VALIDATION == 'on':#add user to the record
- for aq in aq_list:
- aq.author = user
- aq.save()
- for aa in aa_list:
- aa.author = user
- aa.save()
- #maybe add pending posts message?
- else: #just publish the questions
- for aq in aq_list:
- aq.publish(user)
- for aa in aa_list:
- aa.publish(user)
-
-#signal for User modle save changes
-pre_save.connect(calculate_gravatar_hash, sender=User)
-post_save.connect(record_ask_event, sender=Question)
-post_save.connect(record_answer_event, sender=Answer)
-post_save.connect(record_comment_event, sender=Comment)
-post_save.connect(record_revision_question_event, sender=QuestionRevision)
-post_save.connect(record_revision_answer_event, sender=AnswerRevision)
-post_save.connect(record_award_event, sender=Award)
-post_save.connect(notify_award_message, sender=Award)
-post_save.connect(record_answer_accepted, sender=Answer)
-post_save.connect(update_last_seen, sender=Activity)
-post_save.connect(record_vote, sender=Vote)
-post_delete.connect(record_cancel_vote, sender=Vote)
-delete_post_or_answer.connect(record_delete_question, sender=Question)
-delete_post_or_answer.connect(record_delete_question, sender=Answer)
-mark_offensive.connect(record_mark_offensive, sender=Question)
-mark_offensive.connect(record_mark_offensive, sender=Answer)
-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
-QuestionView = QuestionView
-FavoriteQuestion = FavoriteQuestion
-AnonymousQuestion = AnonymousQuestion
-
-Answer = Answer
-AnswerRevision = AnswerRevision
-AnonymousAnswer = AnonymousAnswer
-
-Tag = Tag
-Comment = Comment
-Vote = Vote
-FlaggedItem = FlaggedItem
-MarkedTag = MarkedTag
-
-Badge = Badge
-Award = Award
-Repute = Repute
-
-Activity = Activity
-EmailFeedSetting = EmailFeedSetting
-ValidationHash = ValidationHash
-AuthKeyUserAssociation = AuthKeyUserAssociation
-
-__all__ = [
- 'Question',
- 'QuestionRevision',
- 'QuestionView',
- 'FavoriteQuestion',
- 'AnonymousQuestion',
-
- 'Answer',
- 'AnswerRevision',
- 'AnonymousAnswer',
-
- 'Tag',
- 'Comment',
- 'Vote',
- 'FlaggedItem',
- 'MarkedTag',
-
- 'Badge',
- 'Award',
- 'Repute',
-
- 'Activity',
- 'EmailFeedSetting',
- 'ValidationHash',
- 'AuthKeyUserAssociation',
-
- 'User',
- ]
-
-
-from forum.modules import get_modules_script_classes
-
-for k, v in get_modules_script_classes('models', models.Model).items():
- if not k in __all__:
- __all__.append(k)
- exec "%s = v" % k
diff --git a/forum/models/base.py b/forum/models/base.py
deleted file mode 100755
index fcec47b4..00000000
--- a/forum/models/base.py
+++ /dev/null
@@ -1,160 +0,0 @@
-import datetime
-import hashlib
-from urllib import quote_plus, urlencode
-from django.db import models, IntegrityError, connection, transaction
-from django.utils.http import urlquote as django_urlquote
-from django.utils.html import strip_tags
-from django.core.urlresolvers import reverse
-from django.contrib.auth.models import User
-from django.contrib.contenttypes import generic
-from django.contrib.contenttypes.models import ContentType
-from django.template.defaultfilters import slugify
-from django.db.models.signals import post_delete, post_save, pre_save
-from django.utils.translation import ugettext as _
-from django.utils.safestring import mark_safe
-from django.contrib.sitemaps import ping_google
-import django.dispatch
-from django.conf import settings
-import logging
-
-#todo: sphinx search import used to be here
-
-from forum.const import *
-
-class UserContent(models.Model):
- user = models.ForeignKey(User, related_name='%(class)ss')
-
- class Meta:
- abstract = True
- app_label = 'forum'
-
-class MetaContent(models.Model):
- """
- Base class for Vote, Comment and FlaggedItem
- """
- content_type = models.ForeignKey(ContentType)
- object_id = models.PositiveIntegerField()
- content_object = generic.GenericForeignKey('content_type', 'object_id')
-
- class Meta:
- abstract = True
- app_label = 'forum'
-
-
-class DeletableContent(models.Model):
- deleted = models.BooleanField(default=False)
- deleted_at = models.DateTimeField(null=True, blank=True)
- deleted_by = models.ForeignKey(User, null=True, blank=True, related_name='deleted_%(class)ss')
-
- class Meta:
- abstract = True
- app_label = 'forum'
-
-
-class ContentRevision(models.Model):
- """
- Base class for QuestionRevision and AnswerRevision
- """
- revision = models.PositiveIntegerField()
- author = models.ForeignKey(User, related_name='%(class)ss')
- revised_at = models.DateTimeField()
- summary = models.CharField(max_length=300, blank=True)
- text = models.TextField()
-
- class Meta:
- abstract = True
- app_label = 'forum'
-
-
-class AnonymousContent(models.Model):
- """
- Base class for AnonymousQuestion and AnonymousAnswer
- """
- session_key = models.CharField(max_length=40) #session id for anonymous questions
- wiki = models.BooleanField(default=False)
- added_at = models.DateTimeField(default=datetime.datetime.now)
- ip_addr = models.IPAddressField(max_length=21) #allow high port numbers
- author = models.ForeignKey(User,null=True)
- text = models.TextField()
- summary = models.CharField(max_length=180)
-
- class Meta:
- abstract = True
- app_label = 'forum'
-
-
-from meta import Comment, Vote, FlaggedItem
-
-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)
-
- 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)
-
- 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)
- 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')
-
- 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
- app_label = 'forum'
-
- def save(self,**kwargs):
- super(Content,self).save(**kwargs)
- try:
- ping_google()
- except Exception:
- logging.debug('problem pinging google did you register you sitemap with google?')
-
- def get_comments(self):
- comments = self.comments.all().order_by('id')
- return comments
-
- def add_comment(self, comment=None, user=None, added_at=None):
- if added_at is None:
- added_at = datetime.datetime.now()
- if None in (comment ,user):
- raise Exception('arguments comment and user are required')
-
- Comment = models.get_model('forum','Comment')#todo: forum hardcoded
- comment = Comment(content_object=self, comment=comment, user=user, added_at=added_at)
- comment.save()
- self.comment_count = self.comment_count + 1
- self.save()
-
- 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:
- when = self.last_edited_at
- who = self.last_edited_by
- comments = self.comments.all()
- if len(comments) > 0:
- for c in comments:
- if c.added_at > when:
- when = c.added_at
- who = c.user
- return when, who
diff --git a/forum/models/meta.py b/forum/models/meta.py
deleted file mode 100755
index 114d2130..00000000
--- a/forum/models/meta.py
+++ /dev/null
@@ -1,93 +0,0 @@
-from base import *
-
-class VoteManager(models.Manager):
- def get_up_vote_count_from_user(self, user):
- if user is not None:
- return self.filter(user=user, vote=1).count()
- else:
- return 0
-
- def get_down_vote_count_from_user(self, user):
- if user is not None:
- return self.filter(user=user, vote=-1).count()
- else:
- return 0
-
- def get_votes_count_today_from_user(self, user):
- if user is not None:
- today = datetime.date.today()
- return self.filter(user=user, voted_at__range=(today, today + datetime.timedelta(1))).count()
-
- else:
- return 0
-
-
-class Vote(MetaContent, UserContent):
- VOTE_UP = +1
- VOTE_DOWN = -1
- VOTE_CHOICES = (
- (VOTE_UP, u'Up'),
- (VOTE_DOWN, u'Down'),
- )
-
- vote = models.SmallIntegerField(choices=VOTE_CHOICES)
- voted_at = models.DateTimeField(default=datetime.datetime.now)
-
- objects = VoteManager()
-
- class Meta(MetaContent.Meta):
- unique_together = ('content_type', 'object_id', 'user')
- db_table = u'vote'
-
- def __unicode__(self):
- return '[%s] voted at %s: %s' %(self.user, self.voted_at, self.vote)
-
- def is_upvote(self):
- return self.vote == self.VOTE_UP
-
- def is_downvote(self):
- return self.vote == self.VOTE_DOWN
-
- def is_opposite(self, vote_type):
- assert(vote_type in (self.VOTE_UP, self.VOTE_DOWN))
- return self.vote != vote_type
-
-
-class FlaggedItemManager(models.Manager):
- def get_flagged_items_count_today(self, user):
- if user is not None:
- today = datetime.date.today()
- return self.filter(user=user, flagged_at__range=(today, today + datetime.timedelta(1))).count()
- else:
- return 0
-
-class FlaggedItem(MetaContent, UserContent):
- """A flag on a Question or Answer indicating offensive content."""
- flagged_at = models.DateTimeField(default=datetime.datetime.now)
-
- objects = FlaggedItemManager()
-
- class Meta(MetaContent.Meta):
- unique_together = ('content_type', 'object_id', 'user')
- db_table = u'flagged_item'
-
- def __unicode__(self):
- return '[%s] flagged at %s' %(self.user, self.flagged_at)
-
-class Comment(MetaContent, UserContent):
- comment = models.CharField(max_length=300)
- added_at = models.DateTimeField(default=datetime.datetime.now)
-
- class Meta(MetaContent.Meta):
- ordering = ('-added_at',)
- db_table = u'comment'
-
- def save(self,**kwargs):
- super(Comment,self).save(**kwargs)
- try:
- ping_google()
- except Exception:
- logging.debug('problem pinging google did you register you sitemap with google?')
-
- def __unicode__(self):
- return self.comment
diff --git a/forum/models/user.py b/forum/models/user.py
deleted file mode 100755
index 6d871bf4..00000000
--- a/forum/models/user.py
+++ /dev/null
@@ -1,134 +0,0 @@
-from base import *
-from django.contrib.contenttypes.models import ContentType
-from django.contrib.auth.models import User
-from hashlib import md5
-import string
-from random import Random
-
-from django.utils.translation import ugettext as _
-
-class Activity(models.Model):
- """
- We keep some history data for user activities
- """
- user = models.ForeignKey(User)
- activity_type = models.SmallIntegerField(choices=TYPE_ACTIVITY)
- active_at = models.DateTimeField(default=datetime.datetime.now)
- content_type = models.ForeignKey(ContentType)
- object_id = models.PositiveIntegerField()
- content_object = generic.GenericForeignKey('content_type', 'object_id')
- is_auditted = models.BooleanField(default=False)
-
- def __unicode__(self):
- return u'[%s] was active at %s' % (self.user.username, self.active_at)
-
- class Meta:
- app_label = 'forum'
- db_table = u'activity'
-
-class EmailFeedSetting(models.Model):
- DELTA_TABLE = {
- 'w':datetime.timedelta(7),
- 'd':datetime.timedelta(1),
- 'n':datetime.timedelta(-1),
- }
- FEED_TYPES = (
- ('q_all',_('Entire forum')),
- ('q_ask',_('Questions that I asked')),
- ('q_ans',_('Questions that I answered')),
- ('q_sel',_('Individually selected questions')),
- )
- UPDATE_FREQUENCY = (
- ('w',_('Weekly')),
- ('d',_('Daily')),
- ('n',_('No email')),
- )
- subscriber = models.ForeignKey(User)
- feed_type = models.CharField(max_length=16,choices=FEED_TYPES)
- frequency = models.CharField(max_length=8,choices=UPDATE_FREQUENCY,default='n')
- added_at = models.DateTimeField(auto_now_add=True)
- reported_at = models.DateTimeField(null=True)
-
- def save(self,*args,**kwargs):
- type = self.feed_type
- subscriber = self.subscriber
- similar = self.__class__.objects.filter(feed_type=type,subscriber=subscriber).exclude(pk=self.id)
- if len(similar) > 0:
- raise IntegrityError('email feed setting already exists')
- super(EmailFeedSetting,self).save(*args,**kwargs)
-
- class Meta:
- app_label = 'forum'
-
-from forum.utils.time import one_day_from_now
-
-class ValidationHashManager(models.Manager):
- def _generate_md5_hash(self, user, type, hash_data, seed):
- return md5("%s%s%s%s" % (seed, "".join(map(str, hash_data)), user.id, type)).hexdigest()
-
- def create_new(self, user, type, hash_data=[], expiration=None):
- seed = ''.join(Random().sample(string.letters+string.digits, 12))
- hash = self._generate_md5_hash(user, type, hash_data, seed)
-
- obj = ValidationHash(hash_code=hash, seed=seed, user=user, type=type)
-
- if expiration is not None:
- obj.expiration = expiration
-
- try:
- obj.save()
- except:
- return None
-
- return obj
-
- def validate(self, hash, user, type, hash_data=[]):
- try:
- obj = self.get(hash_code=hash)
- except:
- return False
-
- if obj.type != type:
- return False
-
- if obj.user != user:
- return False
-
- valid = (obj.hash_code == self._generate_md5_hash(obj.user, type, hash_data, obj.seed))
-
- if valid:
- if obj.expiration < datetime.datetime.now():
- obj.delete()
- return False
- else:
- obj.delete()
- return True
-
- return False
-
-class ValidationHash(models.Model):
- #todo: was 256 chars - is that important?
- #on mysql 255 is max for unique=True
- hash_code = models.CharField(max_length=255,unique=True)
- seed = models.CharField(max_length=12)
- expiration = models.DateTimeField(default=one_day_from_now)
- type = models.CharField(max_length=12)
- user = models.ForeignKey(User)
-
- objects = ValidationHashManager()
-
- class Meta:
- unique_together = ('user', 'type')
- app_label = 'forum'
-
- def __str__(self):
- return self.hash_code
-
-class AuthKeyUserAssociation(models.Model):
- key = models.CharField(max_length=255,null=False,unique=True)
- provider = models.CharField(max_length=64)#string 'yahoo', 'google', etc.
- user = models.ForeignKey(User, related_name="auth_keys")
- added_at = models.DateTimeField(default=datetime.datetime.now)
-
- class Meta:
- app_label = 'forum'
diff --git a/forum/modules.py b/forum/modules.py
deleted file mode 100755
index 6c9a9dba..00000000
--- a/forum/modules.py
+++ /dev/null
@@ -1,78 +0,0 @@
-import os
-import types
-import re
-
-from django.template import Template, TemplateDoesNotExist
-
-MODULES_PACKAGE = 'forum_modules'
-
-MODULES_FOLDER = os.path.join(os.path.dirname(__file__), '../' + MODULES_PACKAGE)
-
-MODULE_LIST = [
- __import__('forum_modules.%s' % f, globals(), locals(), ['forum_modules'])
- for f in os.listdir(MODULES_FOLDER)
- if os.path.isdir(os.path.join(MODULES_FOLDER, f)) and
- os.path.exists(os.path.join(MODULES_FOLDER, "%s/__init__.py" % f)) and
- not os.path.exists(os.path.join(MODULES_FOLDER, "%s/DISABLED" % f))
-]
-
-def get_modules_script(script_name):
- all = []
-
- for m in MODULE_LIST:
- try:
- all.append(__import__('%s.%s' % (m.__name__, script_name), globals(), locals(), [m.__name__]))
- except Exception, e:
- #print script_name + ":" + str(e)
- pass
-
- return all
-
-def get_modules_script_classes(script_name, base_class):
- scripts = get_modules_script(script_name)
- all_classes = {}
-
- for script in scripts:
- all_classes.update(dict([
- (n, c) for (n, c) in [(n, getattr(script, n)) for n in dir(script)]
- if isinstance(c, (type, types.ClassType)) and issubclass(c, base_class)
- ]))
-
- return all_classes
-
-def get_all_handlers(name):
- handler_files = get_modules_script('handlers')
-
- return [
- h for h in [
- getattr(f, name) for f in handler_files
- if hasattr(f, name)
- ]
-
- if callable(h)
- ]
-
-def get_handler(name, default):
- all = get_all_handlers(name)
- return len(all) and all[0] or default
-
-module_template_re = re.compile('^modules\/(\w+)\/(.*)$')
-
-def module_templates_loader(name, dirs=None):
- result = module_template_re.search(name)
-
- if result is not None:
- file_name = os.path.join(MODULES_FOLDER, result.group(1), 'templates', result.group(2))
-
- if os.path.exists(file_name):
- try:
- f = open(file_name, 'r')
- source = f.read()
- f.close()
- return (source, file_name)
- except:
- pass
-
- raise TemplateDoesNotExist, name
-
-module_templates_loader.is_usable = True
diff --git a/forum/settings.py b/forum/settings.py
deleted file mode 100755
index 04a7c399..00000000
--- a/forum/settings.py
+++ /dev/null
@@ -1,51 +0,0 @@
-import os
-
-
-INSTALLED_APPS = ['forum']
-
-MIDDLEWARE_CLASSES = [
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.common.CommonMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'forum.middleware.anon_user.ConnectToSessionMessagesMiddleware',
- 'forum.middleware.pagesize.QuestionsPageSizeMiddleware',
- 'forum.middleware.cancel.CancelActionMiddleware',
- 'django.middleware.transaction.TransactionMiddleware',
-]
-
-TEMPLATE_LOADERS = [
- 'django.template.loaders.filesystem.load_template_source',
- 'django.template.loaders.app_directories.load_template_source',
- 'forum.modules.module_templates_loader',
- 'forum.skins.load_template_source',
-]
-
-TEMPLATE_CONTEXT_PROCESSORS = [
- 'django.core.context_processors.request',
- 'forum.context.application_settings',
- 'forum.user_messages.context_processors.user_messages',
- 'django.core.context_processors.auth',
-]
-
-TEMPLATE_DIRS = [
- os.path.join(os.path.dirname(__file__),'skins').replace('\\','/'),
-]
-
-def setup_settings(settings):
-
- if (hasattr(settings, 'DEBUG') and getattr(settings, 'DEBUG')):
- try:
- import debug_toolbar
- INSTALLED_APPS.append('debug_toolbar')
- MIDDLEWARE_CLASSES.append('debug_toolbar.middleware.DebugToolbarMiddleware')
- except:
- pass
-
-
- settings.INSTALLED_APPS = set(settings.INSTALLED_APPS) | set(INSTALLED_APPS)
- settings.MIDDLEWARE_CLASSES = set(settings.MIDDLEWARE_CLASSES) | set(MIDDLEWARE_CLASSES)
- settings.TEMPLATE_LOADERS = set(settings.TEMPLATE_LOADERS) | set(TEMPLATE_LOADERS)
- settings.TEMPLATE_CONTEXT_PROCESSORS = set(settings.TEMPLATE_CONTEXT_PROCESSORS) | set(TEMPLATE_CONTEXT_PROCESSORS)
- settings.TEMPLATE_DIRS = set(settings.TEMPLATE_DIRS) | set(TEMPLATE_DIRS)
-
- \ No newline at end of file
diff --git a/forum/skins/common/media/js/closure/README.rst b/forum/skins/common/media/js/closure/README.rst
deleted file mode 100644
index b7423694..00000000
--- a/forum/skins/common/media/js/closure/README.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-This directory contains source javascript files
-written with Google Closure library
-
-* to start developing with closure here, run (Unix shell) script
- setup-closure.sh (if your environment does not like the script
- please take a look what's inside and replicate it for your system)
-* please don't commit closure sources to our repo
- i.e. add this line to .gitignore
- forum/skins/common/media/js/closure/google-closure
diff --git a/forum/skins/common/media/js/closure/setup-closure.sh b/forum/skins/common/media/js/closure/setup-closure.sh
deleted file mode 100644
index a3ebaf75..00000000
--- a/forum/skins/common/media/js/closure/setup-closure.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-svn checkout http://closure-library.googlecode.com/svn/trunk/ google-closure
-mkdir google-closure/tools
-mkdir google-closure/tools/compiler
-cd google-closure/tools/compiler
-wget http://closure-compiler.googlecode.com/files/compiler-latest.zip
-unzip compiler-latest.zip
-cd ../../..
-mkdir google-closure/tools/soy
-cd google-closure/tools/soy
-wget http://closure-templates.googlecode.com/files/closure-templates-for-javascript-latest.zip
-unzip closure-templates-for-javascript-latest.zip
-cd ../../
diff --git a/forum/skins/default/templates/about.html b/forum/skins/default/templates/about.html
deleted file mode 100644
index 686141b3..00000000
--- a/forum/skins/default/templates/about.html
+++ /dev/null
@@ -1,36 +0,0 @@
-{% extends "base.html" %}
-<!-- template about.html -->
-{% load i18n %}
-{% load extra_tags %}
-{% load humanize %}
-{% block title %}{% spaceless %}{% trans "About" %}{% endspaceless %}{% endblock %}
-{% block forejs %}
-{% endblock %}
-{% block content %}
-<div class="headNormal">
-{% trans "About" %}
-</div>
-
-<div class="content">
- <p class="strong">Please customize file templates/about.html</p>
-
- <p>Here you can <strong>ask</strong> and <strong>answer</strong> questions, <strong>comment</strong>
- and <strong>vote</strong> for the questions of others and their answers. Both questions and answers
- <strong>can be revised</strong> and improved. Questions can be <strong>tagged</strong> with
- the relevant keywords to simplify future access and organize the accumulated material.
- </p>
-
- <p>This <span class="orange">Q&amp;A</span> site is moderated by its members, hopefully - including yourself!
- Moderation rights are gradually assigned to the site users based on the accumulated <strong>"reputation"</strong>
- points. These points are added to the users account when others vote for his/her questions or answers.
- These points (very) roughly reflect the level of trust of the community.
- </p>
- <p>No points are necessary to ask or answer the questions - so please -
- <strong><a href="{% url user_signin %}">join us!</a></strong>
- </p>
- <p>
- If you would like to find out more about this site - please see <strong><a href="{% url faq %}">frequently asked questions</a></strong>.
- </p>
-</div>
-{% endblock %}
-<!-- end template about.html -->
diff --git a/forum/skins/default/templates/header.html b/forum/skins/default/templates/header.html
deleted file mode 100644
index 0a1a3296..00000000
--- a/forum/skins/default/templates/header.html
+++ /dev/null
@@ -1,47 +0,0 @@
-<!-- template header.html -->
-{% load extra_tags %}
-{% load smart_if %}
-{% load i18n %}
- <div id="roof">
- <div id="navBar">
- <div id="top">
- {% if request.user.is_authenticated %}
- <a href="{% url user_profile id=request.user.id,slug=request.user.username|slugify %}">{{ request.user.username }}</a> {% get_score_badge request.user %}
- <a href="{% url logout %}">{% trans "logout" %}</a>
- {% else %}
- <a href="{% url user_signin %}">{% trans "login" %}</a>
- {% endif %}
- <a href="{% url about %}">{% trans "about" %}</a>
- <a href="{% url faq %}">{% trans "faq" %}</a>
- </div>
- <table border="0" cellspacing="0" cellpadding="0">
- <tr>
- <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>
- {% endcomment %}
- </div>
- </td>
- </tr>
- </table>
- </div>
- </div>
-<!-- end template header.html -->
diff --git a/forum/skins/default/templates/privacy.html b/forum/skins/default/templates/privacy.html
deleted file mode 100644
index e66086dd..00000000
--- a/forum/skins/default/templates/privacy.html
+++ /dev/null
@@ -1,42 +0,0 @@
-{% extends "base_content.html" %}
-<!-- privacy.html -->
-{% load extra_tags %}
-{% load i18n %}
-{% load humanize %}
-{% block title %}{% spaceless %}{% trans "Privacy policy" %}{% endspaceless %}{% endblock %}
-{% block forejs %}
-{% endblock %}
-{% block content %}
-<div class="headNormal">
- {% trans "Privacy policy" %}
-</div>
-<div id="main-body" style="width:100%">
- <p>
- {% trans "general message about privacy" %}
- </p>
-
- <h3 class="subtitle">{% trans "Site Visitors" %}</h3>
- <p>
- {% trans "what technical information is collected about visitors" %}
- </p>
-
- <h3 class="subtitle">{% trans "Personal Information" %}</h3>
- <p>
- {% trans "details on personal information policies" %}
- </p>
-
- <h3 class="subtitle">{% trans "Other Services" %}</h3>
- <p>
- {% trans "details on sharing data with third parties" %}
- </p>
-
- <h3 class="subtitle">Cookies</h3>
- <p>
- {% trans "cookie policy details" %}
- </p>
- <h3 class="subtitle">{% trans "Policy Changes" %}</h3>
- <p>{% trans "how privacy policies can be changed" %}
- </p>
-</div>
-{% endblock %}
-<!-- end privacy.html -->
diff --git a/forum/skins/default/templates/user_responses.html b/forum/skins/default/templates/user_responses.html
deleted file mode 100644
index c4f4ffed..00000000
--- a/forum/skins/default/templates/user_responses.html
+++ /dev/null
@@ -1,23 +0,0 @@
-{% extends "user.html" %}
-<!-- user_responses.html -->
-{% load extra_tags %}
-{% load humanize %}
-
-{% block usercontent %}
- <div style="padding-top:5px;font-size:13px;">
- {% for response in responses %}
- <div style="clear:both;line-height:18px">
- <div style="width:150px;float:left">{% diff_date response.time 3 %}</div>
- <div style="width:100px;float:left"><a href="{{ response.userlink }}">{{ response.username }}</a></div>
- <div style="float:left;overflow:hidden;width:680px">
- <strong {% ifequal response.type "question_answered" %}class="user-action-2"{% endifequal %}{% ifequal response.type "answer_accepted" %}class="user-action-8"{% endifequal %}>{{ response.type }}</strong>:
- <a href="{{ response.titlelink }}">{{ response.title }}</a><br/>
- {{ response.content|safe }}
- <div style="height:10px"></div>
- </div>
-
- </div>
- {% endfor %}
- </div>
-{% endblock %}
-<!-- end user_responses.html -->
diff --git a/forum/sql_scripts/update_2010_01_23.sql b/forum/sql_scripts/update_2010_01_23.sql
deleted file mode 100755
index 621207be..00000000
--- a/forum/sql_scripts/update_2010_01_23.sql
+++ /dev/null
@@ -1,9 +0,0 @@
-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/urls.py b/forum/urls.py
deleted file mode 100755
index 41ffbcf7..00000000
--- a/forum/urls.py
+++ /dev/null
@@ -1,104 +0,0 @@
-import os.path
-from django.conf.urls.defaults import *
-from django.contrib import admin
-from forum import views as app
-from forum.feed import RssLastestQuestionsFeed
-from forum.sitemap import QuestionsSitemap
-from django.utils.translation import ugettext as _
-import logging
-
-admin.autodiscover()
-feeds = {
- 'rss': RssLastestQuestionsFeed
-}
-sitemaps = {
- 'questions': QuestionsSitemap
-}
-
-APP_PATH = os.path.dirname(__file__)
-urlpatterns = patterns('',
- url(r'^$', app.readers.index, name='index'),
- url(r'^sitemap.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}, name='sitemap'),
- #(r'^favicon\.ico$', 'django.views.generic.simple.redirect_to', {'url': '/media/images/favicon.ico'}),
- #(r'^favicon\.gif$', 'django.views.generic.simple.redirect_to', {'url': '/media/images/favicon.gif'}),
- url(r'^m/(?P<path>.*)$', 'django.views.static.serve',
- {'document_root': os.path.join(APP_PATH,'skins').replace('\\','/')},
- name='askbot_media',
- ),
- url(r'^%s(?P<path>.*)$' % _('upfiles/'), 'django.views.static.serve',
- {'document_root': os.path.join(APP_PATH,'upfiles').replace('\\','/')},
- name='uploaded_file',
- ),
- #url(r'^%s/$' % _('signin/'), 'django_authopenid.views.signin', name='signin'),
- url(r'^%s$' % _('about/'), app.meta.about, name='about'),
- url(r'^%s$' % _('faq/'), app.meta.faq, name='faq'),
- url(r'^%s$' % _('privacy/'), app.meta.privacy, name='privacy'),
- url(r'^%s$' % _('logout/'), app.meta.logout, name='logout'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('comments/')), app.writers.answer_comments, name='answer_comments'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('edit/')), app.writers.edit_answer, name='edit_answer'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('revisions/')), app.readers.answer_revisions, name='answer_revisions'),
- url(r'^%s$' % _('questions/'), app.readers.questions, name='questions'),
- url(r'^%s%s$' % (_('questions/'), _('ask/')), app.writers.ask, name='ask'),
- url(r'^%s%s$' % (_('questions/'), _('unanswered/')), app.readers.unanswered, name='unanswered'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('edit/')), app.writers.edit_question, name='edit_question'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('close/')), app.commands.close, name='close'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('reopen/')), app.commands.reopen, name='reopen'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('answer/')), app.writers.answer, name='answer'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('vote/')), app.commands.vote, name='vote'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('revisions/')), app.readers.question_revisions, name='question_revisions'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('comments/')), app.writers.question_comments, name='question_comments'),
- url(r'^%s$' % _('command/'), app.commands.ajax_command, name='call_ajax'),
-
- url(r'^%s(?P<object_id>\d+)/%s(?P<comment_id>\d+)/%s$' % (_('questions/'), _('comments/'),_('delete/')), \
- app.writers.delete_comment, kwargs={'commented_object_type':'question'},\
- name='delete_question_comment'),
-
- url(r'^%s(?P<object_id>\d+)/%s(?P<comment_id>\d+)/%s$' % (_('answers/'), _('comments/'),_('delete/')), \
- app.writers.delete_comment, kwargs={'commented_object_type':'answer'}, \
- name='delete_answer_comment'), \
- #place general question item in the end of other operations
- url(r'^%s(?P<id>\d+)/' % _('question/'), app.readers.question, name='question'),
- url(r'^%s$' % _('tags/'), app.readers.tags, name='tags'),
- url(r'^%s(?P<tag>[^/]+)/$' % _('tags/'), app.readers.tag, name='tag_questions'),
-
- url(r'^%s%s(?P<tag>[^/]+)/$' % (_('mark-tag/'),_('interesting/')), app.commands.mark_tag, \
- kwargs={'reason':'good','action':'add'}, \
- name='mark_interesting_tag'),
-
- url(r'^%s%s(?P<tag>[^/]+)/$' % (_('mark-tag/'),_('ignored/')), app.commands.mark_tag, \
- kwargs={'reason':'bad','action':'add'}, \
- name='mark_ignored_tag'),
-
- url(r'^%s(?P<tag>[^/]+)/$' % _('unmark-tag/'), app.commands.mark_tag, \
- kwargs={'action':'remove'}, \
- name='mark_ignored_tag'),
-
- url(r'^%s$' % _('users/'),app.users.users, name='users'),
- url(r'^%s(?P<id>\d+)/$' % _('moderate-user/'), app.users.moderate_user, name='moderate_user'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('users/'), _('edit/')), app.users.edit_user, name='edit_user'),
- url(r'^%s(?P<id>\d+)/(?P<slug>.+)/$' % _('users/'), app.users.user, name='user_profile'),
- url(r'^%s$' % _('badges/'),app.meta.badges, name='badges'),
- url(r'^%s(?P<id>\d+)//*' % _('badges/'), app.meta.badge, name='badge'),
- url(r'^%s%s$' % (_('messages/'), _('markread/')),app.commands.read_message, name='read_message'),
- # (r'^admin/doc/' % _('admin/doc'), include('django.contrib.admindocs.urls')),
- url(r'^%s(.*)' % _('nimda/'), admin.site.root, name='askbot_admin'),
- url(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', {'feed_dict': feeds}, name='feeds'),
- url(r'^%s$' % _('upload/'), app.writers.upload, name='upload'),
- url(r'^%s$' % _('search/'), app.readers.search, name='search'),
- url(r'^%s$' % _('feedback/'), app.meta.feedback, name='feedback'),
- (r'^%sfb/' % _('account/'), include('fbconnect.urls')),
- (r'^%s' % _('account/'), include('django_authopenid.urls')),
- (r'^i18n/', include('django.conf.urls.i18n')),
-
- url(r'^feeds/rss/$', RssLastestQuestionsFeed, name="latest_questions_feed"),
-)
-
-from forum.modules import get_modules_script
-
-module_patterns = get_modules_script('urls')
-
-for pattern_file in module_patterns:
- pattern = getattr(pattern_file, 'urlpatterns', None)
- if pattern:
- urlpatterns += pattern
-
diff --git a/forum/utils/functions.py b/forum/utils/functions.py
deleted file mode 100644
index 671ddc2c..00000000
--- a/forum/utils/functions.py
+++ /dev/null
@@ -1,5 +0,0 @@
-def get_from_dict_or_object(object,key):
- try:
- return object[key]
- except:
- return getattr(object,key)
diff --git a/forum/utils/odict.py b/forum/utils/odict.py
deleted file mode 100755
index 2c8391d7..00000000
--- a/forum/utils/odict.py
+++ /dev/null
@@ -1,1399 +0,0 @@
-# odict.py
-# An Ordered Dictionary object
-# Copyright (C) 2005 Nicola Larosa, Michael Foord
-# E-mail: nico AT tekNico DOT net, fuzzyman AT voidspace DOT org DOT uk
-
-# This software is licensed under the terms of the BSD license.
-# http://www.voidspace.org.uk/python/license.shtml
-# Basically you're free to copy, modify, distribute and relicense it,
-# So long as you keep a copy of the license with it.
-
-# Documentation at http://www.voidspace.org.uk/python/odict.html
-# For information about bugfixes, updates and support, please join the
-# Pythonutils mailing list:
-# http://groups.google.com/group/pythonutils/
-# Comments, suggestions and bug reports welcome.
-
-"""A dict that keeps keys in insertion order"""
-from __future__ import generators
-
-__author__ = ('Nicola Larosa <nico-NoSp@m-tekNico.net>,'
- 'Michael Foord <fuzzyman AT voidspace DOT org DOT uk>')
-
-__docformat__ = "restructuredtext en"
-
-__revision__ = '$Id: odict.py 129 2005-09-12 18:15:28Z teknico $'
-
-__version__ = '0.2.2'
-
-__all__ = ['OrderedDict', 'SequenceOrderedDict']
-
-import sys
-INTP_VER = sys.version_info[:2]
-if INTP_VER < (2, 2):
- raise RuntimeError("Python v.2.2 or later required")
-
-import types, warnings
-
-class OrderedDict(dict):
- """
- A class of dictionary that keeps the insertion order of keys.
-
- All appropriate methods return keys, items, or values in an ordered way.
-
- All normal dictionary methods are available. Update and comparison is
- restricted to other OrderedDict objects.
-
- Various sequence methods are available, including the ability to explicitly
- mutate the key ordering.
-
- __contains__ tests:
-
- >>> d = OrderedDict(((1, 3),))
- >>> 1 in d
- 1
- >>> 4 in d
- 0
-
- __getitem__ tests:
-
- >>> OrderedDict(((1, 3), (3, 2), (2, 1)))[2]
- 1
- >>> OrderedDict(((1, 3), (3, 2), (2, 1)))[4]
- Traceback (most recent call last):
- KeyError: 4
-
- __len__ tests:
-
- >>> len(OrderedDict())
- 0
- >>> len(OrderedDict(((1, 3), (3, 2), (2, 1))))
- 3
-
- get tests:
-
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d.get(1)
- 3
- >>> d.get(4) is None
- 1
- >>> d.get(4, 5)
- 5
- >>> d
- OrderedDict([(1, 3), (3, 2), (2, 1)])
-
- has_key tests:
-
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d.has_key(1)
- 1
- >>> d.has_key(4)
- 0
- """
-
- def __init__(self, init_val=(), strict=False):
- """
- Create a new ordered dictionary. Cannot init from a normal dict,
- nor from kwargs, since items order is undefined in those cases.
-
- If the ``strict`` keyword argument is ``True`` (``False`` is the
- default) then when doing slice assignment - the ``OrderedDict`` you are
- assigning from *must not* contain any keys in the remaining dict.
-
- >>> OrderedDict()
- OrderedDict([])
- >>> OrderedDict({1: 1})
- Traceback (most recent call last):
- TypeError: undefined order, cannot get items from dict
- >>> OrderedDict({1: 1}.items())
- OrderedDict([(1, 1)])
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d
- OrderedDict([(1, 3), (3, 2), (2, 1)])
- >>> OrderedDict(d)
- OrderedDict([(1, 3), (3, 2), (2, 1)])
- """
- self.strict = strict
- dict.__init__(self)
- if isinstance(init_val, OrderedDict):
- self._sequence = init_val.keys()
- dict.update(self, init_val)
- elif isinstance(init_val, dict):
- # we lose compatibility with other ordered dict types this way
- raise TypeError('undefined order, cannot get items from dict')
- else:
- self._sequence = []
- self.update(init_val)
-
-### Special methods ###
-
- def __delitem__(self, key):
- """
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> del d[3]
- >>> d
- OrderedDict([(1, 3), (2, 1)])
- >>> del d[3]
- Traceback (most recent call last):
- KeyError: 3
- >>> d[3] = 2
- >>> d
- OrderedDict([(1, 3), (2, 1), (3, 2)])
- >>> del d[0:1]
- >>> d
- OrderedDict([(2, 1), (3, 2)])
- """
- if isinstance(key, types.SliceType):
- # FIXME: efficiency?
- keys = self._sequence[key]
- for entry in keys:
- dict.__delitem__(self, entry)
- del self._sequence[key]
- else:
- # do the dict.__delitem__ *first* as it raises
- # the more appropriate error
- dict.__delitem__(self, key)
- self._sequence.remove(key)
-
- def __eq__(self, other):
- """
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d == OrderedDict(d)
- True
- >>> d == OrderedDict(((1, 3), (2, 1), (3, 2)))
- False
- >>> d == OrderedDict(((1, 0), (3, 2), (2, 1)))
- False
- >>> d == OrderedDict(((0, 3), (3, 2), (2, 1)))
- False
- >>> d == dict(d)
- False
- >>> d == False
- False
- """
- if isinstance(other, OrderedDict):
- # FIXME: efficiency?
- # Generate both item lists for each compare
- return (self.items() == other.items())
- else:
- return False
-
- def __lt__(self, other):
- """
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
- >>> c < d
- True
- >>> d < c
- False
- >>> d < dict(c)
- Traceback (most recent call last):
- TypeError: Can only compare with other OrderedDicts
- """
- if not isinstance(other, OrderedDict):
- raise TypeError('Can only compare with other OrderedDicts')
- # FIXME: efficiency?
- # Generate both item lists for each compare
- return (self.items() < other.items())
-
- def __le__(self, other):
- """
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
- >>> e = OrderedDict(d)
- >>> c <= d
- True
- >>> d <= c
- False
- >>> d <= dict(c)
- Traceback (most recent call last):
- TypeError: Can only compare with other OrderedDicts
- >>> d <= e
- True
- """
- if not isinstance(other, OrderedDict):
- raise TypeError('Can only compare with other OrderedDicts')
- # FIXME: efficiency?
- # Generate both item lists for each compare
- return (self.items() <= other.items())
-
- def __ne__(self, other):
- """
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d != OrderedDict(d)
- False
- >>> d != OrderedDict(((1, 3), (2, 1), (3, 2)))
- True
- >>> d != OrderedDict(((1, 0), (3, 2), (2, 1)))
- True
- >>> d == OrderedDict(((0, 3), (3, 2), (2, 1)))
- False
- >>> d != dict(d)
- True
- >>> d != False
- True
- """
- if isinstance(other, OrderedDict):
- # FIXME: efficiency?
- # Generate both item lists for each compare
- return not (self.items() == other.items())
- else:
- return True
-
- def __gt__(self, other):
- """
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
- >>> d > c
- True
- >>> c > d
- False
- >>> d > dict(c)
- Traceback (most recent call last):
- TypeError: Can only compare with other OrderedDicts
- """
- if not isinstance(other, OrderedDict):
- raise TypeError('Can only compare with other OrderedDicts')
- # FIXME: efficiency?
- # Generate both item lists for each compare
- return (self.items() > other.items())
-
- def __ge__(self, other):
- """
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
- >>> e = OrderedDict(d)
- >>> c >= d
- False
- >>> d >= c
- True
- >>> d >= dict(c)
- Traceback (most recent call last):
- TypeError: Can only compare with other OrderedDicts
- >>> e >= d
- True
- """
- if not isinstance(other, OrderedDict):
- raise TypeError('Can only compare with other OrderedDicts')
- # FIXME: efficiency?
- # Generate both item lists for each compare
- return (self.items() >= other.items())
-
- def __repr__(self):
- """
- Used for __repr__ and __str__
-
- >>> r1 = repr(OrderedDict((('a', 'b'), ('c', 'd'), ('e', 'f'))))
- >>> r1
- "OrderedDict([('a', 'b'), ('c', 'd'), ('e', 'f')])"
- >>> r2 = repr(OrderedDict((('a', 'b'), ('e', 'f'), ('c', 'd'))))
- >>> r2
- "OrderedDict([('a', 'b'), ('e', 'f'), ('c', 'd')])"
- >>> r1 == str(OrderedDict((('a', 'b'), ('c', 'd'), ('e', 'f'))))
- True
- >>> r2 == str(OrderedDict((('a', 'b'), ('e', 'f'), ('c', 'd'))))
- True
- """
- return '%s([%s])' % (self.__class__.__name__, ', '.join(
- ['(%r, %r)' % (key, self[key]) for key in self._sequence]))
-
- def __setitem__(self, key, val):
- """
- Allows slice assignment, so long as the slice is an OrderedDict
- >>> d = OrderedDict()
- >>> d['a'] = 'b'
- >>> d['b'] = 'a'
- >>> d[3] = 12
- >>> d
- OrderedDict([('a', 'b'), ('b', 'a'), (3, 12)])
- >>> d[:] = OrderedDict(((1, 2), (2, 3), (3, 4)))
- >>> d
- OrderedDict([(1, 2), (2, 3), (3, 4)])
- >>> d[::2] = OrderedDict(((7, 8), (9, 10)))
- >>> d
- OrderedDict([(7, 8), (2, 3), (9, 10)])
- >>> d = OrderedDict(((0, 1), (1, 2), (2, 3), (3, 4)))
- >>> d[1:3] = OrderedDict(((1, 2), (5, 6), (7, 8)))
- >>> d
- OrderedDict([(0, 1), (1, 2), (5, 6), (7, 8), (3, 4)])
- >>> d = OrderedDict(((0, 1), (1, 2), (2, 3), (3, 4)), strict=True)
- >>> d[1:3] = OrderedDict(((1, 2), (5, 6), (7, 8)))
- >>> d
- OrderedDict([(0, 1), (1, 2), (5, 6), (7, 8), (3, 4)])
-
- >>> a = OrderedDict(((0, 1), (1, 2), (2, 3)), strict=True)
- >>> a[3] = 4
- >>> a
- OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
- >>> a[::1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
- >>> a
- OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
- >>> a[:2] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)])
- Traceback (most recent call last):
- ValueError: slice assignment must be from unique keys
- >>> a = OrderedDict(((0, 1), (1, 2), (2, 3)))
- >>> a[3] = 4
- >>> a
- OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
- >>> a[::1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
- >>> a
- OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
- >>> a[:2] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
- >>> a
- OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
- >>> a[::-1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
- >>> a
- OrderedDict([(3, 4), (2, 3), (1, 2), (0, 1)])
-
- >>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
- >>> d[:1] = 3
- Traceback (most recent call last):
- TypeError: slice assignment requires an OrderedDict
-
- >>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
- >>> d[:1] = OrderedDict([(9, 8)])
- >>> d
- OrderedDict([(9, 8), (1, 2), (2, 3), (3, 4)])
- """
- if isinstance(key, types.SliceType):
- if not isinstance(val, OrderedDict):
- # FIXME: allow a list of tuples?
- raise TypeError('slice assignment requires an OrderedDict')
- keys = self._sequence[key]
- # NOTE: Could use ``range(*key.indices(len(self._sequence)))``
- indexes = range(len(self._sequence))[key]
- if key.step is None:
- # NOTE: new slice may not be the same size as the one being
- # overwritten !
- # NOTE: What is the algorithm for an impossible slice?
- # e.g. d[5:3]
- pos = key.start or 0
- del self[key]
- newkeys = val.keys()
- for k in newkeys:
- if k in self:
- if self.strict:
- raise ValueError('slice assignment must be from '
- 'unique keys')
- else:
- # NOTE: This removes duplicate keys *first*
- # so start position might have changed?
- del self[k]
- self._sequence = (self._sequence[:pos] + newkeys +
- self._sequence[pos:])
- dict.update(self, val)
- else:
- # extended slice - length of new slice must be the same
- # as the one being replaced
- if len(keys) != len(val):
- raise ValueError('attempt to assign sequence of size %s '
- 'to extended slice of size %s' % (len(val), len(keys)))
- # FIXME: efficiency?
- del self[key]
- item_list = zip(indexes, val.items())
- # smallest indexes first - higher indexes not guaranteed to
- # exist
- item_list.sort()
- for pos, (newkey, newval) in item_list:
- if self.strict and newkey in self:
- raise ValueError('slice assignment must be from unique'
- ' keys')
- self.insert(pos, newkey, newval)
- else:
- if key not in self:
- self._sequence.append(key)
- dict.__setitem__(self, key, val)
-
- def __getitem__(self, key):
- """
- Allows slicing. Returns an OrderedDict if you slice.
- >>> b = OrderedDict([(7, 0), (6, 1), (5, 2), (4, 3), (3, 4), (2, 5), (1, 6)])
- >>> b[::-1]
- OrderedDict([(1, 6), (2, 5), (3, 4), (4, 3), (5, 2), (6, 1), (7, 0)])
- >>> b[2:5]
- OrderedDict([(5, 2), (4, 3), (3, 4)])
- >>> type(b[2:4])
- <class '__main__.OrderedDict'>
- """
- if isinstance(key, types.SliceType):
- # FIXME: does this raise the error we want?
- keys = self._sequence[key]
- # FIXME: efficiency?
- return OrderedDict([(entry, self[entry]) for entry in keys])
- else:
- return dict.__getitem__(self, key)
-
- __str__ = __repr__
-
- def __setattr__(self, name, value):
- """
- Implemented so that accesses to ``sequence`` raise a warning and are
- diverted to the new ``setkeys`` method.
- """
- if name == 'sequence':
- warnings.warn('Use of the sequence attribute is deprecated.'
- ' Use the keys method instead.', DeprecationWarning)
- # NOTE: doesn't return anything
- self.setkeys(value)
- else:
- # FIXME: do we want to allow arbitrary setting of attributes?
- # Or do we want to manage it?
- object.__setattr__(self, name, value)
-
- def __getattr__(self, name):
- """
- Implemented so that access to ``sequence`` raises a warning.
-
- >>> d = OrderedDict()
- >>> d.sequence
- []
- """
- if name == 'sequence':
- warnings.warn('Use of the sequence attribute is deprecated.'
- ' Use the keys method instead.', DeprecationWarning)
- # NOTE: Still (currently) returns a direct reference. Need to
- # because code that uses sequence will expect to be able to
- # mutate it in place.
- return self._sequence
- else:
- # raise the appropriate error
- raise AttributeError("OrderedDict has no '%s' attribute" % name)
-
- def __deepcopy__(self, memo):
- """
- To allow deepcopy to work with OrderedDict.
-
- >>> from copy import deepcopy
- >>> a = OrderedDict([(1, 1), (2, 2), (3, 3)])
- >>> a['test'] = {}
- >>> b = deepcopy(a)
- >>> b == a
- True
- >>> b is a
- False
- >>> a['test'] is b['test']
- False
- """
- from copy import deepcopy
- return self.__class__(deepcopy(self.items(), memo), self.strict)
-
-
-### Read-only methods ###
-
- def copy(self):
- """
- >>> OrderedDict(((1, 3), (3, 2), (2, 1))).copy()
- OrderedDict([(1, 3), (3, 2), (2, 1)])
- """
- return OrderedDict(self)
-
- def items(self):
- """
- ``items`` returns a list of tuples representing all the
- ``(key, value)`` pairs in the dictionary.
-
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d.items()
- [(1, 3), (3, 2), (2, 1)]
- >>> d.clear()
- >>> d.items()
- []
- """
- return zip(self._sequence, self.values())
-
- def keys(self):
- """
- Return a list of keys in the ``OrderedDict``.
-
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d.keys()
- [1, 3, 2]
- """
- return self._sequence[:]
-
- def values(self, values=None):
- """
- Return a list of all the values in the OrderedDict.
-
- Optionally you can pass in a list of values, which will replace the
- current list. The value list must be the same len as the OrderedDict.
-
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d.values()
- [3, 2, 1]
- """
- return [self[key] for key in self._sequence]
-
- def iteritems(self):
- """
- >>> ii = OrderedDict(((1, 3), (3, 2), (2, 1))).iteritems()
- >>> ii.next()
- (1, 3)
- >>> ii.next()
- (3, 2)
- >>> ii.next()
- (2, 1)
- >>> ii.next()
- Traceback (most recent call last):
- StopIteration
- """
- def make_iter(self=self):
- keys = self.iterkeys()
- while True:
- key = keys.next()
- yield (key, self[key])
- return make_iter()
-
- def iterkeys(self):
- """
- >>> ii = OrderedDict(((1, 3), (3, 2), (2, 1))).iterkeys()
- >>> ii.next()
- 1
- >>> ii.next()
- 3
- >>> ii.next()
- 2
- >>> ii.next()
- Traceback (most recent call last):
- StopIteration
- """
- return iter(self._sequence)
-
- __iter__ = iterkeys
-
- def itervalues(self):
- """
- >>> iv = OrderedDict(((1, 3), (3, 2), (2, 1))).itervalues()
- >>> iv.next()
- 3
- >>> iv.next()
- 2
- >>> iv.next()
- 1
- >>> iv.next()
- Traceback (most recent call last):
- StopIteration
- """
- def make_iter(self=self):
- keys = self.iterkeys()
- while True:
- yield self[keys.next()]
- return make_iter()
-
-### Read-write methods ###
-
- def clear(self):
- """
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d.clear()
- >>> d
- OrderedDict([])
- """
- dict.clear(self)
- self._sequence = []
-
- def pop(self, key, *args):
- """
- No dict.pop in Python 2.2, gotta reimplement it
-
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d.pop(3)
- 2
- >>> d
- OrderedDict([(1, 3), (2, 1)])
- >>> d.pop(4)
- Traceback (most recent call last):
- KeyError: 4
- >>> d.pop(4, 0)
- 0
- >>> d.pop(4, 0, 1)
- Traceback (most recent call last):
- TypeError: pop expected at most 2 arguments, got 3
- """
- if len(args) > 1:
- raise TypeError, ('pop expected at most 2 arguments, got %s' %
- (len(args) + 1))
- if key in self:
- val = self[key]
- del self[key]
- else:
- try:
- val = args[0]
- except IndexError:
- raise KeyError(key)
- return val
-
- def popitem(self, i=-1):
- """
- Delete and return an item specified by index, not a random one as in
- dict. The index is -1 by default (the last item).
-
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d.popitem()
- (2, 1)
- >>> d
- OrderedDict([(1, 3), (3, 2)])
- >>> d.popitem(0)
- (1, 3)
- >>> OrderedDict().popitem()
- Traceback (most recent call last):
- KeyError: 'popitem(): dictionary is empty'
- >>> d.popitem(2)
- Traceback (most recent call last):
- IndexError: popitem(): index 2 not valid
- """
- if not self._sequence:
- raise KeyError('popitem(): dictionary is empty')
- try:
- key = self._sequence[i]
- except IndexError:
- raise IndexError('popitem(): index %s not valid' % i)
- return (key, self.pop(key))
-
- def setdefault(self, key, defval = None):
- """
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d.setdefault(1)
- 3
- >>> d.setdefault(4) is None
- True
- >>> d
- OrderedDict([(1, 3), (3, 2), (2, 1), (4, None)])
- >>> d.setdefault(5, 0)
- 0
- >>> d
- OrderedDict([(1, 3), (3, 2), (2, 1), (4, None), (5, 0)])
- """
- if key in self:
- return self[key]
- else:
- self[key] = defval
- return defval
-
- def update(self, from_od):
- """
- Update from another OrderedDict or sequence of (key, value) pairs
-
- >>> d = OrderedDict(((1, 0), (0, 1)))
- >>> d.update(OrderedDict(((1, 3), (3, 2), (2, 1))))
- >>> d
- OrderedDict([(1, 3), (0, 1), (3, 2), (2, 1)])
- >>> d.update({4: 4})
- Traceback (most recent call last):
- TypeError: undefined order, cannot get items from dict
- >>> d.update((4, 4))
- Traceback (most recent call last):
- TypeError: cannot convert dictionary update sequence element "4" to a 2-item sequence
- """
- if isinstance(from_od, OrderedDict):
- for key, val in from_od.items():
- self[key] = val
- elif isinstance(from_od, dict):
- # we lose compatibility with other ordered dict types this way
- raise TypeError('undefined order, cannot get items from dict')
- else:
- # FIXME: efficiency?
- # sequence of 2-item sequences, or error
- for item in from_od:
- try:
- key, val = item
- except TypeError:
- raise TypeError('cannot convert dictionary update'
- ' sequence element "%s" to a 2-item sequence' % item)
- self[key] = val
-
- def rename(self, old_key, new_key):
- """
- Rename the key for a given value, without modifying sequence order.
-
- For the case where new_key already exists this raise an exception,
- since if new_key exists, it is ambiguous as to what happens to the
- associated values, and the position of new_key in the sequence.
-
- >>> od = OrderedDict()
- >>> od['a'] = 1
- >>> od['b'] = 2
- >>> od.items()
- [('a', 1), ('b', 2)]
- >>> od.rename('b', 'c')
- >>> od.items()
- [('a', 1), ('c', 2)]
- >>> od.rename('c', 'a')
- Traceback (most recent call last):
- ValueError: New key already exists: 'a'
- >>> od.rename('d', 'b')
- Traceback (most recent call last):
- KeyError: 'd'
- """
- if new_key == old_key:
- # no-op
- return
- if new_key in self:
- raise ValueError("New key already exists: %r" % new_key)
- # rename sequence entry
- value = self[old_key]
- old_idx = self._sequence.index(old_key)
- self._sequence[old_idx] = new_key
- # rename internal dict entry
- dict.__delitem__(self, old_key)
- dict.__setitem__(self, new_key, value)
-
- def setitems(self, items):
- """
- This method allows you to set the items in the dict.
-
- It takes a list of tuples - of the same sort returned by the ``items``
- method.
-
- >>> d = OrderedDict()
- >>> d.setitems(((3, 1), (2, 3), (1, 2)))
- >>> d
- OrderedDict([(3, 1), (2, 3), (1, 2)])
- """
- self.clear()
- # FIXME: this allows you to pass in an OrderedDict as well :-)
- self.update(items)
-
- def setkeys(self, keys):
- """
- ``setkeys`` all ows you to pass in a new list of keys which will
- replace the current set. This must contain the same set of keys, but
- need not be in the same order.
-
- If you pass in new keys that don't match, a ``KeyError`` will be
- raised.
-
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d.keys()
- [1, 3, 2]
- >>> d.setkeys((1, 2, 3))
- >>> d
- OrderedDict([(1, 3), (2, 1), (3, 2)])
- >>> d.setkeys(['a', 'b', 'c'])
- Traceback (most recent call last):
- KeyError: 'Keylist is not the same as current keylist.'
- """
- # FIXME: Efficiency? (use set for Python 2.4 :-)
- # NOTE: list(keys) rather than keys[:] because keys[:] returns
- # a tuple, if keys is a tuple.
- kcopy = list(keys)
- kcopy.sort()
- self._sequence.sort()
- if kcopy != self._sequence:
- raise KeyError('Keylist is not the same as current keylist.')
- # NOTE: This makes the _sequence attribute a new object, instead
- # of changing it in place.
- # FIXME: efficiency?
- self._sequence = list(keys)
-
- def setvalues(self, values):
- """
- You can pass in a list of values, which will replace the
- current list. The value list must be the same len as the OrderedDict.
-
- (Or a ``ValueError`` is raised.)
-
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d.setvalues((1, 2, 3))
- >>> d
- OrderedDict([(1, 1), (3, 2), (2, 3)])
- >>> d.setvalues([6])
- Traceback (most recent call last):
- ValueError: Value list is not the same length as the OrderedDict.
- """
- if len(values) != len(self):
- # FIXME: correct error to raise?
- raise ValueError('Value list is not the same length as the '
- 'OrderedDict.')
- self.update(zip(self, values))
-
-### Sequence Methods ###
-
- def index(self, key):
- """
- Return the position of the specified key in the OrderedDict.
-
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d.index(3)
- 1
- >>> d.index(4)
- Traceback (most recent call last):
- ValueError: list.index(x): x not in list
- """
- return self._sequence.index(key)
-
- def insert(self, index, key, value):
- """
- Takes ``index``, ``key``, and ``value`` as arguments.
-
- Sets ``key`` to ``value``, so that ``key`` is at position ``index`` in
- the OrderedDict.
-
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d.insert(0, 4, 0)
- >>> d
- OrderedDict([(4, 0), (1, 3), (3, 2), (2, 1)])
- >>> d.insert(0, 2, 1)
- >>> d
- OrderedDict([(2, 1), (4, 0), (1, 3), (3, 2)])
- >>> d.insert(8, 8, 1)
- >>> d
- OrderedDict([(2, 1), (4, 0), (1, 3), (3, 2), (8, 1)])
- """
- if key in self:
- # FIXME: efficiency?
- del self[key]
- self._sequence.insert(index, key)
- dict.__setitem__(self, key, value)
-
- def reverse(self):
- """
- Reverse the order of the OrderedDict.
-
- >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
- >>> d.reverse()
- >>> d
- OrderedDict([(2, 1), (3, 2), (1, 3)])
- """
- self._sequence.reverse()
-
- def sort(self, *args, **kwargs):
- """
- Sort the key order in the OrderedDict.
-
- This method takes the same arguments as the ``list.sort`` method on
- your version of Python.
-
- >>> d = OrderedDict(((4, 1), (2, 2), (3, 3), (1, 4)))
- >>> d.sort()
- >>> d
- OrderedDict([(1, 4), (2, 2), (3, 3), (4, 1)])
- """
- self._sequence.sort(*args, **kwargs)
-
-class Keys(object):
- # FIXME: should this object be a subclass of list?
- """
- Custom object for accessing the keys of an OrderedDict.
-
- Can be called like the normal ``OrderedDict.keys`` method, but also
- supports indexing and sequence methods.
- """
-
- def __init__(self, main):
- self._main = main
-
- def __call__(self):
- """Pretend to be the keys method."""
- return self._main._keys()
-
- def __getitem__(self, index):
- """Fetch the key at position i."""
- # NOTE: this automatically supports slicing :-)
- return self._main._sequence[index]
-
- def __setitem__(self, index, name):
- """
- You cannot assign to keys, but you can do slice assignment to re-order
- them.
-
- You can only do slice assignment if the new set of keys is a reordering
- of the original set.
- """
- if isinstance(index, types.SliceType):
- # FIXME: efficiency?
- # check length is the same
- indexes = range(len(self._main._sequence))[index]
- if len(indexes) != len(name):
- raise ValueError('attempt to assign sequence of size %s '
- 'to slice of size %s' % (len(name), len(indexes)))
- # check they are the same keys
- # FIXME: Use set
- old_keys = self._main._sequence[index]
- new_keys = list(name)
- old_keys.sort()
- new_keys.sort()
- if old_keys != new_keys:
- raise KeyError('Keylist is not the same as current keylist.')
- orig_vals = [self._main[k] for k in name]
- del self._main[index]
- vals = zip(indexes, name, orig_vals)
- vals.sort()
- for i, k, v in vals:
- if self._main.strict and k in self._main:
- raise ValueError('slice assignment must be from '
- 'unique keys')
- self._main.insert(i, k, v)
- else:
- raise ValueError('Cannot assign to keys')
-
- ### following methods pinched from UserList and adapted ###
- def __repr__(self): return repr(self._main._sequence)
-
- # FIXME: do we need to check if we are comparing with another ``Keys``
- # object? (like the __cast method of UserList)
- def __lt__(self, other): return self._main._sequence < other
- def __le__(self, other): return self._main._sequence <= other
- def __eq__(self, other): return self._main._sequence == other
- def __ne__(self, other): return self._main._sequence != other
- def __gt__(self, other): return self._main._sequence > other
- def __ge__(self, other): return self._main._sequence >= other
- # FIXME: do we need __cmp__ as well as rich comparisons?
- def __cmp__(self, other): return cmp(self._main._sequence, other)
-
- def __contains__(self, item): return item in self._main._sequence
- def __len__(self): return len(self._main._sequence)
- def __iter__(self): return self._main.iterkeys()
- def count(self, item): return self._main._sequence.count(item)
- def index(self, item, *args): return self._main._sequence.index(item, *args)
- def reverse(self): self._main._sequence.reverse()
- def sort(self, *args, **kwds): self._main._sequence.sort(*args, **kwds)
- def __mul__(self, n): return self._main._sequence*n
- __rmul__ = __mul__
- def __add__(self, other): return self._main._sequence + other
- def __radd__(self, other): return other + self._main._sequence
-
- ## following methods not implemented for keys ##
- def __delitem__(self, i): raise TypeError('Can\'t delete items from keys')
- def __iadd__(self, other): raise TypeError('Can\'t add in place to keys')
- def __imul__(self, n): raise TypeError('Can\'t multiply keys in place')
- def append(self, item): raise TypeError('Can\'t append items to keys')
- def insert(self, i, item): raise TypeError('Can\'t insert items into keys')
- def pop(self, i=-1): raise TypeError('Can\'t pop items from keys')
- def remove(self, item): raise TypeError('Can\'t remove items from keys')
- def extend(self, other): raise TypeError('Can\'t extend keys')
-
-class Items(object):
- """
- Custom object for accessing the items of an OrderedDict.
-
- Can be called like the normal ``OrderedDict.items`` method, but also
- supports indexing and sequence methods.
- """
-
- def __init__(self, main):
- self._main = main
-
- def __call__(self):
- """Pretend to be the items method."""
- return self._main._items()
-
- def __getitem__(self, index):
- """Fetch the item at position i."""
- if isinstance(index, types.SliceType):
- # fetching a slice returns an OrderedDict
- return self._main[index].items()
- key = self._main._sequence[index]
- return (key, self._main[key])
-
- def __setitem__(self, index, item):
- """Set item at position i to item."""
- if isinstance(index, types.SliceType):
- # NOTE: item must be an iterable (list of tuples)
- self._main[index] = OrderedDict(item)
- else:
- # FIXME: Does this raise a sensible error?
- orig = self._main.keys[index]
- key, value = item
- if self._main.strict and key in self and (key != orig):
- raise ValueError('slice assignment must be from '
- 'unique keys')
- # delete the current one
- del self._main[self._main._sequence[index]]
- self._main.insert(index, key, value)
-
- def __delitem__(self, i):
- """Delete the item at position i."""
- key = self._main._sequence[i]
- if isinstance(i, types.SliceType):
- for k in key:
- # FIXME: efficiency?
- del self._main[k]
- else:
- del self._main[key]
-
- ### following methods pinched from UserList and adapted ###
- def __repr__(self): return repr(self._main.items())
-
- # FIXME: do we need to check if we are comparing with another ``Items``
- # object? (like the __cast method of UserList)
- def __lt__(self, other): return self._main.items() < other
- def __le__(self, other): return self._main.items() <= other
- def __eq__(self, other): return self._main.items() == other
- def __ne__(self, other): return self._main.items() != other
- def __gt__(self, other): return self._main.items() > other
- def __ge__(self, other): return self._main.items() >= other
- def __cmp__(self, other): return cmp(self._main.items(), other)
-
- def __contains__(self, item): return item in self._main.items()
- def __len__(self): return len(self._main._sequence) # easier :-)
- def __iter__(self): return self._main.iteritems()
- def count(self, item): return self._main.items().count(item)
- def index(self, item, *args): return self._main.items().index(item, *args)
- def reverse(self): self._main.reverse()
- def sort(self, *args, **kwds): self._main.sort(*args, **kwds)
- def __mul__(self, n): return self._main.items()*n
- __rmul__ = __mul__
- def __add__(self, other): return self._main.items() + other
- def __radd__(self, other): return other + self._main.items()
-
- def append(self, item):
- """Add an item to the end."""
- # FIXME: this is only append if the key isn't already present
- key, value = item
- self._main[key] = value
-
- def insert(self, i, item):
- key, value = item
- self._main.insert(i, key, value)
-
- def pop(self, i=-1):
- key = self._main._sequence[i]
- return (key, self._main.pop(key))
-
- def remove(self, item):
- key, value = item
- try:
- assert value == self._main[key]
- except (KeyError, AssertionError):
- raise ValueError('ValueError: list.remove(x): x not in list')
- else:
- del self._main[key]
-
- def extend(self, other):
- # FIXME: is only a true extend if none of the keys already present
- for item in other:
- key, value = item
- self._main[key] = value
-
- def __iadd__(self, other):
- self.extend(other)
-
- ## following methods not implemented for items ##
-
- def __imul__(self, n): raise TypeError('Can\'t multiply items in place')
-
-class Values(object):
- """
- Custom object for accessing the values of an OrderedDict.
-
- Can be called like the normal ``OrderedDict.values`` method, but also
- supports indexing and sequence methods.
- """
-
- def __init__(self, main):
- self._main = main
-
- def __call__(self):
- """Pretend to be the values method."""
- return self._main._values()
-
- def __getitem__(self, index):
- """Fetch the value at position i."""
- if isinstance(index, types.SliceType):
- return [self._main[key] for key in self._main._sequence[index]]
- else:
- return self._main[self._main._sequence[index]]
-
- def __setitem__(self, index, value):
- """
- Set the value at position i to value.
-
- You can only do slice assignment to values if you supply a sequence of
- equal length to the slice you are replacing.
- """
- if isinstance(index, types.SliceType):
- keys = self._main._sequence[index]
- if len(keys) != len(value):
- raise ValueError('attempt to assign sequence of size %s '
- 'to slice of size %s' % (len(name), len(keys)))
- # FIXME: efficiency? Would be better to calculate the indexes
- # directly from the slice object
- # NOTE: the new keys can collide with existing keys (or even
- # contain duplicates) - these will overwrite
- for key, val in zip(keys, value):
- self._main[key] = val
- else:
- self._main[self._main._sequence[index]] = value
-
- ### following methods pinched from UserList and adapted ###
- def __repr__(self): return repr(self._main.values())
-
- # FIXME: do we need to check if we are comparing with another ``Values``
- # object? (like the __cast method of UserList)
- def __lt__(self, other): return self._main.values() < other
- def __le__(self, other): return self._main.values() <= other
- def __eq__(self, other): return self._main.values() == other
- def __ne__(self, other): return self._main.values() != other
- def __gt__(self, other): return self._main.values() > other
- def __ge__(self, other): return self._main.values() >= other
- def __cmp__(self, other): return cmp(self._main.values(), other)
-
- def __contains__(self, item): return item in self._main.values()
- def __len__(self): return len(self._main._sequence) # easier :-)
- def __iter__(self): return self._main.itervalues()
- def count(self, item): return self._main.values().count(item)
- def index(self, item, *args): return self._main.values().index(item, *args)
-
- def reverse(self):
- """Reverse the values"""
- vals = self._main.values()
- vals.reverse()
- # FIXME: efficiency
- self[:] = vals
-
- def sort(self, *args, **kwds):
- """Sort the values."""
- vals = self._main.values()
- vals.sort(*args, **kwds)
- self[:] = vals
-
- def __mul__(self, n): return self._main.values()*n
- __rmul__ = __mul__
- def __add__(self, other): return self._main.values() + other
- def __radd__(self, other): return other + self._main.values()
-
- ## following methods not implemented for values ##
- def __delitem__(self, i): raise TypeError('Can\'t delete items from values')
- def __iadd__(self, other): raise TypeError('Can\'t add in place to values')
- def __imul__(self, n): raise TypeError('Can\'t multiply values in place')
- def append(self, item): raise TypeError('Can\'t append items to values')
- def insert(self, i, item): raise TypeError('Can\'t insert items into values')
- def pop(self, i=-1): raise TypeError('Can\'t pop items from values')
- def remove(self, item): raise TypeError('Can\'t remove items from values')
- def extend(self, other): raise TypeError('Can\'t extend values')
-
-class SequenceOrderedDict(OrderedDict):
- """
- Experimental version of OrderedDict that has a custom object for ``keys``,
- ``values``, and ``items``.
-
- These are callable sequence objects that work as methods, or can be
- manipulated directly as sequences.
-
- Test for ``keys``, ``items`` and ``values``.
-
- >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
- >>> d
- SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
- >>> d.keys
- [1, 2, 3]
- >>> d.keys()
- [1, 2, 3]
- >>> d.setkeys((3, 2, 1))
- >>> d
- SequenceOrderedDict([(3, 4), (2, 3), (1, 2)])
- >>> d.setkeys((1, 2, 3))
- >>> d.keys[0]
- 1
- >>> d.keys[:]
- [1, 2, 3]
- >>> d.keys[-1]
- 3
- >>> d.keys[-2]
- 2
- >>> d.keys[0:2] = [2, 1]
- >>> d
- SequenceOrderedDict([(2, 3), (1, 2), (3, 4)])
- >>> d.keys.reverse()
- >>> d.keys
- [3, 1, 2]
- >>> d.keys = [1, 2, 3]
- >>> d
- SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
- >>> d.keys = [3, 1, 2]
- >>> d
- SequenceOrderedDict([(3, 4), (1, 2), (2, 3)])
- >>> a = SequenceOrderedDict()
- >>> b = SequenceOrderedDict()
- >>> a.keys == b.keys
- 1
- >>> a['a'] = 3
- >>> a.keys == b.keys
- 0
- >>> b['a'] = 3
- >>> a.keys == b.keys
- 1
- >>> b['b'] = 3
- >>> a.keys == b.keys
- 0
- >>> a.keys > b.keys
- 0
- >>> a.keys < b.keys
- 1
- >>> 'a' in a.keys
- 1
- >>> len(b.keys)
- 2
- >>> 'c' in d.keys
- 0
- >>> 1 in d.keys
- 1
- >>> [v for v in d.keys]
- [3, 1, 2]
- >>> d.keys.sort()
- >>> d.keys
- [1, 2, 3]
- >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)), strict=True)
- >>> d.keys[::-1] = [1, 2, 3]
- >>> d
- SequenceOrderedDict([(3, 4), (2, 3), (1, 2)])
- >>> d.keys[:2]
- [3, 2]
- >>> d.keys[:2] = [1, 3]
- Traceback (most recent call last):
- KeyError: 'Keylist is not the same as current keylist.'
-
- >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
- >>> d
- SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
- >>> d.values
- [2, 3, 4]
- >>> d.values()
- [2, 3, 4]
- >>> d.setvalues((4, 3, 2))
- >>> d
- SequenceOrderedDict([(1, 4), (2, 3), (3, 2)])
- >>> d.values[::-1]
- [2, 3, 4]
- >>> d.values[0]
- 4
- >>> d.values[-2]
- 3
- >>> del d.values[0]
- Traceback (most recent call last):
- TypeError: Can't delete items from values
- >>> d.values[::2] = [2, 4]
- >>> d
- SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
- >>> 7 in d.values
- 0
- >>> len(d.values)
- 3
- >>> [val for val in d.values]
- [2, 3, 4]
- >>> d.values[-1] = 2
- >>> d.values.count(2)
- 2
- >>> d.values.index(2)
- 0
- >>> d.values[-1] = 7
- >>> d.values
- [2, 3, 7]
- >>> d.values.reverse()
- >>> d.values
- [7, 3, 2]
- >>> d.values.sort()
- >>> d.values
- [2, 3, 7]
- >>> d.values.append('anything')
- Traceback (most recent call last):
- TypeError: Can't append items to values
- >>> d.values = (1, 2, 3)
- >>> d
- SequenceOrderedDict([(1, 1), (2, 2), (3, 3)])
-
- >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
- >>> d
- SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
- >>> d.items()
- [(1, 2), (2, 3), (3, 4)]
- >>> d.setitems([(3, 4), (2 ,3), (1, 2)])
- >>> d
- SequenceOrderedDict([(3, 4), (2, 3), (1, 2)])
- >>> d.items[0]
- (3, 4)
- >>> d.items[:-1]
- [(3, 4), (2, 3)]
- >>> d.items[1] = (6, 3)
- >>> d.items
- [(3, 4), (6, 3), (1, 2)]
- >>> d.items[1:2] = [(9, 9)]
- >>> d
- SequenceOrderedDict([(3, 4), (9, 9), (1, 2)])
- >>> del d.items[1:2]
- >>> d
- SequenceOrderedDict([(3, 4), (1, 2)])
- >>> (3, 4) in d.items
- 1
- >>> (4, 3) in d.items
- 0
- >>> len(d.items)
- 2
- >>> [v for v in d.items]
- [(3, 4), (1, 2)]
- >>> d.items.count((3, 4))
- 1
- >>> d.items.index((1, 2))
- 1
- >>> d.items.index((2, 1))
- Traceback (most recent call last):
- ValueError: list.index(x): x not in list
- >>> d.items.reverse()
- >>> d.items
- [(1, 2), (3, 4)]
- >>> d.items.reverse()
- >>> d.items.sort()
- >>> d.items
- [(1, 2), (3, 4)]
- >>> d.items.append((5, 6))
- >>> d.items
- [(1, 2), (3, 4), (5, 6)]
- >>> d.items.insert(0, (0, 0))
- >>> d.items
- [(0, 0), (1, 2), (3, 4), (5, 6)]
- >>> d.items.insert(-1, (7, 8))
- >>> d.items
- [(0, 0), (1, 2), (3, 4), (7, 8), (5, 6)]
- >>> d.items.pop()
- (5, 6)
- >>> d.items
- [(0, 0), (1, 2), (3, 4), (7, 8)]
- >>> d.items.remove((1, 2))
- >>> d.items
- [(0, 0), (3, 4), (7, 8)]
- >>> d.items.extend([(1, 2), (5, 6)])
- >>> d.items
- [(0, 0), (3, 4), (7, 8), (1, 2), (5, 6)]
- """
-
- def __init__(self, init_val=(), strict=True):
- OrderedDict.__init__(self, init_val, strict=strict)
- self._keys = self.keys
- self._values = self.values
- self._items = self.items
- self.keys = Keys(self)
- self.values = Values(self)
- self.items = Items(self)
- self._att_dict = {
- 'keys': self.setkeys,
- 'items': self.setitems,
- 'values': self.setvalues,
- }
-
- def __setattr__(self, name, value):
- """Protect keys, items, and values."""
- if not '_att_dict' in self.__dict__:
- object.__setattr__(self, name, value)
- else:
- try:
- fun = self._att_dict[name]
- except KeyError:
- OrderedDict.__setattr__(self, name, value)
- else:
- fun(value)
-
-if __name__ == '__main__':
- if INTP_VER < (2, 3):
- raise RuntimeError("Tests require Python v.2.3 or later")
- # turn off warnings for tests
- warnings.filterwarnings('ignore')
- # run the code tests in doctest format
- import doctest
- m = sys.modules.get('__main__')
- globs = m.__dict__.copy()
- globs.update({
- 'INTP_VER': INTP_VER,
- })
- doctest.testmod(m, globs=globs)
-
diff --git a/forum/views/__init__.py b/forum/views/__init__.py
deleted file mode 100755
index 291fee2a..00000000
--- a/forum/views/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-import readers
-import writers
-import commands
-import users
-import meta
diff --git a/forum_modules/authentication/README b/forum_modules/authentication/README
deleted file mode 100644
index a602dc2c..00000000
--- a/forum_modules/authentication/README
+++ /dev/null
@@ -1,3 +0,0 @@
-THIS DIRECTORY IS NOT USED
-
-authentication module will be redone as separate application
diff --git a/forum_modules/authentication/auth.py b/forum_modules/authentication/auth.py
deleted file mode 100755
index 96025dc1..00000000
--- a/forum_modules/authentication/auth.py
+++ /dev/null
@@ -1,144 +0,0 @@
-from django.shortcuts import render_to_response, get_object_or_404
-from django.template import RequestContext
-from django.core.urlresolvers import reverse
-from django.contrib.auth.models import User
-from django.http import HttpResponseRedirect, Http404
-from django.utils.safestring import mark_safe
-from django.utils.translation import ugettext as _
-from django.utils.http import urlquote_plus
-from django.contrib.auth.decorators import login_required
-from django.contrib.auth import login, logout
-from django.http import get_host
-import types
-import datetime
-
-from forum.models import AuthKeyUserAssociation, ValidationHash
-from forum.authentication.forms import SimpleRegistrationForm, SimpleEmailSubscribeForm, \
- TemporaryLoginRequestForm, ChangePasswordForm, SetPasswordForm
-from forum.utils.email import send_email
-
-from forum.authentication.base import InvalidAuthentication
-from forum.authentication import AUTH_PROVIDERS
-
-from forum.models import Question, Answer
-
-def send_validation_email(user):
- hash = ValidationHash.objects.create_new(user, 'email', [user.email])
- send_email(_("Email Validation"), [user.email], "auth/email_validation.html", {
- 'validation_code': hash,
- 'user': user
- })
-
-def validate_email(request, user, code):
- user = get_object_or_404(User, id=user)
-
- if (ValidationHash.objects.validate(code, user, 'email', [user.email])):
- user.email_isvalid = True
- user.save()
- return login_and_forward(request, user, None, _("Thank you, your email is now validated."))
- else:
- raise Http404()
-
-@login_required
-def auth_settings(request):
- """
- change password view.
-
- url : /changepw/
- template: authopenid/changepw.html
- """
- user_ = request.user
- auth_keys = user_.auth_keys.all()
-
- if user_.has_usable_password():
- FormClass = ChangePasswordForm
- else:
- FormClass = SetPasswordForm
-
- if request.POST:
- form = FormClass(request.POST, user=user_)
- if form.is_valid():
- if user_.has_usable_password():
- request.user.message_set.create(message=_("Your password was changed"))
- else:
- request.user.message_set.create(message=_("New password set"))
- FormClass = ChangePasswordForm
-
- user_.set_password(form.cleaned_data['password1'])
- user_.save()
- return HttpResponseRedirect(reverse('user_authsettings'))
-
- form = FormClass(user=user_)
-
- auth_keys_list = []
-
- for k in auth_keys:
- provider = AUTH_PROVIDERS.get(k.provider, None)
-
- if provider is not None:
- name = "%s: %s" % (provider.context.human_name, provider.context.readable_key(k))
- else:
- from forum.authentication.base import ConsumerTemplateContext
- "unknown: %s" % ConsumerTemplateContext.readable_key(k)
-
- auth_keys_list.append({
- 'name': name,
- 'id': k.id
- })
-
- return render_to_response('auth/auth_settings.html', {
- 'form': form,
- 'has_password': user_.has_usable_password(),
- 'auth_keys': auth_keys_list,
- }, context_instance=RequestContext(request))
-
-def newquestion_signin_action(user):
- question = Question.objects.filter(author=user).order_by('-added_at')[0]
- return question.get_absolute_url()
-
-def newanswer_signin_action(user):
- answer = Answer.objects.filter(author=user).order_by('-added_at')[0]
- return answer.get_absolute_url()
-
-POST_SIGNIN_ACTIONS = {
- 'newquestion': newquestion_signin_action,
- 'newanswer': newanswer_signin_action,
-}
-
-def login_and_forward(request, user, forward=None, message=None):
- old_session = request.session.session_key
- user.backend = "django.contrib.auth.backends.ModelBackend"
- login(request, user)
-
- from forum.models import user_logged_in
- user_logged_in.send(user=user,session_key=old_session,sender=None)
-
- if not forward:
- signin_action = request.session.get('on_signin_action', None)
- if not signin_action:
- forward = request.session.get('on_signin_url', None)
-
- if not forward:
- forward = reverse('index')
- else:
- try:
- forward = POST_SIGNIN_ACTIONS[signin_action](user)
- except:
- forward = reverse('index')
-
- if message is None:
- message = _("Welcome back %s, you are now logged in") % user.username
-
- request.user.message_set.create(message=message)
- return HttpResponseRedirect(forward)
-
-@login_required
-def signout(request):
- """
- signout from the website. Remove openid from session and kill it.
-
- url : /signout/"
- """
-
- logout(request)
- return HttpResponseRedirect(reverse('index'))
diff --git a/forum_modules/books/__init__.py b/forum_modules/books/__init__.py
deleted file mode 100755
index c51a2bfb..00000000
--- a/forum_modules/books/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-NAME = 'Books'
-DESCRIPTION = "Allows discussion around books."
-CAN_ENABLE = True
diff --git a/forum_modules/books/models.py b/forum_modules/books/models.py
deleted file mode 100755
index a78c0e76..00000000
--- a/forum_modules/books/models.py
+++ /dev/null
@@ -1,63 +0,0 @@
-from django.db import models
-from django.contrib.auth.models import User
-from forum.models import Question
-from django.core.urlresolvers import reverse
-from django.utils.http import urlquote as django_urlquote
-from django.template.defaultfilters import slugify
-
-class Book(models.Model):
- """
- Model for book info
- """
- user = models.ForeignKey(User)
- title = models.CharField(max_length=255)
- short_name = models.CharField(max_length=255)
- author = models.CharField(max_length=255)
- price = models.DecimalField(max_digits=6, decimal_places=2)
- pages = models.SmallIntegerField()
- published_at = models.DateTimeField()
- publication = models.CharField(max_length=255)
- cover_img = models.CharField(max_length=255)
- tagnames = models.CharField(max_length=125)
- added_at = models.DateTimeField()
- last_edited_at = models.DateTimeField()
- questions = models.ManyToManyField(Question, related_name='book', db_table='book_question')
-
- def get_absolute_url(self):
- return reverse('book', args=[django_urlquote(slugify(self.short_name))])
-
- def __unicode__(self):
- return self.title
-
- class Meta:
- app_label = 'forum'
- db_table = u'book'
-
-class BookAuthorInfo(models.Model):
- """
- Model for book author info
- """
- user = models.ForeignKey(User)
- book = models.ForeignKey(Book)
- blog_url = models.CharField(max_length=255)
- added_at = models.DateTimeField()
- last_edited_at = models.DateTimeField()
-
- class Meta:
- app_label = 'forum'
- db_table = u'book_author_info'
-
-class BookAuthorRss(models.Model):
- """
- Model for book author blog rss
- """
- user = models.ForeignKey(User)
- book = models.ForeignKey(Book)
- title = models.CharField(max_length=255)
- url = models.CharField(max_length=255)
- rss_created_at = models.DateTimeField()
- added_at = models.DateTimeField()
-
- class Meta:
- app_label = 'forum'
- db_table = u'book_author_rss' \ No newline at end of file
diff --git a/forum_modules/books/urls.py b/forum_modules/books/urls.py
deleted file mode 100755
index bc0811e7..00000000
--- a/forum_modules/books/urls.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from django.conf.urls.defaults import *
-from django.utils.translation import ugettext as _
-
-import views as app
-
-urlpatterns = patterns('',
- url(r'^%s$' % _('books/'), app.books, name='books'),
- url(r'^%s%s(?P<short_name>[^/]+)/$' % (_('books/'), _('ask/')), app.ask_book, name='ask_book'),
- url(r'^%s(?P<short_name>[^/]+)/$' % _('books/'), app.book, name='book'),
-) \ No newline at end of file
diff --git a/forum_modules/books/views.py b/forum_modules/books/views.py
deleted file mode 100755
index d4907e5f..00000000
--- a/forum_modules/books/views.py
+++ /dev/null
@@ -1,142 +0,0 @@
-from django.shortcuts import render_to_response, get_object_or_404
-from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden, Http404
-from django.template import RequestContext
-from django.contrib.auth.decorators import login_required
-from django.core.urlresolvers import reverse
-from django.utils.html import *
-
-from models import *
-
-from forum.forms import AskForm
-from forum.views.readers import _get_tags_cache_json
-from forum.models import *
-from forum.utils.html import sanitize_html
-
-def books(request):
- return HttpResponseRedirect(reverse('books') + '/mysql-zhaoyang')
-
-def book(request, short_name, unanswered=False):
- """
- 1. questions list
- 2. book info
- 3. author info and blog rss items
- """
- """
- List of Questions, Tagged questions, and Unanswered questions.
- """
- books = Book.objects.extra(where=['short_name = %s'], params=[short_name])
- match_count = len(books)
- if match_count == 0:
- raise Http404
- else:
- # the book info
- book = books[0]
- # get author info
- author_info = BookAuthorInfo.objects.get(book=book)
- # get author rss info
- author_rss = BookAuthorRss.objects.filter(book=book)
-
- # get pagesize from session, if failed then get default value
- user_page_size = request.session.get("page_size", 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'))
- except ValueError:
- page = 1
-
- 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"
-
- # check if request is from tagged questions
- if unanswered:
- # check if request is from unanswered questions
- # Article.objects.filter(publications__id__exact=1)
- objects = Question.objects.filter(book__id__exact=book.id, deleted=False, answer_count=0).order_by(orderby)
- else:
- objects = Question.objects.filter(book__id__exact=book.id, deleted=False).order_by(orderby)
-
- # RISK - inner join queries
- objects = objects.select_related();
- objects_list = Paginator(objects, user_page_size)
- questions = objects_list.page(page)
-
- return render_to_response('book.html', {
- "book" : book,
- "author_info" : author_info,
- "author_rss" : author_rss,
- "questions" : questions,
- "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,
- 'page_size' : user_page_size
- }
- }, context_instance=RequestContext(request))
-
-@login_required
-def ask_book(request, short_name):
- if request.method == "POST":
- form = AskForm(request.POST)
- if form.is_valid():
- added_at = datetime.datetime.now()
- html = sanitize_html(markdowner.convert(form.cleaned_data['text']))
- question = Question(
- title = strip_tags(form.cleaned_data['title']),
- author = request.user,
- added_at = added_at,
- last_activity_at = added_at,
- last_activity_by = request.user,
- wiki = form.cleaned_data['wiki'],
- tagnames = form.cleaned_data['tags'].strip(),
- html = html,
- summary = strip_tags(html)[:120]
- )
- if question.wiki:
- question.last_edited_by = question.author
- question.last_edited_at = added_at
- question.wikified_at = added_at
-
- question.save()
-
- # create the first revision
- QuestionRevision.objects.create(
- question = question,
- revision = 1,
- title = question.title,
- author = request.user,
- revised_at = added_at,
- tagnames = question.tagnames,
- summary = CONST['default_version'],
- text = form.cleaned_data['text']
- )
-
- books = Book.objects.extra(where=['short_name = %s'], params=[short_name])
- match_count = len(books)
- if match_count == 1:
- # the book info
- book = books[0]
- book.questions.add(question)
-
- return HttpResponseRedirect(question.get_absolute_url())
- else:
- form = AskForm()
-
- tags = _get_tags_cache_json()
- return render_to_response('ask.html', {
- 'form' : form,
- 'tags' : tags,
- 'email_validation_faq_url': reverse('faq') + '#validate',
- }, context_instance=RequestContext(request))
diff --git a/forum_modules/pgfulltext/__init__.py b/forum_modules/pgfulltext/__init__.py
deleted file mode 100644
index 8215e1a9..00000000
--- a/forum_modules/pgfulltext/__init__.py
+++ /dev/null
@@ -1,9 +0,0 @@
-NAME = 'Postgresql Full Text Search'
-DESCRIPTION = "Enables PostgreSql full text search functionality."
-
-try:
- import psycopg2
- CAN_ENABLE = True
-except:
- CAN_ENABLE = False
- \ No newline at end of file
diff --git a/forum_modules/pgfulltext/handlers.py b/forum_modules/pgfulltext/handlers.py
deleted file mode 100644
index f4a7a3b2..00000000
--- a/forum_modules/pgfulltext/handlers.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from forum.models import Question
-
-def question_search(keywords, orderby):
- return Question.objects.filter(deleted=False).extra(
- select={
- 'ranking': "ts_rank_cd(tsv, plainto_tsquery(%s), 32)",
- },
- where=["tsv @@ plainto_tsquery(%s)"],
- params=[keywords],
- select_params=[keywords]
- ).order_by(orderby, '-ranking') \ No newline at end of file
diff --git a/forum_modules/pgfulltext/management.py b/forum_modules/pgfulltext/management.py
deleted file mode 100644
index 15ba3bd7..00000000
--- a/forum_modules/pgfulltext/management.py
+++ /dev/null
@@ -1,30 +0,0 @@
-import os
-
-from django.db import connection, transaction
-from django.conf import settings
-
-import forum.models
-
-if settings.DATABASE_ENGINE in ('postgresql_psycopg2', 'postgresql', ):
- from django.db.models.signals import post_syncdb
-
- def setup_pgfulltext(sender, **kwargs):
- if sender == forum.models:
- install_pg_fts()
-
- post_syncdb.connect(setup_pgfulltext)
-
-def install_pg_fts():
- f = open(os.path.join(os.path.dirname(__file__), 'pg_fts_install.sql'), 'r')
-
- try:
- try:
- cursor = connection.cursor()
- cursor.execute(f.read())
- transaction.commit_unless_managed()
- except:
- pass
- finally:
- cursor.close()
-
- f.close()
diff --git a/forum_modules/pgfulltext/pg_fts_install.sql b/forum_modules/pgfulltext/pg_fts_install.sql
deleted file mode 100644
index 72eca516..00000000
--- a/forum_modules/pgfulltext/pg_fts_install.sql
+++ /dev/null
@@ -1,38 +0,0 @@
-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 question_tsv ON question USING gin(tsv);
-
-UPDATE question SET title = title;
diff --git a/forum_modules/robotstxt/DISABLED b/forum_modules/robotstxt/DISABLED
deleted file mode 100755
index e69de29b..00000000
--- a/forum_modules/robotstxt/DISABLED
+++ /dev/null
diff --git a/forum_modules/robotstxt/templates/robots.txt b/forum_modules/robotstxt/templates/robots.txt
deleted file mode 100755
index 574fc315..00000000
--- a/forum_modules/robotstxt/templates/robots.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-User-agent: *
-Disallow: / \ No newline at end of file
diff --git a/forum_modules/robotstxt/urls.py b/forum_modules/robotstxt/urls.py
deleted file mode 100755
index 79a6d84c..00000000
--- a/forum_modules/robotstxt/urls.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from django.conf.urls.defaults import *
-from django.views.generic.simple import direct_to_template
-
-urlpatterns = patterns('',
- (r'^robots.txt$', direct_to_template, {'template': 'modules/robotsdennyall/robots.txt'}),
-)
diff --git a/forum_modules/sphinxfulltext/DISABLED b/forum_modules/sphinxfulltext/DISABLED
deleted file mode 100644
index e69de29b..00000000
--- a/forum_modules/sphinxfulltext/DISABLED
+++ /dev/null
diff --git a/forum_modules/sphinxfulltext/dependencies.py b/forum_modules/sphinxfulltext/dependencies.py
deleted file mode 100644
index 046ebfc5..00000000
--- a/forum_modules/sphinxfulltext/dependencies.py
+++ /dev/null
@@ -1,2 +0,0 @@
-DJANGO_APPS = ('djangosphinx', )
-
diff --git a/forum_modules/sphinxfulltext/handlers.py b/forum_modules/sphinxfulltext/handlers.py
deleted file mode 100644
index 226acf72..00000000
--- a/forum_modules/sphinxfulltext/handlers.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from forum.models import Question
-
-def question_search(keywords, orderby):
- return Question.search.query(keywords) \ No newline at end of file
diff --git a/forum_modules/sphinxfulltext/models.py b/forum_modules/sphinxfulltext/models.py
deleted file mode 100644
index a188728d..00000000
--- a/forum_modules/sphinxfulltext/models.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from forum.models import Question
-from django.conf import settings
-from djangosphinx.manager import SphinxSearch
-
-from djangosphinx.models import SphinxSearch
-
-Question.add_to_class('search', SphinxSearch(
- index=' '.join(settings.SPHINX_SEARCH_INDICES),
- mode='SPH_MATCH_ALL',
- )
- )
diff --git a/forum_modules/sphinxfulltext/settings.py b/forum_modules/sphinxfulltext/settings.py
deleted file mode 100644
index 564404c6..00000000
--- a/forum_modules/sphinxfulltext/settings.py
+++ /dev/null
@@ -1,5 +0,0 @@
-SPHINX_API_VERSION = 0x113 #refer to djangosphinx documentation
-SPHINX_SEARCH_INDICES=('askbot',) #a tuple of index names remember about a comma after the
-#last item, especially if you have just one :)
-SPHINX_SERVER='localhost'
-SPHINX_PORT=3312
diff --git a/locale/en/LC_MESSAGES/django.mo b/locale/en/LC_MESSAGES/django.mo
deleted file mode 100644
index a751a47c..00000000
--- a/locale/en/LC_MESSAGES/django.mo
+++ /dev/null
Binary files differ
diff --git a/log/README.TXT b/log/README.TXT
deleted file mode 100755
index 9c51276d..00000000
--- a/log/README.TXT
+++ /dev/null
@@ -1 +0,0 @@
-this file is just a placeholder so the empty directory is not ignored by version control
diff --git a/run b/run
deleted file mode 100755
index 06279161..00000000
--- a/run
+++ /dev/null
@@ -1 +0,0 @@
-python manage.py runserver `hostname -i`:8000
diff --git a/settings.py b/settings.py
deleted file mode 100644
index 2acc920e..00000000
--- a/settings.py
+++ /dev/null
@@ -1,96 +0,0 @@
-# encoding:utf-8
-# Django settings for lanai project.
-import os.path
-import sys
-
-SITE_ID = 1
-
-ADMIN_MEDIA_PREFIX = '/admin/media/'
-SECRET_KEY = '$oo^&_m&qwbib=(_4m_n*zn-d=g#s0he5fx9xonnym#8p6yigm'
-# List of callables that know how to import templates from various sources.
-TEMPLATE_LOADERS = (
- 'django.template.loaders.filesystem.load_template_source',
- 'django.template.loaders.app_directories.load_template_source',
- 'forum.modules.module_templates_loader',#todo: remove this
- 'forum.skins.load_template_source',
-# 'django.template.loaders.eggs.load_template_source',
-)
-
-MIDDLEWARE_CLASSES = (
- #'django.middleware.gzip.GZipMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- #'django.middleware.locale.LocaleMiddleware',
- #'django.middleware.cache.UpdateCacheMiddleware',
- 'django.middleware.common.CommonMiddleware',
- #'django.middleware.cache.FetchFromCacheMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- #'django.middleware.sqlprint.SqlPrintingMiddleware',
- 'forum.middleware.anon_user.ConnectToSessionMessagesMiddleware',
- 'forum.middleware.pagesize.QuestionsPageSizeMiddleware',
- 'forum.middleware.cancel.CancelActionMiddleware',
- #'recaptcha_django.middleware.ReCaptchaMiddleware',
- 'django.middleware.transaction.TransactionMiddleware',
- 'debug_toolbar.middleware.DebugToolbarMiddleware',
- 'forum.middleware.view_log.ViewLogMiddleware',
-)
-
-TEMPLATE_CONTEXT_PROCESSORS = (
- 'django.core.context_processors.request',
- 'forum.context.application_settings',
- #'django.core.context_processors.i18n',
- 'forum.user_messages.context_processors.user_messages',#must be before auth
- 'django.core.context_processors.auth', #this is required for admin
-)
-
-ROOT_URLCONF = 'urls'
-
-TEMPLATE_DIRS = (
- os.path.join(os.path.dirname(__file__),'forum','skins').replace('\\','/'),
-)
-
-#UPLOAD SETTINGS
-FILE_UPLOAD_TEMP_DIR = os.path.join(os.path.dirname(__file__), 'tmp').replace('\\','/')
-FILE_UPLOAD_HANDLERS = ("django.core.files.uploadhandler.MemoryFileUploadHandler",
- "django.core.files.uploadhandler.TemporaryFileUploadHandler",)
-DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
-# for user upload
-ALLOW_FILE_TYPES = ('.jpg', '.jpeg', '.gif', '.bmp', '.png', '.tiff')
-# unit byte
-ALLOW_MAX_FILE_SIZE = 1024 * 1024
-
-# User settings
-from settings_local import *
-
-INSTALLED_APPS = (
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.sites',
- 'django.contrib.admin',
- 'django.contrib.humanize',
- 'django.contrib.sitemaps',
- 'debug_toolbar',
- 'forum',
- 'django_authopenid',
- 'debug_toolbar' ,
- #'forum.importers.stackexchange', #se loader
- 'south',
-)
-
-AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',)
-
-if USE_FB_CONNECT:
- INSTALLED_APPS += ('fbconnect',)
-
-#load optional plugin module for external password login
-if 'USE_EXTERNAL_LEGACY_LOGIN' in locals() and USE_EXTERNAL_LEGACY_LOGIN:
- INSTALLED_APPS += (EXTERNAL_LEGACY_LOGIN_MODULE,)
-
- if 'EXTERNAL_LEGACY_LOGIN_AUTHENTICATION_BACKEND' in locals():
- AUTHENTICATION_BACKENDS += (EXTERNAL_LEGACY_LOGIN_AUTHENTICATION_BACKEND,)
- if 'EXTERNAL_LEGACY_LOGIN_AUTHENTICATION_MIDDLEWARE' in locals():
- MIDDLEWARE_CLASSES += (EXTERNAL_LEGACY_LOGIN_AUTHENTICATION_MIDDLEWARE,)
- def LOAD_EXTERNAL_LOGIN_APP():
- return __import__(EXTERNAL_LEGACY_LOGIN_MODULE, [], [], ['api','forms','views'])
-else:
- LOAD_EXTERNAL_LOGIN_APP = lambda: None
diff --git a/settings_local.py.dist b/settings_local.py.dist
deleted file mode 100755
index 3d02a024..00000000
--- a/settings_local.py.dist
+++ /dev/null
@@ -1,126 +0,0 @@
-# encoding:utf-8
-import os.path
-from django.utils.translation import ugettext as _
-
-SITE_SRC_ROOT = os.path.dirname(__file__)
-LOG_FILENAME = 'askbot.log'
-
-#for logging
-import logging
-logging.basicConfig(
- filename=os.path.join(SITE_SRC_ROOT, 'log', LOG_FILENAME),
- level=logging.DEBUG,
- format='%(pathname)s TIME: %(asctime)s MSG: %(filename)s:%(funcName)s:%(lineno)d %(message)s',
-)
-
-#ADMINS and MANAGERS
-ADMINS = (('Forum Admin', 'forum@example.com'),)
-MANAGERS = ADMINS
-
-#DEBUG SETTINGS
-DEBUG = False
-TEMPLATE_DEBUG = DEBUG
-INTERNAL_IPS = ('127.0.0.1',)
-
-DATABASE_NAME = '' # Or path to database file if using sqlite3.
-DATABASE_USER = '' # Not used with sqlite3.
-DATABASE_PASSWORD = '' # Not used with sqlite3.
-DATABASE_ENGINE = '' #mysql, etc
-DATABASE_HOST = ''
-DATABASE_PORT = ''
-
-#set this value to 'locmem://'
-#use memcached for production
-#see http://docs.djangoproject.com/en/1.1/topics/cache/ for details
-CACHE_BACKEND = 'locmem://'
-
-#If you use memcache you may want to uncomment the following line to enable memcached based sessions
-#SESSION_ENGINE = 'django.contrib.sessions.backends.cache_db'
-
-#email server settings
-SERVER_EMAIL = ''
-DEFAULT_FROM_EMAIL = ''
-EMAIL_HOST_USER = ''
-EMAIL_HOST_PASSWORD = ''
-EMAIL_SUBJECT_PREFIX = '[ASKBOT] '
-EMAIL_HOST='askbot.org'
-EMAIL_PORT='25'
-EMAIL_USE_TLS=False
-
-#HACK - anonymous user email - for email-less users
-ANONYMOUS_USER_EMAIL = 'anonymous@askbot.org'
-
-#LOCALIZATIONS
-TIME_ZONE = 'America/New_York'
-
-###########################
-#
-# this will allow running your forum with url like http://site.com/forum
-#
-# FORUM_SCRIPT_ALIAS = 'forum/'
-#
-FORUM_SCRIPT_ALIAS = '' #no leading slash, default = '' empty string
-
-
-#OTHER SETTINGS
-APP_TITLE = u'ASKBOT: Open Source Q&A Forum'
-APP_SHORT_NAME = u'ASKBOT'
-APP_KEYWORDS = u'ASKBOT,CNPROG,forum,community'
-APP_DESCRIPTION = u'Ask and answer questions.'
-APP_INTRO = u'<p>Ask and answer questions, make the world better!</p>'
-APP_COPYRIGHT = 'Copyright ASKBOT, 2009. Some rights reserved under creative commons license.'
-LOGIN_URL = '/%s%s%s' % (FORUM_SCRIPT_ALIAS,'account/','signin/')
-GREETING_URL = LOGIN_URL #may be url of "faq" page or "about", etc
-
-USE_I18N = True
-LANGUAGE_CODE = 'en'
-EMAIL_VALIDATION = 'off' #string - on|off
-MIN_USERNAME_LENGTH = 1
-EMAIL_UNIQUE = False
-APP_URL = 'http://askbot.org' #used by email notif system and RSS
-GOOGLE_SITEMAP_CODE = ''
-GOOGLE_ANALYTICS_KEY = ''
-WIKI_ON = True
-FEEDBACK_SITE_URL = None #None or url
-EDITABLE_SCREEN_NAME = False #True or False - can user change screen name?
-
-DJANGO_VERSION = 1.1
-RESOURCE_REVISION=4
-
-#please get these at recaptcha.net
-RECAPTCHA_PRIVATE_KEY='...'
-RECAPTCHA_PUBLIC_KEY='...'
-ASKBOT_DEFAULT_SKIN = 'default'
-
-
-#Facebook settings
-USE_FB_CONNECT=False
-FB_API_KEY='' #your api key from facebook
-FB_SECRET='' #your application secret
-
-USE_EXTERNAL_LEGACY_LOGIN = False #DO NOT USE, and do not delete this line, will be removed later
-#counter colors
-from forum_modules.grapefruit import Color
-VOTE_COUNTER_EXPECTED_MAXIMUM = 5
-COLORS_VOTE_COUNTER_EMPTY_BG = 'white'
-COLORS_VOTE_COUNTER_EMPTY_FG = 'gray'
-COLORS_VOTE_COUNTER_MIN_BG = 'white'
-COLORS_VOTE_COUNTER_MIN_FG = 'black'
-COLORS_VOTE_COUNTER_MAX_BG = '#a9d0f5'
-COLORS_VOTE_COUNTER_MAX_FG = Color.NewFromHtml(COLORS_VOTE_COUNTER_MAX_BG).DarkerColor(0.7).html
-VIEW_COUNTER_EXPECTED_MAXIMUM = 100
-COLORS_VIEW_COUNTER_EMPTY_BG = 'gray'
-COLORS_VIEW_COUNTER_EMPTY_FG = 'white'
-COLORS_VIEW_COUNTER_MIN_BG = '#D0F5A9'
-COLORS_VIEW_COUNTER_MIN_FG = Color.NewFromHtml(COLORS_VIEW_COUNTER_MIN_BG).DarkerColor(0.6).html
-COLORS_VIEW_COUNTER_MAX_BG = '#FF8000'#'#F7BE81'
-COLORS_VIEW_COUNTER_MAX_FG = Color.NewFromHtml(COLORS_VIEW_COUNTER_MAX_BG).DarkerColor(0.7).html
-ANSWER_COUNTER_EXPECTED_MAXIMUM = 4
-COLORS_ANSWER_COUNTER_EMPTY_BG = Color.NewFromHtml('#a40000').Blend(Color.NewFromHtml('white'),0.8).html
-COLORS_ANSWER_COUNTER_EMPTY_FG = 'yellow'
-COLORS_ANSWER_COUNTER_MIN_BG = '#AEB404'#'#81F7F3'#'#A9D0F5'#'#045FB4'
-COLORS_ANSWER_COUNTER_MIN_FG = 'white'#'#81F7F3'
-COLORS_ANSWER_COUNTER_MAX_BG = Color.NewFromHtml('#61380B').Blend(Color.NewFromHtml('white'),0.75).html
-COLORS_ANSWER_COUNTER_MAX_FG = '#ffff00'
-COLORS_ANSWER_COUNTER_ACCEPTED_BG = Color.NewFromHtml('darkgreen').Blend(Color.NewFromHtml('white'),0.8).html
-COLORS_ANSWER_COUNTER_ACCEPTED_FG = '#D0F5A9'
diff --git a/setup.py b/setup.py
new file mode 100644
index 00000000..565eb190
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,77 @@
+import ez_setup
+ez_setup.use_setuptools()
+from setuptools import setup, find_packages
+import sys
+
+install_requires = [
+ 'django==1.1.2',
+ 'django-debug-toolbar==0.7.0',
+ 'South>=0.7.1',
+ 'recaptcha-client',
+ 'markdown2',
+ 'html5lib',
+ 'python-openid',
+ 'django-keyedcache',
+ 'django-threaded-multihost',
+]
+WIN_PLATFORMS = ('win32', 'cygwin',)
+if sys.platform not in WIN_PLATFORMS:
+ install_requires.append('mysql-python')
+
+setup(
+ name = "askbot",
+ version = "0.6.1",
+ description = 'Question and Answer forum, like StackOverflow, written in python and Django',
+ packages = find_packages(),
+ author = 'Evgeny.Fadeev',
+ author_email = 'evgeny.fadeev@gmail.com',
+ license = 'GPLv3',
+ keywords = 'forum, community, wiki, Q&A',
+ entry_points = {
+ 'console_scripts' : [
+ 'startforum = askbot.deployment:startforum',
+ ]
+ },
+ url = 'http://askbot.org',
+ include_package_data = True,
+ install_requires = install_requires,
+ classifiers = [
+ 'Development Status :: 4 - Beta',
+ 'Environment :: Web Environment',
+ 'Framework :: Django',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: GNU General Public License (GPL)',
+ 'Natural Language :: English',
+ 'Natural Language :: German',
+ 'Natural Language :: Russian',
+ 'Natural Language :: Serbian',
+ 'Natural Language :: Turkish',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python :: 2.4',
+ 'Programming Language :: Python :: 2.5',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: JavaScript',
+ 'Topic :: Communications :: Usenet News',
+ 'Topic :: Communications :: Email :: Mailing List Servers',
+ 'Topic :: Communications',
+ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+ ],
+ long_description = """Open Source Question and Answer forum.
+ Based on CNPROG project by Mike Chen and Sailing Cai, project
+ inspired by StackOverflow.
+ """,
+)
+
+if sys.platform in WIN_PLATFORMS:
+ print 'ATTENTION!! please install windows binary mysql-python package'
+ print 'at http://www.codegood.com/archives/4'
+
+print '**************************************************************'
+print '* *'
+print '* Thanks for installing Askbot. *'
+print '* To start deploying type: >startforum *'
+print '* Please take a look at the manual askbot/doc/INSTALL *'
+print '* And please do not hesitate to ask your questions at *'
+print '* at http://askbot.org *'
+print '* *'
+print '**************************************************************'