summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MANIFEST.in6
-rw-r--r--askbot/__init__.py13
-rw-r--r--askbot/auth.py108
-rw-r--r--askbot/conf/__init__.py1
-rw-r--r--askbot/conf/badges.py27
-rw-r--r--askbot/conf/email.py59
-rw-r--r--askbot/conf/forum_data_rules.py111
-rw-r--r--askbot/conf/login_providers.py72
-rw-r--r--askbot/conf/markup.py10
-rw-r--r--askbot/conf/minimum_reputation.py296
-rw-r--r--askbot/conf/user_settings.py17
-rw-r--r--askbot/const/__init__.py15
-rw-r--r--askbot/context.py12
-rw-r--r--askbot/deployment/assertions.py26
-rw-r--r--askbot/deployment/package_utils.py28
-rw-r--r--askbot/deps/django_authopenid/backends.py1
-rw-r--r--askbot/deps/django_authopenid/forms.py7
-rw-r--r--askbot/deps/django_authopenid/middleware.py1
-rw-r--r--askbot/deps/django_authopenid/migrations/0005_auto__del_externallogindata.py118
-rw-r--r--askbot/deps/django_authopenid/models.py9
-rw-r--r--askbot/deps/django_authopenid/urls.py1
-rw-r--r--askbot/deps/django_authopenid/util.py60
-rw-r--r--askbot/deps/django_authopenid/views.py97
-rw-r--r--askbot/deps/livesettings/overrides.py1
-rw-r--r--askbot/deps/livesettings/values.py1
-rw-r--r--askbot/doc/source/about.rst9
-rw-r--r--askbot/doc/source/askbot/layout.html17
-rw-r--r--askbot/doc/source/askbot/static/traditional.css677
-rw-r--r--askbot/doc/source/askbot/theme.conf4
-rw-r--r--askbot/doc/source/conf.py11
-rw-r--r--askbot/doc/source/contributors.rst31
-rw-r--r--askbot/doc/source/download.rst6
-rw-r--r--askbot/doc/source/import-data.rst20
-rw-r--r--askbot/doc/source/index.rst2
-rw-r--r--askbot/doc/source/management-commands.rst24
-rw-r--r--askbot/exceptions.py4
-rw-r--r--askbot/feed.py8
-rw-r--r--askbot/forms.py358
-rw-r--r--askbot/importers/stackexchange/management/__init__.py24
-rw-r--r--askbot/importers/stackexchange/management/commands/load_stackexchange.py74
-rw-r--r--askbot/locale/en/LC_MESSAGES/django.mobin22748 -> 21637 bytes
-rw-r--r--askbot/locale/en/LC_MESSAGES/django.po3574
-rw-r--r--askbot/locale/ro/LC_MESSAGES/django.mobin0 -> 87643 bytes
-rw-r--r--askbot/locale/ro/LC_MESSAGES/django.po5727
-rw-r--r--askbot/locale/ru/LC_MESSAGES/djangojs.mobin0 -> 619 bytes
-rw-r--r--askbot/locale/ru/LC_MESSAGES/djangojs.po26
-rw-r--r--askbot/management/__init__.py82
-rw-r--r--askbot/management/commands/add_admin.py7
-rw-r--r--askbot/management/commands/delete_unused_tags.py8
-rw-r--r--askbot/management/commands/dump_forum.py2
-rw-r--r--askbot/management/commands/fix_inbox_counts.py46
-rw-r--r--askbot/management/commands/fix_question_tags.py79
-rw-r--r--askbot/management/commands/get_tag_stats.py218
-rw-r--r--askbot/management/commands/junk.py36
-rw-r--r--askbot/management/commands/load_forum.py2
-rw-r--r--askbot/management/commands/pg_base_command.py35
-rw-r--r--askbot/management/commands/post_emailed_questions.py207
-rw-r--r--askbot/management/commands/remove_admin.py7
-rw-r--r--askbot/management/commands/rename_tags.py3
-rw-r--r--askbot/management/commands/send_email_alerts.py57
-rw-r--r--askbot/management/commands/subscribe_everyone.py1
-rw-r--r--askbot/middleware/cancel.py1
-rw-r--r--askbot/middleware/pagesize.py7
-rw-r--r--askbot/middleware/view_log.py56
-rw-r--r--askbot/migrations/0025_transfer_flagged_items_to_activity.py21
-rw-r--r--askbot/migrations/0033_add__consecutive_days_visit_count__to__auth_user.py309
-rw-r--r--askbot/migrations/0034_auto__add_field_user_avatar_url.py305
-rw-r--r--askbot/migrations/0035_add_country_fields_to_user.py309
-rw-r--r--askbot/migrations/0036_auto__add_field_anonymousquestion_is_anonymous__add_field_questionrevi.py319
-rw-r--r--askbot/migrations/0037_add_marked_tags_to_user_profile.py315
-rw-r--r--askbot/migrations/0038_add_tag_filter_strategies.py321
-rw-r--r--askbot/migrations/0039_populate_tag_filter_strategies.py333
-rw-r--r--askbot/migrations/0040_delete_old_tag_filter_strategies.py317
-rw-r--r--askbot/models/__init__.py569
-rw-r--r--askbot/models/answer.py6
-rw-r--r--askbot/models/badges.py75
-rw-r--r--askbot/models/base.py35
-rw-r--r--askbot/models/content.py217
-rw-r--r--askbot/models/meta.py42
-rw-r--r--askbot/models/question.py247
-rw-r--r--askbot/models/signals.py70
-rw-r--r--askbot/models/tag.py67
-rw-r--r--askbot/models/user.py14
-rw-r--r--askbot/patches/__init__.py28
-rw-r--r--askbot/patches/coffin_patches.py34
-rw-r--r--askbot/patches/django_patches.py327
-rw-r--r--askbot/search/indexer.py9
-rw-r--r--askbot/search/state_manager.py85
-rw-r--r--askbot/setup_templates/settings.py33
-rwxr-xr-xaskbot/skins/README73
-rwxr-xr-xaskbot/skins/common/media/README1
-rw-r--r--askbot/skins/default/media/images/anon.pngbin0 -> 687 bytes
-rw-r--r--askbot/skins/default/media/images/flags/.DS_Storebin0 -> 12292 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ad.gifbin0 -> 371 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ae.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/af.gifbin0 -> 369 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ag.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ai.gifbin0 -> 369 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/al.gifbin0 -> 370 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/am.gifbin0 -> 363 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/an.gifbin0 -> 368 bytes
-rw-r--r--askbot/skins/default/media/images/flags/ao.gifbin0 -> 244 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ar.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/as.gifbin0 -> 365 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/at.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/au.gifbin0 -> 378 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/aw.gifbin0 -> 365 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ax.gifbin0 -> 376 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/az.gifbin0 -> 370 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ba.gifbin0 -> 363 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/bb.gifbin0 -> 368 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/bd.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/be.gifbin0 -> 359 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/bf.gifbin0 -> 358 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/bg.gifbin0 -> 360 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/bh.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/bi.gifbin0 -> 374 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/bj.gifbin0 -> 368 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/bm.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/bn.gifbin0 -> 373 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/bo.gifbin0 -> 359 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/br.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/bs.gifbin0 -> 351 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/bt.gifbin0 -> 377 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/bv.gifbin0 -> 376 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/bw.gifbin0 -> 364 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/by.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/bz.gifbin0 -> 368 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ca.gifbin0 -> 376 bytes
-rw-r--r--askbot/skins/default/media/images/flags/catalonia.gifbin0 -> 238 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/cc.gifbin0 -> 371 bytes
-rw-r--r--askbot/skins/default/media/images/flags/cd.gifbin0 -> 243 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/cf.gifbin0 -> 364 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/cg.gifbin0 -> 359 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ch.gifbin0 -> 332 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ci.gifbin0 -> 368 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ck.gifbin0 -> 362 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/cl.gifbin0 -> 364 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/cm.gifbin0 -> 369 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/cn.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/co.gifbin0 -> 353 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/cr.gifbin0 -> 359 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/cs.gifbin0 -> 364 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/cu.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/cv.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/cx.gifbin0 -> 363 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/cy.gifbin0 -> 365 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/cz.gifbin0 -> 362 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/de.gifbin0 -> 362 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/dj.gifbin0 -> 369 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/dk.gifbin0 -> 374 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/dm.gifbin0 -> 368 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/do.gifbin0 -> 362 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/dz.gifbin0 -> 370 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ec.gifbin0 -> 362 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ee.gifbin0 -> 364 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/eg.gifbin0 -> 363 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/eh.gifbin0 -> 359 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/england.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/er.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/es.gifbin0 -> 360 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/et.gifbin0 -> 364 bytes
-rw-r--r--askbot/skins/default/media/images/flags/europeanunion.gifbin0 -> 171 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/fam.gifbin0 -> 370 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/fi.gifbin0 -> 371 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/fj.gifbin0 -> 370 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/fk.gifbin0 -> 372 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/fm.gifbin0 -> 377 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/fo.gifbin0 -> 370 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/fr.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ga.gifbin0 -> 359 bytes
-rw-r--r--askbot/skins/default/media/images/flags/gb.gifbin0 -> 260 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/gd.gifbin0 -> 364 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ge.gifbin0 -> 379 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/gf.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/gh.gifbin0 -> 358 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/gi.gifbin0 -> 370 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/gl.gifbin0 -> 368 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/gm.gifbin0 -> 362 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/gn.gifbin0 -> 363 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/gp.gifbin0 -> 357 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/gq.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/gr.gifbin0 -> 368 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/gs.gifbin0 -> 363 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/gt.gifbin0 -> 374 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/gu.gifbin0 -> 370 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/gw.gifbin0 -> 358 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/gy.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/hk.gifbin0 -> 373 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/hm.gifbin0 -> 378 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/hn.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/hr.gifbin0 -> 364 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ht.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/hu.gifbin0 -> 357 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/id.gifbin0 -> 362 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ie.gifbin0 -> 371 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/il.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/in.gifbin0 -> 363 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/io.gifbin0 -> 373 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/iq.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ir.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/is.gifbin0 -> 373 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/it.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/jm.gifbin0 -> 365 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/jo.gifbin0 -> 360 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/jp.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ke.gifbin0 -> 360 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/kg.gifbin0 -> 373 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/kh.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ki.gifbin0 -> 371 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/km.gifbin0 -> 358 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/kn.gifbin0 -> 370 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/kp.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/kr.gifbin0 -> 385 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/kw.gifbin0 -> 362 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ky.gifbin0 -> 373 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/kz.gifbin0 -> 374 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/la.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/lb.gifbin0 -> 366 bytes
-rw-r--r--askbot/skins/default/media/images/flags/lc.gifbin0 -> 259 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/li.gifbin0 -> 359 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/lk.gifbin0 -> 377 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/lr.gifbin0 -> 360 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ls.gifbin0 -> 369 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/lt.gifbin0 -> 362 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/lu.gifbin0 -> 368 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/lv.gifbin0 -> 363 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ly.gifbin0 -> 362 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ma.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/mc.gifbin0 -> 359 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/md.gifbin0 -> 367 bytes
-rw-r--r--askbot/skins/default/media/images/flags/me.gifbin0 -> 238 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/mg.gifbin0 -> 372 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/mh.gifbin0 -> 370 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/mk.gifbin0 -> 382 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ml.gifbin0 -> 363 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/mm.gifbin0 -> 365 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/mn.gifbin0 -> 368 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/mo.gifbin0 -> 378 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/mp.gifbin0 -> 368 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/mq.gifbin0 -> 379 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/mr.gifbin0 -> 377 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ms.gifbin0 -> 371 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/mt.gifbin0 -> 369 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/mu.gifbin0 -> 358 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/mv.gifbin0 -> 372 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/mw.gifbin0 -> 364 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/mx.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/my.gifbin0 -> 375 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/mz.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/na.gifbin0 -> 371 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/nc.gifbin0 -> 364 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ne.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/nf.gifbin0 -> 375 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ng.gifbin0 -> 371 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ni.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/nl.gifbin0 -> 360 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/no.gifbin0 -> 376 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/np.gifbin0 -> 302 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/nr.gifbin0 -> 364 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/nu.gifbin0 -> 369 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/nz.gifbin0 -> 369 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/om.gifbin0 -> 364 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/pa.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/pe.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/pf.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/pg.gifbin0 -> 360 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ph.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/pk.gifbin0 -> 377 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/pl.gifbin0 -> 360 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/pm.gifbin0 -> 374 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/pn.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/pr.gifbin0 -> 369 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ps.gifbin0 -> 358 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/pt.gifbin0 -> 369 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/pw.gifbin0 -> 374 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/py.gifbin0 -> 363 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/qa.gifbin0 -> 364 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/re.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ro.gifbin0 -> 363 bytes
-rw-r--r--askbot/skins/default/media/images/flags/rs.gifbin0 -> 238 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ru.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/rw.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/sa.gifbin0 -> 370 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/sb.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/sc.gifbin0 -> 357 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/scotland.gifbin0 -> 378 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/sd.gifbin0 -> 355 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/se.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/sg.gifbin0 -> 364 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/sh.gifbin0 -> 371 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/si.gifbin0 -> 362 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/sj.gifbin0 -> 376 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/sk.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/sl.gifbin0 -> 363 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/sm.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/sn.gifbin0 -> 364 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/so.gifbin0 -> 376 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/sr.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/st.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/sv.gifbin0 -> 363 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/sy.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/sz.gifbin0 -> 363 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/tc.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/td.gifbin0 -> 368 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/tf.gifbin0 -> 365 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/tg.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/th.gifbin0 -> 360 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/tj.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/tk.gifbin0 -> 372 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/tl.gifbin0 -> 360 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/tm.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/tn.gifbin0 -> 375 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/to.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/tr.gifbin0 -> 371 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/tt.gifbin0 -> 377 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/tv.gifbin0 -> 361 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/tw.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/tz.gifbin0 -> 366 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ua.gifbin0 -> 360 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ug.gifbin0 -> 359 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/um.gifbin0 -> 371 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/us.gifbin0 -> 367 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/uy.gifbin0 -> 373 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/uz.gifbin0 -> 364 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/va.gifbin0 -> 369 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/vc.gifbin0 -> 370 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ve.gifbin0 -> 364 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/vg.gifbin0 -> 368 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/vi.gifbin0 -> 376 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/vn.gifbin0 -> 370 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/vu.gifbin0 -> 365 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/wales.gifbin0 -> 372 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/wf.gifbin0 -> 377 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ws.gifbin0 -> 365 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/ye.gifbin0 -> 356 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/yt.gifbin0 -> 382 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/za.gifbin0 -> 363 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/zm.gifbin0 -> 358 bytes
-rwxr-xr-xaskbot/skins/default/media/images/flags/zw.gifbin0 -> 365 bytes
-rw-r--r--askbot/skins/default/media/images/tag-left.pngbin0 -> 290 bytes
-rw-r--r--askbot/skins/default/media/images/tag-right.pngbin0 -> 187 bytes
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/jquery.openid.js8
-rw-r--r--askbot/skins/default/media/js/autocompleter.js766
-rw-r--r--askbot/skins/default/media/js/editor.js10
-rw-r--r--askbot/skins/default/media/js/jquery-fieldselection.js83
-rw-r--r--askbot/skins/default/media/js/jquery-fieldselection.min.js1
-rw-r--r--askbot/skins/default/media/js/live_search.js327
-rw-r--r--askbot/skins/default/media/js/post.js153
-rw-r--r--askbot/skins/default/media/js/tag_selector.js390
-rw-r--r--askbot/skins/default/media/js/utils.js291
-rw-r--r--[-rwxr-xr-x]askbot/skins/default/media/style/jquery.autocomplete.css42
-rwxr-xr-xaskbot/skins/default/media/style/style.css1409
-rw-r--r--askbot/skins/default/templates/404.html2
-rw-r--r--askbot/skins/default/templates/404.jinja.html8
-rw-r--r--askbot/skins/default/templates/500.html2
-rw-r--r--askbot/skins/default/templates/500.jinja.html6
-rw-r--r--askbot/skins/default/templates/about.html7
-rw-r--r--askbot/skins/default/templates/answer_edit.html13
-rw-r--r--askbot/skins/default/templates/ask.html29
-rw-r--r--askbot/skins/default/templates/authopenid/changeemail.html4
-rw-r--r--askbot/skins/default/templates/authopenid/complete.html4
-rw-r--r--askbot/skins/default/templates/authopenid/macros.html55
-rw-r--r--askbot/skins/default/templates/authopenid/providers_javascript.html63
-rw-r--r--askbot/skins/default/templates/authopenid/signin.html137
-rw-r--r--askbot/skins/default/templates/authopenid/signup_with_password.html45
-rw-r--r--askbot/skins/default/templates/avatar/add.html15
-rw-r--r--askbot/skins/default/templates/avatar/change.html24
-rw-r--r--askbot/skins/default/templates/avatar/confirm_delete.html16
-rw-r--r--askbot/skins/default/templates/badge.html7
-rw-r--r--askbot/skins/default/templates/badges.html54
-rw-r--r--askbot/skins/default/templates/base.html24
-rw-r--r--askbot/skins/default/templates/blocks/answer_edit_tips.html (renamed from askbot/skins/default/templates/answer_edit_tips.html)8
-rw-r--r--askbot/skins/default/templates/blocks/ask_form.html (renamed from askbot/skins/default/templates/ask_form.html)13
-rw-r--r--askbot/skins/default/templates/blocks/bottom_scripts.html3
-rw-r--r--askbot/skins/default/templates/blocks/editor_data.html (renamed from askbot/skins/default/templates/editor_data.html)0
-rw-r--r--askbot/skins/default/templates/blocks/footer.html (renamed from askbot/skins/default/templates/footer.html)2
-rw-r--r--askbot/skins/default/templates/blocks/head.html25
-rw-r--r--askbot/skins/default/templates/blocks/header.html (renamed from askbot/skins/default/templates/header.html)32
-rw-r--r--askbot/skins/default/templates/blocks/header_meta_links.html57
-rw-r--r--askbot/skins/default/templates/blocks/input_bar.html (renamed from askbot/skins/default/templates/input_bar.html)8
-rw-r--r--askbot/skins/default/templates/blocks/paginator.html (renamed from askbot/skins/default/templates/paginator.html)0
-rw-r--r--askbot/skins/default/templates/blocks/question_edit_tips.html (renamed from askbot/skins/default/templates/question_edit_tips.html)34
-rw-r--r--askbot/skins/default/templates/blocks/system_messages.html8
-rw-r--r--askbot/skins/default/templates/blocks/tag_selector.html46
-rw-r--r--askbot/skins/default/templates/close.html14
-rw-r--r--askbot/skins/default/templates/faq.html187
-rw-r--r--askbot/skins/default/templates/feedback.html80
-rw-r--r--askbot/skins/default/templates/html.list56
-rw-r--r--askbot/skins/default/templates/import_data.html31
-rw-r--r--askbot/skins/default/templates/logout.html37
-rw-r--r--askbot/skins/default/templates/macros.html301
-rw-r--r--askbot/skins/default/templates/main_page.html24
-rw-r--r--askbot/skins/default/templates/main_page/content.html17
-rw-r--r--askbot/skins/default/templates/main_page/headline.html48
-rw-r--r--askbot/skins/default/templates/main_page/javascript.html26
-rw-r--r--askbot/skins/default/templates/main_page/nothing_found.html31
-rw-r--r--askbot/skins/default/templates/main_page/paginator.html7
-rw-r--r--askbot/skins/default/templates/main_page/sidebar.html37
-rw-r--r--askbot/skins/default/templates/main_page/tab_bar.html86
-rw-r--r--askbot/skins/default/templates/one_column_body.html18
-rw-r--r--askbot/skins/default/templates/privacy.html8
-rw-r--r--askbot/skins/default/templates/question.html687
-rw-r--r--askbot/skins/default/templates/question_edit.html68
-rw-r--r--askbot/skins/default/templates/question_retag.html98
-rw-r--r--askbot/skins/default/templates/questions.html260
-rw-r--r--askbot/skins/default/templates/reopen.html54
-rw-r--r--askbot/skins/default/templates/revisions.html4
-rw-r--r--askbot/skins/default/templates/subscribe_for_tags.html19
-rw-r--r--askbot/skins/default/templates/tag_selector.html41
-rw-r--r--askbot/skins/default/templates/tags.html52
-rw-r--r--askbot/skins/default/templates/two_column_body.html26
-rw-r--r--askbot/skins/default/templates/unused/email_base.html23
-rw-r--r--askbot/skins/default/templates/unused/notarobot.html15
-rw-r--r--askbot/skins/default/templates/unused/question_counter_widget.html119
-rw-r--r--askbot/skins/default/templates/unused/question_list.html68
-rw-r--r--askbot/skins/default/templates/unused/question_summary_list_roll.html55
-rw-r--r--askbot/skins/default/templates/unused/questions_ajax.html118
-rw-r--r--askbot/skins/default/templates/unused/user_footer.html4
-rw-r--r--askbot/skins/default/templates/user_favorites.html6
-rw-r--r--askbot/skins/default/templates/user_profile/user.html (renamed from askbot/skins/default/templates/user.html)18
-rw-r--r--askbot/skins/default/templates/user_profile/user_edit.html (renamed from askbot/skins/default/templates/user_edit.html)28
-rw-r--r--askbot/skins/default/templates/user_profile/user_email_subscriptions.html (renamed from askbot/skins/default/templates/user_email_subscriptions.html)5
-rw-r--r--askbot/skins/default/templates/user_profile/user_favorites.html9
-rw-r--r--askbot/skins/default/templates/user_profile/user_inbox.html (renamed from askbot/skins/default/templates/user_inbox.html)5
-rw-r--r--askbot/skins/default/templates/user_profile/user_info.html (renamed from askbot/skins/default/templates/user_info.html)56
-rw-r--r--askbot/skins/default/templates/user_profile/user_moderate.html (renamed from askbot/skins/default/templates/user_moderate.html)5
-rw-r--r--askbot/skins/default/templates/user_profile/user_recent.html (renamed from askbot/skins/default/templates/user_recent.html)5
-rw-r--r--askbot/skins/default/templates/user_profile/user_reputation.html (renamed from askbot/skins/default/templates/user_reputation.html)15
-rw-r--r--askbot/skins/default/templates/user_profile/user_stats.html (renamed from askbot/skins/default/templates/user_stats.html)34
-rw-r--r--askbot/skins/default/templates/user_profile/user_tabs.html (renamed from askbot/skins/default/templates/user_tabs.html)24
-rw-r--r--askbot/skins/default/templates/user_profile/user_votes.html (renamed from askbot/skins/default/templates/user_votes.html)5
-rw-r--r--askbot/skins/default/templates/user_profile/users_questions.html (renamed from askbot/skins/default/templates/users_questions.html)0
-rw-r--r--askbot/skins/default/templates/users.html68
-rw-r--r--askbot/skins/loaders.py97
-rw-r--r--askbot/skins/utils.py13
-rw-r--r--askbot/sql_scripts/091111_upgrade_evgeny.sql1
-rw-r--r--askbot/sql_scripts/091208_upgrade_evgeny.sql1
-rw-r--r--askbot/sql_scripts/091208_upgrade_evgeny_1.sql1
-rw-r--r--askbot/sql_scripts/100108_upgrade_ef.sql4
-rw-r--r--askbot/sql_scripts/badges.sql37
-rw-r--r--askbot/sql_scripts/cnprog.xml1498
-rw-r--r--askbot/sql_scripts/cnprog_new_install.sql811
-rw-r--r--askbot/sql_scripts/cnprog_new_install_2009_02_28.sql456
-rw-r--r--askbot/sql_scripts/cnprog_new_install_2009_03_31.sql891
-rw-r--r--askbot/sql_scripts/cnprog_new_install_2009_04_07.sql24
-rw-r--r--askbot/sql_scripts/cnprog_new_install_2009_04_09.sql904
-rw-r--r--askbot/sql_scripts/drop-all-tables.sh4
-rw-r--r--askbot/sql_scripts/drop-auth.sql8
-rw-r--r--askbot/sql_scripts/pg_fts_install.sql38
-rw-r--r--askbot/sql_scripts/update_2009_01_13_001.sql62
-rw-r--r--askbot/sql_scripts/update_2009_01_13_002.sql1
-rw-r--r--askbot/sql_scripts/update_2009_01_18_001.sql62
-rw-r--r--askbot/sql_scripts/update_2009_01_24.sql2
-rw-r--r--askbot/sql_scripts/update_2009_01_25_001.sql2
-rw-r--r--askbot/sql_scripts/update_2009_02_26_001.sql19
-rw-r--r--askbot/sql_scripts/update_2009_04_10_001.sql3
-rw-r--r--askbot/sql_scripts/update_2009_07_05_EF.sql3
-rw-r--r--askbot/sql_scripts/update_2009_12_24_001.sql5
-rw-r--r--askbot/sql_scripts/update_2009_12_27_001.sql3
-rw-r--r--askbot/sql_scripts/update_2009_12_27_002.sql1
-rw-r--r--askbot/sql_scripts/update_2010_02_22.sql1
-rw-r--r--askbot/startup_procedures.py54
-rw-r--r--askbot/tasks.py118
-rw-r--r--askbot/templatetags/extra_filters.py23
-rw-r--r--askbot/templatetags/extra_filters_jinja.py31
-rw-r--r--askbot/templatetags/extra_tags.py16
-rw-r--r--askbot/templatetags/smart_if.py401
-rw-r--r--askbot/tests/__init__.py2
-rw-r--r--askbot/tests/badge_tests.py33
-rw-r--r--askbot/tests/db_api_tests.py229
-rw-r--r--askbot/tests/email_alert_tests.py92
-rw-r--r--askbot/tests/form_tests.py228
-rw-r--r--askbot/tests/page_load_tests.py93
-rw-r--r--askbot/tests/permission_assertion_tests.py147
-rw-r--r--askbot/tests/search_state_tests.py60
-rw-r--r--askbot/tests/skin_tests.py1
-rw-r--r--askbot/tests/utils.py30
-rw-r--r--askbot/urls.py61
-rw-r--r--askbot/utils/console.py13
-rw-r--r--askbot/utils/email.py13
-rw-r--r--askbot/utils/http.py45
-rw-r--r--askbot/utils/mail.py27
-rw-r--r--askbot/version.py0
-rw-r--r--askbot/views/__init__.py3
-rw-r--r--askbot/views/avatar_views.py186
-rw-r--r--askbot/views/commands.py207
-rw-r--r--askbot/views/meta.py51
-rw-r--r--askbot/views/readers.py203
-rw-r--r--askbot/views/users.py86
-rw-r--r--askbot/views/writers.py203
-rw-r--r--setup.py13
-rw-r--r--tox.ini4
493 files changed, 20370 insertions, 11516 deletions
diff --git a/MANIFEST.in b/MANIFEST.in
index 2cbc3a7c..05201977 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,4 +1,5 @@
include ez_setup.py
+include tox.ini
recursive-include askbot *
recursive-exclude askbot *.pyc
recursive-exclude .git
@@ -9,3 +10,8 @@ exclude settings.py
exclude manage.py
exclude __init__.py
exclude urls.py
+exclude askbot/upfiles/*.*
+recursive-exclude avatar *
+recursive-exclude adzone *
+recursive-exclude env
+recursive-exclude .tox
diff --git a/askbot/__init__.py b/askbot/__init__.py
index f06e4e61..8d907571 100644
--- a/askbot/__init__.py
+++ b/askbot/__init__.py
@@ -6,7 +6,17 @@ basic actions on behalf of the forum application
"""
import os
import smtplib
+import sys
import logging
+from askbot import patches
+from askbot.deployment.assertions import assert_package_compatibility
+
+VERSION = (0, 6, 76)
+
+#necessary for interoperability of django and coffin
+assert_package_compatibility()
+patches.patch_django()
+patches.patch_coffin()#must go after django
def get_install_directory():
"""returns path to directory
@@ -15,8 +25,9 @@ def get_install_directory():
"""
return os.path.dirname(__file__)
+
def get_version():
"""returns version of the askbot app
this version is meaningful for pypi only
"""
- return '0.6.51'
+ return '.'.join([str(subversion) for subversion in VERSION])
diff --git a/askbot/auth.py b/askbot/auth.py
index 7b4fac68..118810ca 100644
--- a/askbot/auth.py
+++ b/askbot/auth.py
@@ -8,39 +8,15 @@ Many of these functions are being replaced with assertions:
User.assert_can...
"""
import datetime
-from django.utils.translation import ugettext as _
from django.db import transaction
from askbot.models import Repute
-from askbot.models import Question
from askbot.models import Answer
from askbot.models import signals
-import logging
-
from askbot.conf import settings as askbot_settings
-# user preferences view permissions
-def is_user_self(request_user, target_user):
- return (request_user.is_authenticated() and request_user == target_user)
-
-def can_view_user_votes(request_user, target_user):
- return (request_user.is_authenticated() and request_user == target_user)
-
-def can_view_user_preferences(request_user, target_user):
- return (request_user.is_authenticated() and request_user == target_user)
-
-def can_view_user_edit(request_user, target_user):
- return (request_user.is_authenticated() and request_user == target_user)
-
###########################################
## actions and reputation changes event
###########################################
-def calculate_reputation(origin, offset):
- result = int(origin) + int(offset)
- if (result > 0):
- return result
- else:
- return 1
-
@transaction.commit_on_success
def onFlaggedItem(post, user, timestamp=None):
if timestamp is None:
@@ -49,10 +25,9 @@ def onFlaggedItem(post, user, timestamp=None):
post.offensive_flag_count = post.offensive_flag_count + 1
post.save()
- post.author.reputation = calculate_reputation(
- post.author.reputation,
- askbot_settings.REP_LOSS_FOR_RECEIVING_FLAG
- )
+ post.author.receive_reputation(
+ askbot_settings.REP_LOSS_FOR_RECEIVING_FLAG
+ )
post.author.save()
question = post.get_origin_post()
@@ -75,11 +50,9 @@ def onFlaggedItem(post, user, timestamp=None):
#todo: These should be updated to work on same revisions.
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.receive_reputation(
+ askbot_settings.REP_LOSS_FOR_RECEIVING_THREE_FLAGS_PER_REVISION
+ )
post.author.save()
@@ -95,11 +68,9 @@ def onFlaggedItem(post, user, timestamp=None):
reputation.save()
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.receive_reputation(
+ askbot_settings.REP_LOSS_FOR_RECEIVING_FIVE_FLAGS_PER_REVISION
+ )
post.author.save()
@@ -127,10 +98,9 @@ def onAnswerAccept(answer, user, timestamp=None):
answer.save()
answer.question.save()
- answer.author.reputation = calculate_reputation(
- answer.author.reputation,
- askbot_settings.REP_GAIN_FOR_RECEIVING_ANSWER_ACCEPTANCE
- )
+ answer.author.receive_reputation(
+ askbot_settings.REP_GAIN_FOR_RECEIVING_ANSWER_ACCEPTANCE
+ )
answer.author.save()
reputation = Repute(user=answer.author,
positive=askbot_settings.REP_GAIN_FOR_RECEIVING_ANSWER_ACCEPTANCE,
@@ -140,8 +110,7 @@ def onAnswerAccept(answer, user, timestamp=None):
reputation=answer.author.reputation)
reputation.save()
- user.reputation = calculate_reputation(user.reputation,
- askbot_settings.REP_GAIN_FOR_ACCEPTING_ANSWER)
+ user.receive_reputation(askbot_settings.REP_GAIN_FOR_ACCEPTING_ANSWER)
user.save()
reputation = Repute(user=user,
positive=askbot_settings.REP_GAIN_FOR_ACCEPTING_ANSWER,
@@ -161,8 +130,7 @@ def onAnswerAcceptCanceled(answer, user, timestamp=None):
answer.save()
answer.question.save()
- answer.author.reputation = calculate_reputation(
- answer.author.reputation,
+ answer.author.receive_reputation(
askbot_settings.REP_LOSS_FOR_RECEIVING_CANCELATION_OF_ANSWER_ACCEPTANCE
)
answer.author.save()
@@ -177,8 +145,9 @@ def onAnswerAcceptCanceled(answer, user, timestamp=None):
)
reputation.save()
- user.reputation = calculate_reputation(user.reputation,
- askbot_settings.REP_LOSS_FOR_CANCELING_ANSWER_ACCEPTANCE)
+ user.receive_reputation(
+ askbot_settings.REP_LOSS_FOR_CANCELING_ANSWER_ACCEPTANCE
+ )
user.save()
reputation = Repute(user=user,
negative=askbot_settings.REP_LOSS_FOR_CANCELING_ANSWER_ACCEPTANCE,
@@ -198,12 +167,13 @@ def onUpVoted(vote, post, user, timestamp=None):
post.score = int(post.score) + 1
post.save()
- if not post.wiki:
+ if not (post.wiki or post.is_anonymous):
author = post.author
todays_rep_gain = Repute.objects.get_reputation_by_upvoted_today(author)
if todays_rep_gain < askbot_settings.MAX_REP_GAIN_PER_USER_PER_DAY:
- author.reputation = calculate_reputation(author.reputation,
- askbot_settings.REP_GAIN_FOR_RECEIVING_UPVOTE)
+ author.receive_reputation(
+ askbot_settings.REP_GAIN_FOR_RECEIVING_UPVOTE
+ )
author.save()
question = post
@@ -230,13 +200,11 @@ def onUpVotedCanceled(vote, post, user, timestamp=None):
post.score = int(post.score) - 1
post.save()
- if not post.wiki:
+ if not (post.wiki or post.is_anonymous):
author = post.author
- author.reputation = \
- calculate_reputation(
- author.reputation,
- askbot_settings.REP_LOSS_FOR_RECEIVING_UPVOTE_CANCELATION
- )
+ author.receive_reputation(
+ askbot_settings.REP_LOSS_FOR_RECEIVING_UPVOTE_CANCELATION
+ )
author.save()
question = post
@@ -263,12 +231,9 @@ def onDownVoted(vote, post, user, timestamp=None):
post.score = int(post.score) - 1
post.save()
- if not post.wiki:
+ if not (post.wiki or post.is_anonymous):
author = post.author
- author.reputation = calculate_reputation(
- author.reputation,
- askbot_settings.REP_LOSS_FOR_DOWNVOTING
- )
+ author.receive_reputation(askbot_settings.REP_LOSS_FOR_DOWNVOTING)
author.save()
question = post
@@ -283,10 +248,9 @@ def onDownVoted(vote, post, user, timestamp=None):
reputation=author.reputation)
reputation.save()
- user.reputation = calculate_reputation(
- user.reputation,
- askbot_settings.REP_LOSS_FOR_RECEIVING_DOWNVOTE
- )
+ user.receive_reputation(
+ askbot_settings.REP_LOSS_FOR_RECEIVING_DOWNVOTE
+ )
user.save()
reputation = Repute(user=user,
@@ -309,12 +273,11 @@ def onDownVotedCanceled(vote, post, user, timestamp=None):
post.score = post.score + 1
post.save()
- if not post.wiki:
+ if not (post.wiki or post.is_anonymous):
author = post.author
- author.reputation = calculate_reputation(
- author.reputation,
- askbot_settings.REP_GAIN_FOR_RECEIVING_DOWNVOTE_CANCELATION
- )
+ author.receive_reputation(
+ askbot_settings.REP_GAIN_FOR_RECEIVING_DOWNVOTE_CANCELATION
+ )
author.save()
question = post
@@ -331,8 +294,7 @@ def onDownVotedCanceled(vote, post, user, timestamp=None):
)
reputation.save()
- user.reputation = calculate_reputation(user.reputation,
- askbot_settings.REP_GAIN_FOR_CANCELING_DOWNVOTE)
+ user.receive_reputation(askbot_settings.REP_GAIN_FOR_CANCELING_DOWNVOTE)
user.save()
reputation = Repute(user=user,
diff --git a/askbot/conf/__init__.py b/askbot/conf/__init__.py
index 29a967c9..05818b44 100644
--- a/askbot/conf/__init__.py
+++ b/askbot/conf/__init__.py
@@ -13,6 +13,7 @@ import askbot.conf.user_settings
import askbot.conf.markup
import askbot.conf.social_sharing
import askbot.conf.badges
+import askbot.conf.login_providers
#import main settings object
from askbot.conf.settings_wrapper import settings
diff --git a/askbot/conf/badges.py b/askbot/conf/badges.py
index 778be54b..b113af2e 100644
--- a/askbot/conf/badges.py
+++ b/askbot/conf/badges.py
@@ -201,3 +201,30 @@ settings.register(
description=_('Stellar Question: minimum stars')
)
)
+
+settings.register(
+ IntegerValue(
+ BADGES,
+ 'COMMENTATOR_BADGE_MIN_COMMENTS',
+ default=10,
+ description=_('Commentator: minimum comments')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ BADGES,
+ 'TAXONOMIST_BADGE_MIN_USE_COUNT',
+ default = 10,
+ description = _('Taxonomist: minimum tag use count')
+ )
+)
+
+settings.register(
+ IntegerValue(
+ BADGES,
+ 'ENTHUSIAST_BADGE_MIN_DAYS',
+ default = 30,
+ description = _('Enthusiast: minimum days')
+ )
+)
diff --git a/askbot/conf/email.py b/askbot/conf/email.py
index 77407d70..f18a554d 100644
--- a/askbot/conf/email.py
+++ b/askbot/conf/email.py
@@ -2,18 +2,34 @@
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.deps import livesettings
from askbot import const
+from django.utils.translation import ugettext as _
+from django.conf import settings as django_settings
+
+EMAIL_SUBJECT_PREFIX = getattr(django_settings, 'EMAIL_SUBJECT_PREFIX', '')
-EMAIL = ConfigurationGroup(
+EMAIL = livesettings.ConfigurationGroup(
'EMAIL',
_('Email and email alert settings'),
)
settings.register(
- IntegerValue(
+ livesettings.StringValue(
+ EMAIL,
+ 'EMAIL_SUBJECT_PREFIX',
+ default = EMAIL_SUBJECT_PREFIX,
+ description = _('Prefix for the email subject line'),
+ help_text = _(
+ 'This setting takes default from the django setting'
+ 'EMAIL_SUBJECT_PREFIX. A value entered here will override'
+ 'the default.'
+ )
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
EMAIL,
'MAX_ALERTS_PER_EMAIL',
default=7,
@@ -22,7 +38,7 @@ settings.register(
)
settings.register(
- StringValue(
+ livesettings.StringValue(
EMAIL,
'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE',
default='w',
@@ -39,7 +55,7 @@ settings.register(
)
settings.register(
- BooleanValue(
+ livesettings.BooleanValue(
EMAIL,
'EMAIL_VALIDATION',
default=False,
@@ -50,7 +66,7 @@ settings.register(
)
settings.register(
- BooleanValue(
+ livesettings.BooleanValue(
EMAIL,
'EMAIL_UNIQUE',
default=True,
@@ -59,7 +75,7 @@ settings.register(
)
settings.register(
- StringValue(
+ livesettings.StringValue(
EMAIL,
'ANONYMOUS_USER_EMAIL',
default='anonymous@askbot.org',
@@ -69,10 +85,27 @@ settings.register(
)
settings.register(
- StringValue(
+ livesettings.BooleanValue(
EMAIL,
- 'EMAIL_SUBJECT_PREFIX',
- default='',
- description=_('Prefix for the email subject line'),
+ 'ALLOW_ASKING_BY_EMAIL',
+ default = False,
+ description=_('Allow posting questions by email'),
+ help_text=_(
+ 'Before enabling this setting - please fill out IMAP settings '
+ 'in the settings.py file'
+ )
+ )
+)
+
+settings.register(
+ livesettings.BooleanValue(
+ EMAIL,
+ 'REPLACE_SPACE_WITH_DASH_IN_EMAILED_TAGS',
+ default = True,
+ description = _('Replace space in emailed tags with dash'),
+ help_text = _(
+ 'This setting applies to tags written in the subject line '
+ 'of questions asked by email'
+ )
)
)
diff --git a/askbot/conf/forum_data_rules.py b/askbot/conf/forum_data_rules.py
index ff2a7310..bf38393e 100644
--- a/askbot/conf/forum_data_rules.py
+++ b/askbot/conf/forum_data_rules.py
@@ -2,18 +2,17 @@
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 askbot.deps import livesettings
from django.utils.translation import ugettext as _
from askbot import const
-FORUM_DATA_RULES = ConfigurationGroup(
+FORUM_DATA_RULES = livesettings.ConfigurationGroup(
'FORUM_DATA_RULES',
_('Settings for askbot data entry and display')
)
settings.register(
- BooleanValue(
+ livesettings.BooleanValue(
FORUM_DATA_RULES,
'WIKI_ON',
default=True,
@@ -22,7 +21,21 @@ settings.register(
)
settings.register(
- IntegerValue(
+ livesettings.BooleanValue(
+ FORUM_DATA_RULES,
+ 'ALLOW_ASK_ANONYMOUSLY',
+ default=True,
+ description=_('Allow asking questions anonymously'),
+ help_text=_(
+ 'Users do not accrue reputation for anonymous questions '
+ 'and their identity is not revealed until they change their '
+ 'mind'
+ )
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
FORUM_DATA_RULES,
'MAX_TAG_LENGTH',
default=20,
@@ -31,7 +44,36 @@ settings.register(
)
settings.register(
- IntegerValue(
+ livesettings.BooleanValue(
+ FORUM_DATA_RULES,
+ 'FORCE_LOWERCASE_TAGS',
+ default = False,
+ description = _('Force lowercase the tags'),
+ help_text = _(
+ 'Attention: after checking this, please back up the database, '
+ 'and run a management command: '
+ '<code>python manage.py fix_question_tags</code> to globally '
+ 'rename the tags'
+ )
+ )
+)
+
+settings.register(
+ livesettings.BooleanValue(
+ FORUM_DATA_RULES,
+ 'USE_WILDCARD_TAGS',
+ default = False,
+ description = _('Use wildcard tags'),
+ help_text = _(
+ 'Wildcard tags can be used to follow or ignore '
+ 'many tags at once, a valid wildcard tag has a single '
+ 'wildcard at the very end'
+ )
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
FORUM_DATA_RULES,
'MAX_COMMENTS_TO_SHOW',
default=5,
@@ -42,7 +84,7 @@ settings.register(
)
settings.register(
- IntegerValue(
+ livesettings.IntegerValue(
FORUM_DATA_RULES,
'MAX_COMMENT_LENGTH',
default=300,
@@ -53,7 +95,39 @@ settings.register(
)
settings.register(
- IntegerValue(
+ livesettings.BooleanValue(
+ FORUM_DATA_RULES,
+ 'USE_TIME_LIMIT_TO_EDIT_COMMENT',
+ default = True,
+ description = _('Limit time to edit comments'),
+ help_text = _(
+ 'If unchecked, there will be no time '
+ 'limit to edit the comments'
+ )
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ FORUM_DATA_RULES,
+ 'MINUTES_TO_EDIT_COMMENT',
+ default = 10,
+ description = _('Minutes allowed to edit a comment'),
+ help_text = _('To enable this setting, check the previous one')
+ )
+)
+
+settings.register(
+ livesettings.BooleanValue(
+ FORUM_DATA_RULES,
+ 'SAVE_COMMENT_ON_ENTER',
+ default = True,
+ description = _('Save comment by pressing <Enter> key')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
FORUM_DATA_RULES,
'MIN_SEARCH_WORD_LENGTH',
default=4,
@@ -63,7 +137,22 @@ settings.register(
)
settings.register(
- IntegerValue(
+ livesettings.BooleanValue(
+ FORUM_DATA_RULES,
+ 'DECOUPLE_TEXT_QUERY_FROM_SEARCH_STATE',
+ default=False,
+ description=_('Do not make text query sticky in search'),
+ help_text=_(
+ 'Check to disable the "sticky" behavior of the search query. '
+ 'This may be useful if you want to move the search bar away '
+ 'from the default position or do not like the default '
+ 'sticky behavior of the text search query.'
+ )
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
FORUM_DATA_RULES,
'MAX_TAGS_PER_POST',
default=5,
@@ -74,7 +163,7 @@ settings.register(
#todo: looks like there is a bug in askbot.deps.livesettings
#that does not allow Integer values with defaults and choices
settings.register(
- StringValue(
+ livesettings.StringValue(
FORUM_DATA_RULES,
'DEFAULT_QUESTIONS_PAGE_SIZE',
choices=const.PAGE_SIZE_CHOICES,
@@ -84,7 +173,7 @@ settings.register(
)
settings.register(
- StringValue(
+ livesettings.StringValue(
FORUM_DATA_RULES,
'UNANSWERED_QUESTION_MEANING',
choices=const.UNANSWERED_QUESTION_MEANING_CHOICES,
diff --git a/askbot/conf/login_providers.py b/askbot/conf/login_providers.py
new file mode 100644
index 00000000..132562d5
--- /dev/null
+++ b/askbot/conf/login_providers.py
@@ -0,0 +1,72 @@
+"""
+External service key settings
+"""
+from askbot.conf.settings_wrapper import settings
+from askbot.deps import livesettings
+from django.utils.translation import ugettext as _
+from django.conf import settings as django_settings
+
+LOGIN_PROVIDERS = livesettings.ConfigurationGroup(
+ 'LOGIN_PROVIDERS',
+ _('Login provider setings')
+ )
+
+settings.register(
+ livesettings.BooleanValue(
+ LOGIN_PROVIDERS,
+ 'PASSWORD_REGISTER_SHOW_PROVIDER_BUTTONS',
+ default = True,
+ description=_('Show alternative login provider buttons on the password "Sign Up" page'),
+ )
+)
+
+settings.register(
+ livesettings.BooleanValue(
+ LOGIN_PROVIDERS,
+ 'SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN',
+ default = False,
+ description=_('Always display local login form and hide "Askbot" button.'),
+ )
+)
+
+providers = (
+ 'local',
+ 'AOL',
+ 'Blogger',
+ 'ClaimID',
+ 'Facebook',
+ 'Flickr',
+ 'Google',
+ 'Twitter',
+ 'LinkedIn',
+ 'LiveJournal',
+ 'OpenID',
+ 'Technorati',
+ 'Wordpress',
+ 'Vidoop',
+ 'Verisign',
+ 'Yahoo',
+)
+
+need_extra_setup = ('Twitter', 'Facebook', 'LinkedIn')
+
+for provider in providers:
+ kwargs = {
+ 'description': _('Activate %(provider)s login') % {'provider': provider},
+ 'default': True,
+ }
+ if provider in need_extra_setup:
+ kwargs['help_text'] = _(
+ 'Note: to really enable %(provider)s login '
+ 'some additional parameters will need to be set '
+ 'in the "External keys" section'
+ ) % {'provider': provider}
+
+ setting_name = 'SIGNIN_%s_ENABLED' % provider.upper()
+ settings.register(
+ livesettings.BooleanValue(
+ LOGIN_PROVIDERS,
+ setting_name,
+ **kwargs
+ )
+ )
diff --git a/askbot/conf/markup.py b/askbot/conf/markup.py
index 23a2dc67..026c5536 100644
--- a/askbot/conf/markup.py
+++ b/askbot/conf/markup.py
@@ -15,13 +15,6 @@ MARKUP = ConfigurationGroup(
_('Markup formatting')
)
-mathjax_dir = os.path.join(
- askbot.get_install_directory(),
- 'skins',
- 'common',
- 'media'
- )
-
settings.register(
BooleanValue(
MARKUP,
@@ -47,10 +40,9 @@ settings.register(
help_text=_(
'If you enable this feature, '
'<a href="%(url)s">mathjax</a> must be '
- 'installed in directory %(dir)s'
+ 'installed on your server in its own directory.'
) % {
'url': const.DEPENDENCY_URLS['mathjax'],
- 'dir': mathjax_dir,
},
default = False
)
diff --git a/askbot/conf/minimum_reputation.py b/askbot/conf/minimum_reputation.py
index bb8d7754..6b00766e 100644
--- a/askbot/conf/minimum_reputation.py
+++ b/askbot/conf/minimum_reputation.py
@@ -3,146 +3,160 @@ 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 askbot.deps import livesettings
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_DELETE_OTHERS_POSTS',
- default=5000,
- description=_('Delete questions and answers 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_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')
- )
- )
+MIN_REP = livesettings.ConfigurationGroup(
+ 'MIN_REP',
+ _('Minimum reputation required to perform actions'),
+ ordering=0
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_VOTE_UP',
+ default=15,
+ description=_('Upvote')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_VOTE_DOWN',
+ default=100,
+ description=_('Downvote')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_FLAG_OFFENSIVE',
+ default=15,
+ description=_('Flag offensive')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_LEAVE_COMMENTS',
+ default=50,
+ description=_('Leave comments')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_DELETE_OTHERS_COMMENTS',
+ default=2000,
+ description=_('Delete comments posted by others')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_DELETE_OTHERS_POSTS',
+ default=5000,
+ description=_('Delete questions and answers posted by others')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_UPLOAD_FILES',
+ default=60,
+ description=_('Upload files')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_CLOSE_OWN_QUESTIONS',
+ default=250,
+ description=_('Close own questions'),
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_RETAG_OTHERS_QUESTIONS',
+ default=500,
+ description=_('Retag questions posted by other people')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_REOPEN_OWN_QUESTIONS',
+ default=500,
+ description=_('Reopen own questions')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_EDIT_WIKI',
+ default=750,
+ description=_('Edit community wiki posts')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_EDIT_OTHERS_POSTS',
+ default=2000,
+ description=_('Edit posts authored by other people')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_VIEW_OFFENSIVE_FLAGS',
+ default=2000,
+ description=_('View offensive flags')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_CLOSE_OTHERS_QUESTIONS',
+ default=2000,
+ description=_('Close questions asked by others')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_LOCK_POSTS',
+ default=4000,
+ description=_('Lock posts')
+ )
+)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_HAVE_STRONG_URL',
+ default=250,
+ description=_('Remove rel=nofollow from own homepage'),
+ help_text=_(
+ 'When a search engine crawler will see a rel=nofollow '
+ 'attribute on a link - the link will not count towards '
+ 'the rank of the users personal site.'
+ )
+ )
+)
diff --git a/askbot/conf/user_settings.py b/askbot/conf/user_settings.py
index 9add71b1..142a5b16 100644
--- a/askbot/conf/user_settings.py
+++ b/askbot/conf/user_settings.py
@@ -2,16 +2,16 @@
User policy settings
"""
from askbot.conf.settings_wrapper import settings
-from askbot.deps.livesettings import ConfigurationGroup, BooleanValue, IntegerValue
+from askbot.deps import livesettings
from django.utils.translation import ugettext as _
-USER_SETTINGS = ConfigurationGroup(
+USER_SETTINGS = livesettings.ConfigurationGroup(
'USER_SETTINGS',
_('User policy settings')
)
settings.register(
- BooleanValue(
+ livesettings.BooleanValue(
USER_SETTINGS,
'EDITABLE_SCREEN_NAME',
default=True,
@@ -20,7 +20,7 @@ settings.register(
)
settings.register(
- IntegerValue(
+ livesettings.IntegerValue(
USER_SETTINGS,
'MIN_USERNAME_LENGTH',
hidden=True,
@@ -28,3 +28,12 @@ settings.register(
description=_('Minimum allowed length for screen name')
)
)
+
+settings.register(
+ livesettings.StringValue(
+ USER_SETTINGS,
+ 'NAME_OF_ANONYMOUS_USER',
+ default = '',
+ description = _('Name for the Anonymous user')
+ )
+)
diff --git a/askbot/const/__init__.py b/askbot/const/__init__.py
index 693a7328..5a0781f0 100644
--- a/askbot/const/__init__.py
+++ b/askbot/const/__init__.py
@@ -84,6 +84,7 @@ UNANSWERED_QUESTION_MEANING_CHOICES = (
TAG_CHARS = '\w\+\.\-#'
TAG_REGEX = r'^[%s]+$' % TAG_CHARS
TAG_SPLIT_REGEX = r'[ ,]+'
+EMAIL_REGEX = re.compile(r'\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b', re.I)
TYPE_ACTIVITY_ASK_QUESTION=1
TYPE_ACTIVITY_ANSWER=2
@@ -191,10 +192,14 @@ POST_STATUS = {
'retagged' : _('retagged'),
}
-#how to filter questions by tags in email digests?
-TAG_EMAIL_FILTER_CHOICES = (
- ('ignored', _('exclude ignored tags')),
- ('interesting',_('allow only selected tags'))
+#choices used in email and display filters
+INCLUDE_ALL = 0
+EXCLUDE_IGNORED = 1
+INCLUDE_INTERESTING = 2
+TAG_FILTER_STRATEGY_CHOICES = (
+ (INCLUDE_ALL, _('off')),
+ (EXCLUDE_IGNORED, _('exclude ignored')),
+ (INCLUDE_INTERESTING, _('only selected')),
)
NOTIFICATION_DELIVERY_SCHEDULE_CHOICES= (
@@ -249,6 +254,8 @@ BADGE_CSS_CLASSES = {
}
BADGE_DISPLAY_SYMBOL = '&#9679;'
+MIN_REPUTATION = 1
+
#an exception import * because that file has only strings
from askbot.const.message_keys import *
diff --git a/askbot/context.py b/askbot/context.py
index 47930aef..f3419abd 100644
--- a/askbot/context.py
+++ b/askbot/context.py
@@ -1,14 +1,22 @@
+"""Askbot template context processor that makes some parameters
+from the django settings, all parameters from the askbot livesettings
+and the application available for the templates
+"""
from django.conf import settings
-from askbot.conf import settings as askbot_settings
+import askbot
from askbot import api
-import datetime
+from askbot.conf import settings as askbot_settings
+from askbot.skins.loaders import get_skin
def application_settings(request):
+ """The context processor function"""
my_settings = askbot_settings.as_dict()
my_settings['LANGUAGE_CODE'] = settings.LANGUAGE_CODE
my_settings['ASKBOT_URL'] = settings.ASKBOT_URL
my_settings['DEBUG'] = settings.DEBUG
+ my_settings['ASKBOT_VERSION'] = askbot.get_version()
return {
'settings': my_settings,
+ 'skin': get_skin(request),
'moderation_items': api.get_info_on_moderation_items(request.user)
}
diff --git a/askbot/deployment/assertions.py b/askbot/deployment/assertions.py
new file mode 100644
index 00000000..0db62b84
--- /dev/null
+++ b/askbot/deployment/assertions.py
@@ -0,0 +1,26 @@
+"""assertions regarding deployment of askbot
+todo: move here stuff from startup_procedures.py
+
+the reason - some assertions need to be run in askbot/__init__
+as opposed to startup_procedures.py - which are executed in the
+beginning of the models module
+"""
+from askbot.deployment import package_utils
+from askbot.exceptions import DeploymentError
+
+def assert_package_compatibility():
+ """raises an exception if any known incompatibilities
+ are found
+ """
+ (django_major, django_minor, django_micro) = package_utils.get_django_version()
+ if django_major < 1:
+ raise DeploymentError('Django version < 1.0 is not supported by askbot')
+
+ coffin_version = package_utils.get_coffin_version()
+ if coffin_version == (0, 3, 0) and django_major == 1 and django_minor > 1:
+ raise DeploymentError(
+ 'Coffin package version 0.3 is not compatible '
+ 'with the current version of Django, please upgrade '
+ 'coffin to at least 0.3.3'
+ )
+
diff --git a/askbot/deployment/package_utils.py b/askbot/deployment/package_utils.py
new file mode 100644
index 00000000..c2a9b65c
--- /dev/null
+++ b/askbot/deployment/package_utils.py
@@ -0,0 +1,28 @@
+"""utilities that determine versions of packages
+that are part of askbot
+
+versions of all packages are normalized to three-tuples
+of integers (missing zeroes added)
+"""
+import coffin
+import django
+
+def get_coffin_version():
+ """Returns version of Coffin package
+ as a three integer value tuple
+ """
+ version = coffin.__version__
+ if len(version) == 2:
+ micro_version = 0
+ elif len(version) == 3:
+ micro_version = version[2]
+ else:
+ raise ValueError('unsupported version of coffin %s' % '.'.join(version))
+ major_version = version[0]
+ minor_version = version[1]
+ return (major_version, minor_version, micro_version)
+
+def get_django_version():
+ """returns three-tuple for the version
+ of django"""
+ return django.VERSION[:3]
diff --git a/askbot/deps/django_authopenid/backends.py b/askbot/deps/django_authopenid/backends.py
index 4432246f..cac1ce02 100644
--- a/askbot/deps/django_authopenid/backends.py
+++ b/askbot/deps/django_authopenid/backends.py
@@ -2,7 +2,6 @@
multiple login methods supported by the authenticator
application
"""
-import logging
import datetime
from django.contrib.auth.models import User
from django.core.exceptions import ImproperlyConfigured
diff --git a/askbot/deps/django_authopenid/forms.py b/askbot/deps/django_authopenid/forms.py
index d8e03137..30674eb6 100644
--- a/askbot/deps/django_authopenid/forms.py
+++ b/askbot/deps/django_authopenid/forms.py
@@ -29,13 +29,9 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import types
-import re
import logging
from django import forms
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
@@ -50,9 +46,7 @@ try:
except ImportError:
from yadis import xri
-from askbot.utils.forms import clean_next
from askbot.deps.django_authopenid import util
-from askbot.deps.django_authopenid.models import ExternalLoginData
__all__ = [
'OpenidSigninForm','OpenidRegisterForm',
@@ -413,6 +407,7 @@ class ChangeopenidForm(forms.Form):
class DeleteForm(forms.Form):
""" confirm form to delete an account """
+ #todo: i think this form is not used
confirm = forms.CharField(widget=forms.CheckboxInput(attrs={'class':'required'}))
password = forms.CharField(widget=forms.PasswordInput(attrs={'class':'required'}))
diff --git a/askbot/deps/django_authopenid/middleware.py b/askbot/deps/django_authopenid/middleware.py
index 2101813c..483dee6f 100644
--- a/askbot/deps/django_authopenid/middleware.py
+++ b/askbot/deps/django_authopenid/middleware.py
@@ -2,7 +2,6 @@
from askbot.deps.django_authopenid import mimeparse
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
-from django.conf import settings
import logging
__all__ = ["OpenIDMiddleware"]
diff --git a/askbot/deps/django_authopenid/migrations/0005_auto__del_externallogindata.py b/askbot/deps/django_authopenid/migrations/0005_auto__del_externallogindata.py
new file mode 100644
index 00000000..ef4d0fa4
--- /dev/null
+++ b/askbot/deps/django_authopenid/migrations/0005_auto__del_externallogindata.py
@@ -0,0 +1,118 @@
+# 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):
+
+ # Deleting model 'ExternalLoginData'
+ db.delete_table('django_authopenid_externallogindata')
+
+
+ def backwards(self, orm):
+
+ # Adding model 'ExternalLoginData'
+ db.create_table('django_authopenid_externallogindata', (
+ ('external_username', self.gf('django.db.models.fields.CharField')(max_length=40, unique=True)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('external_session_data', self.gf('django.db.models.fields.TextField')()),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True)),
+ ))
+ db.send_create_signal('django_authopenid', ['ExternalLoginData'])
+
+
+ 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'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'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_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'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ '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'})
+ },
+ 'django_authopenid.association': {
+ 'Meta': {'object_name': 'Association'},
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
+ },
+ 'django_authopenid.nonce': {
+ 'Meta': {'object_name': 'Nonce'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'server_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'django_authopenid.userassociation': {
+ 'Meta': {'unique_together': "(('user', 'provider_name'), ('openid_url', 'provider_name'))", 'object_name': 'UserAssociation'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_used_timestamp': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'openid_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'provider_name': ('django.db.models.fields.CharField', [], {'default': "'unknown'", 'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'django_authopenid.userpasswordqueue': {
+ 'Meta': {'object_name': 'UserPasswordQueue'},
+ 'confirm_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'new_password': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
+ }
+ }
+
+ complete_apps = ['django_authopenid']
diff --git a/askbot/deps/django_authopenid/models.py b/askbot/deps/django_authopenid/models.py
index 8a1fa118..31ec36f9 100644
--- a/askbot/deps/django_authopenid/models.py
+++ b/askbot/deps/django_authopenid/models.py
@@ -82,12 +82,3 @@ class UserPasswordQueue(models.Model):
def __unicode__(self):
return self.user.username
-
-class ExternalLoginData(models.Model):
- """this class was added by Evgeny to associate
- external authentication user with django user
- probably it just does not belong here... (EF)
- """
- external_username = models.CharField(max_length=40, unique=True, null=False)
- external_session_data = models.TextField()
- user = models.ForeignKey(User, null=True)
diff --git a/askbot/deps/django_authopenid/urls.py b/askbot/deps/django_authopenid/urls.py
index 3ed2eaa3..c0846c18 100644
--- a/askbot/deps/django_authopenid/urls.py
+++ b/askbot/deps/django_authopenid/urls.py
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from django.conf.urls.defaults import patterns, url
from django.utils.translation import ugettext as _
-from django.conf import settings
urlpatterns = patterns('askbot.deps.django_authopenid.views',
# yadis rdf
diff --git a/askbot/deps/django_authopenid/util.py b/askbot/deps/django_authopenid/util.py
index 67d3ba43..a913400f 100644
--- a/askbot/deps/django_authopenid/util.py
+++ b/askbot/deps/django_authopenid/util.py
@@ -9,7 +9,6 @@ import oauth2 as oauth
from django.db.models.query import Q
from django.conf import settings
-from django.core.urlresolvers import reverse
from django.utils.datastructures import SortedDict
from django.utils.translation import ugettext as _
from django.core.exceptions import ImproperlyConfigured
@@ -28,8 +27,6 @@ except:
from yadis import xri
import time, base64, hashlib, operator, logging
-from askbot.utils.forms import clean_next, get_next_url
-
from models import Association, Nonce
__all__ = ['OpenID', 'DjangoOpenIDStore', 'from_openid_response', 'clean_next']
@@ -171,23 +168,44 @@ def use_password_login():
return True
def get_major_login_providers():
- """returns a tuple with data about login providers
+ """returns a dictionary with data about login providers
whose icons are to be shown in large format
- items of tuple are dictionaries with keys:
+ items of the dictionary are dictionaries with keys:
* name
* display_name
* icon_media_path (relative to /media directory)
* type (oauth|openid-direct|openid-generic|openid-username|password)
- Fields dependent on type:
+ Fields dependent on type of the login provider type
+ ---------------------------------------------------
+
+ Password (type = password) - login provider using login name and password:
+
+ * extra_token_name - a phrase describing what the login name and the
+ password are from
+ * create_password_prompt - a phrase prompting to create an account
+ * change_password_prompt - a phrase prompting to change password
+
+ OpenID (type = openid) - Provider of login using the OpenID protocol
* openid_endpoint (required for type=openid|openid-username)
for type openid-username - the string must have %(username)s
format variable, plain string url otherwise
* extra_token_name - required for type=openid-username
describes name of required extra token - e.g. "XYZ user name"
+
+ OAuth2 (type = oauth)
+
+ * request_token_url - url to initiate OAuth2 protocol with the resource
+ * access_token_url - url to access users data on the resource via OAuth2
+ * authorize_url - url at which user can authorize the app to access a resource
+ * authenticate_url - url to authenticate user (lower privilege than authorize)
+ * get_user_id_function - a function that returns user id from data dictionary
+ containing: response to the access token url & consumer_key
+ and consumer secret. The purpose of this function is to hide the differences
+ between the ways user id is accessed from the different OAuth providers
"""
data = SortedDict()
@@ -204,13 +222,13 @@ def get_major_login_providers():
'icon_media_path': askbot_settings.LOCAL_LOGIN_ICON,
}
- if askbot_settings.FACEBOOK_KEY and askbot_settings.FACEBOOK_SECRET:
- data['facebook'] = {
- 'name': 'facebook',
- 'display_name': 'Facebook',
- 'type': 'facebook',
- 'icon_media_path': '/jquery-openid/images/facebook.gif',
- }
+ #if askbot_settings.FACEBOOK_KEY and askbot_settings.FACEBOOK_SECRET:
+ # data['facebook'] = {
+ # 'name': 'facebook',
+ # 'display_name': 'Facebook',
+ # 'type': 'facebook',
+ # 'icon_media_path': '/jquery-openid/images/facebook.gif',
+ # }
if askbot_settings.TWITTER_KEY and askbot_settings.TWITTER_SECRET:
data['twitter'] = {
'name': 'twitter',
@@ -306,14 +324,6 @@ def get_minor_login_providers():
'icon_media_path': '/jquery-openid/images/flickr.png',
'openid_endpoint': 'http://flickr.com/%(username)s/'
}
- data['flickr'] = {
- 'name': 'flickr',
- 'display_name': 'Flickr',
- 'type': 'openid-username',
- 'extra_token_name': _('Flickr user name'),
- 'icon_media_path': '/jquery-openid/images/flickr.png',
- 'openid_endpoint': 'http://flickr.com/%(username)s/'
- }
data['technorati'] = {
'name': 'technorati',
'display_name': 'Technorati',
@@ -479,6 +489,8 @@ class OAuthConnection(object):
)
def start(self, callback_url = None):
+ """starts the OAuth protocol communication and
+ saves request token as :attr:`request_token`"""
if callback_url is None:
callback_url = self.callback_url
@@ -515,6 +527,9 @@ class OAuthConnection(object):
return self.request_token
def get_user_id(self, oauth_token = None, oauth_verifier = None):
+ """Returns user ID within the OAuth provider system,
+ based on ``oauth_token`` and ``oauth_verifier``
+ """
token = oauth.Token(
oauth_token['oauth_token'],
@@ -531,8 +546,7 @@ class OAuthConnection(object):
def get_auth_url(self, login_only = False):
"""returns OAuth redirect url.
- callback_url is the redirect that will be used by the
- provider server, if login_only is True, authentication
+ if ``login_only`` is True, authentication
endpoint will be used, if available, otherwise authorization
url (potentially granting full access to the server) will
be used.
diff --git a/askbot/deps/django_authopenid/views.py b/askbot/deps/django_authopenid/views.py
index 7eb853d7..411f18ef 100644
--- a/askbot/deps/django_authopenid/views.py
+++ b/askbot/deps/django_authopenid/views.py
@@ -31,9 +31,7 @@
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import datetime
-from django.utils import simplejson
-from django.http import HttpResponseRedirect, get_host, Http404, \
- HttpResponseServerError
+from django.http import HttpResponseRedirect, get_host, Http404
from django.http import HttpResponse
from django.template import RequestContext, Context
from django.conf import settings
@@ -45,12 +43,9 @@ from django.core.urlresolvers import reverse
from django.utils.encoding import smart_unicode
from django.utils.html import escape
from django.utils.translation import ugettext as _
-from django.utils.http import urlquote_plus
from django.utils.safestring import mark_safe
from django.core.mail import send_mail
-from django.views.defaults import server_error
-
-from askbot.skins.loaders import ENV
+from askbot.skins.loaders import render_into_skin, get_template
from askbot.deps.openid.consumer.consumer import Consumer, \
SUCCESS, CANCEL, FAILURE, SETUP_NEEDED
@@ -62,18 +57,16 @@ try:
except ImportError:
from yadis import xri
-import re
import urllib
-
from askbot import forms as askbot_forms
from askbot.deps.django_authopenid import util
from askbot.deps.django_authopenid import decorators
-from askbot.deps.django_authopenid.models import UserAssociation, UserPasswordQueue, ExternalLoginData
+from askbot.deps.django_authopenid.models import UserAssociation
from askbot.deps.django_authopenid import forms
from askbot.deps.django_authopenid.backends import AuthBackend
-from django import forms as django_forms
import logging
from askbot.utils.forms import get_next_url
+from askbot.utils.http import get_request_info
#todo: decouple from askbot
def login(request,user):
@@ -96,7 +89,12 @@ def login(request,user):
#5) send signal with old session key as argument
logging.debug('logged in user %s with session key %s' % (user.username, session_key))
#todo: move to auth app
- signals.user_logged_in.send(user=user,session_key=session_key,sender=None)
+ signals.user_logged_in.send(
+ request = request,
+ user = user,
+ session_key=session_key,
+ sender=None
+ )
#todo: uncouple this from askbot
def logout(request):
@@ -319,6 +317,8 @@ def signin(
login_provider_name = ldap_provider_name,
redirect_url = next_url
)
+ else:
+ login_form.set_password_login_error()
else:
if password_action == 'login':
user = authenticate(
@@ -556,9 +556,7 @@ def show_signin_view(
data['major_login_providers'] = major_login_providers.values()
data['minor_login_providers'] = minor_login_providers.values()
- template = ENV.get_template('authopenid/signin.html')
- context = RequestContext(request, data)
- return HttpResponse(template.render(context))
+ return render_into_skin('authopenid/signin.html', data, request)
@login_required
def delete_login_method(request):
@@ -815,7 +813,6 @@ def register(request, login_provider_name=None, user_identifier=None):
provider_logo = providers[login_provider_name]
logging.debug('printing authopenid/complete.html output')
- template = ENV.get_template('authopenid/complete.html')
data = {
'openid_register_form': register_form,
'email_feeds_form': email_feeds_form,
@@ -825,8 +822,7 @@ def register(request, login_provider_name=None, user_identifier=None):
'login_type':'openid',
'gravatar_faq_url':reverse('faq') + '#gravatar',
}
- context = RequestContext(request, data)
- return HttpResponse(template.render(context))
+ return render_into_skin('authopenid/complete.html', data, request)
def signin_failure(request, message):
"""
@@ -841,8 +837,10 @@ def signup_with_password(request):
"""Create a password-protected account
template: authopenid/signup_with_password.html
"""
-
+
+ logging.debug(get_request_info(request))
next = get_next_url(request)
+ login_form = forms.LoginForm(initial = {'next': next})
#this is safe because second decorator cleans this field
provider_name = request.REQUEST['login_provider']
@@ -895,7 +893,7 @@ def signup_with_password(request):
# send email
#subject = _("Welcome email subject line")
- #message_template = ENV.get_template(
+ #message_template = get_emplate(
# 'authopenid/confirm_email.txt'
#)
#message_context = Context({
@@ -922,13 +920,22 @@ def signup_with_password(request):
)
email_feeds_form = askbot_forms.SimpleEmailSubscribeForm()
logging.debug('printing legacy signup form')
+
+ major_login_providers = util.get_major_login_providers()
+ minor_login_providers = util.get_minor_login_providers()
context_data = {
'form': form,
- 'email_feeds_form': email_feeds_form
+ 'page_class': 'openid-signin',
+ 'email_feeds_form': email_feeds_form,
+ 'major_login_providers': major_login_providers.values(),
+ 'minor_login_providers': minor_login_providers.values(),
+ 'login_form': login_form
}
- template = ENV.get_template('authopenid/signup_with_password.html')
- context = RequestContext(request, context_data)
- return HttpResponse(template.render(context))
+ return render_into_skin(
+ 'authopenid/signup_with_password.html',
+ context_data,
+ request
+ )
#what if request is not posted?
@login_required
@@ -995,16 +1002,16 @@ def _send_email_key(user):
"""private function. sends email containing validation key
to user's email address
"""
- subject = _("Email verification subject line")
- message_template = ENV.get_template('authopenid/email_validation.txt')
- import settings
- message_context = Context({
- 'validation_link': askbot_settings.APP_URL + reverse(
- 'user_account_recover',
- kwargs={'key':user.email_key}
- )
- })
- message = message_template.render(message_context)
+ subject = _("Recover your %(site)s account") % {'site': askbot_settings.APP_SHORT_NAME}
+ data = {
+ 'validation_link': askbot_settings.APP_URL + \
+ reverse(
+ 'user_account_recover',
+ kwargs={'key':user.email_key}
+ )
+ }
+ template = get_template('authopenid/email_validation.txt')
+ message = template.render(data)
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email])
def send_new_email_key(user,nomessage=False):
@@ -1030,14 +1037,16 @@ def send_email_key(request):
"""
if askbot_settings.EMAIL_VALIDATION == True:
if request.user.email_isvalid:
- template = ENV.get_template('authopenid/changeemail.html')
data = {
'email': request.user.email,
'action_type': 'key_not_sent',
'change_link': reverse('user_changeemail')
}
- context = RequestContext(request, data)
- return HttpResponse(template.render(context))
+ return render_into_skin(
+ 'authopenid/changeemail.html',
+ data,
+ request
+ )
else:
send_new_email_key(request.user)
return validation_email_sent(request)
@@ -1080,7 +1089,7 @@ def account_recover(request, key = None):
if user:
if request.user.is_authenticated():
if user != request.user:
- logout(request.user)
+ logout(request)
login(request, user)
else:
login(request, user)
@@ -1100,14 +1109,12 @@ def validation_email_sent(request):
set to True bolean value, basically dead now"""
assert(askbot_settings.EMAIL_VALIDATION == True)
logging.debug('')
- template = ENV.get_template('authopenid/changeemail.html')
data = {
'email': request.user.email,
'change_email_url': reverse('user_changeemail'),
'action_type': 'validate'
}
- context = RequestContext(request, data)
- return HttpResponse(template.render(context))
+ return render_into_skin('authopenid/changeemail.html', data, request)
def verifyemail(request,id=None,key=None):
"""
@@ -1122,10 +1129,12 @@ def verifyemail(request,id=None,key=None):
user.email_isvalid = True
clear_email_validation_message(user)
user.save()
- template = ENV.get_template('authopenid/changeemail.html')
data = {'action_type': 'validation_complete'}
- context = RequestContext(request, data)
- return HttpResponse(template.render(context))
+ return render_into_skin(
+ 'authopenid/changeemail.html',
+ data,
+ request
+ )
else:
logging.error('hmm, no user found for email validation message - foul play?')
raise Http404
diff --git a/askbot/deps/livesettings/overrides.py b/askbot/deps/livesettings/overrides.py
index 3d8404ef..f3dc3355 100644
--- a/askbot/deps/livesettings/overrides.py
+++ b/askbot/deps/livesettings/overrides.py
@@ -4,7 +4,6 @@ for settings retrieval.
from django.conf import settings as djangosettings
from django.contrib.sites.models import Site
-import logging
__all__ = ['get_overrides']
diff --git a/askbot/deps/livesettings/values.py b/askbot/deps/livesettings/values.py
index 5a9b2bf8..6d994410 100644
--- a/askbot/deps/livesettings/values.py
+++ b/askbot/deps/livesettings/values.py
@@ -17,7 +17,6 @@ from askbot.deps.livesettings.widgets import ImageInput
import datetime
import logging
import signals
-import tempfile
import os
__all__ = ['BASE_GROUP', 'ConfigurationGroup', 'Value', 'BooleanValue', 'DecimalValue', 'DurationValue',
diff --git a/askbot/doc/source/about.rst b/askbot/doc/source/about.rst
new file mode 100644
index 00000000..3dadec74
--- /dev/null
+++ b/askbot/doc/source/about.rst
@@ -0,0 +1,9 @@
+.. _about:
+========================
+Basic facts about Askbot
+========================
+
+* Askbot is Question and Answer (Q&A) forum.
+* Open source GPL3 license
+* Written in Python using Django framework
+
diff --git a/askbot/doc/source/askbot/layout.html b/askbot/doc/source/askbot/layout.html
new file mode 100644
index 00000000..251d8386
--- /dev/null
+++ b/askbot/doc/source/askbot/layout.html
@@ -0,0 +1,17 @@
+{% extends "basic/layout.html" %}
+{% block relbar1 %}
+<div class="ab-proj-header">
+ <ul>
+ <li class="first"><a href="/">Home (forum)</a>
+ <span class="sep">|</span>
+ </li>
+ {#<li><a href="/doc/about.html">About</a></li>
+ <span class="sep">|</span>#}
+ <li><a href="/doc/index.html">Documentation</a></li>
+ {#<span class="sep">|</span>
+ <li><a href="/doc/download.html">Download</a></li>#}
+ </ul>
+</div>
+{% endblock %}
+{% block relbar2 %}
+{% endblock %}
diff --git a/askbot/doc/source/askbot/static/traditional.css b/askbot/doc/source/askbot/static/traditional.css
new file mode 100644
index 00000000..cfbdaf79
--- /dev/null
+++ b/askbot/doc/source/askbot/static/traditional.css
@@ -0,0 +1,677 @@
+/*
+ * traditional.css
+ * ~~~~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- traditional docs.python.org theme.
+ *
+ * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+body {
+ color: #000;
+ margin: 0;
+ padding: 0;
+}
+
+/* :::: LAYOUT :::: */
+
+div.documentwrapper {
+ float: left;
+ width: 100%;
+}
+
+div.bodywrapper {
+ margin: 0 230px 0 0;
+}
+
+div.body {
+ background-color: white;
+ padding: 0 20px 30px 0;
+ font-family: "Lucida Grande",Verdana,"Bitstream Vera Sans",Arial,sans-serif;
+}
+
+div.sphinxsidebarwrapper {
+ border: 1px solid #99ccff;
+ padding: 10px;
+ margin: 55px 15px 10px 0;
+}
+
+div.sphinxsidebar {
+ float: right;
+ margin-left: -100%;
+ width: 230px;
+}
+
+div.clearer {
+ clear: both;
+}
+
+div.document {
+ width: 960px;
+ margin: auto;
+}
+
+div.footer {
+ clear: both;
+ width: 100%;
+ background-color: #dcdcdc;
+ padding: 9px 0 9px 0;
+ text-align: center;
+}
+
+div.related {
+ background-color: #99ccff;
+ color: #333;
+ width: 960px;
+ margin: auto;
+ height: 30px;
+ line-height: 30px;
+ border-bottom: 5px solid white;
+}
+
+div.related h3 {
+ display: none;
+}
+
+div.related ul {
+ margin: 0;
+ padding: 0 0 0 10px;
+ list-style: none;
+}
+
+div.related li {
+ display: inline;
+ font-weight: bold;
+}
+
+div.related li.right {
+ float: right;
+ margin-right: 5px;
+}
+
+/* ::: SIDEBAR :::: */
+div.sphinxsidebar h3 {
+ margin: 0;
+}
+
+div.sphinxsidebar h4 {
+ margin: 5px 0 0 0;
+}
+
+div.sphinxsidebar p,
+div.sphinxsidebar a {
+ font-family: "Lucida Grande",Verdana,"Bitstream Vera Sans",Arial,sans-serif;
+}
+
+div.sphinxsidebar p.topless {
+ margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+ margin: 10px;
+ margin-left: 15px;
+ padding: 0;
+}
+
+div.sphinxsidebar ul ul {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+div.sphinxsidebar form {
+ margin-top: 10px;
+}
+
+
+/* :::: SEARCH :::: */
+ul.search {
+ margin: 10px 0 0 20px;
+ padding: 0;
+}
+
+ul.search li {
+ padding: 5px 0 5px 20px;
+ background-image: url(file.png);
+ background-repeat: no-repeat;
+ background-position: 0 7px;
+}
+
+ul.search li a {
+ font-weight: bold;
+}
+
+ul.search li div.context {
+ color: #888;
+ margin: 2px 0 0 30px;
+ text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+ font-weight: bold;
+}
+
+/* :::: COMMON FORM STYLES :::: */
+
+div.actions {
+ border-top: 1px solid #aaa;
+ background-color: #ddd;
+ margin: 10px 0 0 -20px;
+ padding: 5px 0 5px 20px;
+}
+
+form dl {
+ color: #333;
+}
+
+form dt {
+ clear: both;
+ float: left;
+ min-width: 110px;
+ margin-right: 10px;
+ padding-top: 2px;
+}
+
+input#homepage {
+ display: none;
+}
+
+div.error {
+ margin: 5px 20px 0 0;
+ padding: 5px;
+ border: 1px solid #d00;
+ /*border: 2px solid #05171e;
+ background-color: #092835;
+ color: white;*/
+ font-weight: bold;
+}
+
+/* :::: INLINE COMMENTS :::: */
+
+div.inlinecommentswrapper {
+ float: right;
+ max-width: 40%;
+}
+
+div.commentmarker {
+ float: right;
+ background-image: url(style/comment.png);
+ background-repeat: no-repeat;
+ width: 25px;
+ height: 25px;
+ text-align: center;
+ padding-top: 3px;
+}
+
+div.nocommentmarker {
+ float: right;
+ background-image: url(style/nocomment.png);
+ background-repeat: no-repeat;
+ width: 25px;
+ height: 25px;
+}
+
+div.inlinecomments {
+ margin-left: 10px;
+ margin-bottom: 5px;
+ background-color: #eee;
+ border: 1px solid #ccc;
+ padding: 5px;
+}
+
+div.inlinecomment {
+ border-top: 1px solid #ccc;
+ padding-top: 5px;
+ margin-top: 5px;
+}
+
+.inlinecomments p {
+ margin: 5px 0 5px 0;
+}
+
+.inlinecomments .head {
+ font-weight: bold;
+}
+
+.inlinecomments .meta {
+ font-style: italic;
+}
+
+
+/* :::: COMMENTS :::: */
+
+div#comments h3 {
+ border-top: 1px solid #aaa;
+ padding: 5px 20px 5px 20px;
+ margin: 20px -20px 20px -20px;
+ background-color: #ddd;
+}
+
+div#comments em.important {
+ color: #d00;
+ font-weight: bold;
+ font-style: normal;
+}*/
+
+/* :::: SUGGEST CHANGES :::: */
+div#suggest-changes-box input, div#suggest-changes-box textarea {
+ border: 1px solid #ccc;
+ background-color: white;
+ color: black;
+}
+
+div#suggest-changes-box textarea {
+ width: 99%;
+ height: 400px;
+}
+
+
+/* :::: PREVIEW :::: */
+div.preview {
+ background-image: url(style/preview.png);
+ padding: 0 20px 20px 20px;
+ margin-bottom: 30px;
+}
+
+
+/* :::: INDEX PAGE :::: */
+
+table.contentstable {
+ width: 90%;
+}
+
+table.contentstable p.biglink {
+ line-height: 150%;
+}
+
+a.biglink {
+ font-size: 1.5em;
+}
+
+span.linkdescr {
+ font-style: italic;
+ padding-top: 5px;
+}
+
+/* :::: GENINDEX STYLES :::: */
+
+table.indextable td {
+ text-align: left;
+ vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+ height: 10px;
+}
+
+table.indextable tr.cap {
+ margin-top: 10px;
+ background-color: #f2f2f2;
+}
+
+img.toggler {
+ margin-right: 3px;
+ margin-top: 3px;
+ cursor: pointer;
+}
+
+/* :::: GLOBAL STYLES :::: */
+
+p.subhead {
+ font-weight: bold;
+ margin-top: 20px;
+}
+
+a {
+ text-decoration: none;
+ border-bottom: 1px solid #dfdfdf;
+}
+a:link:active { color: #ff0000; }
+a:link:hover { background-color: #bbeeff; }
+a:visited:hover { background-color: #bbeeff; }
+a:visited { color: #3185AB; }
+a:link { color: #21759B; }
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+ font-family: Georgia, Times, "Times New Roman", serif;
+ font-weight: bold;
+}
+
+div.body h1 { font-size: 180%; }
+div.body h2 { font-size: 150%; }
+div.body h3 { font-size: 120%; }
+div.body h4 { font-size: 120%; }
+
+div.body p { font-size: 100%; }
+
+a.headerlink,
+a.headerlink,
+a.headerlink,
+a.headerlink,
+a.headerlink,
+a.headerlink {
+ color: #c60f0f;
+ font-size: 0.8em;
+ padding: 0 4px 0 4px;
+ text-decoration: none;
+ visibility: hidden;
+}
+
+*:hover > a.headerlink,
+*:hover > a.headerlink,
+*:hover > a.headerlink,
+*:hover > a.headerlink,
+*:hover > a.headerlink,
+*:hover > a.headerlink {
+ visibility: visible;
+}
+
+a.headerlink:hover,
+a.headerlink:hover,
+a.headerlink:hover,
+a.headerlink:hover,
+a.headerlink:hover,
+a.headerlink:hover {
+ background-color: #c60f0f;
+ color: white;
+}
+
+div.body p, div.body dd, div.body li {
+ text-align: justify;
+}
+
+div.body td {
+ text-align: left;
+}
+
+ul.fakelist {
+ list-style: none;
+ margin: 10px 0 10px 20px;
+ padding: 0;
+}
+
+/* "Footnotes" heading */
+p.rubric {
+ margin-top: 30px;
+ font-weight: bold;
+}
+
+/* "Topics" */
+
+div.topic {
+ background-color: #eee;
+ border: 1px solid #ccc;
+ padding: 0 7px 0 7px;
+ margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 10px;
+}
+
+/* Admonitions */
+
+div.admonition {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 7px;
+}
+
+div.admonition dt {
+ font-weight: bold;
+}
+
+div.admonition dd {
+ margin-bottom: 10px;
+}
+
+div.admonition dl {
+ margin-bottom: 0;
+}
+
+div.admonition p {
+ display: inline;
+}
+
+div.seealso {
+ background-color: #ffc;
+ border: 1px solid #ff6;
+}
+
+div.warning {
+ background-color: #ffe4e4;
+ border: 1px solid #f66;
+}
+
+div.note {
+ background-color: #eee;
+ border: 1px solid #ccc;
+}
+
+p.admonition-title {
+ margin: 0px 10px 5px 0px;
+ font-weight: bold;
+ display: inline;
+}
+
+p.admonition-title:after {
+ content: ":";
+}
+
+div.body p.centered {
+ text-align: center;
+ margin-top: 25px;
+}
+
+table.docutils {
+ border: 0;
+}
+
+table.docutils td, table.docutils th {
+ padding: 0 8px 2px 0;
+ border-top: 0;
+ border-left: 0;
+ border-right: 0;
+ border-bottom: 1px solid #aaa;
+}
+
+table.field-list td, table.field-list th {
+ border: 0 !important;
+}
+
+table.footnote td, table.footnote th {
+ border: 0 !important;
+}
+
+dl {
+ margin-bottom: 15px;
+ clear: both;
+}
+
+dd p {
+ margin-top: 0px;
+}
+
+dd ul, dd table {
+ margin-bottom: 10px;
+}
+
+dd {
+ margin-top: 3px;
+ margin-bottom: 10px;
+ margin-left: 30px;
+}
+
+dl.glossary dt {
+ font-weight: bold;
+ font-size: 1.1em;
+}
+
+.refcount {
+ color: #060;
+}
+
+th {
+ text-align: left;
+ padding-right: 5px;
+}
+
+pre {
+ font-family: monospace;
+ padding: 5px;
+ color: #00008b;
+ border-left: none;
+ border-right: none;
+}
+
+tt {
+ font-family: monospace;
+ background-color: #ecf0f3;
+ padding: 0 1px 0 1px;
+}
+
+tt.descname {
+ background-color: transparent;
+ font-weight: bold;
+ font-size: 1.2em;
+}
+
+tt.descclassname {
+ background-color: transparent;
+}
+
+tt.xref, a tt {
+ background-color: transparent;
+ font-weight: bold;
+}
+
+.footnote:target { background-color: #ffa }
+
+.line-block {
+ display: block;
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+.line-block .line-block {
+ margin-top: 0;
+ margin-bottom: 0;
+ margin-left: 1.5em;
+}
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+ background-color: transparent;
+}
+
+.optional {
+ font-size: 1.3em;
+}
+
+.versionmodified {
+ font-style: italic;
+}
+
+form.comment {
+ margin: 0;
+ padding: 10px 30px 10px 30px;
+ background-color: #eee;
+}
+
+form.comment h3 {
+ background-color: #326591;
+ color: white;
+ margin: -10px -30px 10px -30px;
+ padding: 5px;
+ font-size: 1.4em;
+}
+
+form.comment input,
+form.comment textarea {
+ border: 1px solid #ccc;
+ padding: 2px;
+ font-family: sans-serif;
+ font-size: 13px;
+}
+
+form.comment input[type="text"] {
+ width: 240px;
+}
+
+form.comment textarea {
+ width: 100%;
+ height: 200px;
+ margin-bottom: 10px;
+}
+
+/* :::: PRINT :::: */
+@media print {
+ div.documentwrapper {
+ width: 100%;
+ }
+
+ div.body {
+ margin: 0;
+ }
+
+ div.sphinxsidebar,
+ div.related,
+ div.footer,
+ div#comments div.new-comment-box,
+ #top-link {
+ display: none;
+ }
+}
+
+.viewcode-link {
+ float: right;
+}
+
+.viewcode-back {
+ float: right;
+ font-family: serif;
+}
+
+div.viewcode-block:target {
+ background-color: #f4debf;
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+ margin: -1px -10px;
+ padding: 0 10px;
+}
+
+div.ab-proj-header {
+ width: 960px;
+ margin: auto;
+ font-family: "Lucida Grande",Tahoma,"Bitstream Vera Sans",Arial,sans-serif;
+}
+div.ab-proj-header li {
+ display: inline;
+ padding: 0;
+}
+div.ab-proj-header a,
+div.ab-proj-header a:visited,
+{
+ text-decoration: none;
+}
+div.ab-proj-header ul {
+ margin: 0;
+ padding: 5px 0 0 0;
+ list-style: none;
+}
+div.ab-proj-header .sep {
+ color: #aaa;
+ padding: 0 10px;
+}
diff --git a/askbot/doc/source/askbot/theme.conf b/askbot/doc/source/askbot/theme.conf
new file mode 100644
index 00000000..9f67df58
--- /dev/null
+++ b/askbot/doc/source/askbot/theme.conf
@@ -0,0 +1,4 @@
+[theme]
+inherit = traditional
+stylesheet = traditional.css
+pygments_style = sphinx
diff --git a/askbot/doc/source/conf.py b/askbot/doc/source/conf.py
index 1039dff0..09fe821f 100644
--- a/askbot/doc/source/conf.py
+++ b/askbot/doc/source/conf.py
@@ -44,10 +44,11 @@ sys.path.append(parent_dir(__file__, 2))
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.coverage',]# 'sphinx.ext.viewcode']
+extensions = ['sphinx.ext.todo', 'sphinx.ext.coverage',]# 'sphinx.ext.viewcode']
+#extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.coverage',]# 'sphinx.ext.viewcode']
# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+templates_path = ['_templates', 'askbot']
# The suffix of source filenames.
source_suffix = '.rst'
@@ -110,7 +111,7 @@ modindex_common_prefix = ['askbot.']
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-html_theme = 'traditional'
+html_theme = 'askbot'
#html_theme_options = {
# 'rightsidebar':'false',
#}
@@ -121,7 +122,7 @@ html_theme = 'traditional'
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
+html_theme_path = ['.',]
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
@@ -169,7 +170,7 @@ html_static_path = ['_static']
#html_split_index = False
# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
+html_show_sourcelink = False
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
diff --git a/askbot/doc/source/contributors.rst b/askbot/doc/source/contributors.rst
new file mode 100644
index 00000000..67d8fdeb
--- /dev/null
+++ b/askbot/doc/source/contributors.rst
@@ -0,0 +1,31 @@
+==============================
+Contributors to Askbot Project
+==============================
+
+This is the list of contributors to the code of Askbot project.
+The list is probably incomplete, apologies for any omissions.
+Thanks for all your help
+
+Programming
+-----------
+* Mike Chen & Sailing Cai - original authors of CNPROG forum
+* Evgeny Fadeev - founder of askbot
+* Benoit Lavine (with Windriver Software, Inc.)
+* Adolfo Fitoria
+* Andrei Mamoutkine
+* Ramiro Morales (with Machinalis)
+* Andy Knotts
+
+Translations
+------------
+* Mike Chen, Sailing Cai, suyu8776 - Chinese
+* Bruno Sarlo, Adolfo Fitoria - Spanish
+* Evgeny Kalinin - Russian
+* Evgeny Fadeev - English
+* Oktay Yildiz, Onur Mat, Cemre - Turkish
+* Jérôme Blondon (bearstech) - French
+* Pekka Gaiser - German
+* Pekka Järvinen - Finnish
+* Adi Robian - Romanian
+* Dario Ghilardi, Federico Poloni - Italian
+
diff --git a/askbot/doc/source/download.rst b/askbot/doc/source/download.rst
new file mode 100644
index 00000000..d6172fec
--- /dev/null
+++ b/askbot/doc/source/download.rst
@@ -0,0 +1,6 @@
+===============
+Download Askbot
+===============
+
+The entire source code for the Askbot Q & A forum can be downloaded
+at the Python Package index
diff --git a/askbot/doc/source/import-data.rst b/askbot/doc/source/import-data.rst
new file mode 100644
index 00000000..c2cfc1b3
--- /dev/null
+++ b/askbot/doc/source/import-data.rst
@@ -0,0 +1,20 @@
+.. import-data::
+
+===============================
+Import other forums into Askbot
+===============================
+
+At this time only StackExchange import is supported.
+
+There are two ways to import your StackExchange dump into Askbot:
+
+* via the web at url `/import-data/`, relative to your forum installation
+* using a management command::
+
+ python manage.py load_stackexchange /path/to/your-se-data.zip
+
+Before importing the data, an entry `askbot.importers.stackexchange` must be added to
+the `INSTALLED_APPS` list in your `settings.py` file and a command `python manage.py syncdb` run
+to initialize the stackexchange tables.
+
+In the case your database is not empty at the beginning of the process - **please do back it up**.
diff --git a/askbot/doc/source/index.rst b/askbot/doc/source/index.rst
index b986df3a..a7fb8122 100644
--- a/askbot/doc/source/index.rst
+++ b/askbot/doc/source/index.rst
@@ -19,7 +19,9 @@ at the forum_ or by email at admin@askbot.org
Create and configure the site files<initial-configuration>
Initialize the database tables <initialize-database-tables>
Deploy on a webserver <deployment>
+ Import data (StackExchange) <import-data>
Appendix A: Maintenance procedures <management-commands>
+ Contributors <contributors>
Some background information: Askbot is written in Python on top of the Django platform.
Code of Askbot grew out of CNPROG project originally written by
diff --git a/askbot/doc/source/management-commands.rst b/askbot/doc/source/management-commands.rst
index 0e2002b4..188654bf 100644
--- a/askbot/doc/source/management-commands.rst
+++ b/askbot/doc/source/management-commands.rst
@@ -37,11 +37,25 @@ The bulk of the management commands fall into this group and will probably be th
| | any of the external login providers. |
+---------------------------------+-------------------------------------------------------------+
| `dump_forum [--dump-name | Save forum contents into a file. `--dump-name` parameter is |
-| some_name`] | optional |
+| some_name]` | optional |
++---------------------------------+-------------------------------------------------------------+
+| `get_tag_stats [-u|-t] [-e]` | Print tag subscription statistics, per tag (option -t) |
+| | or per user (option -u), if option -e is given, empty |
+| | records will be shown too (longer versions of the options |
+| | are: --per-tag-subscription-counts for -t, |
+| | --per-user-tag-subscription-counts for -u, and --print-empty|
+| | for -e). |
+---------------------------------+-------------------------------------------------------------+
| `load_forum <file_name>` | Load forum data from a file saved by the `dump_forum` |
| | command |
+---------------------------------+-------------------------------------------------------------+
+| `load_stackexchange <file.zip>` | Load SackExchange dump into Askbot. It is best to run this |
+| | command on empty database. Also - before running, make sure |
+| | that `askbot.importers.stackexchange` is in the list of |
+| | installed apps within your settings.py file (it might also |
+| | be necessary to run `syncdb` command to initiate the |
+| | SE importer tables). |
++---------------------------------+-------------------------------------------------------------+
| `rename_tags --from <from_tags> | Rename, merge or split tags. User ID is the id of the user |
| --to <to_tags> --user-id | who will be assigned as the performer of the retag action. |
| <user_id>` | If more than is in the `--from` or the `--to` parameters |
@@ -98,8 +112,16 @@ The commands from this section will help fix those issues.
+--------------------------------+-------------------------------------------------------------+
| `fix_answer_counts` | recalculates answer counts for all questions |
+--------------------------------+-------------------------------------------------------------+
+| `fix_inbox_counts` | recalculates response counts in the user inboxes |
++--------------------------------+-------------------------------------------------------------+
| `fix_revisionless_posts` | adds a revision record to posts that lack them |
+--------------------------------+-------------------------------------------------------------+
+| `fix_question_tags` | takes tag names from the record on the question table |
+| | and stores them in the tag table. This defect may show when |
+| | the server process is interrupted after the question was |
+| | saved, but tags were not updated, and the symptom is that |
+| | the question cannot be found via the tag search. |
++--------------------------------+-------------------------------------------------------------+
The above commands are safe to run at any time, also they do not require
additional parameters. In the future all these will be replaced with just one simple command.
diff --git a/askbot/exceptions.py b/askbot/exceptions.py
index a1d76a67..d2d5ddf0 100644
--- a/askbot/exceptions.py
+++ b/askbot/exceptions.py
@@ -1,6 +1,10 @@
from django.core import exceptions
from django.utils.translation import ugettext as _
+class DeploymentError(exceptions.ImproperlyConfigured):
+ """raised when there is some error with deployment"""
+ pass
+
class LoginRequired(exceptions.PermissionDenied):
"""raised when an operation required a logged
in user"""
diff --git a/askbot/feed.py b/askbot/feed.py
index a204b98d..23416677 100644
--- a/askbot/feed.py
+++ b/askbot/feed.py
@@ -12,7 +12,7 @@
"""
#!/usr/bin/env python
#encoding:utf-8
-from django.contrib.syndication.feeds import Feed, FeedDoesNotExist
+from django.contrib.syndication.feeds import Feed
from django.utils.translation import ugettext as _
from askbot.models import Question
from askbot.conf import settings as askbot_settings
@@ -45,6 +45,12 @@ class RssLastestQuestionsFeed(Feed):
"""
return item.added_at
+ def item_guid(self, item):
+ """returns url without the slug
+ because the slug can change
+ """
+ return self.link + item.get_absolute_url(no_slug = True)
+
def items(self, item):
"""get questions for the feed
"""
diff --git a/askbot/forms.py b/askbot/forms.py
index 08b5a4d9..aa021370 100644
--- a/askbot/forms.py
+++ b/askbot/forms.py
@@ -2,11 +2,13 @@ import re
from django import forms
from askbot import models
from askbot import const
-from django.utils.translation import ugettext as _
-from django.utils.translation import ungettext
+from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import ungettext_lazy
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
+from django_countries import countries
from askbot.utils.forms import NextUrlField, UserNameField
+from askbot.utils.mail import extract_first_email_address
from askbot.deps.recaptcha_django import ReCaptchaField
from askbot.conf import settings as askbot_settings
import logging
@@ -18,6 +20,31 @@ def cleanup_dict(dictionary, key, empty_value):
if key in dictionary and dictionary[key] == empty_value:
del dictionary[key]
+def clean_marked_tagnames(tagnames):
+ """return two strings - one containing tagnames
+ that are straight names of tags, and the second one
+ containing names of wildcard tags,
+ wildcard tags are those that have an asterisk at the end
+ the function does not verify that the tag names are valid
+ """
+ if askbot_settings.USE_WILDCARD_TAGS == False:
+ return tagnames, list()
+
+ pure_tags = list()
+ wildcards = list()
+ for tagname in tagnames:
+ if tagname == '':
+ continue
+ if tagname.endswith('*'):
+ if tagname.count('*') > 1:
+ continue
+ else:
+ wildcards.append(tagname)
+ else:
+ pure_tags.append(tagname)
+
+ return pure_tags, wildcards
+
def filter_choices(remove_choices = None, from_choices = None):
"""a utility function that will remove choice tuples
usable for the forms.ChoicesField from
@@ -43,6 +70,28 @@ def filter_choices(remove_choices = None, from_choices = None):
return filtered_choices
+COUNTRY_CHOICES = (('unknown',_('select country')),) + countries.COUNTRIES
+
+class CountryField(forms.ChoiceField):
+ """this is better placed into the django_coutries app"""
+
+ def __init__(self, *args, **kwargs):
+ """sets label and the country choices
+ """
+ kwargs['choices'] = kwargs.pop('choices', COUNTRY_CHOICES)
+ kwargs['label'] = kwargs.pop('label', _('Country'))
+ super(CountryField, self).__init__(*args, **kwargs)
+
+ def clean(self, value):
+ """Handles case of 'unknown' country selection
+ """
+ if self.required:
+ if value == 'unknown':
+ raise forms.ValidationError(_('Country field is required'))
+ if value == 'unknown':
+ return None
+ return value
+
class TitleField(forms.CharField):
def __init__(self, *args, **kwargs):
super(TitleField, self).__init__(*args, **kwargs)
@@ -94,11 +143,11 @@ class TagNamesField(forms.CharField):
split_re = re.compile(const.TAG_SPLIT_REGEX)
tag_strings = split_re.split(data)
- out_tag_list = []
+ entered_tags = []
tag_count = len(tag_strings)
if tag_count > askbot_settings.MAX_TAGS_PER_POST:
max_tags = askbot_settings.MAX_TAGS_PER_POST
- msg = ungettext(
+ msg = ungettext_lazy(
'please use %(tag_count)d tag or less',
'please use %(tag_count)d tags or less',
tag_count) % {'tag_count':max_tags}
@@ -108,7 +157,7 @@ class TagNamesField(forms.CharField):
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
+ msg = ungettext_lazy('each tag must be shorter than %(max_chars)d character',#odd but added for completeness
'each tag must be shorter than %(max_chars)d characters',
tag_length) % {'max_chars':tag_length}
raise forms.ValidationError(msg)
@@ -118,16 +167,40 @@ class TagNamesField(forms.CharField):
if not tagname_re.search(tag):
raise forms.ValidationError(_('use-these-chars-in-tags'))
#only keep unique tags
- if tag not in out_tag_list:
- out_tag_list.append(tag)
- return u' '.join(out_tag_list)
+ if tag not in entered_tags:
+ entered_tags.append(tag)
+
+ #normalize character case of tags
+ cleaned_entered_tags = list()
+ if askbot_settings.FORCE_LOWERCASE_TAGS:
+ #a simpler way to handle tags - just lowercase thew all
+ for name in entered_tags:
+ lowercased_name = name.lower()
+ if lowercased_name not in cleaned_entered_tags:
+ cleaned_entered_tags.append(lowercased_name)
+ else:
+ #make names of tags in the input to agree with the database
+ for entered_tag in entered_tags:
+ try:
+ #looks like we have to load tags one-by one
+ #because we need tag name cases to be the same
+ #as those stored in the database
+ stored_tag = models.Tag.objects.get(
+ name__iexact = entered_tag
+ )
+ if stored_tag.name not in cleaned_entered_tags:
+ cleaned_entered_tags.append(stored_tag.name)
+ except models.Tag.DoesNotExist:
+ cleaned_entered_tags.append(entered_tag)
+
+ return u' '.join(cleaned_entered_tags)
class WikiField(forms.BooleanField):
def __init__(self, *args, **kwargs):
super(WikiField, self).__init__(*args, **kwargs)
self.required = False
self.initial = False
- self.label = _('community wiki')
+ self.label = _('community wiki (karma is not awarded & many others can edit wiki post)')
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 askbot_settings.WIKI_ON
@@ -148,6 +221,13 @@ class SummaryField(forms.CharField):
self.help_text = _('enter a brief summary of your revision (e.g. fixed spelling, grammar, improved style, this field is optional)')
+class DumpUploadForm(forms.Form):
+ """This form handles importing
+ data into the forum. At the moment it only
+ supports stackexchange import.
+ """
+ dump_file = forms.FileField()
+
class ShowQuestionForm(forms.Form):
answer = forms.IntegerField(required = False)
comment = forms.IntegerField(required = False)
@@ -332,16 +412,20 @@ class SendMessageForm(forms.Form):
class AdvancedSearchForm(forms.Form):
- #nothing must be required in this form
- #it is used by the main questions view
+ """nothing must be required in this form
+ it is used by the main questions view for input validation only
+ """
scope = forms.ChoiceField(choices=const.POST_SCOPE_LIST, required=False)
sort = forms.ChoiceField(choices=const.POST_SORT_METHODS, required=False)
query = forms.CharField(max_length=256, required=False)
+ #search field is actually a button, used to detect manual button click
+ search = forms.CharField(max_length=16, required=False)
reset_tags = forms.BooleanField(required=False)
reset_author = forms.BooleanField(required=False)
reset_query = forms.BooleanField(required=False)
start_over = forms.BooleanField(required=False)
tags = forms.CharField(max_length=256, required=False)
+ remove_tag = 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)
@@ -387,9 +471,11 @@ class AdvancedSearchForm(forms.Form):
cleanup_dict(data, 'tags', None)
cleanup_dict(data, 'sort', '')
cleanup_dict(data, 'query', None)
+ cleanup_dict(data, 'search', '')
cleanup_dict(data, 'reset_tags', False)
cleanup_dict(data, 'reset_author', False)
cleanup_dict(data, 'reset_query', False)
+ cleanup_dict(data, 'remove_tag', '')
cleanup_dict(data, 'start_over', False)
cleanup_dict(data, 'author', None)
cleanup_dict(data, 'page', None)
@@ -405,16 +491,131 @@ class FeedbackForm(forms.Form):
message = forms.CharField(label=_('Your message:'), max_length=800,widget=forms.Textarea(attrs={'cols':60}))
next = NextUrlField()
-class AskForm(forms.Form):
+class FormWithHideableFields(object):
+ """allows to swap a field widget to HiddenInput() and back"""
+
+ def hide_field(self, name):
+ """replace widget with HiddenInput()
+ and save the original in the __hidden_fields dictionary
+ """
+ if not hasattr(self, '__hidden_fields'):
+ self.__hidden_fields = dict()
+ if name in self.__hidden_fields:
+ return
+ self.__hidden_fields[name] = self.fields[name].widget
+ self.fields[name].widget = forms.HiddenInput()
+
+ def show_field(self, name):
+ """restore the original widget on the field
+ if it was previously hidden
+ """
+ if name in self.__hidden_fields:
+ self.fields[name] = self.__hidden_fields.pop(name)
+
+class AskForm(forms.Form, FormWithHideableFields):
+ """the form used to askbot questions
+ field ask_anonymously is shown to the user if the
+ if ALLOW_ASK_ANONYMOUSLY live setting is True
+ however, for simplicity, the value will always be present
+ in the cleaned data, and will evaluate to False if the
+ settings forbids anonymous asking
+ """
title = TitleField()
text = EditorField()
tags = TagNamesField()
wiki = WikiField()
-
+ ask_anonymously = forms.BooleanField(
+ label = _('ask anonymously'),
+ help_text = _(
+ 'Check if you do not want to reveal your name '
+ 'when asking this question'
+ ),
+ required = False,
+ )
openid = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 40, 'class':'openid-input'}))
user = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35}))
email = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35}))
+ def __init__(self, *args, **kwargs):
+ super(AskForm, self).__init__(*args, **kwargs)
+ #hide ask_anonymously field
+ if askbot_settings.ALLOW_ASK_ANONYMOUSLY == False:
+ self.hide_field('ask_anonymously')
+
+ def clean_ask_anonymously(self):
+ """returns false if anonymous asking is not allowed
+ """
+ if askbot_settings.ALLOW_ASK_ANONYMOUSLY == False:
+ self.cleaned_data['ask_anonymously'] = False
+ return self.cleaned_data['ask_anonymously']
+
+
+class AskByEmailForm(forms.Form):
+ """:class:`~askbot.forms.AskByEmailForm`
+ validates question data, where question was posted
+ by email.
+
+ It is ivoked by the management command
+ :mod:`~askbot.management.commands.post_emailed_questions`
+
+ Input is text data with attributes:
+
+ * :attr:`~askbot.forms.AskByEmailForm.sender` - unparsed "from" data
+ * :attr:`~askbot.forms.AskByEmailForm.subject` - subject line
+ * :attr:`~askbot.forms.AskByEmailForm.body_text` - body text of the email
+
+ Cleaned values are:
+ * ``email`` - email address
+ * ``title`` - question title
+ * ``tagnames`` - tag names all in one string
+ * ``body_text`` - body of question text - a pass-through, no extra validation
+ """
+ sender = forms.CharField(max_length = 255)
+ subject = forms.CharField(max_length = 255)
+ body_text = EditorField()
+
+ def clean_sender(self):
+ """Cleans the :attr:`~askbot.forms.AskByEmail.sender` attribute
+
+ If the field is valid, cleaned data will receive value ``email``
+ """
+ raw_email = self.cleaned_data['sender']
+ email = extract_first_email_address(raw_email)
+ if email is None:
+ raise forms.ValidationError('Could not extract email address')
+ self.cleaned_data['email'] = email
+ return self.cleaned_data['sender']
+
+ def clean_subject(self):
+ """Cleans the :attr:`~askbot.forms.AskByEmail.subject` attribute
+
+ If the field is valid, cleaned data will receive values
+ ``tagnames`` and ``title``
+ """
+ raw_subject = self.cleaned_data['subject'].strip()
+ subject_re = re.compile(r'^\[([^]]+)\](.*)$')
+ match = subject_re.match(raw_subject)
+ if match:
+ #make raw tags comma-separated
+ tagnames = match.group(1).replace(';',',')
+
+ #pre-process tags
+ tag_list = [tag.strip() for tag in tagnames.split(',')]
+ tag_list = [re.sub(r'\s+', ' ', tag) for tag in tag_list]
+ if askbot_settings.REPLACE_SPACE_WITH_DASH_IN_EMAILED_TAGS:
+ tag_list = [tag.replace(' ', '-') for tag in tag_list]
+ tagnames = ' '.join(tag_list)#todo: use tag separator char here
+
+ #clean tags - may raise ValidationError
+ self.cleaned_data['tagnames'] = TagNamesField().clean(tagnames)
+
+ #clean title - may raise ValidationError
+ title = match.group(2).strip()
+ self.cleaned_data['title'] = TitleField().clean(title)
+ else:
+ raise forms.ValidationError('could not parse subject line')
+ return self.cleaned_data['subject']
+
class AnswerForm(forms.Form):
text = EditorField()
wiki = WikiField()
@@ -460,21 +661,113 @@ class RevisionForm(forms.Form):
for r in revisions]
self.fields['revision'].initial = latest_revision.revision
-class EditQuestionForm(forms.Form):
+class EditQuestionForm(forms.Form, FormWithHideableFields):
title = TitleField()
text = EditorField()
tags = TagNamesField()
summary = SummaryField()
wiki = WikiField()
+ reveal_identity = forms.BooleanField(
+ help_text = _(
+ 'You have asked this question anonymously, '
+ 'if you decide to reveal your identity, please check '
+ 'this box.'
+ ),
+ label = _('reveal identity'),
+ required = False,
+ )
#todo: this is odd that this form takes question as an argument
- def __init__(self, question, revision, *args, **kwargs):
+ def __init__(self, *args, **kwargs):
"""populate EditQuestionForm with initial data"""
+ self.question = kwargs.pop('question')
+ self.user = kwargs.pop('user')
+ revision = kwargs.pop('revision')
super(EditQuestionForm, self).__init__(*args, **kwargs)
self.fields['title'].initial = revision.title
self.fields['text'].initial = revision.text
self.fields['tags'].initial = revision.tagnames
- self.fields['wiki'].initial = question.wiki
+ self.fields['wiki'].initial = self.question.wiki
+ #hide the reveal identity field
+ if not self.can_stay_anonymous():
+ self.hide_field('reveal_identity')
+
+ def can_stay_anonymous(self):
+ """determines if the user cat keep editing the question
+ anonymously"""
+ return (askbot_settings.ALLOW_ASK_ANONYMOUSLY \
+ and self.question.is_anonymous \
+ and self.user.is_owner_of(self.question)
+ )
+
+ def clean_reveal_identity(self):
+ """cleans the reveal_identity field
+ which determines whether previous anonymous
+ edits must be rewritten as not anonymous
+ this does not necessarily mean that the edit will be anonymous
+
+ only does real work when question is anonymous
+ based on the following truth table:
+
+ is_anon can owner checked cleaned data
+ - * * * False (ignore choice in checkbox)
+ + + + + True
+ + + + - False
+ + + - + Raise(Not owner)
+ + + - - False
+ + - + + True (setting "can" changed, say yes)
+ + - + - False, warn (but prev edits stay anon)
+ + - - + Raise(Not owner)
+ + - - - False
+ """
+ value = self.cleaned_data['reveal_identity']
+ if self.question.is_anonymous:
+ if value == True:
+ if self.user.is_owner_of(self.question):
+ #regardless of the ALLOW_ASK_ANONYMOUSLY
+ return True
+ else:
+ self.show_field('reveal_identity')
+ del self.cleaned_data['reveal_identity']
+ raise forms.ValidationError(
+ _(
+ 'Sorry, only owner of the anonymous '
+ 'question can reveal his or her '
+ 'identity, please uncheck the '
+ 'box'
+ )
+ )
+ else:
+ can_ask_anon = askbot_settings.ALLOW_ASK_ANONYMOUSLY
+ is_owner = self.user.is_owner_of(self.question)
+ if can_ask_anon == False and is_owner:
+ self.show_field('reveal_identity')
+ raise forms.ValidationError(
+ _(
+ 'Sorry, apparently rules have just changed - '
+ 'it is no longer possible to ask anonymously. '
+ 'Please either check the "reveal identity" box '
+ 'or reload this page and try editing the question '
+ 'again.'
+ )
+ )
+ return False
+ else:
+ #takes care of 8 possibilities - first row of the table
+ return False
+
+ def clean(self):
+ """Purpose of this function is to determine whether
+ it is ok to apply edit anonymously in the synthetic
+ field edit_anonymously. It relies on correct cleaning
+ if the "reveal_identity" field
+ """
+ reveal_identity = self.cleaned_data.get('reveal_identity', False)
+ stay_anonymous = False
+ if reveal_identity == False and self.can_stay_anonymous():
+ stay_anonymous = True
+ self.cleaned_data['stay_anonymous'] = stay_anonymous
+ return self.cleaned_data
class EditAnswerForm(forms.Form):
text = EditorField()
@@ -489,7 +782,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'),
+ help_text=_('this email will be linked to gravatar'),
required=True,
max_length=255,
widget=forms.TextInput(attrs={'size' : 35})
@@ -510,12 +803,19 @@ class EditUserForm(forms.Form):
)
city = forms.CharField(
- label=_('Location'),
+ label=_('City'),
required=False,
max_length=255,
widget=forms.TextInput(attrs={'size' : 35})
)
+ country = CountryField(required = False)
+
+ show_country = forms.BooleanField(
+ label=_('Show country'),
+ required=False
+ )
+
birthday = forms.DateField(
label=_('Date of birth'),
help_text=_('will not be shown, used to calculate age, format: YYYY-MM-DD'),
@@ -540,6 +840,12 @@ class EditUserForm(forms.Form):
self.fields['realname'].initial = user.real_name
self.fields['website'].initial = user.website
self.fields['city'].initial = user.location
+ if user.country == None:
+ country = 'unknown'
+ else:
+ country = user.country
+ self.fields['country'].initial = country
+ self.fields['show_country'].initial = user.show_country
if user.date_of_birth is not None:
self.fields['birthday'].initial = user.date_of_birth
@@ -563,18 +869,20 @@ class EditUserForm(forms.Form):
return self.cleaned_data['email']
class TagFilterSelectionForm(forms.ModelForm):
- tag_filter_setting = forms.ChoiceField(choices=const.TAG_EMAIL_FILTER_CHOICES,
- initial='ignored',
- label=_('Choose email tag filter'),
- widget=forms.RadioSelect)
+ email_tag_filter_strategy = forms.ChoiceField(
+ choices = const.TAG_FILTER_STRATEGY_CHOICES,
+ initial = const.EXCLUDE_IGNORED,
+ label = _('Choose email tag filter'),
+ widget = forms.RadioSelect
+ )
class Meta:
model = User
- fields = ('tag_filter_setting',)
+ fields = ('email_tag_filter_strategy',)
def save(self):
- before = self.instance.tag_filter_setting
+ before = self.instance.email_tag_filter_strategy
super(TagFilterSelectionForm, self).save()
- after = self.instance.tag_filter_setting #User.objects.get(pk=self.instance.id).tag_filter_setting
+ after = self.instance.email_tag_filter_strategy
if before != after:
return True
return False
diff --git a/askbot/importers/stackexchange/management/__init__.py b/askbot/importers/stackexchange/management/__init__.py
index e69de29b..174bdaaf 100644
--- a/askbot/importers/stackexchange/management/__init__.py
+++ b/askbot/importers/stackexchange/management/__init__.py
@@ -0,0 +1,24 @@
+import logging
+import threading
+from django.core import management
+from django.core.exceptions import ImproperlyConfigured
+from django.db.models import get_model
+
+class ImporterThread(threading.Thread):
+ def __init__(self, dump_file = None):
+ self.dump_file = dump_file
+ super(ImporterThread, self).__init__()
+
+ def run(self):
+ management.call_command('load_stackexchange', self.dump_file)
+
+def is_ready():
+ """determines whether the stackexchange app is ready to roll
+ by trying to load a model from the database
+ """
+ try:
+ get_model('stackexchange', 'User2Vote')
+ return True
+ except Exception:
+ return False
+
diff --git a/askbot/importers/stackexchange/management/commands/load_stackexchange.py b/askbot/importers/stackexchange/management/commands/load_stackexchange.py
index 83c8c02f..c1d045ae 100644
--- a/askbot/importers/stackexchange/management/commands/load_stackexchange.py
+++ b/askbot/importers/stackexchange/management/commands/load_stackexchange.py
@@ -1,8 +1,9 @@
-from django.core.management.base import BaseCommand
#todo: http://stackoverflow.com/questions/837828/how-to-use-a-slug-in-django
import os
import re
import sys
+import zipfile
+from django.core.management.base import BaseCommand, CommandError
import askbot.importers.stackexchange.parse_models as se_parser
from xml.etree import ElementTree as et
from django.db import models, transaction
@@ -15,6 +16,7 @@ from django.contrib.auth.models import Message as DjangoMessage
from django.utils.translation import ugettext as _
from askbot.utils.slug import slugify
from askbot.models.badges import award_badges_signal, award_badges
+from askbot.importers.stackexchange.management import is_ready as importer_is_ready
#from markdown2 import Markdown
#markdowner = Markdown(html4tags=True)
@@ -252,6 +254,7 @@ class X(object):#
if len(badge_summary) > 3:
print 'warning: guessing that badge summary is comma separated'
print 'have %s' % badge_summary
+ sys.stdout.flush()
bits = badge_summary.split(',')
else:
bits = [badge_summary]
@@ -275,18 +278,23 @@ class Command(BaseCommand):
@transaction.commit_manually
def handle(self, *arg, **kwarg):
+ if not importer_is_ready():
+ raise CommandError(
+ "Looks like stackexchange tables are not yet initialized in the database.\n"
+ "Please, run command: \npython manage.py syncdb\n"
+ "then import the data."
+ )
+
+
award_badges_signal.disconnect(award_badges)
- if len(arg) < 1 or not os.path.isdir(arg[0]):
- print 'Error: first argument must be a directory with all the SE *.xml files'
- sys.exit(1)
+ if len(arg) < 1 or not os.path.isfile(arg[0]):
+ raise CommandError('Error: first argument must be a zip file with the SE forum data')
- self.dump_path = arg[0]
+ self.zipfile = self.open_dump(arg[0])
#read the data into SE tables
- for xml in xml_read_order:
- xml_path = self.get_xml_path(xml)
- table_name = self.get_table_name(xml)
- self.load_xml_file(xml_path, table_name)
+ for item in xml_read_order:
+ self.load_xml_file(item)
transaction.commit()
#this is important so that when we clean up messages
@@ -304,6 +312,7 @@ class Command(BaseCommand):
self.transfer_users()
transaction.commit()
print 'done.'
+ sys.stdout.flush()
print 'Transferring content edits...',
sys.stdout.flush()
self.transfer_question_and_answer_activity()
@@ -343,6 +352,19 @@ class Command(BaseCommand):
self.transfer_meta_pages()
transaction.commit()
+ def open_dump(self, path):
+ """open the zipfile, raise error if it
+ does not exist or does not contain files with expected names"""
+ if not zipfile.is_zipfile(path):
+ raise CommandError('%s is not a zip file' % path)
+ dump = zipfile.ZipFile(path)
+ filenames = [item.filename for item in dump.infolist()]
+ for component in xml_read_order:
+ expected_file = component + '.xml'
+ if expected_file not in filenames:
+ raise CommandError('file %s not found in the archive' % expected_file)
+ return dump
+
def save_askbot_message_id_list(self):
id_list = list(DjangoMessage.objects.all().values('id'))
self._askbot_message_id_list = id_list
@@ -612,6 +634,7 @@ class Command(BaseCommand):
for se_c in se.PostComment.objects.all():
if se_c.deletion_date:
print 'Warning deleted comment %d dropped' % se_c.id
+ sys.stdout.flush()
continue
se_post = se_c.post
askbot_post = X.get_post(se_post)
@@ -636,6 +659,7 @@ class Command(BaseCommand):
self._missing_badges[name] = 0
if len(se_b.description) > 300:
print 'Warning truncated description for badge %d' % se_b.id
+ sys.stdout.flush()
def _award_badges(self):
#note: SE does not keep information on
@@ -670,6 +694,7 @@ class Command(BaseCommand):
dropped = [name for name in d.keys() if d[name] > 0]
print 'Warning - following unsupported badges were dropped:'
print ', '.join(dropped)
+ sys.stdout.flush()
def transfer_badges(self):
#note: badge level is neglected
@@ -712,8 +737,15 @@ class Command(BaseCommand):
#so we can't do this
pass
- def load_xml_file(self, xml_path, table_name):
- tree = et.parse(xml_path)
+ def load_xml_file(self, item):
+ """read data from the zip file for the item
+ """
+ xml_path = self.get_xml_path(item)
+ table_name = self.get_table_name(item)
+
+ xml_data = self.zipfile.read(xml_path)
+
+ tree = et.fromstring(xml_data)
print 'loading from %s to %s' % (xml_path, table_name) ,
model = models.get_model('stackexchange', table_name)
i = 0
@@ -727,16 +759,13 @@ class Command(BaseCommand):
setattr(model_entry, field_name, field_value)
model_entry.save()
print '... %d objects saved' % i
+ sys.stdout.flush()
- def get_table_name(self,xml):
- return se_parser.get_table_name(xml)
+ def get_table_name(self, xml_file_basename):
+ return se_parser.get_table_name(xml_file_basename)
- def get_xml_path(self, xml):
- xml_path = os.path.join(self.dump_path, xml + '.xml')
- if not os.path.isfile(xml_path):
- print 'Error: file %s not found' % xml_path
- sys.exit(1)
- return xml_path
+ def get_xml_path(self, xml_file_basename):
+ return xml_file_basename + '.xml'
def transfer_users(self):
for se_u in se.User.objects.all():
@@ -745,9 +774,9 @@ class Command(BaseCommand):
u = askbot.User()
u_type = se_u.user_type.name
if u_type == 'Administrator':
- u.is_superuser = True
+ u.set_admin_status()
elif u_type == 'Moderator':
- u.is_staff = True
+ u.set_status('m')
elif u_type not in ('Unregistered', 'Registered'):
raise Exception('unknown user type %s' % u_type)
@@ -766,9 +795,11 @@ class Command(BaseCommand):
except AssertionError:
print 'User %s (id=%d) does not have openid' % \
(se_u.display_name, se_u.id)
+ sys.stdout.flush()
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)'
+ sys.stdout.flush()
u.reputation = 1#se_u.reputation, it's actually re-computed
u.last_seen = se_u.last_access_date
@@ -815,6 +846,7 @@ class Command(BaseCommand):
try:
other = askbot.User.objects.get(username = u.username)
print 'alert - have a second user with name %s' % u.username
+ sys.sdtout.flush()
except askbot.User.DoesNotExist:
pass
u.save()
diff --git a/askbot/locale/en/LC_MESSAGES/django.mo b/askbot/locale/en/LC_MESSAGES/django.mo
index 621b8b23..20542d6e 100644
--- a/askbot/locale/en/LC_MESSAGES/django.mo
+++ b/askbot/locale/en/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/locale/en/LC_MESSAGES/django.po b/askbot/locale/en/LC_MESSAGES/django.po
index 46d4b1a4..5bb75eca 100644
--- a/askbot/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-12-23 17:20-0600\n"
+"POT-Creation-Date: 2011-04-10 15:12-0500\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,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: exceptions.py:9
+#: exceptions.py:13
msgid "Sorry, but anonymous visitors cannot access this function"
msgstr ""
@@ -28,343 +28,368 @@ msgstr ""
msgid "latest questions"
msgstr ""
-#: forms.py:54 skins/default/templates/answer_edit_tips.html:43
-#: skins/default/templates/answer_edit_tips.html:47
-#: skins/default/templates/question_edit_tips.html:40
-#: skins/default/templates/question_edit_tips.html:45
+#: forms.py:73
+msgid "select country"
+msgstr ""
+
+#: forms.py:82
+msgid "Country"
+msgstr ""
+
+#: forms.py:90
+msgid "Country field is required"
+msgstr ""
+
+#: forms.py:103 skins/default/templates/blocks/answer_edit_tips.html:43
+#: skins/default/templates/blocks/answer_edit_tips.html:47
+#: skins/default/templates/blocks/question_edit_tips.html:38
+#: skins/default/templates/blocks/question_edit_tips.html:43
msgid "title"
msgstr ""
-#: forms.py:55
+#: forms.py:104
msgid "please enter a descriptive title for your question"
msgstr ""
-#: forms.py:60
+#: forms.py:109
msgid "title must be > 10 characters"
msgstr ""
-#: forms.py:69
+#: forms.py:118
msgid "content"
msgstr ""
-#: forms.py:75
+#: forms.py:124
msgid "question content must be > 10 characters"
msgstr ""
-#: forms.py:84 skins/default/templates/header.html:31
+#: forms.py:133 skins/default/templates/blocks/header.html:22
msgid "tags"
msgstr ""
-#: forms.py:86
+#: forms.py:135
msgid ""
"Tags are short keywords, with no spaces within. Up to five tags can be used."
msgstr ""
-#: forms.py:93 skins/default/templates/question_retag.html:78
+#: forms.py:142 skins/default/templates/question_retag.html:60
msgid "tags are required"
msgstr ""
-#: forms.py:102
+#: forms.py:151
#, 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] ""
-#: forms.py:111
+#: forms.py:160
#, 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] ""
-#: forms.py:119
+#: forms.py:168
msgid "use-these-chars-in-tags"
msgstr ""
-#: forms.py:130
-#: skins/default/templates/unused/question_summary_list_roll.html:26
-#: skins/default/templates/unused/question_summary_list_roll.html:38
-msgid "community wiki"
+#: forms.py:203
+msgid "community wiki (karma is not awarded & many others can edit wiki post)"
msgstr ""
-#: forms.py:131
+#: forms.py:204
msgid ""
"if you choose community wiki option, the question and answer do not generate "
"points and name of author will not be shown"
msgstr ""
-#: forms.py:147
+#: forms.py:220
msgid "update summary:"
msgstr ""
-#: forms.py:148
+#: forms.py:221
msgid ""
"enter a brief summary of your revision (e.g. fixed spelling, grammar, "
"improved style, this field is optional)"
msgstr ""
-#: forms.py:204
+#: forms.py:284
msgid "Enter number of points to add or subtract"
msgstr ""
-#: forms.py:218 const/__init__.py:220
+#: forms.py:298 const/__init__.py:225
msgid "approved"
msgstr ""
-#: forms.py:219 const/__init__.py:221
+#: forms.py:299 const/__init__.py:226
msgid "watched"
msgstr ""
-#: forms.py:220 const/__init__.py:222
+#: forms.py:300 const/__init__.py:227
msgid "suspended"
msgstr ""
-#: forms.py:221 const/__init__.py:223
+#: forms.py:301 const/__init__.py:228
msgid "blocked"
msgstr ""
-#: forms.py:223 const/__init__.py:219
+#: forms.py:303 const/__init__.py:224
msgid "moderator"
msgstr ""
-#: forms.py:243
+#: forms.py:323
msgid "Change status to"
msgstr ""
-#: forms.py:270
+#: forms.py:350
msgid "which one?"
msgstr ""
-#: forms.py:291
+#: forms.py:371
msgid "Cannot change own status"
msgstr ""
-#: forms.py:297
+#: forms.py:377
msgid "Cannot turn other user to moderator"
msgstr ""
-#: forms.py:304
+#: forms.py:384
msgid "Cannot change status of another moderator"
msgstr ""
-#: forms.py:310
+#: forms.py:390
#, python-format
msgid ""
"If you wish to change %(username)s's status, please make a meaningful "
"selection."
msgstr ""
-#: forms.py:319
+#: forms.py:399
msgid "Subject line"
msgstr ""
-#: forms.py:326
+#: forms.py:406
msgid "Message text"
msgstr ""
-#: forms.py:403
+#: forms.py:489
msgid "Your name:"
msgstr ""
-#: forms.py:404
+#: forms.py:490
msgid "Email (not shared with anyone):"
msgstr ""
-#: forms.py:405
+#: forms.py:491
msgid "Your message:"
msgstr ""
-#: forms.py:492
-msgid "this email does not have to be linked to gravatar"
+#: forms.py:528
+msgid "ask anonymously"
+msgstr ""
+
+#: forms.py:530
+msgid "Check if you do not want to reveal your name when asking this question"
+msgstr ""
+
+#: forms.py:672
+msgid ""
+"You have asked this question anonymously, if you decide to reveal your "
+"identity, please check this box."
+msgstr ""
+
+#: forms.py:676
+msgid "reveal identity"
+msgstr ""
+
+#: forms.py:734
+msgid ""
+"Sorry, only owner of the anonymous question can reveal his or her identity, "
+"please uncheck the box"
msgstr ""
-#: forms.py:499
+#: forms.py:747
+msgid ""
+"Sorry, apparently rules have just changed - it is no longer possible to ask "
+"anonymously. Please either check the \"reveal identity\" box or reload this "
+"page and try editing the question again."
+msgstr ""
+
+#: forms.py:785
+msgid "this email will be linked to gravatar"
+msgstr ""
+
+#: forms.py:792
msgid "Real name"
msgstr ""
-#: forms.py:506
+#: forms.py:799
msgid "Website"
msgstr ""
-#: forms.py:513
-msgid "Location"
+#: forms.py:806
+msgid "City"
+msgstr ""
+
+#: forms.py:815
+msgid "Show country"
msgstr ""
-#: forms.py:520
+#: forms.py:820
msgid "Date of birth"
msgstr ""
-#: forms.py:521
+#: forms.py:821
msgid "will not be shown, used to calculate age, format: YYYY-MM-DD"
msgstr ""
-#: forms.py:527
+#: forms.py:827
msgid "Profile"
msgstr ""
-#: forms.py:536
+#: forms.py:836
msgid "Screen name"
msgstr ""
-#: forms.py:561 forms.py:562
+#: forms.py:867 forms.py:868
msgid "this email has already been registered, please use another one"
msgstr ""
-#: forms.py:568
+#: forms.py:875
msgid "Choose email tag filter"
msgstr ""
-#: forms.py:607
+#: forms.py:915
msgid "Asked by me"
msgstr ""
-#: forms.py:610
+#: forms.py:918
msgid "Answered by me"
msgstr ""
-#: forms.py:613
+#: forms.py:921
msgid "Individually selected"
msgstr ""
-#: forms.py:616
+#: forms.py:924
msgid "Entire forum (tag filtered)"
msgstr ""
-#: forms.py:620
+#: forms.py:928
msgid "Comments and posts mentioning me"
msgstr ""
-#: forms.py:678
+#: forms.py:998
msgid "okay, let's try!"
msgstr ""
-#: forms.py:679
+#: forms.py:999
msgid "no community email please, thanks"
msgstr "no askbot email please, thanks"
-#: forms.py:683
+#: forms.py:1003
msgid "please choose one of the options above"
msgstr ""
-#: urls.py:42
+#: urls.py:44
msgid "about/"
msgstr ""
-#: urls.py:43 conf/site_settings.py:79
+#: urls.py:45 conf/site_settings.py:79
msgid "faq/"
msgstr ""
-#: urls.py:44
+#: urls.py:46
msgid "privacy/"
msgstr ""
-#: urls.py:45
+#: urls.py:47
msgid "logout/"
msgstr ""
-#: urls.py:47 urls.py:52
+#: urls.py:49 urls.py:54
msgid "answers/"
msgstr ""
-#: urls.py:47 urls.py:68 urls.py:164
+#: urls.py:49 urls.py:75 urls.py:186
msgid "edit/"
msgstr ""
-#: urls.py:52 urls.py:98
+#: urls.py:54 urls.py:105
msgid "revisions/"
msgstr ""
-#: urls.py:58 urls.py:63 urls.py:68 urls.py:73 urls.py:78 urls.py:83
-#: urls.py:88 urls.py:93 urls.py:98 skins/default/templates/question.html:431
+#: urls.py:60 urls.py:70 urls.py:75 urls.py:80 urls.py:85 urls.py:90
+#: urls.py:95 urls.py:100 urls.py:105
+#: skins/default/templates/question.html:438
msgid "questions/"
msgstr ""
-#: urls.py:63
+#: urls.py:70
msgid "ask/"
msgstr ""
-#: urls.py:73
+#: urls.py:80
msgid "retag/"
msgstr ""
-#: urls.py:78
+#: urls.py:85
msgid "close/"
msgstr ""
-#: urls.py:83
+#: urls.py:90
msgid "reopen/"
msgstr ""
-#: urls.py:88
+#: urls.py:95
msgid "answer/"
msgstr ""
-#: urls.py:93 skins/default/templates/question.html:431
+#: urls.py:100 skins/default/templates/question.html:438
msgid "vote/"
msgstr ""
-#: urls.py:114
-msgid "command/"
-msgstr ""
-
-#: urls.py:130 skins/default/templates/question.html:429
-#: skins/default/templates/questions.html:252
+#: urls.py:132 skins/default/templates/question.html:436
+#: skins/default/templates/main_page/javascript.html:18
msgid "question/"
msgstr ""
-#: urls.py:135
+#: urls.py:137
msgid "tags/"
msgstr ""
-#: urls.py:140 urls.py:146 skins/default/templates/questions.html:247
-#: skins/default/templates/questions.html:248
-msgid "mark-tag/"
-msgstr ""
-
-#: urls.py:140 skins/default/templates/questions.html:247
-msgid "interesting/"
-msgstr ""
-
-#: urls.py:146 skins/default/templates/questions.html:248
-msgid "ignored/"
-msgstr ""
-
-#: urls.py:152 skins/default/templates/questions.html:249
-msgid "unmark-tag/"
+#: urls.py:175
+msgid "subscribe-for-tags/"
msgstr ""
-#: urls.py:158 urls.py:164 urls.py:169
-#: skins/default/templates/questions.html:253
+#: urls.py:180 urls.py:186 urls.py:191
+#: skins/default/templates/main_page/javascript.html:19
msgid "users/"
msgstr ""
-#: urls.py:174 urls.py:179
+#: urls.py:196 urls.py:201
msgid "badges/"
msgstr ""
-#: urls.py:184
+#: urls.py:206
msgid "messages/"
msgstr ""
-#: urls.py:184
+#: urls.py:206
msgid "markread/"
msgstr ""
-#: urls.py:200
+#: urls.py:222
msgid "upload/"
msgstr ""
-#: urls.py:201
-msgid "search/"
-msgstr ""
-
-#: urls.py:202
+#: urls.py:223
msgid "feedback/"
msgstr ""
-#: urls.py:203 setup_templates/settings.py:182
-#: skins/default/templates/authopenid/signin.html:249
+#: urls.py:224 setup_templates/settings.py:201
+#: skins/default/templates/authopenid/providers_javascript.html:7
msgid "account/"
msgstr ""
@@ -456,19 +481,41 @@ msgstr ""
msgid "Stellar Question: minimum stars"
msgstr ""
-#: conf/email.py:12
+#: conf/badges.py:210
+msgid "Commentator: minimum comments"
+msgstr ""
+
+#: conf/badges.py:219
+msgid "Taxonomist: minimum tag use count"
+msgstr ""
+
+#: conf/badges.py:228
+msgid "Enthusiast: minimum days"
+msgstr ""
+
+#: conf/email.py:14
msgid "Email and email alert settings"
msgstr ""
-#: conf/email.py:20
+#: conf/email.py:22
+msgid "Prefix for the email subject line"
+msgstr "Welcome to the Q&A forum"
+
+#: conf/email.py:24
+msgid ""
+"This setting takes default from the django settingEMAIL_SUBJECT_PREFIX. A "
+"value entered here will overridethe default."
+msgstr ""
+
+#: conf/email.py:36
msgid "Maximum number of news entries in an email alert"
msgstr ""
-#: conf/email.py:30
+#: conf/email.py:46
msgid "Default news notification frequency"
msgstr ""
-#: conf/email.py:32
+#: conf/email.py:48
msgid ""
"This option currently defines default frequency of emailed updates in the "
"following five categories: questions asked by user, answered by user, "
@@ -476,30 +523,52 @@ msgid ""
"posts mentioning the user and comment responses"
msgstr ""
-#: conf/email.py:47
+#: conf/email.py:63
msgid "Require email verification before allowing to post"
msgstr ""
-#: conf/email.py:48
+#: conf/email.py:64
msgid ""
"Active email verification is done by sending a verification key in email"
msgstr ""
-#: conf/email.py:57
+#: conf/email.py:73
msgid "Allow only one account per email address"
msgstr ""
-#: conf/email.py:66
+#: conf/email.py:82
msgid "Fake email for anonymous user"
msgstr ""
-#: conf/email.py:67
+#: conf/email.py:83
msgid "Use this setting to control gravatar for email-less user"
msgstr ""
-#: conf/email.py:76
-msgid "Prefix for the email subject line"
-msgstr "Welcome to the Q&A forum"
+#: conf/email.py:92
+#, fuzzy
+msgid "Allow posting questions by email"
+msgstr ""
+"<span class=\"strong big\">You are welcome to start submitting your question "
+"anonymously</span>. When you submit the post, you will be redirected to the "
+"login/signup page. Your question will be saved in the current session and "
+"will be published after you log in. Login/signup process is very simple. "
+"Login takes about 30 seconds, initial signup takes a minute or less."
+
+#: conf/email.py:94
+msgid ""
+"Before enabling this setting - please fill out IMAP settings in the settings."
+"py file"
+msgstr ""
+
+#: conf/email.py:105
+msgid "Replace space in emailed tags with dash"
+msgstr ""
+
+#: conf/email.py:107
+msgid ""
+"This setting applies to tags written in the subject line of questions asked "
+"by email"
+msgstr ""
#: conf/external_keys.py:11
msgid "Keys to connect the site with external services like Facebook, etc."
@@ -623,56 +692,144 @@ msgid ""
"the \"privacy\" page to check your input."
msgstr ""
-#: conf/forum_data_rules.py:12
+#: conf/forum_data_rules.py:11
msgid "Settings for askbot data entry and display"
msgstr ""
-#: conf/forum_data_rules.py:20
+#: conf/forum_data_rules.py:19
msgid "Check to enable community wiki feature"
msgstr ""
-#: conf/forum_data_rules.py:29
+#: conf/forum_data_rules.py:28
+msgid "Allow asking questions anonymously"
+msgstr ""
+
+#: conf/forum_data_rules.py:30
+msgid ""
+"Users do not accrue reputation for anonymous questions and their identity is "
+"not revealed until they change their mind"
+msgstr ""
+
+#: conf/forum_data_rules.py:42
msgid "Maximum length of tag (number of characters)"
msgstr ""
-#: conf/forum_data_rules.py:39
+#: conf/forum_data_rules.py:51
+msgid "Force lowercase the tags"
+msgstr ""
+
+#: conf/forum_data_rules.py:53
+msgid ""
+"Attention: after checking this, please back up the database, and run a "
+"management command: <code>python manage.py fix_question_tags</code> to "
+"globally rename the tags"
+msgstr ""
+
+#: conf/forum_data_rules.py:66
+#, fuzzy
+msgid "Use wildcard tags"
+msgstr "Tags"
+
+#: conf/forum_data_rules.py:68
+msgid ""
+"Wildcard tags can be used to follow or ignore many tags at once, a valid "
+"wildcard tag has a single wildcard at the very end"
+msgstr ""
+
+#: conf/forum_data_rules.py:81
msgid "Default max number of comments to display under posts"
msgstr ""
-#: conf/forum_data_rules.py:50
+#: conf/forum_data_rules.py:92
#, python-format
msgid "Maximum comment length, must be < %(max_len)s"
msgstr ""
-#: conf/forum_data_rules.py:60
+#: conf/forum_data_rules.py:102
+msgid "Limit time to edit comments"
+msgstr ""
+
+#: conf/forum_data_rules.py:104
+msgid "If unchecked, there will be no time limit to edit the comments"
+msgstr ""
+
+#: conf/forum_data_rules.py:115
+msgid "Minutes allowed to edit a comment"
+msgstr ""
+
+#: conf/forum_data_rules.py:116
+msgid "To enable this setting, check the previous one"
+msgstr ""
+
+#: conf/forum_data_rules.py:125
+msgid "Save comment by pressing <Enter> key"
+msgstr ""
+
+#: conf/forum_data_rules.py:134
msgid "Minimum length of search term for Ajax search"
msgstr ""
-#: conf/forum_data_rules.py:61
+#: conf/forum_data_rules.py:135
msgid "Must match the corresponding database backend setting"
msgstr ""
-#: conf/forum_data_rules.py:70
+#: conf/forum_data_rules.py:144
+msgid "Do not make text query sticky in search"
+msgstr ""
+
+#: conf/forum_data_rules.py:146
+msgid ""
+"Check to disable the \"sticky\" behavior of the search query. This may be "
+"useful if you want to move the search bar away from the default position or "
+"do not like the default sticky behavior of the text search query."
+msgstr ""
+
+#: conf/forum_data_rules.py:159
msgid "Maximum number of tags per question"
msgstr ""
-#: conf/forum_data_rules.py:82
+#: conf/forum_data_rules.py:171
msgid "Number of questions to list by default"
msgstr ""
-#: conf/forum_data_rules.py:92
+#: conf/forum_data_rules.py:181
msgid "What should \"unanswered question\" mean?"
msgstr ""
+#: conf/login_providers.py:11
+msgid "Login provider setings"
+msgstr ""
+
+#: conf/login_providers.py:19
+msgid ""
+"Show alternative login provider buttons on the password \"Sign Up\" page"
+msgstr ""
+
+#: conf/login_providers.py:28
+msgid "Always display local login form and hide \"Askbot\" button."
+msgstr ""
+
+#: conf/login_providers.py:55
+#, python-format
+msgid "Activate %(provider)s login"
+msgstr ""
+
+#: conf/login_providers.py:60
+#, python-format
+msgid ""
+"Note: to really enable %(provider)s login some additional parameters will "
+"need to be set in the \"External keys\" section"
+msgstr ""
+
#: conf/markup.py:15
msgid "Markup formatting"
msgstr ""
-#: conf/markup.py:29
+#: conf/markup.py:22
msgid "Enable code-friendly Markdown"
msgstr ""
-#: conf/markup.py:31
+#: conf/markup.py:24
msgid ""
"If checked, underscore characters will not trigger italic or bold formatting "
"- bold and italic text can still be marked up with asterisks. Note that "
@@ -680,22 +837,22 @@ msgid ""
"are heavily used in LaTeX input."
msgstr ""
-#: conf/markup.py:46
+#: conf/markup.py:39
msgid "Mathjax support (rendering of LaTeX)"
msgstr ""
-#: conf/markup.py:48
+#: conf/markup.py:41
#, python-format
msgid ""
"If you enable this feature, <a href=\"%(url)s\">mathjax</a> must be "
-"installed in directory %(dir)s"
+"installed on your server in its own directory."
msgstr ""
-#: conf/markup.py:63
+#: conf/markup.py:55
msgid "Base url of MathJax deployment"
msgstr ""
-#: conf/markup.py:65
+#: conf/markup.py:57
msgid ""
"Note - <strong>MathJax is not included with askbot</strong> - you should "
"deploy it yourself, preferably at a separate domain and enter url pointing "
@@ -766,6 +923,16 @@ msgstr ""
msgid "Lock posts"
msgstr ""
+#: conf/minimum_reputation.py:155
+msgid "Remove rel=nofollow from own homepage"
+msgstr ""
+
+#: conf/minimum_reputation.py:157
+msgid ""
+"When a search engine crawler will see a rel=nofollow attribute on a link - "
+"the link will not count towards the rank of the users personal site."
+msgstr ""
+
#: conf/reputation_changes.py:12
msgid "Reputation loss and gain rules"
msgstr ""
@@ -981,33 +1148,33 @@ msgstr ""
msgid "Foreground color for accepted answer"
msgstr ""
-#: conf/skin_general_settings.py:15
+#: conf/skin_general_settings.py:14
msgid "Skin and User Interface settings"
msgstr ""
-#: conf/skin_general_settings.py:22
+#: conf/skin_general_settings.py:21
msgid "Q&A site logo"
msgstr ""
-#: conf/skin_general_settings.py:24
+#: conf/skin_general_settings.py:23
msgid "To change the logo, select new file, then submit this whole form."
msgstr ""
-#: conf/skin_general_settings.py:38
+#: conf/skin_general_settings.py:37
msgid "Show logo"
msgstr ""
-#: conf/skin_general_settings.py:40
+#: conf/skin_general_settings.py:39
msgid ""
"Check if you want to show logo in the forum header or uncheck in the case "
"you do not want the logo to appear in the default location"
msgstr ""
-#: conf/skin_general_settings.py:52
+#: conf/skin_general_settings.py:51
msgid "Site favicon"
msgstr ""
-#: conf/skin_general_settings.py:54
+#: conf/skin_general_settings.py:53
#, python-format
msgid ""
"A small 16x16 or 32x32 pixel icon image used to distinguish your site in the "
@@ -1025,39 +1192,120 @@ msgid ""
"button."
msgstr ""
-#: conf/skin_general_settings.py:86
-msgid "Show footer"
-msgstr ""
-
-#: conf/skin_general_settings.py:88
-msgid "Check if you want to show the footer on each forum page"
-msgstr ""
-
-#: conf/skin_general_settings.py:99
+#: conf/skin_general_settings.py:87
msgid "Show all UI functions to all users"
msgstr ""
-#: conf/skin_general_settings.py:101
+#: conf/skin_general_settings.py:89
msgid ""
"If checked, all forum functions will be shown to users, regardless of their "
"reputation. However to use those functions, moderation rules, reputation and "
"other limits will still apply."
msgstr ""
-#: conf/skin_general_settings.py:116
+#: conf/skin_general_settings.py:104
msgid "Select skin"
msgstr ""
-#: conf/skin_general_settings.py:125
+#: conf/skin_general_settings.py:113
msgid "Skin media revision number"
msgstr ""
-#: conf/skin_general_settings.py:127
+#: conf/skin_general_settings.py:115
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 ""
+#: conf/skin_general_settings.py:128
+msgid "Customize HTML <HEAD>"
+msgstr ""
+
+#: conf/skin_general_settings.py:137
+msgid "Custom portion of the HTML <HEAD>"
+msgstr ""
+
+#: conf/skin_general_settings.py:139
+msgid ""
+"<strong>To use this option</strong>, check \"Customize HTML &lt;HEAD&gt;\" "
+"above. Contents of this box will be inserted into the &lt;HEAD&gt; portion "
+"of the HTML output, where elements such as &lt;script&gt;, &lt;link&gt;, &lt;"
+"meta&gt; may be added. Please, keep in mind that adding external javascript "
+"to the &lt;HEAD&gt; is not recommended because it slows loading of the "
+"pages. Instead, it will be more efficient to place links to the javascript "
+"files into the footer. <strong>Note:</strong> if you do use this setting, "
+"please test the site with the W3C HTML validator service."
+msgstr ""
+
+#: conf/skin_general_settings.py:159
+msgid "Site footer mode"
+msgstr ""
+
+#: conf/skin_general_settings.py:161
+msgid ""
+"Footer is the bottom portion of the content, which is common to all pages. "
+"You can disable, customize, or use the default footer."
+msgstr ""
+
+#: conf/skin_general_settings.py:178
+msgid "Custom footer (HTML format)"
+msgstr ""
+
+#: conf/skin_general_settings.py:180
+msgid ""
+"<strong>To enable this function</strong>, please select option 'customize' "
+"in the \"Site footer mode\" above. Use this area to enter contents of the "
+"footer in the HTML format. When customizing the site footer (as well as the "
+"HTML &lt;HEAD&gt;), use the HTML validation service to make sure that your "
+"input is valid and works well in all browsers."
+msgstr ""
+
+#: conf/skin_general_settings.py:195
+msgid "Apply custom style sheet (CSS)"
+msgstr ""
+
+#: conf/skin_general_settings.py:197
+msgid ""
+"Check if you want to change appearance of your form by adding custom style "
+"sheet rules (please see the next item)"
+msgstr ""
+
+#: conf/skin_general_settings.py:209
+msgid "Custom style sheet (CSS)"
+msgstr ""
+
+#: conf/skin_general_settings.py:211
+msgid ""
+"<strong>To use this function</strong>, check \"Apply custom style sheet\" "
+"option above. The CSS rules added in this window will be applied after the "
+"default style sheet rules. The custom style sheet will be served dynamically "
+"at url \"&lt;forum url&gt;/custom.css\", where the \"&lt;forum url&gt; part "
+"depends (default is empty string) on the url configuration in your urls.py."
+msgstr ""
+
+#: conf/skin_general_settings.py:227
+msgid "Add custom javascript"
+msgstr ""
+
+#: conf/skin_general_settings.py:230
+msgid "Check to enable javascript that you can enter in the next field"
+msgstr ""
+
+#: conf/skin_general_settings.py:240
+msgid "Custom javascript"
+msgstr ""
+
+#: conf/skin_general_settings.py:242
+msgid ""
+"Type or paste plain javascript that you would like to run on your site. Link "
+"to the script will be inserted at the bottom of the HTML output and will be "
+"served at the url \"&lt;forum url&gt;/custom.js\". Please, bear in mind that "
+"your javascript code may break other functionalities of the site and that "
+"the behavior may not be consistent across different browsers (<strong>to "
+"enable your custom code</strong>, check \"Add custom javascript\" option "
+"above)."
+msgstr ""
+
#: conf/social_sharing.py:10
msgid "Sharing content on social networks"
msgstr ""
@@ -1078,6 +1326,10 @@ msgstr ""
msgid "Minimum allowed length for screen name"
msgstr ""
+#: conf/user_settings.py:37
+msgid "Name for the Anonymous user"
+msgstr ""
+
#: conf/vote_rules.py:13
msgid "Limits applicable to votes and moderation flags"
msgstr ""
@@ -1175,20 +1427,20 @@ msgstr ""
msgid "least voted"
msgstr ""
-#: const/__init__.py:48 skins/default/templates/questions.html:33
+#: const/__init__.py:48 skins/default/templates/main_page/tab_bar.html:29
msgid "relevance"
msgstr ""
-#: const/__init__.py:55 skins/default/templates/questions.html:14
-#: skins/default/templates/user_inbox.html:47
+#: const/__init__.py:55 skins/default/templates/main_page/tab_bar.html:10
+#: skins/default/templates/user_profile/user_inbox.html:50
msgid "all"
msgstr ""
-#: const/__init__.py:56 skins/default/templates/questions.html:19
+#: const/__init__.py:56 skins/default/templates/main_page/tab_bar.html:15
msgid "unanswered"
msgstr ""
-#: const/__init__.py:57 skins/default/templates/questions.html:25
+#: const/__init__.py:57 skins/default/templates/main_page/tab_bar.html:21
msgid "favorite"
msgstr ""
@@ -1200,147 +1452,151 @@ msgstr ""
msgid "Question has no accepted answers"
msgstr ""
-#: const/__init__.py:112
+#: const/__init__.py:113
msgid "asked a question"
msgstr ""
-#: const/__init__.py:113
+#: const/__init__.py:114
msgid "answered a question"
msgstr ""
-#: const/__init__.py:114
+#: const/__init__.py:115
msgid "commented question"
msgstr ""
-#: const/__init__.py:115
+#: const/__init__.py:116
msgid "commented answer"
msgstr ""
-#: const/__init__.py:116
+#: const/__init__.py:117
msgid "edited question"
msgstr ""
-#: const/__init__.py:117
+#: const/__init__.py:118
msgid "edited answer"
msgstr ""
-#: const/__init__.py:118
+#: const/__init__.py:119
msgid "received award"
msgstr "received badge"
-#: const/__init__.py:119
+#: const/__init__.py:120
msgid "marked best answer"
msgstr ""
-#: const/__init__.py:120
+#: const/__init__.py:121
msgid "upvoted"
msgstr ""
-#: const/__init__.py:121
+#: const/__init__.py:122
msgid "downvoted"
msgstr ""
-#: const/__init__.py:122
+#: const/__init__.py:123
msgid "canceled vote"
msgstr ""
-#: const/__init__.py:123
+#: const/__init__.py:124
msgid "deleted question"
msgstr ""
-#: const/__init__.py:124
+#: const/__init__.py:125
msgid "deleted answer"
msgstr ""
-#: const/__init__.py:125
+#: const/__init__.py:126
msgid "marked offensive"
msgstr ""
-#: const/__init__.py:126
+#: const/__init__.py:127
msgid "updated tags"
msgstr ""
-#: const/__init__.py:127
+#: const/__init__.py:128
msgid "selected favorite"
msgstr ""
-#: const/__init__.py:128
+#: const/__init__.py:129
msgid "completed user profile"
msgstr ""
-#: const/__init__.py:129
+#: const/__init__.py:130
msgid "email update sent to user"
msgstr ""
-#: const/__init__.py:130
+#: const/__init__.py:131
msgid "mentioned in the post"
msgstr ""
-#: const/__init__.py:181
+#: const/__init__.py:182
msgid "question_answered"
msgstr "answered question"
-#: const/__init__.py:182
+#: const/__init__.py:183
msgid "question_commented"
msgstr "commented question"
-#: const/__init__.py:183
+#: const/__init__.py:184
msgid "answer_commented"
msgstr ""
-#: const/__init__.py:184
+#: const/__init__.py:185
msgid "answer_accepted"
msgstr ""
-#: const/__init__.py:188
+#: const/__init__.py:189
msgid "[closed]"
msgstr ""
-#: const/__init__.py:189
+#: const/__init__.py:190
msgid "[deleted]"
msgstr ""
-#: const/__init__.py:190 views/readers.py:602
+#: const/__init__.py:191 views/readers.py:561
msgid "initial version"
msgstr ""
-#: const/__init__.py:191
+#: const/__init__.py:192
msgid "retagged"
msgstr ""
-#: const/__init__.py:196
-msgid "exclude ignored tags"
+#: const/__init__.py:200
+msgid "off"
msgstr ""
-#: const/__init__.py:197
-msgid "allow only selected tags"
+#: const/__init__.py:201
+msgid "exclude ignored"
msgstr ""
-#: const/__init__.py:201
+#: const/__init__.py:202
+msgid "only selected"
+msgstr ""
+
+#: const/__init__.py:206
msgid "instantly"
msgstr ""
-#: const/__init__.py:202
+#: const/__init__.py:207
msgid "daily"
msgstr ""
-#: const/__init__.py:203
+#: const/__init__.py:208
msgid "weekly"
msgstr ""
-#: const/__init__.py:204
+#: const/__init__.py:209
msgid "no email"
msgstr ""
-#: const/__init__.py:241 skins/default/templates/badges.html:43
+#: const/__init__.py:246 skins/default/templates/badges.html:37
msgid "gold"
msgstr ""
-#: const/__init__.py:242 skins/default/templates/badges.html:52
+#: const/__init__.py:247 skins/default/templates/badges.html:46
msgid "silver"
msgstr ""
-#: const/__init__.py:243 skins/default/templates/badges.html:59
+#: const/__init__.py:248 skins/default/templates/badges.html:53
msgid "bronze"
msgstr ""
@@ -1349,11 +1605,11 @@ msgstr ""
msgid "First time here? Check out the <a href=\"%s\">FAQ</a>!"
msgstr ""
-#: const/message_keys.py:22 skins/default/templates/questions.html:31
+#: const/message_keys.py:22 skins/default/templates/main_page/tab_bar.html:27
msgid "most relevant questions"
msgstr ""
-#: const/message_keys.py:23 skins/default/templates/questions.html:32
+#: const/message_keys.py:23 skins/default/templates/main_page/tab_bar.html:28
msgid "click to see most relevant questions"
msgstr ""
@@ -1409,255 +1665,256 @@ msgstr "votes"
msgid "click to see most voted questions"
msgstr ""
-#: deps/django_authopenid/forms.py:116 deps/django_authopenid/views.py:137
+#: deps/django_authopenid/forms.py:110 deps/django_authopenid/views.py:134
msgid "i-names are not supported"
msgstr ""
-#: deps/django_authopenid/forms.py:237
+#: deps/django_authopenid/forms.py:231
#, python-format
msgid "Please enter your %(username_token)s"
msgstr ""
-#: deps/django_authopenid/forms.py:263
+#: deps/django_authopenid/forms.py:257
msgid "Please, enter your user name"
msgstr ""
-#: deps/django_authopenid/forms.py:267
+#: deps/django_authopenid/forms.py:261
msgid "Please, enter your password"
msgstr ""
-#: deps/django_authopenid/forms.py:274 deps/django_authopenid/forms.py:278
+#: deps/django_authopenid/forms.py:268 deps/django_authopenid/forms.py:272
msgid "Please, enter your new password"
msgstr ""
-#: deps/django_authopenid/forms.py:289
+#: deps/django_authopenid/forms.py:283
msgid "Passwords did not match"
msgstr ""
-#: deps/django_authopenid/forms.py:301
+#: deps/django_authopenid/forms.py:295
#, python-format
msgid "Please choose password > %(len)s characters"
msgstr ""
-#: deps/django_authopenid/forms.py:336
+#: deps/django_authopenid/forms.py:330
msgid "Current password"
msgstr ""
-#: deps/django_authopenid/forms.py:347
+#: deps/django_authopenid/forms.py:341
msgid ""
"Old password is incorrect. Please enter the correct "
"password."
msgstr ""
-#: deps/django_authopenid/forms.py:400
+#: deps/django_authopenid/forms.py:394
msgid "Sorry, we don't have this email address in the database"
msgstr ""
-#: deps/django_authopenid/forms.py:435
+#: deps/django_authopenid/forms.py:430
msgid "Your user name (<i>required</i>)"
msgstr ""
-#: deps/django_authopenid/forms.py:450
+#: deps/django_authopenid/forms.py:445
msgid "Incorrect username."
msgstr "sorry, there is no such user name"
-#: deps/django_authopenid/urls.py:10 deps/django_authopenid/urls.py:11
-#: deps/django_authopenid/urls.py:12 deps/django_authopenid/urls.py:15
-#: deps/django_authopenid/urls.py:18 setup_templates/settings.py:182
+#: deps/django_authopenid/urls.py:9 deps/django_authopenid/urls.py:10
+#: deps/django_authopenid/urls.py:11 deps/django_authopenid/urls.py:14
+#: deps/django_authopenid/urls.py:17 setup_templates/settings.py:201
msgid "signin/"
msgstr ""
-#: deps/django_authopenid/urls.py:11
+#: deps/django_authopenid/urls.py:10
msgid "newquestion/"
msgstr ""
-#: deps/django_authopenid/urls.py:12
+#: deps/django_authopenid/urls.py:11
msgid "newanswer/"
msgstr ""
-#: deps/django_authopenid/urls.py:13
+#: deps/django_authopenid/urls.py:12
msgid "signout/"
msgstr ""
-#: deps/django_authopenid/urls.py:15
+#: deps/django_authopenid/urls.py:14
msgid "complete/"
msgstr ""
-#: deps/django_authopenid/urls.py:18
+#: deps/django_authopenid/urls.py:17
msgid "complete-oauth/"
msgstr ""
-#: deps/django_authopenid/urls.py:22
+#: deps/django_authopenid/urls.py:21
msgid "register/"
msgstr ""
-#: deps/django_authopenid/urls.py:24
+#: deps/django_authopenid/urls.py:23
msgid "signup/"
msgstr ""
-#: deps/django_authopenid/urls.py:32
+#: deps/django_authopenid/urls.py:31
msgid "recover/"
msgstr ""
-#: deps/django_authopenid/util.py:196
+#: deps/django_authopenid/util.py:193
#, python-format
msgid "%(site)s user name and password"
msgstr ""
-#: deps/django_authopenid/util.py:202
-#: skins/default/templates/authopenid/signin.html:124
+#: deps/django_authopenid/util.py:199
+#: skins/default/templates/authopenid/signin.html:99
msgid "Create a password-protected account"
msgstr ""
-#: deps/django_authopenid/util.py:203
+#: deps/django_authopenid/util.py:200
msgid "Change your password"
msgstr ""
-#: deps/django_authopenid/util.py:265
+#: deps/django_authopenid/util.py:262
msgid "Sign in with Yahoo"
msgstr ""
-#: deps/django_authopenid/util.py:272
+#: deps/django_authopenid/util.py:269
msgid "AOL screen name"
msgstr ""
-#: deps/django_authopenid/util.py:280
+#: deps/django_authopenid/util.py:277
msgid "OpenID url"
msgstr ""
-#: deps/django_authopenid/util.py:297
+#: deps/django_authopenid/util.py:294
msgid "MyOpenid user name"
msgstr ""
-#: deps/django_authopenid/util.py:305 deps/django_authopenid/util.py:313
+#: deps/django_authopenid/util.py:302
msgid "Flickr user name"
msgstr ""
-#: deps/django_authopenid/util.py:321
+#: deps/django_authopenid/util.py:310
msgid "Technorati user name"
msgstr ""
-#: deps/django_authopenid/util.py:329
+#: deps/django_authopenid/util.py:318
msgid "WordPress blog name"
msgstr ""
-#: deps/django_authopenid/util.py:337
+#: deps/django_authopenid/util.py:326
msgid "Blogger blog name"
msgstr ""
-#: deps/django_authopenid/util.py:345
+#: deps/django_authopenid/util.py:334
msgid "LiveJournal blog name"
msgstr ""
-#: deps/django_authopenid/util.py:353
+#: deps/django_authopenid/util.py:342
msgid "ClaimID user name"
msgstr ""
-#: deps/django_authopenid/util.py:361
+#: deps/django_authopenid/util.py:350
msgid "Vidoop user name"
msgstr ""
-#: deps/django_authopenid/util.py:369
+#: deps/django_authopenid/util.py:358
msgid "Verisign user name"
msgstr ""
-#: deps/django_authopenid/util.py:393
+#: deps/django_authopenid/util.py:382
#, python-format
msgid "Change your %(provider)s password"
msgstr ""
-#: deps/django_authopenid/util.py:397
+#: deps/django_authopenid/util.py:386
#, python-format
msgid "Click to see if your %(provider)s signin still works for %(site_name)s"
msgstr ""
-#: deps/django_authopenid/util.py:406
+#: deps/django_authopenid/util.py:395
#, python-format
msgid "Create password for %(provider)s"
msgstr ""
-#: deps/django_authopenid/util.py:410
+#: deps/django_authopenid/util.py:399
#, python-format
msgid "Connect your %(provider)s account to %(site_name)s"
msgstr ""
-#: deps/django_authopenid/util.py:419
+#: deps/django_authopenid/util.py:408
#, python-format
msgid "Signin with %(provider)s user name and password"
msgstr ""
-#: deps/django_authopenid/util.py:426
+#: deps/django_authopenid/util.py:415
#, python-format
msgid "Sign in with your %(provider)s account"
msgstr ""
-#: deps/django_authopenid/views.py:144
+#: deps/django_authopenid/views.py:141
#, python-format
msgid "OpenID %(openid_url)s is invalid"
msgstr ""
-#: deps/django_authopenid/views.py:256 deps/django_authopenid/views.py:399
-#: deps/django_authopenid/views.py:427
+#: deps/django_authopenid/views.py:253 deps/django_authopenid/views.py:395
+#: deps/django_authopenid/views.py:423
#, python-format
msgid ""
"Unfortunately, there was some problem when connecting to %(provider)s, "
"please try again or use another provider"
msgstr ""
-#: deps/django_authopenid/views.py:349
+#: deps/django_authopenid/views.py:345
msgid "Your new password saved"
msgstr ""
-#: deps/django_authopenid/views.py:511
+#: deps/django_authopenid/views.py:507
msgid "Please click any of the icons below to sign in"
msgstr ""
-#: deps/django_authopenid/views.py:513
+#: deps/django_authopenid/views.py:509
msgid "Account recovery email sent"
msgstr ""
-#: deps/django_authopenid/views.py:516
+#: deps/django_authopenid/views.py:512
msgid "Please add one or more login methods."
msgstr ""
-#: deps/django_authopenid/views.py:518
+#: deps/django_authopenid/views.py:514
msgid "If you wish, please add, remove or re-validate your login methods"
msgstr ""
-#: deps/django_authopenid/views.py:520
+#: deps/django_authopenid/views.py:516
msgid "Please wait a second! Your account is recovered, but ..."
msgstr ""
-#: deps/django_authopenid/views.py:522
+#: deps/django_authopenid/views.py:518
msgid "Sorry, this account recovery key has expired or is invalid"
msgstr ""
-#: deps/django_authopenid/views.py:578
+#: deps/django_authopenid/views.py:572
#, python-format
msgid "Login method %(provider_name)s does not exist"
msgstr ""
-#: deps/django_authopenid/views.py:584
+#: deps/django_authopenid/views.py:578
msgid "Oops, sorry - there was some error - please try again"
msgstr ""
-#: deps/django_authopenid/views.py:675
+#: deps/django_authopenid/views.py:669
#, python-format
msgid "Your %(provider)s login works fine"
msgstr ""
-#: deps/django_authopenid/views.py:973 deps/django_authopenid/views.py:979
+#: deps/django_authopenid/views.py:976 deps/django_authopenid/views.py:982
#, 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>."
-#: deps/django_authopenid/views.py:1000
-msgid "Email verification subject line"
-msgstr "Verification Email from Q&A forum"
+#: deps/django_authopenid/views.py:1003
+#, python-format
+msgid "Recover your %(site)s account"
+msgstr ""
-#: deps/django_authopenid/views.py:1065
+#: deps/django_authopenid/views.py:1069
msgid "Please check your email and visit the enclosed link."
msgstr ""
@@ -1665,24 +1922,24 @@ msgstr ""
msgid "Site"
msgstr ""
-#: deps/livesettings/values.py:107
+#: deps/livesettings/values.py:106
msgid "Base Settings"
msgstr ""
-#: deps/livesettings/values.py:214
+#: deps/livesettings/values.py:213
msgid "Default value: \"\""
msgstr ""
-#: deps/livesettings/values.py:221
+#: deps/livesettings/values.py:220
msgid "Default value: "
msgstr ""
-#: deps/livesettings/values.py:224
+#: deps/livesettings/values.py:223
#, python-format
msgid "Default value: %s"
msgstr ""
-#: deps/livesettings/values.py:589
+#: deps/livesettings/values.py:588
#, python-format
msgid "Allowed image file types are %(types)s"
msgstr ""
@@ -1698,7 +1955,7 @@ msgstr ""
#: deps/livesettings/templates/livesettings/group_settings.html:11
#: deps/livesettings/templates/livesettings/site_settings.html:23
-#: skins/default/templates/authopenid/signin.html:142
+#: skins/default/templates/authopenid/signin.html:117
msgid "Change password"
msgstr ""
@@ -1790,27 +2047,58 @@ msgstr ""
msgid "Invalid request"
msgstr ""
-#: importers/stackexchange/management/commands/load_stackexchange.py:126
+#: importers/stackexchange/management/commands/load_stackexchange.py:128
msgid "Congratulations, you are now an Administrator"
msgstr ""
-#: management/commands/send_email_alerts.py:105
+#: management/commands/post_emailed_questions.py:34
+msgid ""
+"<p>To ask by email, please:</p>\n"
+"<ul>\n"
+" <li>Format the subject line as: [Tag1; Tag2] Question title</li>\n"
+" <li>Type details of your question into the email body</li>\n"
+"</ul>\n"
+"<p>Note that tags may consist of more than one word, and tags\n"
+"may be separated by a semicolon or a comma</p>\n"
+msgstr ""
+
+#: management/commands/post_emailed_questions.py:54
+#, python-format
+msgid ""
+"<p>Sorry, there was an error posting your question please contact the %(site)"
+"s administrator</p>"
+msgstr ""
+
+#: management/commands/post_emailed_questions.py:60
+#, python-format
+msgid ""
+"<p>Sorry, in order to post questions on %(site)s by email, please <a href=\"%"
+"(url)s\">register first</a></p>"
+msgstr ""
+
+#: management/commands/post_emailed_questions.py:68
+msgid ""
+"<p>Sorry, your question could not be posted due to insufficient privileges "
+"of your user account</p>"
+msgstr ""
+
+#: management/commands/send_email_alerts.py:103
#, python-format
msgid "\" and \"%s\""
msgstr ""
-#: management/commands/send_email_alerts.py:108
+#: management/commands/send_email_alerts.py:106
msgid "\" and more"
msgstr ""
-#: management/commands/send_email_alerts.py:113
+#: management/commands/send_email_alerts.py:111
#, python-format
msgid "%(question_count)d updated question about %(topics)s"
msgid_plural "%(question_count)d updated questions about %(topics)s"
msgstr[0] ""
msgstr[1] ""
-#: management/commands/send_email_alerts.py:467
+#: management/commands/send_email_alerts.py:484
#, 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"
@@ -1821,38 +2109,38 @@ msgstr[1] ""
"<p>Dear %(name)s,</p><p>The following %(num)d questions have been updated on "
"the Q&A forum:</p>"
-#: management/commands/send_email_alerts.py:484
+#: management/commands/send_email_alerts.py:501
msgid "new question"
msgstr ""
-#: management/commands/send_email_alerts.py:501
+#: management/commands/send_email_alerts.py:518
msgid ""
"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?"
msgstr ""
-#: management/commands/send_email_alerts.py:513
+#: management/commands/send_email_alerts.py:530
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 askbot administrator."
msgstr ""
-#: management/commands/send_email_alerts.py:519
+#: management/commands/send_email_alerts.py:536
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 askbot "
"administrator."
msgstr ""
-#: management/commands/send_email_alerts.py:525
+#: management/commands/send_email_alerts.py:542
msgid ""
"There is a chance that you may be receiving links seen before - due to a "
"technicality that will eventually go away. "
msgstr ""
-#: management/commands/send_email_alerts.py:530
+#: management/commands/send_email_alerts.py:548
#, python-format
msgid ""
"go to %(email_settings_link)s to change frequency of email updates or %"
@@ -1864,136 +2152,141 @@ msgstr ""
"it the forum administrator at %(admin_email)s.</p><p>Sincerely,</p><p>Your "
"friendly Q&A forum server.</p>"
-#: models/__init__.py:170
+#: models/__init__.py:299
msgid ""
"Sorry, you cannot accept or unaccept best answers because your account is "
"blocked"
msgstr ""
-#: models/__init__.py:175
+#: models/__init__.py:304
msgid ""
"Sorry, you cannot accept or unaccept best answers because your account is "
"suspended"
msgstr ""
-#: models/__init__.py:181
+#: models/__init__.py:310
msgid ""
"Sorry, you cannot accept or unaccept your own answer to your own question"
msgstr ""
-#: models/__init__.py:188
+#: models/__init__.py:317
#, python-format
msgid ""
"Sorry, only original author of the question - %(username)s - can accept the "
"best answer"
msgstr ""
-#: models/__init__.py:211
+#: models/__init__.py:340
msgid "cannot vote for own posts"
msgstr "Sorry, you cannot vote for your own posts"
-#: models/__init__.py:214
+#: models/__init__.py:343
msgid "Sorry your account appears to be blocked "
msgstr ""
-#: models/__init__.py:219
+#: models/__init__.py:348
msgid "Sorry your account appears to be suspended "
msgstr ""
-#: models/__init__.py:229
+#: models/__init__.py:358
#, python-format
msgid ">%(points)s points required to upvote"
msgstr ">%(points)s points required to upvote "
-#: models/__init__.py:235
+#: models/__init__.py:364
#, python-format
msgid ">%(points)s points required to downvote"
msgstr ">%(points)s points required to downvote "
-#: models/__init__.py:250
+#: models/__init__.py:379
msgid "Sorry, blocked users cannot upload files"
msgstr ""
-#: models/__init__.py:251
+#: models/__init__.py:380
msgid "Sorry, suspended users cannot upload files"
msgstr ""
-#: models/__init__.py:253
+#: models/__init__.py:382
#, python-format
msgid ""
"uploading images is limited to users with >%(min_rep)s reputation points"
msgstr "sorry, file uploading requires karma >%(min_rep)s"
-#: models/__init__.py:272 models/__init__.py:332 models/__init__.py:2021
+#: models/__init__.py:401 models/__init__.py:468 models/__init__.py:2344
msgid "blocked users cannot post"
msgstr ""
"Sorry, your account appears to be blocked and you cannot make new posts "
"until this issue is resolved. Please contact the forum administrator to "
"reach a resolution."
-#: models/__init__.py:273 models/__init__.py:2024
+#: models/__init__.py:402 models/__init__.py:2347
msgid "suspended users cannot post"
msgstr ""
"Sorry, your account appears to be suspended and you cannot make new posts "
"until this issue is resolved. You can, however edit your existing posts. "
"Please contact the forum administrator to reach a resolution."
-#: models/__init__.py:298
+#: models/__init__.py:429
+#, python-format
msgid ""
-"Sorry, comments (except the last one) are editable only within 10 minutes "
-"from posting"
-msgstr ""
+"Sorry, comments (except the last one) are editable only within %(minutes)s "
+"minute from posting"
+msgid_plural ""
+"Sorry, comments (except the last one) are editable only within %(minutes)s "
+"minutes from posting"
+msgstr[0] ""
+msgstr[1] ""
-#: models/__init__.py:304
+#: models/__init__.py:441
msgid "Sorry, but only post owners or moderators can edit comments"
msgstr ""
-#: models/__init__.py:318
+#: models/__init__.py:454
msgid ""
"Sorry, since your account is suspended you can comment only your own posts"
msgstr ""
-#: models/__init__.py:322
+#: models/__init__.py:458
#, python-format
msgid ""
"Sorry, to comment any post a minimum reputation of %(min_rep)s points is "
"required. You can still comment your own posts and answers to your questions"
msgstr ""
-#: models/__init__.py:350
+#: models/__init__.py:486
msgid ""
"This post has been deleted and can be seen only by post owners, site "
"administrators and moderators"
msgstr ""
-#: models/__init__.py:367
+#: models/__init__.py:503
msgid ""
"Sorry, only moderators, site administrators and post owners can edit deleted "
"posts"
msgstr ""
-#: models/__init__.py:382
+#: models/__init__.py:518
msgid "Sorry, since your account is blocked you cannot edit posts"
msgstr ""
-#: models/__init__.py:386
+#: models/__init__.py:522
msgid "Sorry, since your account is suspended you can edit only your own posts"
msgstr ""
-#: models/__init__.py:391
+#: models/__init__.py:527
#, python-format
msgid ""
"Sorry, to edit wiki posts, a minimum reputation of %(min_rep)s is required"
msgstr ""
-#: models/__init__.py:398
+#: models/__init__.py:534
#, python-format
msgid ""
"Sorry, to edit other people's posts, a minimum reputation of %(min_rep)s is "
"required"
msgstr ""
-#: models/__init__.py:461
+#: models/__init__.py:597
msgid ""
"Sorry, cannot delete your question since it has an upvoted answer posted by "
"someone else"
@@ -2003,207 +2296,215 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
-#: models/__init__.py:476
+#: models/__init__.py:612
msgid "Sorry, since your account is blocked you cannot delete posts"
msgstr ""
-#: models/__init__.py:480
+#: models/__init__.py:616
msgid ""
"Sorry, since your account is suspended you can delete only your own posts"
msgstr ""
-#: models/__init__.py:484
+#: models/__init__.py:620
#, python-format
msgid ""
"Sorry, to deleted other people' posts, a minimum reputation of %(min_rep)s "
"is required"
msgstr ""
-#: models/__init__.py:504
+#: models/__init__.py:640
msgid "Sorry, since your account is blocked you cannot close questions"
msgstr ""
-#: models/__init__.py:508
+#: models/__init__.py:644
msgid "Sorry, since your account is suspended you cannot close questions"
msgstr ""
-#: models/__init__.py:512
+#: models/__init__.py:648
#, python-format
msgid ""
"Sorry, to close other people' posts, a minimum reputation of %(min_rep)s is "
"required"
msgstr ""
-#: models/__init__.py:521
+#: models/__init__.py:657
#, python-format
msgid ""
"Sorry, to close own question a minimum reputation of %(min_rep)s is required"
msgstr ""
-#: models/__init__.py:545
+#: models/__init__.py:681
#, python-format
msgid ""
"Sorry, only administrators, moderators or post owners with reputation > %"
"(min_rep)s can reopen questions."
msgstr ""
-#: models/__init__.py:551
+#: models/__init__.py:687
#, python-format
msgid ""
"Sorry, to reopen own question a minimum reputation of %(min_rep)s is required"
msgstr ""
-#: models/__init__.py:571
+#: models/__init__.py:707
msgid "cannot flag message as offensive twice"
msgstr "You have flagged this question before and cannot do it more than once"
-#: models/__init__.py:576
+#: models/__init__.py:712
msgid "blocked users cannot flag posts"
msgstr ""
"Sorry, since your account is blocked you cannot flag posts as offensive"
-#: models/__init__.py:578
+#: models/__init__.py:714
msgid "suspended users cannot flag posts"
msgstr ""
"Sorry, your account appears to be suspended and you cannot make new posts "
"until this issue is resolved. You can, however edit your existing posts. "
"Please contact the forum administrator to reach a resolution."
-#: models/__init__.py:580
+#: models/__init__.py:716
#, python-format
msgid "need > %(min_rep)s points to flag spam"
msgstr ""
"Sorry, to flag posts as offensive a minimum reputation of %(min_rep)s is "
"required"
-#: models/__init__.py:599
+#: models/__init__.py:735
#, python-format
msgid "%(max_flags_per_day)s exceeded"
msgstr ""
"Sorry, you have exhausted the maximum number of %(max_flags_per_day)s "
"offensive flags per day."
-#: models/__init__.py:614
+#: models/__init__.py:750
msgid ""
"Sorry, only question owners, site administrators and moderators can retag "
"deleted questions"
msgstr ""
-#: models/__init__.py:621
+#: models/__init__.py:757
msgid "Sorry, since your account is blocked you cannot retag questions"
msgstr ""
-#: models/__init__.py:625
+#: models/__init__.py:761
msgid ""
"Sorry, since your account is suspended you can retag only your own questions"
msgstr ""
-#: models/__init__.py:629
+#: models/__init__.py:765
#, python-format
msgid ""
"Sorry, to retag questions a minimum reputation of %(min_rep)s is required"
msgstr ""
-#: models/__init__.py:648
+#: models/__init__.py:784
msgid "Sorry, since your account is blocked you cannot delete comment"
msgstr ""
-#: models/__init__.py:652
+#: models/__init__.py:788
msgid ""
"Sorry, since your account is suspended you can delete only your own comments"
msgstr ""
-#: models/__init__.py:656
+#: models/__init__.py:792
#, python-format
msgid "Sorry, to delete comments reputation of %(min_rep)s is required"
msgstr ""
-#: models/__init__.py:679
+#: models/__init__.py:815
msgid "cannot revoke old vote"
msgstr "sorry, but older votes cannot be revoked"
-#: models/__init__.py:1213 views/users.py:363
+#: models/__init__.py:1370
+msgid "Anonymous"
+msgstr ""
+
+#: models/__init__.py:1456 views/users.py:362
msgid "Site Adminstrator"
msgstr ""
-#: models/__init__.py:1215 views/users.py:365
+#: models/__init__.py:1458 views/users.py:364
msgid "Forum Moderator"
msgstr ""
-#: models/__init__.py:1217 views/users.py:367
+#: models/__init__.py:1460 views/users.py:366
msgid "Suspended User"
msgstr ""
-#: models/__init__.py:1219 views/users.py:369
+#: models/__init__.py:1462 views/users.py:368
msgid "Blocked User"
msgstr ""
-#: models/__init__.py:1221 views/users.py:371
+#: models/__init__.py:1464 views/users.py:370
msgid "Registered User"
msgstr ""
-#: models/__init__.py:1223
+#: models/__init__.py:1466
msgid "Watched User"
msgstr ""
-#: models/__init__.py:1225
+#: models/__init__.py:1468
msgid "Approved User"
msgstr ""
-#: models/__init__.py:1281
+#: models/__init__.py:1524
#, python-format
msgid "%(username)s karma is %(reputation)s"
msgstr ""
-#: models/__init__.py:1291
+#: models/__init__.py:1534
#, python-format
msgid "one gold badge"
msgid_plural "%(count)d gold badges"
msgstr[0] ""
msgstr[1] ""
-#: models/__init__.py:1298
+#: models/__init__.py:1541
#, python-format
msgid "one silver badge"
msgid_plural "%(count)d silver badges"
msgstr[0] ""
msgstr[1] ""
-#: models/__init__.py:1305
+#: models/__init__.py:1548
#, python-format
msgid "one bronze badge"
msgid_plural "%(count)d bronze badges"
msgstr[0] ""
msgstr[1] ""
-#: models/__init__.py:1316
+#: models/__init__.py:1559
#, python-format
msgid "%(item1)s and %(item2)s"
msgstr ""
-#: models/__init__.py:1320
+#: models/__init__.py:1563
#, python-format
msgid "%(user)s has %(badges)s"
msgstr ""
-#: models/__init__.py:1633 models/__init__.py:1639 models/__init__.py:1644
-#: models/__init__.py:1649
+#: models/__init__.py:1936 models/__init__.py:1942 models/__init__.py:1947
+#: models/__init__.py:1952
#, python-format
msgid "Re: \"%(title)s\""
msgstr ""
-#: models/__init__.py:1654 models/__init__.py:1659
+#: models/__init__.py:1957 models/__init__.py:1962
#, python-format
msgid "Question: \"%(title)s\""
msgstr ""
-#: models/__init__.py:1844
+#: models/__init__.py:2140
#, python-format
msgid ""
"Congratulations, you have received a badge '%(badge_name)s'. Check out <a "
"href=\"%(user_profile)s\">your profile</a>."
msgstr ""
+#: models/__init__.py:2319 views/commands.py:409
+msgid "Your tag subscription was saved, thanks!"
+msgstr ""
+
#: models/answer.py:105
msgid ""
"Sorry, the answer you are looking for is no longer available, because the "
@@ -2214,286 +2515,305 @@ msgstr ""
msgid "Sorry, this answer has been removed and is no longer accessible"
msgstr ""
-#: models/badges.py:128
+#: models/badges.py:129
#, python-format
msgid "Deleted own post with %(votes)s or more upvotes"
msgstr ""
-#: models/badges.py:132
+#: models/badges.py:133
msgid "Disciplined"
msgstr ""
-#: models/badges.py:150
+#: models/badges.py:151
#, python-format
msgid "Deleted own post with %(votes)s or more downvotes"
msgstr ""
-#: models/badges.py:154
+#: models/badges.py:155
msgid "Peer Pressure"
msgstr ""
-#: models/badges.py:173
+#: models/badges.py:174
#, python-format
msgid "Received at least %(votes)s upvote for an answer for the first time"
msgstr ""
-#: models/badges.py:177
+#: models/badges.py:178
msgid "Teacher"
msgstr ""
-#: models/badges.py:217
+#: models/badges.py:218
msgid "Supporter"
msgstr ""
-#: models/badges.py:218
+#: models/badges.py:219
msgid "First upvote"
msgstr ""
-#: models/badges.py:226
+#: models/badges.py:227
msgid "Critic"
msgstr ""
-#: models/badges.py:227
+#: models/badges.py:228
msgid "First downvote"
msgstr ""
-#: models/badges.py:236
+#: models/badges.py:237
msgid "Civic Duty"
msgstr ""
-#: models/badges.py:237
+#: models/badges.py:238
#, python-format
msgid "Voted %(num)s times"
msgstr ""
-#: models/badges.py:251
+#: models/badges.py:252
#, python-format
msgid "Answered own question with at least %(num)s up votes"
msgstr ""
-#: models/badges.py:255
+#: models/badges.py:256
msgid "Self-Learner"
msgstr ""
-#: models/badges.py:303
+#: models/badges.py:304
msgid "Nice Answer"
msgstr ""
-#: models/badges.py:308 models/badges.py:320 models/badges.py:332
+#: models/badges.py:309 models/badges.py:321 models/badges.py:333
#, python-format
msgid "Answer voted up %(num)s times"
msgstr ""
-#: models/badges.py:315
+#: models/badges.py:316
msgid "Good Answer"
msgstr ""
-#: models/badges.py:327
+#: models/badges.py:328
msgid "Great Answer"
msgstr ""
-#: models/badges.py:339
+#: models/badges.py:340
msgid "Nice Question"
msgstr ""
-#: models/badges.py:344 models/badges.py:356 models/badges.py:368
+#: models/badges.py:345 models/badges.py:357 models/badges.py:369
#, python-format
msgid "Question voted up %(num)s times"
msgstr ""
-#: models/badges.py:351
+#: models/badges.py:352
msgid "Good Question"
msgstr ""
-#: models/badges.py:363
+#: models/badges.py:364
msgid "Great Question"
msgstr ""
-#: models/badges.py:375
+#: models/badges.py:376
msgid "Student"
msgstr ""
-#: models/badges.py:380
+#: models/badges.py:381
msgid "Asked first question with at least one up vote"
msgstr ""
-#: models/badges.py:413
+#: models/badges.py:414
msgid "Popular Question"
msgstr ""
-#: models/badges.py:417 models/badges.py:428 models/badges.py:440
+#: models/badges.py:418 models/badges.py:429 models/badges.py:441
#, python-format
msgid "Asked a question with %(views)s views"
msgstr ""
-#: models/badges.py:424
+#: models/badges.py:425
msgid "Notable Question"
msgstr ""
-#: models/badges.py:435
+#: models/badges.py:436
msgid "Famous Question"
msgstr ""
-#: models/badges.py:449
+#: models/badges.py:450
msgid "Asked a question and accepted an answer"
msgstr ""
-#: models/badges.py:452
+#: models/badges.py:453
msgid "Scholar"
msgstr ""
-#: models/badges.py:494
+#: models/badges.py:495
msgid "Enlightened"
msgstr ""
-#: models/badges.py:498
+#: models/badges.py:499
#, python-format
msgid "First answer was accepted with %(num)s or more votes"
msgstr ""
-#: models/badges.py:506
+#: models/badges.py:507
msgid "Guru"
msgstr ""
-#: models/badges.py:509
+#: models/badges.py:510
#, python-format
msgid "Answer accepted with %(num)s or more votes"
msgstr ""
-#: models/badges.py:517
+#: models/badges.py:518
#, python-format
msgid ""
"Answered a question more than %(days)s days later with at least %(votes)s "
"votes"
msgstr ""
-#: models/badges.py:524
+#: models/badges.py:525
msgid "Necromancer"
msgstr ""
-#: models/badges.py:547
+#: models/badges.py:548
msgid "Citizen Patrol"
msgstr ""
-#: models/badges.py:550
+#: models/badges.py:551
msgid "First flagged post"
msgstr ""
-#: models/badges.py:562
+#: models/badges.py:563
msgid "Cleanup"
msgstr ""
-#: models/badges.py:565
+#: models/badges.py:566
msgid "First rollback"
msgstr ""
-#: models/badges.py:576
+#: models/badges.py:577
msgid "Pundit"
msgstr ""
-#: models/badges.py:579
+#: models/badges.py:580
msgid "Left 10 comments with score of 10 or more"
msgstr ""
-#: models/badges.py:611
+#: models/badges.py:612
msgid "Editor"
msgstr ""
-#: models/badges.py:614
+#: models/badges.py:615
msgid "First edit"
msgstr ""
-#: models/badges.py:622
+#: models/badges.py:623
msgid "Associate Editor"
msgstr ""
-#: models/badges.py:626
+#: models/badges.py:627
#, python-format
msgid "Edited %(num)s entries"
msgstr ""
-#: models/badges.py:633
+#: models/badges.py:634
msgid "Organizer"
msgstr ""
-#: models/badges.py:636
+#: models/badges.py:637
msgid "First retag"
msgstr ""
-#: models/badges.py:643
+#: models/badges.py:644
msgid "Autobiographer"
msgstr ""
-#: models/badges.py:646
+#: models/badges.py:647
msgid "Completed all user profile fields"
msgstr ""
-#: models/badges.py:662
+#: models/badges.py:663
#, python-format
msgid "Question favorited by %(num)s users"
msgstr ""
-#: models/badges.py:688
+#: models/badges.py:689
msgid "Stellar Question"
msgstr ""
-#: models/badges.py:697
+#: models/badges.py:698
msgid "Favorite Question"
msgstr ""
-#: models/badges.py:707
+#: models/badges.py:710
msgid "Enthusiast"
msgstr ""
-#: models/badges.py:710
-msgid "Visited site every day for 30 days in a row"
+#: models/badges.py:714
+#, python-format
+msgid "Visited site every day for %(num)s days in a row"
msgstr ""
-#: models/badges.py:718
+#: models/badges.py:732
msgid "Commentator"
msgstr ""
-#: models/badges.py:721
-msgid "Posted 10 comments"
+#: models/badges.py:736
+#, python-format
+msgid "Posted %(num_comments)s comments"
+msgstr ""
+
+#: models/badges.py:752
+msgid "Taxonomist"
msgstr ""
-#: models/meta.py:110
+#: models/badges.py:756
+#, python-format
+msgid "Created a tag used by %(num)s questions"
+msgstr ""
+
+#: models/badges.py:776
+msgid "Expert"
+msgstr ""
+
+#: models/badges.py:779
+msgid "Very active in one tag"
+msgstr ""
+
+#: models/meta.py:111
msgid ""
"Sorry, the comment you are looking for is no longer accessible, because the "
"parent question has been removed"
msgstr ""
-#: models/meta.py:117
+#: models/meta.py:118
msgid ""
"Sorry, the comment you are looking for is no longer accessible, because the "
"parent answer has been removed"
msgstr ""
-#: models/question.py:325
+#: models/question.py:387
msgid "Sorry, this question has been deleted and is no longer accessible"
msgstr ""
-#: models/question.py:714
+#: models/question.py:815
#, python-format
msgid "%(author)s modified the question"
msgstr ""
-#: models/question.py:718
+#: models/question.py:819
#, python-format
msgid "%(people)s posted %(new_answer_count)s new answers"
msgstr ""
-#: models/question.py:723
+#: models/question.py:824
#, python-format
msgid "%(people)s commented the question"
msgstr ""
-#: models/question.py:728
+#: models/question.py:829
#, python-format
msgid "%(people)s commented answers"
msgstr ""
-#: models/question.py:730
+#: models/question.py:831
#, python-format
msgid "%(people)s commented an answer"
msgstr ""
@@ -2517,129 +2837,130 @@ msgid ""
"question %(question_title)s"
msgstr ""
-#: models/tag.py:91
+#: models/tag.py:138
msgid "interesting"
msgstr ""
-#: models/tag.py:91
+#: models/tag.py:138
msgid "ignored"
msgstr ""
-#: models/user.py:264
+#: models/user.py:261
msgid "Entire forum"
msgstr ""
-#: models/user.py:265
+#: models/user.py:262
msgid "Questions that I asked"
msgstr ""
-#: models/user.py:266
+#: models/user.py:263
msgid "Questions that I answered"
msgstr ""
-#: models/user.py:267
+#: models/user.py:264
msgid "Individually selected questions"
msgstr ""
-#: models/user.py:268
+#: models/user.py:265
msgid "Mentions and comment responses"
msgstr ""
-#: models/user.py:271
+#: models/user.py:268
msgid "Instantly"
msgstr ""
-#: models/user.py:272
+#: models/user.py:269
msgid "Daily"
msgstr ""
-#: models/user.py:273
+#: models/user.py:270
msgid "Weekly"
msgstr ""
-#: models/user.py:274
+#: models/user.py:271
msgid "No email"
msgstr ""
#: skins/default/templates/404.jinja.html:3
-#: skins/default/templates/404.jinja.html:11
+#: skins/default/templates/404.jinja.html:10
msgid "Page not found"
msgstr ""
-#: skins/default/templates/404.jinja.html:15
+#: skins/default/templates/404.jinja.html:13
msgid "Sorry, could not find the page you requested."
msgstr ""
-#: skins/default/templates/404.jinja.html:17
+#: skins/default/templates/404.jinja.html:15
msgid "This might have happened for the following reasons:"
msgstr ""
-#: skins/default/templates/404.jinja.html:19
+#: skins/default/templates/404.jinja.html:17
msgid "this question or answer has been deleted;"
msgstr ""
-#: skins/default/templates/404.jinja.html:20
+#: skins/default/templates/404.jinja.html:18
msgid "url has error - please check it;"
msgstr ""
-#: skins/default/templates/404.jinja.html:21
+#: skins/default/templates/404.jinja.html:19
msgid ""
"the page you tried to visit is protected or you don't have sufficient "
"points, see"
msgstr ""
-#: skins/default/templates/404.jinja.html:21
-#: skins/default/templates/footer.html:6
-#: skins/default/templates/question_edit_tips.html:16
-#: skins/default/templates/blocks/header_meta_links.html:52
+#: skins/default/templates/404.jinja.html:19
+#: skins/default/templates/blocks/footer.html:6
+#: skins/default/templates/blocks/header_meta_links.html:13
+#: skins/default/templates/blocks/question_edit_tips.html:15
msgid "faq"
msgstr ""
-#: skins/default/templates/404.jinja.html:22
+#: skins/default/templates/404.jinja.html:20
msgid "if you believe this error 404 should not have occured, please"
msgstr ""
-#: skins/default/templates/404.jinja.html:23
+#: skins/default/templates/404.jinja.html:21
msgid "report this problem"
msgstr ""
-#: skins/default/templates/404.jinja.html:32
-#: skins/default/templates/500.jinja.html:13
+#: skins/default/templates/404.jinja.html:30
+#: skins/default/templates/500.jinja.html:11
msgid "back to previous page"
msgstr ""
-#: skins/default/templates/404.jinja.html:33
-#: skins/default/templates/questions.html:13
+#: skins/default/templates/404.jinja.html:31
+#: skins/default/templates/main_page/tab_bar.html:9
msgid "see all questions"
msgstr ""
-#: skins/default/templates/404.jinja.html:34
+#: skins/default/templates/404.jinja.html:32
msgid "see all tags"
msgstr ""
#: skins/default/templates/500.jinja.html:3
-#: skins/default/templates/500.jinja.html:6
+#: skins/default/templates/500.jinja.html:5
msgid "Internal server error"
msgstr ""
-#: skins/default/templates/500.jinja.html:10
+#: skins/default/templates/500.jinja.html:8
msgid "system error log is recorded, error will be fixed as soon as possible"
msgstr ""
-#: skins/default/templates/500.jinja.html:11
+#: skins/default/templates/500.jinja.html:9
msgid "please report the error to the site administrators if you wish"
msgstr ""
-#: skins/default/templates/500.jinja.html:14
+#: skins/default/templates/500.jinja.html:12
msgid "see latest questions"
msgstr ""
-#: skins/default/templates/500.jinja.html:15
+#: skins/default/templates/500.jinja.html:13
msgid "see tags"
msgstr ""
-#: skins/default/templates/about.html:3 skins/default/templates/about.html:6
-msgid "About"
+#: skins/default/templates/about.html:3 skins/default/templates/about.html:5
+#, python-format
+msgid "About %(site_name)s"
msgstr ""
#: skins/default/templates/answer_edit.html:4
@@ -2648,192 +2969,85 @@ msgid "Edit answer"
msgstr ""
#: skins/default/templates/answer_edit.html:10
-#: skins/default/templates/question_edit.html:10
-#: skins/default/templates/question_retag.html:6
+#: skins/default/templates/question_edit.html:9
+#: skins/default/templates/question_retag.html:5
#: skins/default/templates/revisions.html:7
msgid "back"
msgstr ""
#: skins/default/templates/answer_edit.html:15
-#: skins/default/templates/question_edit.html:14
+#: skins/default/templates/question_edit.html:11
msgid "revision"
msgstr ""
#: skins/default/templates/answer_edit.html:18
-#: skins/default/templates/question_edit.html:19
+#: skins/default/templates/question_edit.html:16
msgid "select revision"
msgstr ""
#: skins/default/templates/answer_edit.html:22
-#: skins/default/templates/question_edit.html:28
+#: skins/default/templates/question_edit.html:20
msgid "Save edit"
msgstr ""
#: skins/default/templates/answer_edit.html:23
-#: skins/default/templates/close.html:19
-#: skins/default/templates/feedback.html:45
-#: skins/default/templates/question_edit.html:29
-#: skins/default/templates/question_retag.html:26
-#: skins/default/templates/reopen.html:30
-#: skins/default/templates/user_edit.html:76
+#: skins/default/templates/close.html:16
+#: skins/default/templates/feedback.html:42
+#: skins/default/templates/question_edit.html:21
+#: skins/default/templates/question_retag.html:23
+#: skins/default/templates/reopen.html:27
+#: skins/default/templates/subscribe_for_tags.html:16
#: skins/default/templates/authopenid/changeemail.html:38
+#: skins/default/templates/user_profile/user_edit.html:84
msgid "Cancel"
msgstr ""
-#: skins/default/templates/answer_edit.html:59
#: skins/default/templates/answer_edit.html:62
-#: skins/default/templates/ask.html:36 skins/default/templates/ask.html:39
-#: skins/default/templates/macros.html:444
-#: skins/default/templates/question.html:465
-#: skins/default/templates/question.html:468
-#: skins/default/templates/question_edit.html:63
-#: skins/default/templates/question_edit.html:66
+#: skins/default/templates/answer_edit.html:65
+#: skins/default/templates/ask.html:43 skins/default/templates/ask.html:46
+#: skins/default/templates/macros.html:592
+#: skins/default/templates/question.html:474
+#: skins/default/templates/question.html:477
+#: skins/default/templates/question_edit.html:62
+#: skins/default/templates/question_edit.html:65
msgid "hide preview"
msgstr ""
-#: skins/default/templates/answer_edit.html:62
-#: skins/default/templates/ask.html:39
-#: skins/default/templates/question.html:468
-#: skins/default/templates/question_edit.html:66
+#: skins/default/templates/answer_edit.html:65
+#: skins/default/templates/ask.html:46
+#: skins/default/templates/question.html:477
+#: skins/default/templates/question_edit.html:65
msgid "show preview"
msgstr ""
-#: skins/default/templates/answer_edit_tips.html:3
-msgid "answer tips"
-msgstr "Tips"
-
-#: skins/default/templates/answer_edit_tips.html:6
-msgid "please make your answer relevant to this community"
-msgstr "ask a question interesting to this community"
-
-#: skins/default/templates/answer_edit_tips.html:9
-msgid "try to give an answer, rather than engage into a discussion"
-msgstr ""
-
-#: skins/default/templates/answer_edit_tips.html:12
-msgid "please try to provide details"
-msgstr "provide enough details"
-
-#: skins/default/templates/answer_edit_tips.html:15
-#: skins/default/templates/question_edit_tips.html:12
-msgid "be clear and concise"
-msgstr ""
-
-#: skins/default/templates/answer_edit_tips.html:19
-#: skins/default/templates/question_edit_tips.html:16
-msgid "see frequently asked questions"
-msgstr ""
-
-#: skins/default/templates/answer_edit_tips.html:25
-#: skins/default/templates/question_edit_tips.html:22
-msgid "Markdown tips"
-msgstr "Markdown basics"
-
-#: skins/default/templates/answer_edit_tips.html:29
-#: skins/default/templates/question_edit_tips.html:26
-msgid "*italic*"
-msgstr ""
-
-#: skins/default/templates/answer_edit_tips.html:32
-#: skins/default/templates/question_edit_tips.html:29
-msgid "**bold**"
-msgstr ""
-
-#: skins/default/templates/answer_edit_tips.html:36
-#: skins/default/templates/question_edit_tips.html:33
-msgid "*italic* or _italic_"
-msgstr ""
-
-#: skins/default/templates/answer_edit_tips.html:39
-#: skins/default/templates/question_edit_tips.html:36
-msgid "**bold** or __bold__"
-msgstr ""
-
-#: skins/default/templates/answer_edit_tips.html:43
-#: skins/default/templates/question_edit_tips.html:40
-msgid "link"
-msgstr ""
-
-#: skins/default/templates/answer_edit_tips.html:43
-#: skins/default/templates/answer_edit_tips.html:47
-#: skins/default/templates/question_edit_tips.html:40
-#: skins/default/templates/question_edit_tips.html:45
-msgid "text"
-msgstr ""
-
-#: skins/default/templates/answer_edit_tips.html:47
-#: skins/default/templates/question_edit_tips.html:45
-msgid "image"
-msgstr ""
-
-#: skins/default/templates/answer_edit_tips.html:51
-#: skins/default/templates/question_edit_tips.html:49
-msgid "numbered list:"
-msgstr ""
-
-#: skins/default/templates/answer_edit_tips.html:56
-#: skins/default/templates/question_edit_tips.html:54
-msgid "basic HTML tags are also supported"
-msgstr ""
-
-#: skins/default/templates/answer_edit_tips.html:60
-#: skins/default/templates/question_edit_tips.html:58
-msgid "learn more about Markdown"
-msgstr ""
-
-#: skins/default/templates/ask.html:3
+#: skins/default/templates/ask.html:4
msgid "Ask a question"
msgstr ""
-#: skins/default/templates/ask_form.html:7
-msgid "login to post question info"
-msgstr ""
-"<span class=\"strong big\">You are welcome to start submitting your question "
-"anonymously</span>. When you submit the post, you will be redirected to the "
-"login/signup page. Your question will be saved in the current session and "
-"will be published after you log in. Login/signup process is very simple. "
-"Login takes about 30 seconds, initial signup takes a minute or less."
-
-#: skins/default/templates/ask_form.html:11
-#, python-format
-msgid ""
-"must have valid %(email)s to post, \n"
-" see %(email_validation_faq_url)s\n"
-" "
-msgstr ""
-"<span class='strong big'>Looks like your email address, %(email)s has not "
-"yet been validated.</span> To post messages you must verify your email, "
-"please see <a href='%(email_validation_faq_url)s'>more details here</a>."
-"<br>You can submit your question now and validate email after that. Your "
-"question will saved as pending meanwhile. "
-
-#: skins/default/templates/ask_form.html:27
-msgid "Login/signup to post your question"
-msgstr "Login/Signup to Post"
-
-#: skins/default/templates/ask_form.html:29
-msgid "Ask your question"
-msgstr "Ask Your Question"
-
-#: skins/default/templates/badge.html:4 skins/default/templates/badge.html:11
-#: skins/default/templates/user_recent.html:13
-#: skins/default/templates/user_stats.html:88
+#: skins/default/templates/badge.html:4 skins/default/templates/badge.html:8
+#: skins/default/templates/user_profile/user_recent.html:16
+#: skins/default/templates/user_profile/user_stats.html:106
#, python-format
msgid "%(name)s"
msgstr ""
-#: skins/default/templates/badge.html:4 skins/default/templates/badge.html:7
+#: skins/default/templates/badge.html:4
msgid "Badge"
msgstr ""
-#: skins/default/templates/badge.html:11
-#: skins/default/templates/user_recent.html:13
-#: skins/default/templates/user_stats.html:88
+#: skins/default/templates/badge.html:6
+#, python-format
+msgid "Badge \"%(name)s\""
+msgstr ""
+
+#: skins/default/templates/badge.html:8
+#: skins/default/templates/user_profile/user_recent.html:16
+#: skins/default/templates/user_profile/user_stats.html:106
#, python-format
msgid "%(description)s"
msgstr ""
-#: skins/default/templates/badge.html:16
+#: skins/default/templates/badge.html:13
msgid "user received this badge:"
msgid_plural "users received this badge:"
msgstr[0] ""
@@ -2843,113 +3057,92 @@ msgstr[1] ""
msgid "Badges summary"
msgstr "Badges"
-#: skins/default/templates/badges.html:6
+#: skins/default/templates/badges.html:5
msgid "Badges"
msgstr ""
-#: skins/default/templates/badges.html:10
+#: skins/default/templates/badges.html:7
msgid "Community gives you awards for your questions, answers and votes."
msgstr ""
-#: skins/default/templates/badges.html:11
+#: skins/default/templates/badges.html:8
#, python-format
msgid ""
"Below is the list of available badges and number \n"
-" of times each type of badge has been awarded. Give us feedback at %"
+"of times each type of badge has been awarded. Give us feedback at %"
"(feedback_faq_url)s.\n"
-" "
msgstr ""
"Below is the list of available badges and number \n"
" of times each type of badge has been awarded. Have ideas about fun "
-"badges? Please, give us your <a href='%(feedback_faq_url)s'>feedback</a>"
+"badges? Please, give us your <a href='%(feedback_faq_url)s'>feedback</a>\n"
-#: skins/default/templates/badges.html:40
+#: skins/default/templates/badges.html:35
msgid "Community badges"
msgstr "Badge levels"
-#: skins/default/templates/badges.html:43
+#: skins/default/templates/badges.html:37
msgid "gold badge: the highest honor and is very rare"
msgstr ""
-#: skins/default/templates/badges.html:46
+#: skins/default/templates/badges.html:40
msgid "gold badge description"
msgstr ""
"Gold badge is the highest award in this community. To obtain it have to show "
"profound knowledge and ability in addition to your active participation."
-#: skins/default/templates/badges.html:51
+#: skins/default/templates/badges.html:45
msgid ""
"silver badge: occasionally awarded for the very high quality contributions"
msgstr ""
-#: skins/default/templates/badges.html:55
+#: skins/default/templates/badges.html:49
msgid "silver badge description"
msgstr ""
"silver badge: occasionally awarded for the very high quality contributions"
-#: skins/default/templates/badges.html:58
+#: skins/default/templates/badges.html:52
msgid "bronze badge: often given as a special honor"
msgstr ""
-#: skins/default/templates/badges.html:62
+#: skins/default/templates/badges.html:56
msgid "bronze badge description"
msgstr "bronze badge: often given as a special honor"
-#: skins/default/templates/close.html:3 skins/default/templates/close.html:6
+#: skins/default/templates/close.html:3 skins/default/templates/close.html:5
msgid "Close question"
msgstr ""
-#: skins/default/templates/close.html:9
+#: skins/default/templates/close.html:6
msgid "Close the question"
msgstr ""
-#: skins/default/templates/close.html:14
+#: skins/default/templates/close.html:11
msgid "Reasons"
msgstr ""
-#: skins/default/templates/close.html:18
+#: skins/default/templates/close.html:15
msgid "OK to close"
msgstr ""
-#: skins/default/templates/editor_data.html:5
-#, python-format
-msgid "each tag must be shorter that %(max_chars)s character"
-msgid_plural "each tag must be shorter than %(max_chars)s characters"
-msgstr[0] ""
-msgstr[1] ""
-
-#: skins/default/templates/editor_data.html:7
-#, python-format
-msgid "please use %(tag_count)s tag"
-msgid_plural "please use %(tag_count)s tags or less"
-msgstr[0] ""
-msgstr[1] ""
-
-#: skins/default/templates/editor_data.html:8
-#, python-format
-msgid ""
-"please use up to %(tag_count)s tags, less than %(max_chars)s characters each"
-msgstr ""
-
-#: skins/default/templates/faq.html:3 skins/default/templates/faq.html.py:6
+#: skins/default/templates/faq.html:3 skins/default/templates/faq.html.py:5
msgid "FAQ"
msgstr ""
-#: skins/default/templates/faq.html:6
+#: skins/default/templates/faq.html:5
msgid "Frequently Asked Questions "
msgstr ""
-#: skins/default/templates/faq.html:11
+#: skins/default/templates/faq.html:6
msgid "What kinds of questions can I ask here?"
msgstr ""
-#: skins/default/templates/faq.html:12
+#: skins/default/templates/faq.html:7
msgid ""
"Most importanly - questions should be <strong>relevant</strong> to this "
"community."
msgstr ""
-#: skins/default/templates/faq.html:13
+#: skins/default/templates/faq.html:8
msgid ""
"Before asking the question - please make sure to use search to see whether "
"your question has alredy been answered."
@@ -2957,21 +3150,21 @@ msgstr ""
"Before you ask - please make sure to search for a similar question. You can "
"search questions by their title or tags."
-#: skins/default/templates/faq.html:15
+#: skins/default/templates/faq.html:10
msgid "What questions should I avoid asking?"
msgstr "What kinds of questions should be avoided?"
-#: skins/default/templates/faq.html:16
+#: skins/default/templates/faq.html:11
msgid ""
"Please avoid asking questions that are not relevant to this community, too "
"subjective and argumentative."
msgstr ""
-#: skins/default/templates/faq.html:20
+#: skins/default/templates/faq.html:13
msgid "What should I avoid in my answers?"
msgstr ""
-#: skins/default/templates/faq.html:21
+#: skins/default/templates/faq.html:14
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 "
@@ -2982,19 +3175,19 @@ msgstr ""
"they tend to dilute the essense of questions and answers. For the brief "
"discussions please use commenting facility."
-#: skins/default/templates/faq.html:24
+#: skins/default/templates/faq.html:15
msgid "Who moderates this community?"
msgstr ""
-#: skins/default/templates/faq.html:25
+#: skins/default/templates/faq.html:16
msgid "The short answer is: <strong>you</strong>."
msgstr ""
-#: skins/default/templates/faq.html:26
+#: skins/default/templates/faq.html:17
msgid "This website is moderated by the users."
msgstr ""
-#: skins/default/templates/faq.html:27
+#: skins/default/templates/faq.html:18
msgid ""
"The reputation system allows users earn the authorization to perform a "
"variety of moderation tasks."
@@ -3002,11 +3195,11 @@ msgstr ""
"Karma system allows users to earn rights to perform a variety of moderation "
"tasks"
-#: skins/default/templates/faq.html:32
+#: skins/default/templates/faq.html:20
msgid "How does reputation system work?"
msgstr "How does karma system work?"
-#: skins/default/templates/faq.html:33
+#: skins/default/templates/faq.html:21
msgid "Rep system summary"
msgstr ""
"When a question or answer is upvoted, the user who posted them will gain "
@@ -3014,7 +3207,7 @@ msgstr ""
"rough measure of the community trust to him/her. Various moderation tasks "
"are gradually assigned to the users based on those points."
-#: skins/default/templates/faq.html:34
+#: skins/default/templates/faq.html:22
#, python-format
msgid ""
"For example, if you ask an interesting question or give a helpful answer, "
@@ -3027,71 +3220,49 @@ msgid ""
"explains reputation point requirements for each type of moderation task."
msgstr ""
-#: skins/default/templates/faq.html:44
-#: skins/default/templates/user_votes.html:10
+#: skins/default/templates/faq.html:32
+#: skins/default/templates/user_profile/user_votes.html:13
msgid "upvote"
msgstr ""
-#: skins/default/templates/faq.html:49
+#: skins/default/templates/faq.html:37
msgid "use tags"
msgstr ""
-#: skins/default/templates/faq.html:54
+#: skins/default/templates/faq.html:42
msgid "add comments"
msgstr ""
-#: skins/default/templates/faq.html:58
-#: skins/default/templates/user_votes.html:12
+#: skins/default/templates/faq.html:46
+#: skins/default/templates/user_profile/user_votes.html:15
msgid "downvote"
msgstr ""
-#: skins/default/templates/faq.html:61
+#: skins/default/templates/faq.html:49
msgid "open and close own questions"
msgstr ""
-#: skins/default/templates/faq.html:65
+#: skins/default/templates/faq.html:53
msgid "retag other's questions"
msgstr ""
-#: skins/default/templates/faq.html:70
+#: skins/default/templates/faq.html:58
msgid "edit community wiki questions"
msgstr ""
-#: skins/default/templates/faq.html:75
+#: skins/default/templates/faq.html:63
msgid "\"edit any answer"
msgstr ""
-#: skins/default/templates/faq.html:79
+#: skins/default/templates/faq.html:67
msgid "\"delete any comment"
msgstr ""
-#: skins/default/templates/faq.html:86
-msgid "how to validate email title"
-msgstr "How to validate email and why?"
-
-#: skins/default/templates/faq.html:88
-#, python-format
-msgid ""
-"how to validate email info with %(send_email_key_url)s %(gravatar_faq_url)s"
-msgstr ""
-"<form style='margin:0;padding:0;' action='%(send_email_key_url)s'><p><span "
-"class=\"bigger strong\">How?</span> If you have just set or changed your "
-"email address - <strong>check your email and click the included link</"
-"strong>.<br>The link contains a key generated specifically for you. You can "
-"also <button style='display:inline' type='submit'><strong>get a new key</"
-"strong></button> and check your email again.</p></form><span class=\"bigger "
-"strong\">Why?</span> Email validation is required to make sure that "
-"<strong>only you can post messages</strong> on your behalf and to "
-"<strong>minimize spam</strong> posts.<br>With email you can "
-"<strong>subscribe for updates</strong> on the most interesting questions. "
-"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>"
-
-#: skins/default/templates/faq.html:93
+#: skins/default/templates/faq.html:70
msgid "what is gravatar"
msgstr "How to change my picture (gravatar) and what is gravatar?"
-#: skins/default/templates/faq.html:94
+#: skins/default/templates/faq.html:71
msgid "gravatar faq info"
msgstr ""
"<p>The picture that appears on the users profiles is called "
@@ -3108,44 +3279,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>"
-#: skins/default/templates/faq.html:97
+#: skins/default/templates/faq.html:72
msgid "To register, do I need to create new password?"
msgstr ""
-#: skins/default/templates/faq.html:98
+#: skins/default/templates/faq.html:73
msgid ""
"No, you don't have to. You can login through any service that supports "
"OpenID, e.g. Google, Yahoo, AOL, etc.\""
msgstr ""
-#: skins/default/templates/faq.html:99
+#: skins/default/templates/faq.html:74
msgid "\"Login now!\""
msgstr ""
-#: skins/default/templates/faq.html:103
+#: skins/default/templates/faq.html:76
msgid "Why other people can edit my questions/answers?"
msgstr ""
-#: skins/default/templates/faq.html:104
+#: skins/default/templates/faq.html:77
msgid "Goal of this site is..."
msgstr ""
-#: skins/default/templates/faq.html:104
+#: skins/default/templates/faq.html:77
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 ""
-#: skins/default/templates/faq.html:105
+#: skins/default/templates/faq.html:78
msgid "If this approach is not for you, we respect your choice."
msgstr ""
-#: skins/default/templates/faq.html:109
+#: skins/default/templates/faq.html:80
msgid "Still have questions?"
msgstr ""
-#: skins/default/templates/faq.html:110
+#: skins/default/templates/faq.html:81
#, python-format
msgid ""
"Please ask your question at %(ask_question_url)s, help make our community "
@@ -3154,50 +3325,42 @@ msgstr ""
"Please <a href='%(ask_question_url)s'>ask</a> your question, help make our "
"community better!"
-#: skins/default/templates/faq.html:112 skins/default/templates/header.html:26
-msgid "questions"
-msgstr ""
-
-#: skins/default/templates/faq.html:112
-msgid "."
-msgstr ""
-
#: skins/default/templates/feedback.html:3
msgid "Feedback"
msgstr ""
-#: skins/default/templates/feedback.html:6
+#: skins/default/templates/feedback.html:5
msgid "Give us your feedback!"
msgstr ""
-#: skins/default/templates/feedback.html:12
+#: skins/default/templates/feedback.html:9
#, python-format
msgid ""
"\n"
-" <span class='big strong'>Dear %(user_name)s</span>, we look "
-"forward to hearing your feedback. \n"
-" Please type and send us your message below.\n"
-" "
+" <span class='big strong'>Dear %(user_name)s</span>, we look forward "
+"to hearing your feedback. \n"
+" Please type and send us your message below.\n"
+" "
msgstr ""
-#: skins/default/templates/feedback.html:19
+#: skins/default/templates/feedback.html:16
msgid ""
"\n"
-" <span class='big strong'>Dear visitor</span>, we look forward to "
+" <span class='big strong'>Dear visitor</span>, we look forward to "
"hearing your feedback.\n"
-" Please type and send us your message below.\n"
-" "
+" Please type and send us your message below.\n"
+" "
msgstr ""
-#: skins/default/templates/feedback.html:28
+#: skins/default/templates/feedback.html:25
msgid "(please enter a valid email)"
msgstr ""
-#: skins/default/templates/feedback.html:36
+#: skins/default/templates/feedback.html:33
msgid "(this field is required)"
msgstr ""
-#: skins/default/templates/feedback.html:44
+#: skins/default/templates/feedback.html:41
msgid "Send Feedback"
msgstr ""
@@ -3225,42 +3388,34 @@ msgstr ""
msgid "Message body:"
msgstr ""
-#: skins/default/templates/footer.html:5
-#: skins/default/templates/blocks/header_meta_links.html:51
-msgid "about"
-msgstr ""
-
-#: skins/default/templates/footer.html:7
-msgid "privacy policy"
-msgstr ""
-
-#: skins/default/templates/footer.html:16
-msgid "give feedback"
-msgstr ""
-
-#: skins/default/templates/header.html:15
-msgid "back to home page"
+#: skins/default/templates/import_data.html:2
+#: skins/default/templates/import_data.html:4
+msgid "Import StackExchange data"
msgstr ""
-#: skins/default/templates/header.html:16
-#, python-format
-msgid "%(site)s logo"
+#: skins/default/templates/import_data.html:13
+msgid ""
+"<em>Warning:</em> if your database is not empty, please back it up\n"
+" before attempting this operation."
msgstr ""
-#: skins/default/templates/header.html:36
-msgid "users"
-msgstr "people"
-
-#: skins/default/templates/header.html:41
-msgid "badges"
+#: skins/default/templates/import_data.html:16
+msgid ""
+"Upload your stackexchange dump .zip file, then wait until\n"
+" the data import completes. This process may take several minutes.\n"
+" Please note that feedback will be printed in plain text.\n"
+" "
msgstr ""
-#: skins/default/templates/header.html:46
-msgid "ask a question"
+#: skins/default/templates/import_data.html:25
+msgid "Import data"
msgstr ""
-#: skins/default/templates/input_bar.html:32
-msgid "search"
+#: skins/default/templates/import_data.html:27
+msgid ""
+"In the case you experience any difficulties in using this import tool,\n"
+" please try importing your data via command line: <code>python manage."
+"py load_stackexchange path/to/your-data.zip</code>"
msgstr ""
#: skins/default/templates/instant_notification.html:1
@@ -3331,20 +3486,20 @@ msgstr ""
msgid "<p>Sincerely,<br/>Forum Administrator</p>"
msgstr ""
-#: skins/default/templates/logout.html:3 skins/default/templates/logout.html:6
+#: skins/default/templates/logout.html:3 skins/default/templates/logout.html:5
msgid "Logout"
msgstr "Sign out"
-#: skins/default/templates/logout.html:9
+#: skins/default/templates/logout.html:6
msgid ""
"As a registered user you can login with your OpenID, log out of the site or "
"permanently remove your account."
msgstr ""
-"Clicking <strong>Logout</strong> will log you out from the forumbut will not "
-"sign you off from your OpenID provider.</p><p>If you wish to sign off "
+"Clicking <strong>Logout</strong> will log you out from the forum but will "
+"not sign you off from your OpenID provider.</p><p>If you wish to sign off "
"completely - please make sure to log out from your OpenID provider as well."
-#: skins/default/templates/logout.html:10
+#: skins/default/templates/logout.html:7
msgid "Logout now"
msgstr "Logout Now"
@@ -3356,117 +3511,119 @@ msgstr ""
msgid "badges:"
msgstr ""
-#: skins/default/templates/macros.html:52
-#: skins/default/templates/macros.html:53
+#: skins/default/templates/macros.html:82
+#: skins/default/templates/macros.html:83
msgid "previous"
msgstr ""
-#: skins/default/templates/macros.html:64
+#: skins/default/templates/macros.html:94
msgid "current page"
msgstr ""
-#: skins/default/templates/macros.html:66
-#: skins/default/templates/macros.html:73
+#: skins/default/templates/macros.html:96
+#: skins/default/templates/macros.html:103
#, python-format
msgid "page number %(num)s"
msgstr "page %(num)s"
-#: skins/default/templates/macros.html:77
+#: skins/default/templates/macros.html:107
msgid "next page"
msgstr ""
-#: skins/default/templates/macros.html:88
+#: skins/default/templates/macros.html:118
msgid "posts per page"
msgstr ""
-#: skins/default/templates/macros.html:119 templatetags/extra_tags.py:44
+#: skins/default/templates/macros.html:150 templatetags/extra_tags.py:43
#, python-format
msgid "%(username)s gravatar image"
msgstr ""
-#: skins/default/templates/macros.html:142
+#: skins/default/templates/macros.html:159
+#, python-format
+msgid "%(username)s's website is %(url)s"
+msgstr ""
+
+#: skins/default/templates/macros.html:171
+#, fuzzy
+msgid "anonymous user"
+msgstr "Sorry, anonymous users cannot vote"
+
+#: skins/default/templates/macros.html:199
msgid "this post is marked as community wiki"
msgstr ""
-#: skins/default/templates/macros.html:145
+#: skins/default/templates/macros.html:202
#, python-format
msgid ""
"This post is a wiki.\n"
" Anyone with karma &gt;%(wiki_min_rep)s is welcome to improve it."
msgstr ""
-#: skins/default/templates/macros.html:151
+#: skins/default/templates/macros.html:208
msgid "asked"
msgstr ""
-#: skins/default/templates/macros.html:153
+#: skins/default/templates/macros.html:210
msgid "answered"
msgstr ""
-#: skins/default/templates/macros.html:155
+#: skins/default/templates/macros.html:212
msgid "posted"
msgstr ""
-#: skins/default/templates/macros.html:185
+#: skins/default/templates/macros.html:242
msgid "updated"
msgstr ""
-#: skins/default/templates/macros.html:210
-#: skins/default/templates/unused/questions_ajax.html:23 views/readers.py:238
+#: skins/default/templates/macros.html:309
+#, python-format
+msgid "see questions tagged '%(tag)s'"
+msgstr ""
+
+#: skins/default/templates/macros.html:352 views/readers.py:219
msgid "vote"
msgid_plural "votes"
msgstr[0] ""
msgstr[1] ""
-#: skins/default/templates/macros.html:227
-#: skins/default/templates/unused/questions_ajax.html:43 views/readers.py:241
+#: skins/default/templates/macros.html:369 views/readers.py:222
msgid "answer"
msgid_plural "answers"
msgstr[0] ""
msgstr[1] ""
-#: skins/default/templates/macros.html:239
-#: skins/default/templates/unused/questions_ajax.html:55 views/readers.py:244
+#: skins/default/templates/macros.html:380 views/readers.py:225
msgid "view"
msgid_plural "views"
msgstr[0] ""
msgstr[1] ""
-#: skins/default/templates/macros.html:251
-#: skins/default/templates/question.html:88
-#: skins/default/templates/tags.html:38
-#: skins/default/templates/unused/question_list.html:64
-#: skins/default/templates/unused/question_summary_list_roll.html:52
-#: skins/default/templates/unused/questions_ajax.html:68
-#, python-format
-msgid "see questions tagged '%(tag)s'"
-msgstr ""
-
-#: skins/default/templates/macros.html:267
-#: skins/default/templates/question.html:94
-#: skins/default/templates/question.html:250
+#: skins/default/templates/macros.html:409
+#: skins/default/templates/question.html:93
+#: skins/default/templates/question.html:249
#: skins/default/templates/revisions.html:37
msgid "edit"
msgstr ""
-#: skins/default/templates/macros.html:272
+#: skins/default/templates/macros.html:413
msgid "delete this comment"
msgstr ""
-#: skins/default/templates/macros.html:290
-#: skins/default/templates/macros.html:298
-#: skins/default/templates/question.html:432
+#: skins/default/templates/macros.html:431
+#: skins/default/templates/macros.html:439
+#: skins/default/templates/question.html:439
msgid "add comment"
msgstr "post a comment"
-#: skins/default/templates/macros.html:291
+#: skins/default/templates/macros.html:432
#, python-format
msgid "see <strong>%(counter)s</strong> more"
msgid_plural "see <strong>%(counter)s</strong> more"
msgstr[0] ""
msgstr[1] ""
-#: skins/default/templates/macros.html:293
+#: skins/default/templates/macros.html:434
#, python-format
msgid "see <strong>%(counter)s</strong> more comment"
msgid_plural ""
@@ -3475,186 +3632,225 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
-#: skins/default/templates/macros.html:421
+#: skins/default/templates/macros.html:569
msgid "(required)"
msgstr ""
-#: skins/default/templates/macros.html:442
+#: skins/default/templates/macros.html:590
msgid "Toggle the real time Markdown editor preview"
msgstr ""
+#: skins/default/templates/macros.html:602
+#, python-format
+msgid "responses for %(username)s"
+msgstr ""
+
+#: skins/default/templates/macros.html:605
+#, python-format
+msgid "you have a new response"
+msgid_plural "you have %(response_count)s new responses"
+msgstr[0] ""
+msgstr[1] ""
+
+#: skins/default/templates/macros.html:608
+msgid "no new responses yet"
+msgstr ""
+
+#: skins/default/templates/macros.html:623
+#: skins/default/templates/macros.html:624
+#, python-format
+msgid "%(new)s new flagged posts and %(seen)s previous"
+msgstr ""
+
+#: skins/default/templates/macros.html:626
+#: skins/default/templates/macros.html:627
+#, python-format
+msgid "%(new)s new flagged posts"
+msgstr ""
+
+#: skins/default/templates/macros.html:632
+#: skins/default/templates/macros.html:633
+#, python-format
+msgid "%(seen)s flagged posts"
+msgstr ""
+
+#: skins/default/templates/main_page.html:11
+msgid "Questions"
+msgstr ""
+
#: skins/default/templates/privacy.html:3
-#: skins/default/templates/privacy.html:6
+#: skins/default/templates/privacy.html:5
msgid "Privacy policy"
msgstr ""
-#: skins/default/templates/question.html:30
-#: skins/default/templates/question.html:31
-#: skins/default/templates/question.html:46
-#: skins/default/templates/question.html:48
+#: skins/default/templates/question.html:27
+#: skins/default/templates/question.html:28
+#: skins/default/templates/question.html:43
+#: skins/default/templates/question.html:45
msgid "i like this post (click again to cancel)"
msgstr ""
-#: skins/default/templates/question.html:33
-#: skins/default/templates/question.html:50
-#: skins/default/templates/question.html:201
+#: skins/default/templates/question.html:30
+#: skins/default/templates/question.html:47
+#: skins/default/templates/question.html:200
msgid "current number of votes"
msgstr ""
-#: skins/default/templates/question.html:42
-#: skins/default/templates/question.html:43
-#: skins/default/templates/question.html:55
-#: skins/default/templates/question.html:56
+#: skins/default/templates/question.html:39
+#: skins/default/templates/question.html:40
+#: skins/default/templates/question.html:52
+#: skins/default/templates/question.html:53
msgid "i dont like this post (click again to cancel)"
msgstr ""
-#: skins/default/templates/question.html:60
-#: skins/default/templates/question.html:61
+#: skins/default/templates/question.html:57
+#: skins/default/templates/question.html:58
msgid "mark this question as favorite (click again to cancel)"
msgstr ""
-#: skins/default/templates/question.html:67
-#: skins/default/templates/question.html:68
+#: skins/default/templates/question.html:64
+#: skins/default/templates/question.html:65
msgid "remove favorite mark from this question (click again to restore mark)"
msgstr ""
-#: skins/default/templates/question.html:74
+#: skins/default/templates/question.html:71
msgid "Share this question on twitter"
msgstr ""
-#: skins/default/templates/question.html:75
+#: skins/default/templates/question.html:72
msgid "Share this question on facebook"
msgstr ""
-#: skins/default/templates/question.html:97
+#: skins/default/templates/question.html:96
msgid "retag"
msgstr ""
-#: skins/default/templates/question.html:104
+#: skins/default/templates/question.html:103
msgid "reopen"
msgstr ""
-#: skins/default/templates/question.html:108
+#: skins/default/templates/question.html:107
msgid "close"
msgstr ""
-#: skins/default/templates/question.html:113
-#: skins/default/templates/question.html:254
+#: skins/default/templates/question.html:112
+#: skins/default/templates/question.html:253
msgid ""
"report as offensive (i.e containing spam, advertising, malicious text, etc.)"
msgstr ""
-#: skins/default/templates/question.html:114
-#: skins/default/templates/question.html:255
+#: skins/default/templates/question.html:113
+#: skins/default/templates/question.html:254
msgid "flag offensive"
msgstr ""
-#: skins/default/templates/question.html:121
-#: skins/default/templates/question.html:265
+#: skins/default/templates/question.html:120
+#: skins/default/templates/question.html:264
msgid "undelete"
msgstr ""
-#: skins/default/templates/question.html:121
-#: skins/default/templates/question.html:265
-#: skins/default/templates/authopenid/signin.html:175
+#: skins/default/templates/question.html:120
+#: skins/default/templates/question.html:264
+#: skins/default/templates/authopenid/signin.html:149
msgid "delete"
msgstr ""
-#: skins/default/templates/question.html:159
+#: skins/default/templates/question.html:157
#, python-format
msgid ""
"The question has been closed for the following reason \"%(close_reason)s\" by"
msgstr ""
-#: skins/default/templates/question.html:161
+#: skins/default/templates/question.html:159
#, python-format
msgid "close date %(closed_at)s"
msgstr ""
-#: skins/default/templates/question.html:169
+#: skins/default/templates/question.html:165
#, python-format
msgid ""
"\n"
-" %(counter)s Answer:\n"
-" "
+" %(counter)s Answer:\n"
+" "
msgid_plural ""
"\n"
-" %(counter)s Answers:\n"
-" "
+" %(counter)s Answers:\n"
+" "
msgstr[0] ""
msgstr[1] ""
-#: skins/default/templates/question.html:177
+#: skins/default/templates/question.html:173
msgid "oldest answers will be shown first"
msgstr ""
-#: skins/default/templates/question.html:177
+#: skins/default/templates/question.html:174
msgid "oldest answers"
msgstr "oldest"
-#: skins/default/templates/question.html:179
+#: skins/default/templates/question.html:176
msgid "newest answers will be shown first"
msgstr ""
-#: skins/default/templates/question.html:179
+#: skins/default/templates/question.html:177
msgid "newest answers"
msgstr "newest"
-#: skins/default/templates/question.html:181
+#: skins/default/templates/question.html:179
msgid "most voted answers will be shown first"
msgstr ""
-#: skins/default/templates/question.html:181
+#: skins/default/templates/question.html:180
msgid "popular answers"
msgstr "most voted"
+#: skins/default/templates/question.html:198
#: skins/default/templates/question.html:199
-#: skins/default/templates/question.html:200
msgid "i like this answer (click again to cancel)"
msgstr ""
+#: skins/default/templates/question.html:209
#: skins/default/templates/question.html:210
-#: skins/default/templates/question.html:211
msgid "i dont like this answer (click again to cancel)"
msgstr ""
+#: skins/default/templates/question.html:218
#: skins/default/templates/question.html:219
-#: skins/default/templates/question.html:220
msgid "mark this answer as favorite (click again to undo)"
msgstr ""
+#: skins/default/templates/question.html:228
#: skins/default/templates/question.html:229
-#: skins/default/templates/question.html:230
#, python-format
msgid "%(question_author)s has selected this answer as correct"
msgstr ""
-#: skins/default/templates/question.html:245
+#: skins/default/templates/question.html:244
msgid "answer permanent link"
msgstr "permanent link"
-#: skins/default/templates/question.html:246
+#: skins/default/templates/question.html:245
msgid "permanent link"
msgstr "link"
-#: skins/default/templates/question.html:315
-#: skins/default/templates/question.html:317
+#: skins/default/templates/question.html:314
+#: skins/default/templates/question.html:316
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"
-#: skins/default/templates/question.html:319
+#: skins/default/templates/question.html:318
msgid "Notify me weekly when there are any new answers"
msgstr ""
"<strong>Notify me</strong> weekly when there are any new answers or updates"
-#: skins/default/templates/question.html:321
+#: skins/default/templates/question.html:320
msgid "Notify me immediately when there are any new answers"
msgstr ""
-"<strong>Notify me</strong> immediately when there are any new answers or updates"
+"<strong>Notify me</strong> immediately when there are any new answers or "
+"updates"
-#: skins/default/templates/question.html:324
+#: skins/default/templates/question.html:323
#, python-format
msgid ""
"You can always adjust frequency of email updates from your %(profile_url)s"
@@ -3662,21 +3858,21 @@ msgstr ""
"(note: you can always <strong><a href='%(profile_url)s?"
"sort=email_subscriptions'>change</a></strong> how often you receive updates)"
-#: skins/default/templates/question.html:329
+#: skins/default/templates/question.html:328
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."
-#: skins/default/templates/question.html:339
+#: skins/default/templates/question.html:338
msgid "Your answer"
msgstr ""
-#: skins/default/templates/question.html:341
+#: skins/default/templates/question.html:340
msgid "Be the first one to answer this question!"
msgstr ""
-#: skins/default/templates/question.html:347
+#: skins/default/templates/question.html:346
msgid "you can answer anonymously and then login"
msgstr ""
"<span class='strong big'>Please start posting your answer anonymously</span> "
@@ -3685,7 +3881,7 @@ msgstr ""
"answer</strong>, for discussions, <strong>please use comments</strong> and "
"<strong>please do remember to vote</strong> (after you log in)!"
-#: skins/default/templates/question.html:351
+#: skins/default/templates/question.html:350
msgid "answer your own question only to give an answer"
msgstr ""
"<span class='big strong'>You are welcome to answer your own question</span>, "
@@ -3695,7 +3891,7 @@ msgstr ""
"forget to vote :)</strong> for the answers that you liked (or perhaps did "
"not like)! "
-#: skins/default/templates/question.html:353
+#: skins/default/templates/question.html:352
msgid "please only give an answer, no discussions"
msgstr ""
"<span class='big strong'>Please try to give a substantial answer</span>. If "
@@ -3705,275 +3901,100 @@ msgstr ""
"please <strong>don't forget to vote</strong> - it really helps to select the "
"best questions and answers!"
-#: skins/default/templates/question.html:360
+#: skins/default/templates/question.html:359
msgid "Login/Signup to Post Your Answer"
msgstr "Login/Signup to Post"
-#: skins/default/templates/question.html:363
+#: skins/default/templates/question.html:362
msgid "Answer Your Own Question"
msgstr ""
-#: skins/default/templates/question.html:365
+#: skins/default/templates/question.html:364
msgid "Answer the question"
msgstr "Post Your Answer"
-#: skins/default/templates/question.html:379
+#: skins/default/templates/question.html:380
msgid "Question tags"
msgstr "Tags"
-#: skins/default/templates/question.html:384
-#: skins/default/templates/questions.html:222
-#: skins/default/templates/tag_selector.html:9
-#: skins/default/templates/tag_selector.html:26
-#, python-format
-msgid "see questions tagged '%(tag_name)s'"
-msgstr ""
-
-#: skins/default/templates/question.html:390
+#: skins/default/templates/question.html:397
msgid "question asked"
msgstr "Asked"
-#: skins/default/templates/question.html:393
+#: skins/default/templates/question.html:400
msgid "question was seen"
msgstr "Seen"
-#: skins/default/templates/question.html:393
+#: skins/default/templates/question.html:400
msgid "times"
msgstr ""
-#: skins/default/templates/question.html:396
+#: skins/default/templates/question.html:403
msgid "last updated"
msgstr "Last updated"
-#: skins/default/templates/question.html:403
+#: skins/default/templates/question.html:410
msgid "Related questions"
msgstr ""
#: skins/default/templates/question_edit.html:4
-#: skins/default/templates/question_edit.html:10
+#: skins/default/templates/question_edit.html:9
msgid "Edit question"
msgstr ""
-#: skins/default/templates/question_edit_tips.html:3
-msgid "question tips"
-msgstr "Tips"
-
-#: skins/default/templates/question_edit_tips.html:6
-msgid "please ask a relevant question"
-msgstr "ask a question interesting to this community"
-
-#: skins/default/templates/question_edit_tips.html:9
-msgid "please try provide enough details"
-msgstr "provide enough details"
-
#: skins/default/templates/question_retag.html:3
-#: skins/default/templates/question_retag.html:6
+#: skins/default/templates/question_retag.html:5
msgid "Change tags"
msgstr "Retag question"
-#: skins/default/templates/question_retag.html:25
+#: skins/default/templates/question_retag.html:22
msgid "Retag"
msgstr ""
-#: skins/default/templates/question_retag.html:34
+#: skins/default/templates/question_retag.html:30
msgid "Why use and modify tags?"
msgstr ""
-#: skins/default/templates/question_retag.html:36
+#: skins/default/templates/question_retag.html:32
msgid "Tags help to keep the content better organized and searchable"
msgstr ""
-#: skins/default/templates/question_retag.html:38
+#: skins/default/templates/question_retag.html:34
msgid "tag editors receive special awards from the community"
msgstr ""
-#: skins/default/templates/question_retag.html:79
+#: skins/default/templates/question_retag.html:61
msgid "up to 5 tags, less than 20 characters each"
msgstr ""
-#: skins/default/templates/questions.html:4
-msgid "Questions"
-msgstr ""
-
-#: skins/default/templates/questions.html:9
-msgid "In:"
-msgstr ""
-
-#: skins/default/templates/questions.html:18
-msgid "see unanswered questions"
-msgstr ""
-
-#: skins/default/templates/questions.html:24
-msgid "see your favorite questions"
-msgstr ""
-
-#: skins/default/templates/questions.html:29
-msgid "Sort by:"
-msgstr ""
-
-#: skins/default/templates/questions.html:97
-#: skins/default/templates/questions.html:100
-msgid "subscribe to the questions feed"
-msgstr ""
-
-#: skins/default/templates/questions.html:101
-msgid "rss feed"
-msgstr ""
-
-#: skins/default/templates/questions.html:105
-#, python-format
-msgid ""
-"\n"
-" %(q_num)s question\n"
-" "
-msgid_plural ""
-"\n"
-" %(q_num)s questions\n"
-" "
-msgstr[0] ""
-msgstr[1] ""
-
-#: skins/default/templates/questions.html:111 views/readers.py:158
-#, python-format
-msgid "%(q_num)s question"
-msgid_plural "%(q_num)s questions"
-msgstr[0] ""
-msgstr[1] ""
-
-#: skins/default/templates/questions.html:114
-#, python-format
-msgid "with %(author_name)s's contributions"
-msgstr ""
-
-#: skins/default/templates/questions.html:117
-msgid "tagged"
-msgstr ""
-
-#: skins/default/templates/questions.html:122
-msgid "Search tips:"
-msgstr ""
-
-#: skins/default/templates/questions.html:125
-msgid "reset author"
-msgstr ""
-
-#: skins/default/templates/questions.html:127
-#: skins/default/templates/questions.html:130
-#: skins/default/templates/questions.html:168
-#: skins/default/templates/questions.html:171
-msgid " or "
-msgstr ""
-
-#: skins/default/templates/questions.html:128
-msgid "reset tags"
-msgstr ""
-
-#: skins/default/templates/questions.html:131
-#: skins/default/templates/questions.html:134
-msgid "start over"
-msgstr ""
-
-#: skins/default/templates/questions.html:136
-msgid " - to expand, or dig in by adding more tags and revising the query."
-msgstr ""
-
-#: skins/default/templates/questions.html:139
-msgid "Search tip:"
-msgstr ""
-
-#: skins/default/templates/questions.html:139
-msgid "add tags and a query to focus your search"
-msgstr ""
-
-#: skins/default/templates/questions.html:154
-#: skins/default/templates/unused/questions_ajax.html:79
-msgid "There are no unanswered questions here"
-msgstr ""
-
-#: skins/default/templates/questions.html:157
-#: skins/default/templates/unused/questions_ajax.html:82
-msgid "No favorite questions here. "
-msgstr ""
-
-#: skins/default/templates/questions.html:158
-#: skins/default/templates/unused/questions_ajax.html:83
-msgid "Please start (bookmark) some questions when you visit them"
-msgstr ""
-
-#: skins/default/templates/questions.html:163
-#: skins/default/templates/unused/questions_ajax.html:88
-msgid "You can expand your search by "
-msgstr ""
-
-#: skins/default/templates/questions.html:166
-#: skins/default/templates/unused/questions_ajax.html:92
-msgid "resetting author"
-msgstr ""
-
-#: skins/default/templates/questions.html:169
-#: skins/default/templates/unused/questions_ajax.html:96
-msgid "resetting tags"
-msgstr ""
-
-#: skins/default/templates/questions.html:172
-#: skins/default/templates/questions.html:175
-#: skins/default/templates/unused/questions_ajax.html:100
-#: skins/default/templates/unused/questions_ajax.html:104
-msgid "starting over"
-msgstr ""
-
-#: skins/default/templates/questions.html:180
-#: skins/default/templates/unused/questions_ajax.html:109
-msgid "Please always feel free to ask your question!"
-msgstr ""
-
-#: skins/default/templates/questions.html:184
-#: skins/default/templates/unused/questions_ajax.html:113
-msgid "Did not find what you were looking for?"
-msgstr ""
-
-#: skins/default/templates/questions.html:185
-#: skins/default/templates/unused/questions_ajax.html:114
-msgid "Please, post your question!"
-msgstr ""
-
-#: skins/default/templates/questions.html:200
-msgid "Contributors"
-msgstr ""
-
-#: skins/default/templates/questions.html:217
-msgid "Related tags"
-msgstr "Tags"
-
-#: skins/default/templates/reopen.html:3 skins/default/templates/reopen.html:6
+#: skins/default/templates/reopen.html:3 skins/default/templates/reopen.html:5
msgid "Reopen question"
msgstr ""
-#: skins/default/templates/reopen.html:9
+#: skins/default/templates/reopen.html:6
msgid "Title"
msgstr ""
-#: skins/default/templates/reopen.html:14
+#: skins/default/templates/reopen.html:11
#, python-format
msgid ""
"This question has been closed by \n"
-" <a href=\"%(closed_by_profile_url)s\">%(closed_by_username)s</a>\n"
-" "
+" <a href=\"%(closed_by_profile_url)s\">%(closed_by_username)s</a>\n"
msgstr ""
-#: skins/default/templates/reopen.html:19
+#: skins/default/templates/reopen.html:16
msgid "Close reason:"
msgstr ""
-#: skins/default/templates/reopen.html:22
+#: skins/default/templates/reopen.html:19
msgid "When:"
msgstr ""
-#: skins/default/templates/reopen.html:25
+#: skins/default/templates/reopen.html:22
msgid "Reopen this question?"
msgstr ""
-#: skins/default/templates/reopen.html:29
+#: skins/default/templates/reopen.html:26
msgid "Reopen this question"
msgstr ""
@@ -3991,32 +4012,17 @@ msgstr ""
msgid "revision %(number)s"
msgstr ""
-#: skins/default/templates/tag_selector.html:3
-msgid "Interesting tags"
-msgstr ""
-
-#: skins/default/templates/tag_selector.html:13
-#, python-format
-msgid "remove '%(tag_name)s' from the list of interesting tags"
+#: skins/default/templates/subscribe_for_tags.html:3
+#: skins/default/templates/subscribe_for_tags.html:5
+msgid "Subscribe for tags"
msgstr ""
-#: skins/default/templates/tag_selector.html:19
-#: skins/default/templates/tag_selector.html:36
-#: skins/default/templates/user_moderate.html:35
-msgid "Add"
-msgstr ""
-
-#: skins/default/templates/tag_selector.html:20
-msgid "Ignored tags"
-msgstr ""
-
-#: skins/default/templates/tag_selector.html:30
-#, python-format
-msgid "remove '%(tag_name)s' from the list of ignored tags"
+#: skins/default/templates/subscribe_for_tags.html:6
+msgid "Please, subscribe for the following tags:"
msgstr ""
-#: skins/default/templates/tag_selector.html:39
-msgid "keep ignored questions hidden"
+#: skins/default/templates/subscribe_for_tags.html:15
+msgid "Subscribe"
msgstr ""
#: skins/default/templates/tags.html:4 skins/default/templates/tags.html:8
@@ -4039,355 +4045,25 @@ msgstr ""
msgid "by popularity"
msgstr ""
-#: skins/default/templates/tags.html:27
+#: skins/default/templates/tags.html:26
#, python-format
msgid ""
"All tags matching '<span class=\"darkred\"><strong>%(stag)s</strong></span>'"
msgstr ""
-#: skins/default/templates/tags.html:30
+#: skins/default/templates/tags.html:29
msgid "Nothing found"
msgstr ""
-#: skins/default/templates/user.html:14
-#, python-format
-msgid "%(username)s's profile"
-msgstr ""
-
-#: skins/default/templates/user_edit.html:4
-msgid "Edit user profile"
-msgstr ""
-
-#: skins/default/templates/user_edit.html:7
-msgid "edit profile"
-msgstr ""
-
-#: skins/default/templates/user_edit.html:17
-#: skins/default/templates/user_info.html:11
-msgid "change picture"
-msgstr ""
-
-#: skins/default/templates/user_edit.html:20
-msgid "Registered user"
-msgstr ""
-
-#: skins/default/templates/user_edit.html:27
-msgid "Screen Name"
-msgstr ""
-
-#: skins/default/templates/user_edit.html:75
-#: skins/default/templates/user_email_subscriptions.html:18
-msgid "Update"
-msgstr ""
-
-#: skins/default/templates/user_email_subscriptions.html:4
-msgid "Email subscription settings"
-msgstr ""
-
-#: skins/default/templates/user_email_subscriptions.html:5
-msgid "email subscription settings info"
-msgstr ""
-"<span class='big strong'>Adjust frequency of email updates.</span> Receive "
-"updates on interesting questions by email, <strong><br/>help the community</"
-"strong> by answering questions of your colleagues. If you do not wish to "
-"receive emails - select 'no email' on all items below.<br/>Updates are only "
-"sent when there is any new activity on selected items."
-
-#: skins/default/templates/user_email_subscriptions.html:19
-msgid "Stop sending email"
-msgstr "Stop Email"
-
-#: skins/default/templates/user_inbox.html:31
-msgid "Sections:"
-msgstr ""
-
-#: skins/default/templates/user_inbox.html:35
-#, python-format
-msgid "forum responses (%(re_count)s)"
-msgstr ""
-
-#: skins/default/templates/user_inbox.html:40
-#, python-format
-msgid "flagged items (%(flag_count)s)"
-msgstr ""
-
-#: skins/default/templates/user_inbox.html:46
-msgid "select:"
-msgstr ""
-
-#: skins/default/templates/user_inbox.html:48
-msgid "seen"
-msgstr ""
-
-#: skins/default/templates/user_inbox.html:49
-msgid "new"
-msgstr ""
-
-#: skins/default/templates/user_inbox.html:50
-msgid "none"
-msgstr ""
-
-#: skins/default/templates/user_inbox.html:51
-msgid "mark as seen"
-msgstr ""
-
-#: skins/default/templates/user_inbox.html:52
-msgid "mark as new"
-msgstr ""
-
-#: skins/default/templates/user_inbox.html:53
-msgid "dismiss"
-msgstr ""
+#: skins/default/templates/users.html:4 skins/default/templates/users.html:7
+msgid "Users"
+msgstr "People"
-#: skins/default/templates/user_info.html:18
#: skins/default/templates/users.html:13 skins/default/templates/users.html:14
+#: skins/default/templates/user_profile/user_info.html:25
msgid "reputation"
msgstr "karma"
-#: skins/default/templates/user_info.html:30
-msgid "manage login methods"
-msgstr ""
-
-#: skins/default/templates/user_info.html:34
-msgid "update profile"
-msgstr ""
-
-#: skins/default/templates/user_info.html:46
-msgid "real name"
-msgstr ""
-
-#: skins/default/templates/user_info.html:51
-msgid "member for"
-msgstr "member since"
-
-#: skins/default/templates/user_info.html:56
-msgid "last seen"
-msgstr ""
-
-#: skins/default/templates/user_info.html:62
-msgid "user website"
-msgstr "website"
-
-#: skins/default/templates/user_info.html:68
-msgid "location"
-msgstr ""
-
-#: skins/default/templates/user_info.html:75
-msgid "age"
-msgstr ""
-
-#: skins/default/templates/user_info.html:76
-msgid "age unit"
-msgstr "years old"
-
-#: skins/default/templates/user_info.html:83
-msgid "todays unused votes"
-msgstr ""
-
-#: skins/default/templates/user_info.html:84
-msgid "votes left"
-msgstr ""
-
-#: skins/default/templates/user_moderate.html:5
-#, python-format
-msgid "%(username)s's current status is \"%(status)s\""
-msgstr ""
-
-#: skins/default/templates/user_moderate.html:8
-msgid "User status changed"
-msgstr ""
-
-#: skins/default/templates/user_moderate.html:15
-msgid "Save"
-msgstr ""
-
-#: skins/default/templates/user_moderate.html:21
-#, python-format
-msgid "Your current reputation is %(reputation)s points"
-msgstr ""
-
-#: skins/default/templates/user_moderate.html:23
-#, python-format
-msgid "User's current reputation is %(reputation)s points"
-msgstr ""
-
-#: skins/default/templates/user_moderate.html:27
-msgid "User reputation changed"
-msgstr ""
-
-#: skins/default/templates/user_moderate.html:34
-msgid "Subtract"
-msgstr ""
-
-#: skins/default/templates/user_moderate.html:39
-#, python-format
-msgid "Send message to %(username)s"
-msgstr ""
-
-#: skins/default/templates/user_moderate.html:40
-msgid ""
-"An email will be sent to the user with 'reply-to' field set to your email "
-"address. Please make sure that your address is entered correctly."
-msgstr ""
-
-#: skins/default/templates/user_moderate.html:42
-msgid "Message sent"
-msgstr ""
-
-#: skins/default/templates/user_moderate.html:60
-msgid "Send message"
-msgstr ""
-
-#: skins/default/templates/user_reputation.html:7
-msgid "Your karma change log."
-msgstr ""
-
-#: skins/default/templates/user_reputation.html:9
-#, python-format
-msgid "%(user_name)s's karma change log"
-msgstr ""
-
-#: skins/default/templates/user_stats.html:7
-#, python-format
-msgid "<span class=\"count\">%(counter)s</span> Question"
-msgid_plural "<span class=\"count\">%(counter)s</span> Questions"
-msgstr[0] ""
-msgstr[1] ""
-
-#: skins/default/templates/user_stats.html:12
-#, python-format
-msgid "<span class=\"count\">%(counter)s</span> Answer"
-msgid_plural "<span class=\"count\">%(counter)s</span> Answers"
-msgstr[0] ""
-msgstr[1] ""
-
-#: skins/default/templates/user_stats.html:20
-#, python-format
-msgid "the answer has been voted for %(answer_score)s times"
-msgstr ""
-
-#: skins/default/templates/user_stats.html:20
-msgid "this answer has been selected as correct"
-msgstr ""
-
-#: skins/default/templates/user_stats.html:30
-#, python-format
-msgid "(%(comment_count)s comment)"
-msgid_plural "the answer has been commented %(comment_count)s times"
-msgstr[0] ""
-msgstr[1] ""
-
-#: skins/default/templates/user_stats.html:40
-#, python-format
-msgid "<span class=\"count\">%(cnt)s</span> Vote"
-msgid_plural "<span class=\"count\">%(cnt)s</span> Votes "
-msgstr[0] ""
-msgstr[1] ""
-
-#: skins/default/templates/user_stats.html:46
-msgid "thumb up"
-msgstr ""
-
-#: skins/default/templates/user_stats.html:47
-msgid "user has voted up this many times"
-msgstr ""
-
-#: skins/default/templates/user_stats.html:50
-msgid "thumb down"
-msgstr ""
-
-#: skins/default/templates/user_stats.html:51
-msgid "user voted down this many times"
-msgstr ""
-
-#: skins/default/templates/user_stats.html:59
-#, python-format
-msgid "<span class=\"count\">%(counter)s</span> Tag"
-msgid_plural "<span class=\"count\">%(counter)s</span> Tags"
-msgstr[0] ""
-msgstr[1] ""
-
-#: skins/default/templates/user_stats.html:67
-#, python-format
-msgid ""
-"see other questions with %(view_user)s's contributions tagged '%(tag_name)s' "
-msgstr ""
-
-#: skins/default/templates/user_stats.html:81
-#, python-format
-msgid "<span class=\"count\">%(counter)s</span> Badge"
-msgid_plural "<span class=\"count\">%(counter)s</span> Badges"
-msgstr[0] ""
-msgstr[1] ""
-
-#: skins/default/templates/user_tabs.html:5
-msgid "User profile"
-msgstr ""
-
-#: skins/default/templates/user_tabs.html:6
-msgid "overview"
-msgstr ""
-
-#: skins/default/templates/user_tabs.html:9 views/users.py:729
-msgid "comments and answers to others questions"
-msgstr ""
-
-#: skins/default/templates/user_tabs.html:10
-msgid "inbox"
-msgstr ""
-
-#: skins/default/templates/user_tabs.html:13
-msgid "graph of user reputation"
-msgstr "Graph of user karma"
-
-#: skins/default/templates/user_tabs.html:14
-msgid "reputation history"
-msgstr "karma history"
-
-#: skins/default/templates/user_tabs.html:16
-msgid "questions that user selected as his/her favorite"
-msgstr ""
-
-#: skins/default/templates/user_tabs.html:17
-msgid "favorites"
-msgstr ""
-
-#: skins/default/templates/user_tabs.html:19
-msgid "recent activity"
-msgstr ""
-
-#: skins/default/templates/user_tabs.html:20
-msgid "activity"
-msgstr ""
-
-#: skins/default/templates/user_tabs.html:23 views/users.py:794
-msgid "user vote record"
-msgstr ""
-
-#: skins/default/templates/user_tabs.html:24
-msgid "casted votes"
-msgstr "votes"
-
-#: skins/default/templates/user_tabs.html:28 views/users.py:904
-msgid "email subscription settings"
-msgstr ""
-
-#: skins/default/templates/user_tabs.html:29
-msgid "subscriptions"
-msgstr ""
-
-#: skins/default/templates/user_tabs.html:33 views/users.py:216
-msgid "moderate this user"
-msgstr ""
-
-#: skins/default/templates/user_tabs.html:34
-msgid "moderation"
-msgstr ""
-
-#: skins/default/templates/users.html:4 skins/default/templates/users.html:7
-msgid "Users"
-msgstr "People"
-
#: skins/default/templates/users.html:19 skins/default/templates/users.html:20
msgid "recent"
msgstr ""
@@ -4396,31 +4072,15 @@ msgstr ""
msgid "by username"
msgstr ""
-#: skins/default/templates/users.html:38
+#: skins/default/templates/users.html:37
#, python-format
msgid "users matching query %(suser)s:"
msgstr ""
-#: skins/default/templates/users.html:41
+#: skins/default/templates/users.html:40
msgid "Nothing found."
msgstr ""
-#: skins/default/templates/users_questions.html:9
-#: skins/default/templates/users_questions.html:17
-#, python-format
-msgid "this questions was selected as favorite %(cnt)s time"
-msgid_plural "this questions was selected as favorite %(cnt)s times"
-msgstr[0] ""
-msgstr[1] ""
-
-#: skins/default/templates/users_questions.html:10
-msgid "thumb-up on"
-msgstr ""
-
-#: skins/default/templates/users_questions.html:18
-msgid "thumb-up off"
-msgstr ""
-
#: skins/default/templates/authopenid/changeemail.html:2
#: skins/default/templates/authopenid/changeemail.html:8
#: skins/default/templates/authopenid/changeemail.html:36
@@ -4532,11 +4192,11 @@ msgstr ""
"(change_link)s'>change</a> email used for update subscriptions if necessary."
#: skins/default/templates/authopenid/complete.html:21
-#: skins/default/templates/authopenid/complete.html:24
+#: skins/default/templates/authopenid/complete.html:23
msgid "Registration"
msgstr ""
-#: skins/default/templates/authopenid/complete.html:29
+#: skins/default/templates/authopenid/complete.html:27
#, python-format
msgid "register new %(provider)s account info, see %(gravatar_faq_url)s"
msgstr ""
@@ -4547,7 +4207,7 @@ msgstr ""
"questions and will be used to create and retrieve your unique avatar image - "
"<a href='%(gravatar_faq_url)s'><strong>gravatar</strong></a>.</p>"
-#: skins/default/templates/authopenid/complete.html:32
+#: skins/default/templates/authopenid/complete.html:30
#, python-format
msgid ""
"%(username)s already exists, choose another name for \n"
@@ -4564,7 +4224,7 @@ msgstr ""
"updates</strong> on the interesting questions or entire forum by email. "
"Email addresses are never shown or otherwise shared with anybody else.</p>"
-#: skins/default/templates/authopenid/complete.html:36
+#: skins/default/templates/authopenid/complete.html:34
#, python-format
msgid ""
"register new external %(provider)s account info, see %(gravatar_faq_url)s"
@@ -4578,7 +4238,7 @@ msgstr ""
"retrieve your unique avatar image - <a href='%(gravatar_faq_url)"
"s'><strong>gravatar</strong></a>.</p>"
-#: skins/default/templates/authopenid/complete.html:39
+#: skins/default/templates/authopenid/complete.html:37
#, python-format
msgid "register new Facebook connect account info, see %(gravatar_faq_url)s"
msgstr ""
@@ -4589,22 +4249,22 @@ msgstr ""
"and will be used to create and retrieve your unique avatar image - <a href='%"
"(gravatar_faq_url)s'><strong>gravatar</strong></a>.</p>"
-#: skins/default/templates/authopenid/complete.html:42
+#: skins/default/templates/authopenid/complete.html:40
msgid "This account already exists, please use another."
msgstr ""
-#: skins/default/templates/authopenid/complete.html:61
+#: skins/default/templates/authopenid/complete.html:59
msgid "Screen name label"
msgstr "<strong>Screen Name</strong> (<i>will be shown to others</i>)"
-#: skins/default/templates/authopenid/complete.html:68
+#: skins/default/templates/authopenid/complete.html:66
msgid "Email address label"
msgstr ""
"<strong>Email Address</strong> (<i>will <strong>not</strong> be shared with "
"anyone, must be valid</i>)"
-#: skins/default/templates/authopenid/complete.html:74
-#: skins/default/templates/authopenid/signup_with_password.html:17
+#: skins/default/templates/authopenid/complete.html:72
+#: skins/default/templates/authopenid/signup_with_password.html:36
msgid "receive updates motivational blurb"
msgstr ""
"<strong>Receive forum updates by email</strong> - this will help our "
@@ -4613,16 +4273,16 @@ msgstr ""
"week</strong> - only when there is anything new.<br/>If you like, please "
"adjust this now or any time later from your user account."
-#: skins/default/templates/authopenid/complete.html:78
-#: skins/default/templates/authopenid/signup_with_password.html:21
+#: skins/default/templates/authopenid/complete.html:76
+#: skins/default/templates/authopenid/signup_with_password.html:40
msgid "please select one of the options above"
msgstr ""
-#: skins/default/templates/authopenid/complete.html:81
+#: skins/default/templates/authopenid/complete.html:79
msgid "Tag filter tool will be your right panel, once you log in."
msgstr ""
-#: skins/default/templates/authopenid/complete.html:82
+#: skins/default/templates/authopenid/complete.html:80
msgid "create account"
msgstr "Signup"
@@ -4674,11 +4334,24 @@ msgid ""
"for any inconvenience"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:3
+#: skins/default/templates/authopenid/macros.html:50
+msgid "Please enter your <span>user name</span>, then sign in"
+msgstr ""
+
+#: skins/default/templates/authopenid/macros.html:51
+#: skins/default/templates/authopenid/signin.html:84
+msgid "(or select another login method above)"
+msgstr ""
+
+#: skins/default/templates/authopenid/macros.html:53
+msgid "Sign in"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:4
msgid "User login"
msgstr "User login"
-#: skins/default/templates/authopenid/signin.html:11
+#: skins/default/templates/authopenid/signin.html:12
#, python-format
msgid ""
"\n"
@@ -4690,7 +4363,7 @@ msgstr ""
"strong> %(summary)s...\"</i> <span class=\"strong big\">is saved and will be "
"posted once you log in.</span>"
-#: skins/default/templates/authopenid/signin.html:18
+#: skins/default/templates/authopenid/signin.html:19
#, python-format
msgid ""
"Your question \n"
@@ -4701,168 +4374,163 @@ msgstr ""
"strong> %(summary)s...\"</i> <span class=\"strong big\">is saved and will be "
"posted once you log in.</span>"
-#: skins/default/templates/authopenid/signin.html:25
+#: skins/default/templates/authopenid/signin.html:26
msgid ""
"Take a pick of your favorite service below to sign in using secure OpenID or "
"similar technology. Your external service password always stays confidential "
"and you don't have to rememeber or create another one."
msgstr ""
-#: skins/default/templates/authopenid/signin.html:28
+#: skins/default/templates/authopenid/signin.html:29
msgid ""
"It's a good idea to make sure that your existing login methods still work, "
"or add a new one. Please click any of the icons below to check/change or add "
"new login methods."
msgstr ""
-#: skins/default/templates/authopenid/signin.html:30
+#: skins/default/templates/authopenid/signin.html:31
msgid ""
"Please add a more permanent login method by clicking one of the icons below, "
"to avoid logging in via email each time."
msgstr ""
-#: skins/default/templates/authopenid/signin.html:34
+#: skins/default/templates/authopenid/signin.html:35
msgid ""
"Click on one of the icons below to add a new login method or re-validate an "
"existing one."
msgstr ""
-#: skins/default/templates/authopenid/signin.html:36
+#: skins/default/templates/authopenid/signin.html:37
msgid ""
"You don't have a method to log in right now, please add one or more by "
"clicking any of the icons below."
msgstr ""
-#: skins/default/templates/authopenid/signin.html:39
+#: skins/default/templates/authopenid/signin.html:40
msgid ""
"Please check your email and visit the enclosed link to re-connect to your "
"account"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:86
-msgid "Please enter your <span>user name</span>, then sign in"
-msgstr ""
-
-#: skins/default/templates/authopenid/signin.html:87
-#: skins/default/templates/authopenid/signin.html:109
-msgid "(or select another login method above)"
-msgstr ""
-
-#: skins/default/templates/authopenid/signin.html:89
-msgid "Sign in"
-msgstr ""
-
-#: skins/default/templates/authopenid/signin.html:107
+#: skins/default/templates/authopenid/signin.html:82
msgid "Please enter your <span>user name and password</span>, then sign in"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:111
+#: skins/default/templates/authopenid/signin.html:86
msgid "Login failed, please try again"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:114
+#: skins/default/templates/authopenid/signin.html:89
msgid "Login name"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:118
+#: skins/default/templates/authopenid/signin.html:93
msgid "Password"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:122
+#: skins/default/templates/authopenid/signin.html:97
msgid "Login"
msgstr "Sign in"
-#: skins/default/templates/authopenid/signin.html:129
+#: skins/default/templates/authopenid/signin.html:104
msgid "To change your password - please enter the new one twice, then submit"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:132
+#: skins/default/templates/authopenid/signin.html:107
msgid "New password"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:137
+#: skins/default/templates/authopenid/signin.html:112
msgid "Please, retype"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:156
+#: skins/default/templates/authopenid/signin.html:130
msgid "Here are your current login methods"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:160
+#: skins/default/templates/authopenid/signin.html:134
msgid "provider"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:161
+#: skins/default/templates/authopenid/signin.html:135
msgid "last used"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:162
+#: skins/default/templates/authopenid/signin.html:136
msgid "delete, if you like"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:187
+#: skins/default/templates/authopenid/signin.html:162
msgid "Still have trouble signing in?"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:192
+#: skins/default/templates/authopenid/signin.html:167
msgid "Please, enter your email address below and obtain a new key"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:194
+#: skins/default/templates/authopenid/signin.html:169
msgid "Please, enter your email address below to recover your account"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:197
+#: skins/default/templates/authopenid/signin.html:172
msgid "recover your account via email"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:208
+#: skins/default/templates/authopenid/signin.html:183
msgid "Send a new recovery key"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:210
+#: skins/default/templates/authopenid/signin.html:185
msgid "Recover your account via email"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:221
+#: skins/default/templates/authopenid/signin.html:196
msgid "Why use OpenID?"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:224
+#: skins/default/templates/authopenid/signin.html:199
msgid "with openid it is easier"
msgstr "With the OpenID you don't need to create new username and password."
-#: skins/default/templates/authopenid/signin.html:227
+#: skins/default/templates/authopenid/signin.html:202
msgid "reuse openid"
msgstr "You can safely re-use the same login for all OpenID-enabled websites."
-#: skins/default/templates/authopenid/signin.html:230
+#: skins/default/templates/authopenid/signin.html:205
msgid "openid is widely adopted"
msgstr ""
"There are > 160,000,000 OpenID account in use. Over 10,000 sites are OpenID-"
"enabled."
-#: skins/default/templates/authopenid/signin.html:233
+#: skins/default/templates/authopenid/signin.html:208
msgid "openid is supported open standard"
msgstr "OpenID is based on an open standard, supported by many organizations."
-#: skins/default/templates/authopenid/signin.html:237
+#: skins/default/templates/authopenid/signin.html:212
msgid "Find out more"
msgstr ""
-#: skins/default/templates/authopenid/signin.html:238
+#: skins/default/templates/authopenid/signin.html:213
msgid "Get OpenID"
msgstr ""
-#: skins/default/templates/authopenid/signup_with_password.html:3
+#: skins/default/templates/authopenid/signup_with_password.html:4
msgid "Signup"
msgstr ""
-#: skins/default/templates/authopenid/signup_with_password.html:6
+#: skins/default/templates/authopenid/signup_with_password.html:10
+msgid "Please register by clicking on any of the icons below"
+msgstr ""
+
+#: skins/default/templates/authopenid/signup_with_password.html:23
+msgid "or create a new user name and password here"
+msgstr ""
+
+#: skins/default/templates/authopenid/signup_with_password.html:25
msgid "Create login name and password"
msgstr ""
-#: skins/default/templates/authopenid/signup_with_password.html:8
+#: skins/default/templates/authopenid/signup_with_password.html:26
msgid "Traditional signup info"
msgstr ""
"<span class='strong big'>If you prefer, create your forum login name and "
@@ -4871,181 +4539,805 @@ msgstr ""
"simply reuse your external login (e.g. Gmail or AOL) without ever sharing "
"your login details with anyone and having to remember yet another password."
-#: skins/default/templates/authopenid/signup_with_password.html:24
+#: skins/default/templates/authopenid/signup_with_password.html:44
msgid ""
"Please read and type in the two words below to help us prevent automated "
"account creation."
msgstr ""
-#: skins/default/templates/authopenid/signup_with_password.html:26
+#: skins/default/templates/authopenid/signup_with_password.html:47
msgid "Create Account"
msgstr ""
-#: skins/default/templates/authopenid/signup_with_password.html:27
+#: skins/default/templates/authopenid/signup_with_password.html:49
msgid "or"
msgstr ""
-#: skins/default/templates/authopenid/signup_with_password.html:28
+#: skins/default/templates/authopenid/signup_with_password.html:50
msgid "return to OpenID login"
msgstr ""
-#: skins/default/templates/blocks/header_meta_links.html:7
+#: skins/default/templates/avatar/add.html:3
+#, fuzzy
+msgid "add avatar"
+msgstr "How to change my picture (gravatar) and what is gravatar?"
+
+#: skins/default/templates/avatar/add.html:5
+#, fuzzy
+msgid "Change avatar"
+msgstr "Retag question"
+
+#: skins/default/templates/avatar/add.html:6
+#: skins/default/templates/avatar/change.html:7
+msgid "Your current avatar: "
+msgstr ""
+
+#: skins/default/templates/avatar/add.html:9
+#: skins/default/templates/avatar/change.html:11
+msgid "You haven't uploaded an avatar yet. Please upload one now."
+msgstr ""
+
+#: skins/default/templates/avatar/add.html:13
+msgid "Upload New Image"
+msgstr ""
+
+#: skins/default/templates/avatar/change.html:4
+#, fuzzy
+msgid "change avatar"
+msgstr "Retag question"
+
+#: skins/default/templates/avatar/change.html:17
+msgid "Choose new Default"
+msgstr ""
+
+#: skins/default/templates/avatar/change.html:22
+msgid "Upload"
+msgstr ""
+
+#: skins/default/templates/avatar/confirm_delete.html:3
+msgid "delete avatar"
+msgstr ""
+
+#: skins/default/templates/avatar/confirm_delete.html:5
+msgid "Please select the avatars that you would like to delete."
+msgstr ""
+
+#: skins/default/templates/avatar/confirm_delete.html:7
#, python-format
-msgid "responses for %(username)s"
+msgid ""
+"You have no avatars to delete. Please <a href=\"%(avatar_change_url)s"
+"\">upload one</a> now."
msgstr ""
-#: skins/default/templates/blocks/header_meta_links.html:10
+#: skins/default/templates/avatar/confirm_delete.html:13
+msgid "Delete These"
+msgstr ""
+
+#: skins/default/templates/blocks/answer_edit_tips.html:3
+msgid "answer tips"
+msgstr "Tips"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:6
+msgid "please make your answer relevant to this community"
+msgstr "ask a question interesting to this community"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:9
+msgid "try to give an answer, rather than engage into a discussion"
+msgstr ""
+
+#: skins/default/templates/blocks/answer_edit_tips.html:12
+msgid "please try to provide details"
+msgstr "provide enough details"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:15
+#: skins/default/templates/blocks/question_edit_tips.html:11
+msgid "be clear and concise"
+msgstr ""
+
+#: skins/default/templates/blocks/answer_edit_tips.html:19
+#: skins/default/templates/blocks/question_edit_tips.html:15
+msgid "see frequently asked questions"
+msgstr ""
+
+#: skins/default/templates/blocks/answer_edit_tips.html:25
+#: skins/default/templates/blocks/question_edit_tips.html:20
+msgid "Markdown tips"
+msgstr "Markdown basics"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:29
+#: skins/default/templates/blocks/question_edit_tips.html:24
+msgid "*italic*"
+msgstr ""
+
+#: skins/default/templates/blocks/answer_edit_tips.html:32
+#: skins/default/templates/blocks/question_edit_tips.html:27
+msgid "**bold**"
+msgstr ""
+
+#: skins/default/templates/blocks/answer_edit_tips.html:36
+#: skins/default/templates/blocks/question_edit_tips.html:31
+msgid "*italic* or _italic_"
+msgstr ""
+
+#: skins/default/templates/blocks/answer_edit_tips.html:39
+#: skins/default/templates/blocks/question_edit_tips.html:34
+msgid "**bold** or __bold__"
+msgstr ""
+
+#: skins/default/templates/blocks/answer_edit_tips.html:43
+#: skins/default/templates/blocks/question_edit_tips.html:38
+msgid "link"
+msgstr ""
+
+#: skins/default/templates/blocks/answer_edit_tips.html:43
+#: skins/default/templates/blocks/answer_edit_tips.html:47
+#: skins/default/templates/blocks/question_edit_tips.html:38
+#: skins/default/templates/blocks/question_edit_tips.html:43
+msgid "text"
+msgstr ""
+
+#: skins/default/templates/blocks/answer_edit_tips.html:47
+#: skins/default/templates/blocks/question_edit_tips.html:43
+msgid "image"
+msgstr ""
+
+#: skins/default/templates/blocks/answer_edit_tips.html:51
+#: skins/default/templates/blocks/question_edit_tips.html:47
+msgid "numbered list:"
+msgstr ""
+
+#: skins/default/templates/blocks/answer_edit_tips.html:56
+#: skins/default/templates/blocks/question_edit_tips.html:52
+msgid "basic HTML tags are also supported"
+msgstr ""
+
+#: skins/default/templates/blocks/answer_edit_tips.html:60
+#: skins/default/templates/blocks/question_edit_tips.html:56
+msgid "learn more about Markdown"
+msgstr ""
+
+#: skins/default/templates/blocks/ask_form.html:7
+msgid "login to post question info"
+msgstr ""
+"<span class=\"strong big\">You are welcome to start submitting your question "
+"anonymously</span>. When you submit the post, you will be redirected to the "
+"login/signup page. Your question will be saved in the current session and "
+"will be published after you log in. Login/signup process is very simple. "
+"Login takes about 30 seconds, initial signup takes a minute or less."
+
+#: skins/default/templates/blocks/ask_form.html:11
#, python-format
-msgid "you have a new response"
-msgid_plural "you nave %(response_count)s new responses"
+msgid ""
+"must have valid %(email)s to post, \n"
+" see %(email_validation_faq_url)s\n"
+" "
+msgstr ""
+"<span class='strong big'>Looks like your email address, %(email)s has not "
+"yet been validated.</span> To post messages you must verify your email, "
+"please see <a href='%(email_validation_faq_url)s'>more details here</a>."
+"<br>You can submit your question now and validate email after that. Your "
+"question will saved as pending meanwhile. "
+
+#: skins/default/templates/blocks/ask_form.html:28
+msgid "Login/signup to post your question"
+msgstr "Login/Signup to Post"
+
+#: skins/default/templates/blocks/ask_form.html:30
+msgid "Ask your question"
+msgstr "Ask Your Question"
+
+#: skins/default/templates/blocks/editor_data.html:5
+#, python-format
+msgid "each tag must be shorter that %(max_chars)s character"
+msgid_plural "each tag must be shorter than %(max_chars)s characters"
msgstr[0] ""
msgstr[1] ""
-#: skins/default/templates/blocks/header_meta_links.html:13
-msgid "no new responses yet"
-msgstr ""
+#: skins/default/templates/blocks/editor_data.html:7
+#, python-format
+msgid "please use %(tag_count)s tag"
+msgid_plural "please use %(tag_count)s tags or less"
+msgstr[0] ""
+msgstr[1] ""
-#: skins/default/templates/blocks/header_meta_links.html:25
-#: skins/default/templates/blocks/header_meta_links.html:26
+#: skins/default/templates/blocks/editor_data.html:8
#, python-format
-msgid "%(new)s new flagged posts and %(seen)s previous"
+msgid ""
+"please use up to %(tag_count)s tags, less than %(max_chars)s characters each"
msgstr ""
-#: skins/default/templates/blocks/header_meta_links.html:28
-#: skins/default/templates/blocks/header_meta_links.html:29
-#, python-format
-msgid "%(new)s new flagged posts"
+#: skins/default/templates/blocks/footer.html:5
+#: skins/default/templates/blocks/header_meta_links.html:12
+msgid "about"
msgstr ""
-#: skins/default/templates/blocks/header_meta_links.html:34
-#: skins/default/templates/blocks/header_meta_links.html:35
+#: skins/default/templates/blocks/footer.html:7
+msgid "privacy policy"
+msgstr ""
+
+#: skins/default/templates/blocks/footer.html:16
+msgid "give feedback"
+msgstr ""
+
+#: skins/default/templates/blocks/header.html:8
+msgid "back to home page"
+msgstr ""
+
+#: skins/default/templates/blocks/header.html:9
#, python-format
-msgid "%(seen)s flagged posts"
+msgid "%(site)s logo"
+msgstr ""
+
+#: skins/default/templates/blocks/header.html:17
+msgid "questions"
msgstr ""
-#: skins/default/templates/blocks/header_meta_links.html:47
+#: skins/default/templates/blocks/header.html:27
+msgid "users"
+msgstr "people"
+
+#: skins/default/templates/blocks/header.html:32
+msgid "badges"
+msgstr ""
+
+#: skins/default/templates/blocks/header.html:37
+msgid "ask a question"
+msgstr ""
+
+#: skins/default/templates/blocks/header_meta_links.html:8
msgid "logout"
msgstr "sign out"
-#: skins/default/templates/blocks/header_meta_links.html:49
+#: skins/default/templates/blocks/header_meta_links.html:10
msgid "login"
msgstr "Hi, there! Please sign in"
-#: skins/default/templates/blocks/header_meta_links.html:54
+#: skins/default/templates/blocks/header_meta_links.html:15
msgid "settings"
msgstr ""
-#: skins/default/templates/unused/email_base.html:8
-msgid "home"
+#: skins/default/templates/blocks/input_bar.html:34
+msgid "search"
msgstr ""
-#: skins/default/templates/unused/notarobot.html:3
-msgid "Please prove that you are a Human Being"
+#: skins/default/templates/blocks/question_edit_tips.html:3
+msgid "question tips"
+msgstr "Tips"
+
+#: skins/default/templates/blocks/question_edit_tips.html:5
+msgid "please ask a relevant question"
+msgstr "ask a question interesting to this community"
+
+#: skins/default/templates/blocks/question_edit_tips.html:8
+msgid "please try provide enough details"
+msgstr "provide enough details"
+
+#: skins/default/templates/blocks/tag_selector.html:4
+msgid "Interesting tags"
msgstr ""
-#: skins/default/templates/unused/notarobot.html:10
-msgid "I am a Human Being"
+#: skins/default/templates/blocks/tag_selector.html:18
+#: skins/default/templates/blocks/tag_selector.html:34
+#: skins/default/templates/user_profile/user_moderate.html:38
+msgid "Add"
msgstr ""
-#: skins/default/templates/unused/question_counter_widget.html:78
-msgid "Please decide if you like this question or not by voting"
+#: skins/default/templates/blocks/tag_selector.html:20
+msgid "Ignored tags"
msgstr ""
-#: skins/default/templates/unused/question_counter_widget.html:84
-msgid ""
-"\n"
-" vote\n"
-" "
-msgid_plural ""
-"\n"
-" votes\n"
-" "
+#: skins/default/templates/blocks/tag_selector.html:36
+msgid "Display tag filter"
+msgstr ""
+
+#: skins/default/templates/main_page/content.html:13
+msgid "Did not find what you were looking for?"
+msgstr ""
+
+#: skins/default/templates/main_page/content.html:14
+msgid "Please, post your question!"
+msgstr ""
+
+#: skins/default/templates/main_page/headline.html:7
+msgid "subscribe to the questions feed"
+msgstr ""
+
+#: skins/default/templates/main_page/headline.html:8
+msgid "rss feed"
+msgstr ""
+
+#: skins/default/templates/main_page/headline.html:12 views/readers.py:119
+#, fuzzy, python-format
+msgid "%(q_num)s question, tagged"
+msgid_plural "%(q_num)s questions, tagged"
+msgstr[0] "Asked"
+msgstr[1] "Asked"
+
+#: skins/default/templates/main_page/headline.html:14 views/readers.py:127
+#, python-format
+msgid "%(q_num)s question"
+msgid_plural "%(q_num)s questions"
msgstr[0] ""
msgstr[1] ""
-#: skins/default/templates/unused/question_counter_widget.html:93
-#: skins/default/templates/unused/question_list.html:23
-#: skins/default/templates/unused/questions_ajax.html:27
-msgid "this answer has been accepted to be correct"
+#: skins/default/templates/main_page/headline.html:17
+#, python-format
+msgid "with %(author_name)s's contributions"
+msgstr ""
+
+#: skins/default/templates/main_page/headline.html:28
+msgid "Search tips:"
+msgstr ""
+
+#: skins/default/templates/main_page/headline.html:31
+msgid "reset author"
+msgstr ""
+
+#: skins/default/templates/main_page/headline.html:33
+#: skins/default/templates/main_page/headline.html:36
+#: skins/default/templates/main_page/nothing_found.html:18
+#: skins/default/templates/main_page/nothing_found.html:21
+msgid " or "
+msgstr ""
+
+#: skins/default/templates/main_page/headline.html:34
+msgid "reset tags"
+msgstr ""
+
+#: skins/default/templates/main_page/headline.html:37
+#: skins/default/templates/main_page/headline.html:40
+msgid "start over"
+msgstr ""
+
+#: skins/default/templates/main_page/headline.html:42
+msgid " - to expand, or dig in by adding more tags and revising the query."
+msgstr ""
+
+#: skins/default/templates/main_page/headline.html:45
+msgid "Search tip:"
+msgstr ""
+
+#: skins/default/templates/main_page/headline.html:45
+msgid "add tags and a query to focus your search"
+msgstr ""
+
+#: skins/default/templates/main_page/javascript.html:13
+#: skins/default/templates/main_page/javascript.html:14
+msgid "mark-tag/"
+msgstr ""
+
+#: skins/default/templates/main_page/javascript.html:13
+msgid "interesting/"
+msgstr ""
+
+#: skins/default/templates/main_page/javascript.html:14
+msgid "ignored/"
+msgstr ""
+
+#: skins/default/templates/main_page/javascript.html:15
+msgid "unmark-tag/"
+msgstr ""
+
+#: skins/default/templates/main_page/nothing_found.html:4
+msgid "There are no unanswered questions here"
+msgstr ""
+
+#: skins/default/templates/main_page/nothing_found.html:7
+msgid "No favorite questions here. "
+msgstr ""
+
+#: skins/default/templates/main_page/nothing_found.html:8
+msgid "Please start (bookmark) some questions when you visit them"
+msgstr ""
+
+#: skins/default/templates/main_page/nothing_found.html:13
+msgid "You can expand your search by "
+msgstr ""
+
+#: skins/default/templates/main_page/nothing_found.html:16
+msgid "resetting author"
+msgstr ""
+
+#: skins/default/templates/main_page/nothing_found.html:19
+msgid "resetting tags"
+msgstr ""
+
+#: skins/default/templates/main_page/nothing_found.html:22
+#: skins/default/templates/main_page/nothing_found.html:25
+msgid "starting over"
+msgstr ""
+
+#: skins/default/templates/main_page/nothing_found.html:30
+msgid "Please always feel free to ask your question!"
+msgstr ""
+
+#: skins/default/templates/main_page/sidebar.html:5
+msgid "Contributors"
+msgstr ""
+
+#: skins/default/templates/main_page/sidebar.html:22
+msgid "Related tags"
+msgstr "Tags"
+
+#: skins/default/templates/main_page/tab_bar.html:5
+msgid "In:"
+msgstr ""
+
+#: skins/default/templates/main_page/tab_bar.html:14
+msgid "see unanswered questions"
+msgstr ""
+
+#: skins/default/templates/main_page/tab_bar.html:20
+msgid "see your favorite questions"
+msgstr ""
+
+#: skins/default/templates/main_page/tab_bar.html:25
+msgid "Sort by:"
+msgstr ""
+
+#: skins/default/templates/user_profile/user.html:13
+#, python-format
+msgid "%(username)s's profile"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_edit.html:4
+msgid "Edit user profile"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_edit.html:7
+msgid "edit profile"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_edit.html:17
+#: skins/default/templates/user_profile/user_info.html:15
+msgid "change picture"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_edit.html:20
+msgid "Registered user"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_edit.html:27
+msgid "Screen Name"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_edit.html:83
+#: skins/default/templates/user_profile/user_email_subscriptions.html:21
+msgid "Update"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_email_subscriptions.html:4
+#: skins/default/templates/user_profile/user_tabs.html:36
+msgid "subscriptions"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_email_subscriptions.html:7
+msgid "Email subscription settings"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_email_subscriptions.html:8
+msgid "email subscription settings info"
+msgstr ""
+"<span class='big strong'>Adjust frequency of email updates.</span> Receive "
+"updates on interesting questions by email, <strong><br/>help the community</"
+"strong> by answering questions of your colleagues. If you do not wish to "
+"receive emails - select 'no email' on all items below.<br/>Updates are only "
+"sent when there is any new activity on selected items."
+
+#: skins/default/templates/user_profile/user_email_subscriptions.html:22
+msgid "Stop sending email"
+msgstr "Stop Email"
+
+#: skins/default/templates/user_profile/user_favorites.html:4
+#: skins/default/templates/user_profile/user_tabs.html:21
+msgid "favorites"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_inbox.html:18
+#: skins/default/templates/user_profile/user_tabs.html:12
+msgid "inbox"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_inbox.html:34
+msgid "Sections:"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_inbox.html:38
+#, python-format
+msgid "forum responses (%(re_count)s)"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_inbox.html:43
+#, python-format
+msgid "flagged items (%(flag_count)s)"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_inbox.html:49
+msgid "select:"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_inbox.html:51
+msgid "seen"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_inbox.html:52
+msgid "new"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_inbox.html:53
+msgid "none"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_inbox.html:54
+msgid "mark as seen"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_inbox.html:55
+msgid "mark as new"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_inbox.html:56
+msgid "dismiss"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_info.html:19
+msgid "remove"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_info.html:33
+msgid "update profile"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_info.html:37
+msgid "manage login methods"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_info.html:50
+msgid "real name"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_info.html:55
+msgid "member for"
+msgstr "member since"
+
+#: skins/default/templates/user_profile/user_info.html:60
+msgid "last seen"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_info.html:66
+msgid "user website"
+msgstr "website"
+
+#: skins/default/templates/user_profile/user_info.html:72
+msgid "location"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_info.html:79
+msgid "age"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_info.html:80
+msgid "age unit"
+msgstr "years old"
+
+#: skins/default/templates/user_profile/user_info.html:87
+msgid "todays unused votes"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_info.html:88
+msgid "votes left"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_moderate.html:4
+#: skins/default/templates/user_profile/user_tabs.html:42
+msgid "moderation"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_moderate.html:8
+#, python-format
+msgid "%(username)s's current status is \"%(status)s\""
+msgstr ""
+
+#: skins/default/templates/user_profile/user_moderate.html:11
+msgid "User status changed"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_moderate.html:18
+msgid "Save"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_moderate.html:24
+#, python-format
+msgid "Your current reputation is %(reputation)s points"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_moderate.html:26
+#, python-format
+msgid "User's current reputation is %(reputation)s points"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_moderate.html:30
+msgid "User reputation changed"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_moderate.html:37
+msgid "Subtract"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_moderate.html:42
+#, python-format
+msgid "Send message to %(username)s"
msgstr ""
-#: skins/default/templates/unused/question_counter_widget.html:99
+#: skins/default/templates/user_profile/user_moderate.html:43
msgid ""
-"\n"
-" answer \n"
-" "
-msgid_plural ""
-"\n"
-" answers \n"
-" "
+"An email will be sent to the user with 'reply-to' field set to your email "
+"address. Please make sure that your address is entered correctly."
+msgstr ""
+
+#: skins/default/templates/user_profile/user_moderate.html:45
+msgid "Message sent"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_moderate.html:63
+msgid "Send message"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_recent.html:4
+#: skins/default/templates/user_profile/user_tabs.html:25
+msgid "activity"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_reputation.html:4
+msgid "karma"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_reputation.html:11
+msgid "Your karma change log."
+msgstr ""
+
+#: skins/default/templates/user_profile/user_reputation.html:13
+#, python-format
+msgid "%(user_name)s's karma change log"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_stats.html:5
+#: skins/default/templates/user_profile/user_tabs.html:7
+msgid "overview"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_stats.html:11
+#, python-format
+msgid "<span class=\"count\">%(counter)s</span> Question"
+msgid_plural "<span class=\"count\">%(counter)s</span> Questions"
msgstr[0] ""
msgstr[1] ""
-#: skins/default/templates/unused/question_counter_widget.html:111
-msgid ""
-"\n"
-" view\n"
-" "
-msgid_plural ""
-"\n"
-" views\n"
-" "
+#: skins/default/templates/user_profile/user_stats.html:16
+#, python-format
+msgid "<span class=\"count\">%(counter)s</span> Answer"
+msgid_plural "<span class=\"count\">%(counter)s</span> Answers"
msgstr[0] ""
msgstr[1] ""
-#: skins/default/templates/unused/question_list.html:15
-msgid ""
-"\n"
-" vote\n"
-" "
-msgid_plural ""
-"\n"
-" votes\n"
-" "
+#: skins/default/templates/user_profile/user_stats.html:24
+#, python-format
+msgid "the answer has been voted for %(answer_score)s times"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_stats.html:24
+msgid "this answer has been selected as correct"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_stats.html:34
+#, python-format
+msgid "(%(comment_count)s comment)"
+msgid_plural "the answer has been commented %(comment_count)s times"
msgstr[0] ""
msgstr[1] ""
-#: skins/default/templates/unused/question_list.html:35
-msgid ""
-"\n"
-" answer \n"
-" "
-msgid_plural ""
-"\n"
-" answers \n"
-" "
+#: skins/default/templates/user_profile/user_stats.html:44
+#, python-format
+msgid "<span class=\"count\">%(cnt)s</span> Vote"
+msgid_plural "<span class=\"count\">%(cnt)s</span> Votes "
msgstr[0] ""
msgstr[1] ""
-#: skins/default/templates/unused/question_list.html:47
-msgid ""
-"\n"
-" view\n"
-" "
-msgid_plural ""
-"\n"
-" views\n"
-" "
+#: skins/default/templates/user_profile/user_stats.html:50
+msgid "thumb up"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_stats.html:51
+msgid "user has voted up this many times"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_stats.html:54
+msgid "thumb down"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_stats.html:55
+msgid "user voted down this many times"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_stats.html:63
+#, python-format
+msgid "<span class=\"count\">%(counter)s</span> Tag"
+msgid_plural "<span class=\"count\">%(counter)s</span> Tags"
+msgstr[0] ""
+msgstr[1] ""
+
+#: skins/default/templates/user_profile/user_stats.html:99
+#, python-format
+msgid "<span class=\"count\">%(counter)s</span> Badge"
+msgid_plural "<span class=\"count\">%(counter)s</span> Badges"
msgstr[0] ""
msgstr[1] ""
-#: skins/default/templates/unused/question_summary_list_roll.html:13
-msgid "answers"
+#: skins/default/templates/user_profile/user_tabs.html:5
+msgid "User profile"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_tabs.html:10 views/users.py:728
+msgid "comments and answers to others questions"
msgstr ""
-#: skins/default/templates/unused/question_summary_list_roll.html:14
+#: skins/default/templates/user_profile/user_tabs.html:15
+msgid "graph of user reputation"
+msgstr "Graph of user karma"
+
+#: skins/default/templates/user_profile/user_tabs.html:17
+msgid "reputation history"
+msgstr "karma"
+
+#: skins/default/templates/user_profile/user_tabs.html:19
+msgid "questions that user selected as his/her favorite"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_tabs.html:23
+msgid "recent activity"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_tabs.html:28 views/users.py:792
+msgid "user vote record"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_tabs.html:30
+msgid "casted votes"
+msgstr "votes"
+
+#: skins/default/templates/user_profile/user_tabs.html:34 views/users.py:897
+msgid "email subscription settings"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_tabs.html:40 views/users.py:212
+msgid "moderate this user"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_votes.html:4
msgid "votes"
msgstr ""
-#: skins/default/templates/unused/question_summary_list_roll.html:15
-msgid "views"
+#: skins/default/templates/user_profile/users_questions.html:9
+#: skins/default/templates/user_profile/users_questions.html:17
+#, python-format
+msgid "this questions was selected as favorite %(cnt)s time"
+msgid_plural "this questions was selected as favorite %(cnt)s times"
+msgstr[0] ""
+msgstr[1] ""
+
+#: skins/default/templates/user_profile/users_questions.html:10
+msgid "thumb-up on"
+msgstr ""
+
+#: skins/default/templates/user_profile/users_questions.html:18
+msgid "thumb-up off"
msgstr ""
-#: templatetags/extra_filters.py:168 templatetags/extra_filters_jinja.py:234
+#: templatetags/extra_filters.py:145 templatetags/extra_filters_jinja.py:227
msgid "no items in counter"
msgstr "no"
-#: utils/decorators.py:82 views/commands.py:132 views/commands.py:149
+#: utils/decorators.py:82 views/commands.py:128 views/commands.py:145
msgid "Oops, apologies - there was some error"
msgstr ""
@@ -5144,80 +5436,98 @@ msgid_plural "%(min)d mins ago"
msgstr[0] ""
msgstr[1] ""
-#: views/commands.py:42
+#: views/avatar_views.py:94
+msgid "Successfully uploaded a new avatar."
+msgstr ""
+
+#: views/avatar_views.py:134
+msgid "Successfully updated your avatar."
+msgstr ""
+
+#: views/avatar_views.py:173
+msgid "Successfully deleted the requested avatars."
+msgstr ""
+
+#: views/commands.py:38
msgid "anonymous users cannot vote"
msgstr "Sorry, anonymous users cannot vote"
-#: views/commands.py:62
+#: views/commands.py:58
msgid "Sorry you ran out of votes for today"
msgstr ""
-#: views/commands.py:68
+#: views/commands.py:64
#, python-format
msgid "You have %(votes_left)s votes left for today"
msgstr ""
-#: views/commands.py:139
+#: views/commands.py:135
msgid "Sorry, but anonymous users cannot access the inbox"
msgstr ""
-#: views/commands.py:209
+#: views/commands.py:205
msgid "Sorry, something is not right here..."
msgstr ""
-#: views/commands.py:224
+#: views/commands.py:220
msgid "Sorry, but anonymous users cannot accept answers"
msgstr ""
-#: views/commands.py:305
+#: views/commands.py:301
#, 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>"
-#: views/commands.py:313
+#: views/commands.py:309
msgid "email update frequency has been set to daily"
msgstr ""
-#: views/commands.py:371
-msgid "Bad request"
+#: views/commands.py:413
+#, python-format
+msgid "Tag subscription was canceled (<a href=\"%(url)s\">undo</a>)."
msgstr ""
-#: views/meta.py:59
+#: views/commands.py:422
+#, python-format
+msgid "Please sign in to subscribe for: %(tags)s"
+msgstr ""
+
+#: views/meta.py:63
msgid "Q&A forum feedback"
msgstr ""
-#: views/meta.py:60
+#: views/meta.py:64
msgid "Thanks for the feedback!"
msgstr ""
-#: views/meta.py:70
+#: views/meta.py:72
msgid "We look forward to hearing your feedback! Please, give it next time :)"
msgstr ""
-#: views/readers.py:188
+#: views/readers.py:165
#, python-format
msgid "%(badge_count)d %(badge_level)s badge"
msgid_plural "%(badge_count)d %(badge_level)s badges"
msgstr[0] ""
msgstr[1] ""
-#: views/readers.py:425
+#: views/readers.py:388
msgid ""
"Sorry, the comment you are looking for has been deleted and is no longer "
"accessible"
msgstr ""
-#: views/users.py:217
+#: views/users.py:213
msgid "moderate user"
msgstr ""
-#: views/users.py:376
+#: views/users.py:377
msgid "user profile"
msgstr ""
-#: views/users.py:377
+#: views/users.py:378
msgid "user profile overview"
msgstr ""
@@ -5229,39 +5539,39 @@ msgstr ""
msgid "profile - recent activity"
msgstr ""
-#: views/users.py:730
+#: views/users.py:729
msgid "profile - responses"
msgstr ""
-#: views/users.py:795
+#: views/users.py:793
msgid "profile - votes"
msgstr ""
-#: views/users.py:833
+#: views/users.py:828
msgid "user reputation in the community"
msgstr "user karma"
-#: views/users.py:834
+#: views/users.py:829
msgid "profile - user reputation"
msgstr "Profile - User's Karma"
-#: views/users.py:862
+#: views/users.py:856
msgid "users favorite questions"
msgstr ""
-#: views/users.py:863
+#: views/users.py:857
msgid "profile - favorite questions"
msgstr ""
-#: views/users.py:883 views/users.py:887
+#: views/users.py:876 views/users.py:880
msgid "changes saved"
msgstr ""
-#: views/users.py:893
+#: views/users.py:886
msgid "email updates canceled"
msgstr ""
-#: views/users.py:905
+#: views/users.py:898
msgid "profile - email subscriptions"
msgstr ""
@@ -5269,42 +5579,66 @@ msgstr ""
msgid "Sorry, anonymous users cannot upload files"
msgstr ""
-#: views/writers.py:65
+#: views/writers.py:66
#, python-format
msgid "allowed file types are '%(file_types)s'"
msgstr ""
-#: views/writers.py:88
+#: views/writers.py:89
#, python-format
msgid "maximum upload file size is %(file_size)sK"
msgstr ""
-#: views/writers.py:96
+#: views/writers.py:97
msgid "Error uploading file. Please contact the site administrator. Thank you."
msgstr ""
-#: views/writers.py:452
+#: views/writers.py:555
#, python-format
msgid ""
"Sorry, you appear to be logged out and cannot post comments. Please <a href="
"\"%(sign_in_url)s\">sign in</a>."
msgstr ""
-#: views/writers.py:497
+#: views/writers.py:600
msgid "Sorry, anonymous users cannot edit comments"
msgstr ""
-#: views/writers.py:505
+#: views/writers.py:608
#, python-format
msgid ""
"Sorry, you appear to be logged out and cannot delete comments. Please <a "
"href=\"%(sign_in_url)s\">sign in</a>."
msgstr ""
-#: views/writers.py:526
+#: views/writers.py:629
msgid "sorry, we seem to have some technical difficulties"
msgstr ""
+#~ msgid "Email verification subject line"
+#~ msgstr "Verification Email from Q&A forum"
+
+#~ msgid "how to validate email title"
+#~ msgstr "How to validate email and why?"
+
+#~ msgid ""
+#~ "how to validate email info with %(send_email_key_url)s %(gravatar_faq_url)"
+#~ "s"
+#~ msgstr ""
+#~ "<form style='margin:0;padding:0;' action='%(send_email_key_url)"
+#~ "s'><p><span class=\"bigger strong\">How?</span> If you have just set or "
+#~ "changed your email address - <strong>check your email and click the "
+#~ "included link</strong>.<br>The link contains a key generated specifically "
+#~ "for you. You can also <button style='display:inline' "
+#~ "type='submit'><strong>get a new key</strong></button> and check your "
+#~ "email again.</p></form><span class=\"bigger strong\">Why?</span> Email "
+#~ "validation is required to make sure that <strong>only you can post "
+#~ "messages</strong> on your behalf and to <strong>minimize spam</strong> "
+#~ "posts.<br>With email you can <strong>subscribe for updates</strong> on "
+#~ "the most interesting questions. 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>"
+
#, fuzzy
#~ msgid "more answers"
#~ msgstr "oldest"
diff --git a/askbot/locale/ro/LC_MESSAGES/django.mo b/askbot/locale/ro/LC_MESSAGES/django.mo
new file mode 100644
index 00000000..1f9109d8
--- /dev/null
+++ b/askbot/locale/ro/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/locale/ro/LC_MESSAGES/django.po b/askbot/locale/ro/LC_MESSAGES/django.po
new file mode 100644
index 00000000..abd8f70f
--- /dev/null
+++ b/askbot/locale/ro/LC_MESSAGES/django.po
@@ -0,0 +1,5727 @@
+# Romanian translation for ubuntu-ro
+# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
+# This file is distributed under the same license as the ubuntu-ro package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ubuntu-ro\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2011-03-23 15:57-0500\n"
+"PO-Revision-Date: 2011-04-10 19:43+0000\n"
+"Last-Translator: Adi Roiban <adi@roiban.ro>\n"
+"Language-Team: Romanian <ro@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n == 1 ? 0: (((n % 100 > 19) || ((n % 100 "
+"== 0) && (n != 0))) ? 2: 1));\n"
+"X-Launchpad-Export-Date: 2011-04-10 19:44+0000\n"
+"X-Generator: Launchpad (build 12757)\n"
+
+#: exceptions.py:9
+msgid "Sorry, but anonymous visitors cannot access this function"
+msgstr "Vizitatorii anonimi nu pot accesa această funcție"
+
+#: feed.py:22
+msgid " - "
+msgstr " - "
+
+#: feed.py:22
+msgid "latest questions"
+msgstr "ultimele întrebări"
+
+#: forms.py:72
+msgid "select country"
+msgstr "alegeți o țară"
+
+#: forms.py:81
+msgid "Country"
+msgstr "Țară"
+
+#: forms.py:89
+msgid "Country field is required"
+msgstr "Câmpul cu țara este obligatoriu"
+
+#: forms.py:102 skins/default/templates/blocks/answer_edit_tips.html:43
+#: skins/default/templates/blocks/answer_edit_tips.html:47
+#: skins/default/templates/blocks/question_edit_tips.html:38
+#: skins/default/templates/blocks/question_edit_tips.html:43
+msgid "title"
+msgstr "titlu"
+
+#: forms.py:103
+msgid "please enter a descriptive title for your question"
+msgstr "introduceți un titlu descriptiv pentru întrebare"
+
+#: forms.py:108
+msgid "title must be > 10 characters"
+msgstr "titlul trebuie să fie mai lung decât 10 caractere"
+
+#: forms.py:117
+msgid "content"
+msgstr "conținut"
+
+#: forms.py:123
+msgid "question content must be > 10 characters"
+msgstr "conținutul întrebării trebuie să fie mai lung decât 10 caractere"
+
+#: forms.py:132 skins/default/templates/blocks/header.html:22
+msgid "tags"
+msgstr "etichete"
+
+#: forms.py:134
+msgid ""
+"Tags are short keywords, with no spaces within. Up to five tags can be used."
+msgstr ""
+"Etichetele sunt cuvinte cheie scurte, fără spații. Pot fi folosite până la "
+"cinci etichete."
+
+#: forms.py:141 skins/default/templates/question_retag.html:74
+msgid "tags are required"
+msgstr "etichetele sunt obligatorii"
+
+#: forms.py:150
+#, python-format
+msgid "please use %(tag_count)d tag or less"
+msgid_plural "please use %(tag_count)d tags or less"
+msgstr[0] "vă rugăm să folosiți %(tag_count)d etichetă sau mai puțin"
+msgstr[1] "vă rugăm să folosiți %(tag_count)d etichete sau mai puțin"
+msgstr[2] "vă rugăm să folosiți %(tag_count)d de etichete sau mai puțin"
+
+#: forms.py:159
+#, 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] ""
+"fiecare etichetă trebuie să fie mai scurtă de %(max_chars)d caracter"
+msgstr[1] ""
+"fiecare etichetă trebuie să fie mai scurtă de %(max_chars)d caractere"
+msgstr[2] ""
+"fiecare etichetă trebuie să fie mai scurtă de %(max_chars)d de caractere"
+
+#: forms.py:167
+msgid "use-these-chars-in-tags"
+msgstr "folositi-aceste-caractere-in-etichete"
+
+#: forms.py:202
+msgid ""
+"community wiki (karma is not awarded & many others can edit wiki post)"
+msgstr ""
+"wiki al comunității (nu se primesc puncte de reputație și mesajul poate fi "
+"modificat de mai multe persoane)"
+
+#: forms.py:203
+msgid ""
+"if you choose community wiki option, the question and answer do not generate "
+"points and name of author will not be shown"
+msgstr ""
+"dacă alegeți opțiunea wiki al comunității, întrebarea și răspunsul nu vor "
+"genera puncte iar numele autorului nu va fi afișat"
+
+#: forms.py:219
+msgid "update summary:"
+msgstr "sumar actualizare:"
+
+#: forms.py:220
+msgid ""
+"enter a brief summary of your revision (e.g. fixed spelling, grammar, "
+"improved style, this field is optional)"
+msgstr ""
+"introduceți o descriere scurtă a reviziei (de ex. corectare ortografică, "
+"gramaticală, stil îmbunătățit, câmp opțional)"
+
+#: forms.py:283
+msgid "Enter number of points to add or subtract"
+msgstr "Introduceți numărul de puncte pentru a fi adăugate sau retrase"
+
+#: forms.py:297 const/__init__.py:224
+msgid "approved"
+msgstr "aprobat"
+
+#: forms.py:298 const/__init__.py:225
+msgid "watched"
+msgstr "urmărit"
+
+#: forms.py:299 const/__init__.py:226
+msgid "suspended"
+msgstr "suspendat"
+
+#: forms.py:300 const/__init__.py:227
+msgid "blocked"
+msgstr "blocat"
+
+#: forms.py:302 const/__init__.py:223
+msgid "moderator"
+msgstr "moderator"
+
+#: forms.py:322
+msgid "Change status to"
+msgstr "Schimbă starea în"
+
+#: forms.py:349
+msgid "which one?"
+msgstr "care?"
+
+#: forms.py:370
+msgid "Cannot change own status"
+msgstr "Nu se poate schimba propria stare"
+
+#: forms.py:376
+msgid "Cannot turn other user to moderator"
+msgstr "Nu s-a putut schimba alt utilizator în moderator"
+
+#: forms.py:383
+msgid "Cannot change status of another moderator"
+msgstr "Nu se poate schimba starea altui utilizator"
+
+#: forms.py:389
+#, python-format
+msgid ""
+"If you wish to change %(username)s's status, please make a meaningful "
+"selection."
+msgstr ""
+"Dacă doriți să modificați statusul %(username)s alegeți ceva expresiv."
+
+#: forms.py:398
+msgid "Subject line"
+msgstr "Linie subiect"
+
+#: forms.py:405
+msgid "Message text"
+msgstr "Text mesaj"
+
+#: forms.py:488
+msgid "Your name:"
+msgstr "Nume:"
+
+#: forms.py:489
+msgid "Email (not shared with anyone):"
+msgstr "Email (nu este dezvăluit altor părți):"
+
+#: forms.py:490
+msgid "Your message:"
+msgstr "Mesaj:"
+
+#: forms.py:527
+msgid "ask anonymously"
+msgstr "întreabă anonim"
+
+#: forms.py:529
+msgid ""
+"Check if you do not want to reveal your name when asking this question"
+msgstr ""
+"Bifați în cazul în care nu doriți să dezvăluiți numele vostru când puneți "
+"această întrebare"
+
+#: forms.py:604
+msgid ""
+"You have asked this question anonymously, if you decide to reveal your "
+"identity, please check this box."
+msgstr ""
+"Ați răspuns la această întrebare anonim, dacă decideți să vă arătați "
+"identitatea, marcați această căsuță."
+
+#: forms.py:608
+msgid "reveal identity"
+msgstr "arată identitatea"
+
+#: forms.py:666
+msgid ""
+"Sorry, only owner of the anonymous question can reveal his or her identity, "
+"please uncheck the box"
+msgstr ""
+"Doar cel care a pus întrebarea anonimă poate dezvălui identitatea, debifați "
+"căsuța"
+
+#: forms.py:679
+msgid ""
+"Sorry, apparently rules have just changed - it is no longer possible to ask "
+"anonymously. Please either check the \"reveal identity\" box or reload this "
+"page and try editing the question again."
+msgstr ""
+"Aparent, regulile au fost schimbate - nu mai puteți întreba ca anonim. Vă "
+"rugăm să marcați căsuța „arată identitatea” sau să reîncărcați pagina pentru "
+"a încerca din nou să introduceți întrebarea."
+
+#: forms.py:717
+msgid "this email will be linked to gravatar"
+msgstr "această adresă de email va fi conectată cu gravatarul"
+
+#: forms.py:724
+msgid "Real name"
+msgstr "Nume real"
+
+#: forms.py:731
+msgid "Website"
+msgstr "Pagină web"
+
+#: forms.py:738
+msgid "City"
+msgstr "Oraș"
+
+#: forms.py:747
+msgid "Show country"
+msgstr "Arată țara"
+
+#: forms.py:752
+msgid "Date of birth"
+msgstr "Data nașterii"
+
+#: forms.py:753
+msgid "will not be shown, used to calculate age, format: YYYY-MM-DD"
+msgstr ""
+"nu va fi afișată, ci folosită doar pentru calcularea vârstei, format AAAA-LL-"
+"ZZ"
+
+#: forms.py:759
+msgid "Profile"
+msgstr "Profil"
+
+#: forms.py:768
+msgid "Screen name"
+msgstr "Nume afișat"
+
+#: forms.py:799 forms.py:800
+msgid "this email has already been registered, please use another one"
+msgstr "acest email este deja înregistrat, utilizați altul"
+
+#: forms.py:807
+msgid "Choose email tag filter"
+msgstr "Alegeți filtru email etichete"
+
+#: forms.py:847
+msgid "Asked by me"
+msgstr "Întrebate de mine"
+
+#: forms.py:850
+msgid "Answered by me"
+msgstr "Răspunse de mine"
+
+#: forms.py:853
+msgid "Individually selected"
+msgstr "Alese individual"
+
+#: forms.py:856
+msgid "Entire forum (tag filtered)"
+msgstr "Toate întrebările (filtrate pe tag)"
+
+#: forms.py:860
+msgid "Comments and posts mentioning me"
+msgstr "Comentarii și răspunsuri în care sunt menționat eu"
+
+#: forms.py:930
+msgid "okay, let's try!"
+msgstr "Bine, să încercăm!"
+
+#: forms.py:931
+msgid "no community email please, thanks"
+msgstr "fără emailuri de la comunitate, mulțumesc"
+
+#: forms.py:935
+msgid "please choose one of the options above"
+msgstr "alegeți una dintre opțiunile de mai sus"
+
+#: urls.py:44
+msgid "about/"
+msgstr "despre/"
+
+#: urls.py:45 conf/site_settings.py:79
+msgid "faq/"
+msgstr "intrebari-frecvente/"
+
+#: urls.py:46
+msgid "privacy/"
+msgstr "confidentialitate/"
+
+#: urls.py:47
+msgid "logout/"
+msgstr "logout/"
+
+#: urls.py:49 urls.py:54
+msgid "answers/"
+msgstr "raspunsuri/"
+
+#: urls.py:49 urls.py:75 urls.py:181
+msgid "edit/"
+msgstr "edit/"
+
+#: urls.py:54 urls.py:105
+msgid "revisions/"
+msgstr "revizii/"
+
+#: urls.py:60 urls.py:70 urls.py:75 urls.py:80 urls.py:85 urls.py:90
+#: urls.py:95 urls.py:100 urls.py:105
+#: skins/default/templates/question.html:438
+msgid "questions/"
+msgstr "intrebari/"
+
+#: urls.py:70
+msgid "ask/"
+msgstr "intreaba/"
+
+#: urls.py:80
+msgid "retag/"
+msgstr "retag/"
+
+#: urls.py:85
+msgid "close/"
+msgstr "inchide/"
+
+#: urls.py:90
+msgid "reopen/"
+msgstr "redeschide/"
+
+#: urls.py:95
+msgid "answer/"
+msgstr "raspuns/"
+
+#: urls.py:100 skins/default/templates/question.html:438
+msgid "vote/"
+msgstr "vot/"
+
+#: urls.py:132 skins/default/templates/question.html:436
+#: skins/default/templates/main_page/javascript.html:21
+msgid "question/"
+msgstr "intrebare/"
+
+#: urls.py:137
+msgid "tags/"
+msgstr "etichete/"
+
+#: urls.py:170
+msgid "subscribe-for-tags/"
+msgstr "abonare-etichete/"
+
+#: urls.py:175 urls.py:181 urls.py:186
+#: skins/default/templates/main_page/javascript.html:22
+msgid "users/"
+msgstr "utilizatori/"
+
+#: urls.py:191 urls.py:196
+msgid "badges/"
+msgstr "insigne/"
+
+#: urls.py:201
+msgid "messages/"
+msgstr "mesaje/"
+
+#: urls.py:201
+msgid "markread/"
+msgstr "macheaza-citit/"
+
+#: urls.py:217
+msgid "upload/"
+msgstr "incarca/"
+
+#: urls.py:218
+msgid "feedback/"
+msgstr "sugestii/"
+
+#: urls.py:219 setup_templates/settings.py:188
+#: skins/default/templates/authopenid/providers_javascript.html:7
+msgid "account/"
+msgstr "cont/"
+
+#: conf/badges.py:12
+msgid "Badge settings"
+msgstr "Configurări insigne"
+
+#: conf/badges.py:21
+msgid "Disciplined: minimum upvotes for deleted post"
+msgstr ""
+
+#: conf/badges.py:30
+msgid "Peer Pressure: minimum downvotes for deleted post"
+msgstr ""
+
+#: conf/badges.py:39
+msgid "Teacher: minimum upvotes for the answer"
+msgstr ""
+
+#: conf/badges.py:48
+msgid "Nice Answer: minimum upvotes for the answer"
+msgstr ""
+
+#: conf/badges.py:57
+msgid "Good Answer: minimum upvotes for the answer"
+msgstr ""
+
+#: conf/badges.py:66
+msgid "Great Answer: minimum upvotes for the answer"
+msgstr ""
+
+#: conf/badges.py:75
+msgid "Nice Question: minimum upvotes for the question"
+msgstr ""
+
+#: conf/badges.py:84
+msgid "Good Question: minimum upvotes for the question"
+msgstr ""
+
+#: conf/badges.py:93
+msgid "Great Question: minimum upvotes for the question"
+msgstr ""
+
+#: conf/badges.py:102
+msgid "Popular Question: minimum views"
+msgstr ""
+
+#: conf/badges.py:111
+msgid "Notable Question: minimum views"
+msgstr ""
+
+#: conf/badges.py:120
+msgid "Famous Question: minimum views"
+msgstr ""
+
+#: conf/badges.py:129
+msgid "Self-Learner: minimum answer upvotes"
+msgstr ""
+
+#: conf/badges.py:138
+msgid "Civic Duty: minimum votes"
+msgstr ""
+
+#: conf/badges.py:147
+msgid "Enlightened Duty: minimum upvotes"
+msgstr ""
+
+#: conf/badges.py:156
+msgid "Guru: minimum upvotes"
+msgstr ""
+
+#: conf/badges.py:165
+msgid "Necromancer: minimum upvotes"
+msgstr ""
+
+#: conf/badges.py:174
+msgid "Necromancer: minimum delay in days"
+msgstr ""
+
+#: conf/badges.py:183
+msgid "Associate Editor: minimum number of edits"
+msgstr ""
+
+#: conf/badges.py:192
+msgid "Favorite Question: minimum stars"
+msgstr ""
+
+#: conf/badges.py:201
+msgid "Stellar Question: minimum stars"
+msgstr ""
+
+#: conf/badges.py:210
+msgid "Commentator: minimum comments"
+msgstr ""
+
+#: conf/badges.py:219
+msgid "Taxonomist: minimum tag use count"
+msgstr ""
+
+#: conf/badges.py:228
+msgid "Enthusiast: minimum days"
+msgstr ""
+
+#: conf/email.py:14
+msgid "Email and email alert settings"
+msgstr "Configurări email și alerte"
+
+#: conf/email.py:22
+msgid "Prefix for the email subject line"
+msgstr "Prefixul liniei de subiect din email"
+
+#: conf/email.py:24
+msgid ""
+"This setting takes default from the django settingEMAIL_SUBJECT_PREFIX. A "
+"value entered here will overridethe default."
+msgstr ""
+
+#: conf/email.py:36
+msgid "Maximum number of news entries in an email alert"
+msgstr "Număr maxim de intrări întrun email de alerte"
+
+#: conf/email.py:46
+msgid "Default news notification frequency"
+msgstr "Frecvența implicită a notificărilor de noutăți"
+
+#: conf/email.py:48
+msgid ""
+"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 ""
+
+#: conf/email.py:63
+msgid "Require email verification before allowing to post"
+msgstr ""
+
+#: conf/email.py:64
+msgid ""
+"Active email verification is done by sending a verification key in email"
+msgstr ""
+
+#: conf/email.py:73
+msgid "Allow only one account per email address"
+msgstr ""
+
+#: conf/email.py:82
+msgid "Fake email for anonymous user"
+msgstr ""
+
+#: conf/email.py:83
+msgid "Use this setting to control gravatar for email-less user"
+msgstr ""
+
+#: conf/external_keys.py:11
+msgid "Keys to connect the site with external services like Facebook, etc."
+msgstr ""
+
+#: conf/external_keys.py:18
+msgid "Google site verification key"
+msgstr ""
+
+#: conf/external_keys.py:20
+#, python-format
+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 ""
+
+#: conf/external_keys.py:34
+msgid "Google Analytics key"
+msgstr ""
+
+#: conf/external_keys.py:36
+#, python-format
+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 ""
+
+#: conf/external_keys.py:49
+msgid "Enable recaptcha (keys below are required)"
+msgstr ""
+
+#: conf/external_keys.py:58
+msgid "Recaptcha public key"
+msgstr ""
+
+#: conf/external_keys.py:66
+msgid "Recaptcha private key"
+msgstr ""
+
+#: conf/external_keys.py:68
+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 ""
+
+#: conf/external_keys.py:80
+msgid "Facebook public API key"
+msgstr ""
+
+#: conf/external_keys.py:82
+msgid ""
+"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 ""
+
+#: conf/external_keys.py:95
+msgid "Facebook secret key"
+msgstr ""
+
+#: conf/external_keys.py:103
+msgid "Twitter consumer key"
+msgstr ""
+
+#: conf/external_keys.py:105 conf/external_keys.py:126
+msgid ""
+"Please register your forum at <a "
+"href=\"http://dev.twitter.com/apps/\">twitter applications site</a>"
+msgstr ""
+
+#: conf/external_keys.py:116
+msgid "Twitter consumer secret"
+msgstr ""
+
+#: conf/external_keys.py:124
+msgid "LinkedIn consumer key"
+msgstr ""
+
+#: conf/external_keys.py:137
+msgid "LinkedIn consumer secret"
+msgstr ""
+
+#: conf/external_keys.py:145
+msgid "Use LDAP authentication for the password login"
+msgstr ""
+
+#: conf/external_keys.py:154
+msgid "LDAP service provider name"
+msgstr ""
+
+#: conf/external_keys.py:162
+msgid "URL for the LDAP service"
+msgstr ""
+
+#: conf/external_keys.py:170
+msgid "Explain how to change LDAP password"
+msgstr ""
+
+#: conf/flatpages.py:10
+msgid "Flatpages - about, privacy policy, etc."
+msgstr "Pagini statice - despre, confidențialiate, etc"
+
+#: conf/flatpages.py:17
+msgid "Text of the Q&A forum About page (html format)"
+msgstr ""
+
+#: conf/flatpages.py:20
+msgid ""
+"Save, then <a href=\"http://validator.w3.org/\">use HTML validator</a> on "
+"the \"about\" page to check your input."
+msgstr ""
+
+#: conf/flatpages.py:30
+msgid "Text of the Q&A forum Privacy Policy (html format)"
+msgstr "Textul pentru pagina politicii de confidențialitate (format html)"
+
+#: 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 ""
+
+#: conf/forum_data_rules.py:11
+msgid "Settings for askbot data entry and display"
+msgstr ""
+
+#: conf/forum_data_rules.py:19
+msgid "Check to enable community wiki feature"
+msgstr ""
+
+#: conf/forum_data_rules.py:28
+msgid "Allow asking questions anonymously"
+msgstr ""
+
+#: conf/forum_data_rules.py:30
+msgid ""
+"Users do not accrue reputation for anonymous questions and their identity is "
+"not revealed until they change their mind"
+msgstr ""
+
+#: conf/forum_data_rules.py:42
+msgid "Maximum length of tag (number of characters)"
+msgstr ""
+
+#: conf/forum_data_rules.py:51
+msgid "Force lowercase the tags"
+msgstr ""
+
+#: conf/forum_data_rules.py:53
+msgid ""
+"Attention: after checking this, please back up the database, and run a "
+"management command: <code>python manage.py fix_question_tags</code> to "
+"globally rename the tags"
+msgstr ""
+
+#: conf/forum_data_rules.py:66
+msgid "Use wildcard tags"
+msgstr ""
+
+#: conf/forum_data_rules.py:68
+msgid ""
+"Wildcard tags can be used to follow or ignore many tags at once, a valid "
+"wildcard tag has a single wildcard at the very end"
+msgstr ""
+
+#: conf/forum_data_rules.py:81
+msgid "Default max number of comments to display under posts"
+msgstr ""
+
+#: conf/forum_data_rules.py:92
+#, python-format
+msgid "Maximum comment length, must be < %(max_len)s"
+msgstr ""
+
+#: conf/forum_data_rules.py:102
+msgid "Limit time to edit comments"
+msgstr ""
+
+#: conf/forum_data_rules.py:104
+msgid "If unchecked, there will be no time limit to edit the comments"
+msgstr ""
+
+#: conf/forum_data_rules.py:115
+msgid "Minutes allowed to edit a comment"
+msgstr ""
+
+#: conf/forum_data_rules.py:116
+msgid "To enable this setting, check the previous one"
+msgstr ""
+
+#: conf/forum_data_rules.py:125
+msgid "Save comment by pressing <Enter> key"
+msgstr ""
+
+#: conf/forum_data_rules.py:134
+msgid "Minimum length of search term for Ajax search"
+msgstr ""
+
+#: conf/forum_data_rules.py:135
+msgid "Must match the corresponding database backend setting"
+msgstr ""
+
+#: conf/forum_data_rules.py:144
+msgid "Do not make text query sticky in search"
+msgstr ""
+
+#: conf/forum_data_rules.py:146
+msgid ""
+"Check to disable the \"sticky\" behavior of the search query. This may be "
+"useful if you want to move the search bar away from the default position or "
+"do not like the default sticky behavior of the text search query."
+msgstr ""
+
+#: conf/forum_data_rules.py:159
+msgid "Maximum number of tags per question"
+msgstr ""
+
+#: conf/forum_data_rules.py:171
+msgid "Number of questions to list by default"
+msgstr ""
+
+#: conf/forum_data_rules.py:181
+msgid "What should \"unanswered question\" mean?"
+msgstr ""
+
+#: conf/login_providers.py:11
+msgid "Login provider setings"
+msgstr ""
+
+#: conf/login_providers.py:19
+msgid ""
+"Show alternative login provider buttons on the password \"Sign Up\" page"
+msgstr ""
+
+#: conf/login_providers.py:28
+msgid "Always display local login form and hide \"Askbot\" button."
+msgstr ""
+
+#: conf/login_providers.py:55
+#, python-format
+msgid "Activate %(provider)s login"
+msgstr ""
+
+#: conf/login_providers.py:60
+#, python-format
+msgid ""
+"Note: to really enable %(provider)s login some additional parameters will "
+"need to be set in the \"External keys\" section"
+msgstr ""
+
+#: conf/markup.py:15
+msgid "Markup formatting"
+msgstr ""
+
+#: conf/markup.py:22
+msgid "Enable code-friendly Markdown"
+msgstr ""
+
+#: conf/markup.py:24
+msgid ""
+"If checked, underscore characters will not trigger italic or bold formatting "
+"- bold and italic text can still be marked up with asterisks. Note that "
+"\"MathJax support\" implicitly turns this feature on, because underscores "
+"are heavily used in LaTeX input."
+msgstr ""
+
+#: conf/markup.py:39
+msgid "Mathjax support (rendering of LaTeX)"
+msgstr ""
+
+#: conf/markup.py:41
+#, python-format
+msgid ""
+"If you enable this feature, <a href=\"%(url)s\">mathjax</a> must be "
+"installed on your server in its own directory."
+msgstr ""
+
+#: conf/markup.py:55
+msgid "Base url of MathJax deployment"
+msgstr ""
+
+#: conf/markup.py:57
+msgid ""
+"Note - <strong>MathJax is not included with askbot</strong> - you should "
+"deploy it yourself, preferably at a separate domain and enter url pointing "
+"to the \"mathjax\" directory (for example: http://mysite.com/mathjax)"
+msgstr ""
+
+#: conf/minimum_reputation.py:11
+msgid "Minimum reputation required to perform actions"
+msgstr ""
+
+#: conf/minimum_reputation.py:20
+msgid "Upvote"
+msgstr ""
+
+#: conf/minimum_reputation.py:29
+msgid "Downvote"
+msgstr ""
+
+#: conf/minimum_reputation.py:38
+msgid "Flag offensive"
+msgstr "Marchează ofensiv"
+
+#: conf/minimum_reputation.py:47
+msgid "Leave comments"
+msgstr ""
+
+#: conf/minimum_reputation.py:56
+msgid "Delete comments posted by others"
+msgstr ""
+
+#: conf/minimum_reputation.py:65
+msgid "Delete questions and answers posted by others"
+msgstr ""
+
+#: conf/minimum_reputation.py:74
+msgid "Upload files"
+msgstr ""
+
+#: conf/minimum_reputation.py:83
+msgid "Close own questions"
+msgstr ""
+
+#: conf/minimum_reputation.py:92
+msgid "Retag questions posted by other people"
+msgstr ""
+
+#: conf/minimum_reputation.py:101
+msgid "Reopen own questions"
+msgstr ""
+
+#: conf/minimum_reputation.py:110
+msgid "Edit community wiki posts"
+msgstr ""
+
+#: conf/minimum_reputation.py:119
+msgid "Edit posts authored by other people"
+msgstr ""
+
+#: conf/minimum_reputation.py:128
+msgid "View offensive flags"
+msgstr ""
+
+#: conf/minimum_reputation.py:137
+msgid "Close questions asked by others"
+msgstr ""
+
+#: conf/minimum_reputation.py:146
+msgid "Lock posts"
+msgstr ""
+
+#: conf/minimum_reputation.py:155
+msgid "Remove rel=nofollow from own homepage"
+msgstr ""
+
+#: conf/minimum_reputation.py:157
+msgid ""
+"When a search engine crawler will see a rel=nofollow attribute on a link - "
+"the link will not count towards the rank of the users personal site."
+msgstr ""
+
+#: conf/reputation_changes.py:12
+msgid "Reputation loss and gain rules"
+msgstr ""
+
+#: conf/reputation_changes.py:21
+msgid "Maximum daily reputation gain per user"
+msgstr ""
+
+#: conf/reputation_changes.py:30
+msgid "Gain for receiving an upvote"
+msgstr ""
+
+#: conf/reputation_changes.py:39
+msgid "Gain for the author of accepted answer"
+msgstr ""
+
+#: conf/reputation_changes.py:48
+msgid "Gain for accepting best answer"
+msgstr ""
+
+#: conf/reputation_changes.py:57
+msgid "Gain for post owner on canceled downvote"
+msgstr ""
+
+#: conf/reputation_changes.py:66
+msgid "Gain for voter on canceling downvote"
+msgstr ""
+
+#: conf/reputation_changes.py:76
+msgid "Loss for voter for canceling of answer acceptance"
+msgstr ""
+
+#: conf/reputation_changes.py:86
+msgid "Loss for author whose answer was \"un-accepted\""
+msgstr ""
+
+#: conf/reputation_changes.py:96
+msgid "Loss for giving a downvote"
+msgstr ""
+
+#: conf/reputation_changes.py:106
+msgid "Loss for owner of post that was flagged offensive"
+msgstr ""
+
+#: conf/reputation_changes.py:116
+msgid "Loss for owner of post that was downvoted"
+msgstr ""
+
+#: conf/reputation_changes.py:126
+msgid "Loss for owner of post that was flagged 3 times per same revision"
+msgstr ""
+
+#: conf/reputation_changes.py:136
+msgid "Loss for owner of post that was flagged 5 times per same revision"
+msgstr ""
+
+#: conf/reputation_changes.py:146
+msgid "Loss for post owner when upvote is canceled"
+msgstr ""
+
+#: conf/site_settings.py:13
+msgid "Q&A forum website parameters and urls"
+msgstr ""
+
+#: conf/site_settings.py:21
+msgid "Site title for the Q&A forum"
+msgstr ""
+
+#: conf/site_settings.py:30
+msgid "Comma separated list of Q&A site keywords"
+msgstr "Listă separată de virgule pentru cuvintele cheie ale siteului"
+
+#: conf/site_settings.py:40
+msgid "Copyright message to show in the footer"
+msgstr ""
+
+#: conf/site_settings.py:50
+msgid "Site description for the search engines"
+msgstr ""
+
+#: conf/site_settings.py:59
+msgid "Short name for your Q&A forum"
+msgstr ""
+
+#: conf/site_settings.py:69
+msgid "Base URL for your Q&A forum, must start with http or https"
+msgstr ""
+
+#: conf/site_settings.py:82
+msgid "Link shown in the greeting message shown to the anonymous user"
+msgstr ""
+
+#: conf/site_settings.py:85
+msgid ""
+"If you change this url from the default - then you will also probably want "
+"to adjust translation of the following string: "
+msgstr ""
+
+#: conf/site_settings.py:98
+msgid "Feedback site URL"
+msgstr "URL site pentru feedback"
+
+#: conf/site_settings.py:100
+msgid "If left empty, a simple internal feedback form will be used instead"
+msgstr "Dacă este lăsat gol, se va folosi un formular intern de feedback"
+
+#: conf/skin_counter_settings.py:11
+msgid "Skin: view, vote and answer counters"
+msgstr ""
+
+#: conf/skin_counter_settings.py:19
+msgid "Vote counter value to give \"full color\""
+msgstr ""
+
+#: conf/skin_counter_settings.py:29
+msgid "Background color for votes = 0"
+msgstr ""
+
+#: conf/skin_counter_settings.py:30 conf/skin_counter_settings.py:41
+#: conf/skin_counter_settings.py:52 conf/skin_counter_settings.py:62
+#: conf/skin_counter_settings.py:72 conf/skin_counter_settings.py:85
+#: conf/skin_counter_settings.py:106 conf/skin_counter_settings.py:117
+#: conf/skin_counter_settings.py:128 conf/skin_counter_settings.py:138
+#: conf/skin_counter_settings.py:148 conf/skin_counter_settings.py:163
+#: conf/skin_counter_settings.py:186 conf/skin_counter_settings.py:196
+#: conf/skin_counter_settings.py:206 conf/skin_counter_settings.py:216
+#: conf/skin_counter_settings.py:228 conf/skin_counter_settings.py:239
+#: conf/skin_counter_settings.py:252 conf/skin_counter_settings.py:262
+msgid "HTML color name or hex value"
+msgstr ""
+
+#: conf/skin_counter_settings.py:40
+msgid "Foreground color for votes = 0"
+msgstr ""
+
+#: conf/skin_counter_settings.py:51
+msgid "Background color for votes"
+msgstr ""
+
+#: conf/skin_counter_settings.py:61
+msgid "Foreground color for votes"
+msgstr ""
+
+#: conf/skin_counter_settings.py:71
+msgid "Background color for votes = MAX"
+msgstr ""
+
+#: conf/skin_counter_settings.py:84
+msgid "Foreground color for votes = MAX"
+msgstr ""
+
+#: conf/skin_counter_settings.py:95
+msgid "View counter value to give \"full color\""
+msgstr ""
+
+#: conf/skin_counter_settings.py:105
+msgid "Background color for views = 0"
+msgstr ""
+
+#: conf/skin_counter_settings.py:116
+msgid "Foreground color for views = 0"
+msgstr ""
+
+#: conf/skin_counter_settings.py:127
+msgid "Background color for views"
+msgstr ""
+
+#: conf/skin_counter_settings.py:137
+msgid "Foreground color for views"
+msgstr ""
+
+#: conf/skin_counter_settings.py:147
+msgid "Background color for views = MAX"
+msgstr ""
+
+#: conf/skin_counter_settings.py:162
+msgid "Foreground color for views = MAX"
+msgstr ""
+
+#: conf/skin_counter_settings.py:173
+msgid "Answer counter value to give \"full color\""
+msgstr ""
+
+#: conf/skin_counter_settings.py:185
+msgid "Background color for answers = 0"
+msgstr ""
+
+#: conf/skin_counter_settings.py:195
+msgid "Foreground color for answers = 0"
+msgstr ""
+
+#: conf/skin_counter_settings.py:205
+msgid "Background color for answers"
+msgstr ""
+
+#: conf/skin_counter_settings.py:215
+msgid "Foreground color for answers"
+msgstr ""
+
+#: conf/skin_counter_settings.py:227
+msgid "Background color for answers = MAX"
+msgstr ""
+
+#: conf/skin_counter_settings.py:238
+msgid "Foreground color for answers = MAX"
+msgstr ""
+
+#: conf/skin_counter_settings.py:251
+msgid "Background color for accepted"
+msgstr ""
+
+#: conf/skin_counter_settings.py:261
+msgid "Foreground color for accepted answer"
+msgstr ""
+
+#: conf/skin_general_settings.py:14
+msgid "Skin and User Interface settings"
+msgstr ""
+
+#: conf/skin_general_settings.py:21
+msgid "Q&A site logo"
+msgstr ""
+
+#: conf/skin_general_settings.py:23
+msgid "To change the logo, select new file, then submit this whole form."
+msgstr ""
+
+#: conf/skin_general_settings.py:37
+msgid "Show logo"
+msgstr ""
+
+#: conf/skin_general_settings.py:39
+msgid ""
+"Check if you want to show logo in the forum header or uncheck in the case "
+"you do not want the logo to appear in the default location"
+msgstr ""
+
+#: conf/skin_general_settings.py:51
+msgid "Site favicon"
+msgstr ""
+
+#: conf/skin_general_settings.py:53
+#, python-format
+msgid ""
+"A small 16x16 or 32x32 pixel icon image used to distinguish your site in the "
+"browser user interface. Please find more information about favicon at <a "
+"href=\"%(favicon_info_url)s\">this page</a>."
+msgstr ""
+
+#: conf/skin_general_settings.py:70
+msgid "Password login button"
+msgstr ""
+
+#: conf/skin_general_settings.py:72
+msgid ""
+"An 88x38 pixel image that is used on the login screen for the password login "
+"button."
+msgstr ""
+
+#: conf/skin_general_settings.py:87
+msgid "Show all UI functions to all users"
+msgstr ""
+
+#: conf/skin_general_settings.py:89
+msgid ""
+"If checked, all forum functions will be shown to users, regardless of their "
+"reputation. However to use those functions, moderation rules, reputation and "
+"other limits will still apply."
+msgstr ""
+
+#: conf/skin_general_settings.py:104
+msgid "Select skin"
+msgstr ""
+
+#: conf/skin_general_settings.py:113
+msgid "Skin media revision number"
+msgstr ""
+
+#: conf/skin_general_settings.py:115
+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 ""
+
+#: conf/skin_general_settings.py:128
+msgid "Customize HTML <HEAD>"
+msgstr ""
+
+#: conf/skin_general_settings.py:137
+msgid "Custom portion of the HTML <HEAD>"
+msgstr ""
+
+#: conf/skin_general_settings.py:139
+msgid ""
+"<strong>To use this option</strong>, check \"Customize HTML &lt;HEAD&gt;\" "
+"above. Contents of this box will be inserted into the &lt;HEAD&gt; portion "
+"of the HTML output, where elements such as &lt;script&gt;, &lt;link&gt;, "
+"&lt;meta&gt; may be added. Please, keep in mind that adding external "
+"javascript to the &lt;HEAD&gt; is not recommended because it slows loading "
+"of the pages. Instead, it will be more efficient to place links to the "
+"javascript files into the footer. <strong>Note:</strong> if you do use this "
+"setting, please test the site with the W3C HTML validator service."
+msgstr ""
+
+#: conf/skin_general_settings.py:159
+msgid "Site footer mode"
+msgstr ""
+
+#: conf/skin_general_settings.py:161
+msgid ""
+"Footer is the bottom portion of the content, which is common to all pages. "
+"You can disable, customize, or use the default footer."
+msgstr ""
+
+#: conf/skin_general_settings.py:178
+msgid "Custom footer (HTML format)"
+msgstr ""
+
+#: conf/skin_general_settings.py:180
+msgid ""
+"<strong>To enable this function</strong>, please select option 'customize' "
+"in the \"Site footer mode\" above. Use this area to enter contents of the "
+"footer in the HTML format. When customizing the site footer (as well as the "
+"HTML &lt;HEAD&gt;), use the HTML validation service to make sure that your "
+"input is valid and works well in all browsers."
+msgstr ""
+
+#: conf/skin_general_settings.py:195
+msgid "Apply custom style sheet (CSS)"
+msgstr ""
+
+#: conf/skin_general_settings.py:197
+msgid ""
+"Check if you want to change appearance of your form by adding custom style "
+"sheet rules (please see the next item)"
+msgstr ""
+
+#: conf/skin_general_settings.py:209
+msgid "Custom style sheet (CSS)"
+msgstr ""
+
+#: conf/skin_general_settings.py:211
+msgid ""
+"<strong>To use this function</strong>, check \"Apply custom style sheet\" "
+"option above. The CSS rules added in this window will be applied after the "
+"default style sheet rules. The custom style sheet will be served dynamically "
+"at url \"&lt;forum url&gt;/custom.css\", where the \"&lt;forum url&gt; part "
+"depends (default is empty string) on the url configuration in your urls.py."
+msgstr ""
+
+#: conf/skin_general_settings.py:227
+msgid "Add custom javascript"
+msgstr ""
+
+#: conf/skin_general_settings.py:230
+msgid "Check to enable javascript that you can enter in the next field"
+msgstr ""
+
+#: conf/skin_general_settings.py:240
+msgid "Custom javascript"
+msgstr ""
+
+#: conf/skin_general_settings.py:242
+msgid ""
+"Type or paste plain javascript that you would like to run on your site. Link "
+"to the script will be inserted at the bottom of the HTML output and will be "
+"served at the url \"&lt;forum url&gt;/custom.js\". Please, bear in mind that "
+"your javascript code may break other functionalities of the site and that "
+"the behavior may not be consistent across different browsers (<strong>to "
+"enable your custom code</strong>, check \"Add custom javascript\" option "
+"above)."
+msgstr ""
+
+#: conf/social_sharing.py:10
+msgid "Sharing content on social networks"
+msgstr ""
+
+#: conf/social_sharing.py:18
+msgid "Check to enable sharing of questions on Twitter and Facebook"
+msgstr ""
+
+#: conf/user_settings.py:10
+msgid "User policy settings"
+msgstr ""
+
+#: conf/user_settings.py:18
+msgid "Allow editing user screen name"
+msgstr ""
+
+#: conf/user_settings.py:28
+msgid "Minimum allowed length for screen name"
+msgstr ""
+
+#: conf/user_settings.py:37
+msgid "Name for the Anonymous user"
+msgstr ""
+
+#: conf/vote_rules.py:13
+msgid "Limits applicable to votes and moderation flags"
+msgstr ""
+
+#: conf/vote_rules.py:22
+msgid "Number of votes a user can cast per day"
+msgstr ""
+
+#: conf/vote_rules.py:31
+msgid "Maximum number of flags per user per day"
+msgstr ""
+
+#: conf/vote_rules.py:40
+msgid "Threshold for warning about remaining daily votes"
+msgstr ""
+
+#: conf/vote_rules.py:49
+msgid "Number of days to allow canceling votes"
+msgstr ""
+
+#: conf/vote_rules.py:58
+msgid "Number of flags required to automatically hide posts"
+msgstr ""
+
+#: conf/vote_rules.py:67
+msgid "Number of flags required to automatically delete posts"
+msgstr ""
+
+#: const/__init__.py:9
+msgid "duplicate question"
+msgstr "întrebare duplicat"
+
+#: const/__init__.py:10
+msgid "question is off-topic or not relevant"
+msgstr "întrebarea este off-topic sau nu este relevantă"
+
+#: const/__init__.py:11
+msgid "too subjective and argumentative"
+msgstr "prea subiectivă și argumentativă"
+
+#: const/__init__.py:12
+msgid "not a real question"
+msgstr "nu este de fapt o întrebare"
+
+#: const/__init__.py:13
+msgid "the question is answered, right answer was accepted"
+msgstr "întrebarea a căpătat un răspuns, răspunsul a fost acceptat"
+
+#: const/__init__.py:14
+msgid "question is not relevant or outdated"
+msgstr "întrebarea nu este relevantă sau este veche"
+
+#: const/__init__.py:15
+msgid "question contains offensive or malicious remarks"
+msgstr "întrebarea conține remarci ofensatoare sau răutăcioase"
+
+#: const/__init__.py:16
+msgid "spam or advertising"
+msgstr "spam sau reclamă"
+
+#: const/__init__.py:17
+msgid "too localized"
+msgstr "prea localizată"
+
+#: const/__init__.py:40
+msgid "newest"
+msgstr "cele mai noi"
+
+#: const/__init__.py:41 skins/default/templates/users.html:25
+#: skins/default/templates/users.html:26
+msgid "oldest"
+msgstr "mai vechi"
+
+#: const/__init__.py:42
+msgid "active"
+msgstr "activ"
+
+#: const/__init__.py:43
+msgid "inactive"
+msgstr "inactiv"
+
+#: const/__init__.py:44
+msgid "hottest"
+msgstr "cele mai interesante"
+
+#: const/__init__.py:45
+msgid "coldest"
+msgstr "mai reci"
+
+#: const/__init__.py:46
+msgid "most voted"
+msgstr "cele mai votate"
+
+#: const/__init__.py:47
+msgid "least voted"
+msgstr "cele mai puțin votate"
+
+#: const/__init__.py:48 skins/default/templates/main_page/tab_bar.html:29
+msgid "relevance"
+msgstr "relevanță"
+
+#: const/__init__.py:55 skins/default/templates/main_page/tab_bar.html:10
+#: skins/default/templates/user_profile/user_inbox.html:50
+msgid "all"
+msgstr "toate"
+
+#: const/__init__.py:56 skins/default/templates/main_page/tab_bar.html:15
+msgid "unanswered"
+msgstr "fără răspuns"
+
+#: const/__init__.py:57 skins/default/templates/main_page/tab_bar.html:21
+msgid "favorite"
+msgstr "favorite"
+
+#: const/__init__.py:71
+msgid "Question has no answers"
+msgstr "Întrebarea nu are răspuns"
+
+#: const/__init__.py:72
+msgid "Question has no accepted answers"
+msgstr "Întrebarea nu are un răspuns acceptat"
+
+#: const/__init__.py:112
+msgid "asked a question"
+msgstr "a pus o întrebare"
+
+#: const/__init__.py:113
+msgid "answered a question"
+msgstr "a răspuns unei întrebări"
+
+#: const/__init__.py:114
+msgid "commented question"
+msgstr "întrebare comentată"
+
+#: const/__init__.py:115
+msgid "commented answer"
+msgstr "răspuns comentat"
+
+#: const/__init__.py:116
+msgid "edited question"
+msgstr "întrebare editată"
+
+#: const/__init__.py:117
+msgid "edited answer"
+msgstr "răspuns editat"
+
+#: const/__init__.py:118
+msgid "received award"
+msgstr "recompensă primită"
+
+#: const/__init__.py:119
+msgid "marked best answer"
+msgstr "marcat ca cel mai bun răspuns"
+
+#: const/__init__.py:120
+msgid "upvoted"
+msgstr "votat pozitiv"
+
+#: const/__init__.py:121
+msgid "downvoted"
+msgstr "votat negativ"
+
+#: const/__init__.py:122
+msgid "canceled vote"
+msgstr "vot anulat"
+
+#: const/__init__.py:123
+msgid "deleted question"
+msgstr "întrebare ștearsă"
+
+#: const/__init__.py:124
+msgid "deleted answer"
+msgstr "răspuns șters"
+
+#: const/__init__.py:125
+msgid "marked offensive"
+msgstr "marcat ca ofensator"
+
+#: const/__init__.py:126
+msgid "updated tags"
+msgstr "etichete actualizate"
+
+#: const/__init__.py:127
+msgid "selected favorite"
+msgstr ""
+
+#: const/__init__.py:128
+msgid "completed user profile"
+msgstr "profil utilizator complet"
+
+#: const/__init__.py:129
+msgid "email update sent to user"
+msgstr "e-mail actualizat trimis utilizatorului"
+
+#: const/__init__.py:130
+msgid "mentioned in the post"
+msgstr "menționat în postare"
+
+#: const/__init__.py:181
+msgid "question_answered"
+msgstr "întrebare_cu_răspuns"
+
+#: const/__init__.py:182
+msgid "question_commented"
+msgstr "întrebare_comentată"
+
+#: const/__init__.py:183
+msgid "answer_commented"
+msgstr "răspuns_comentat"
+
+#: const/__init__.py:184
+msgid "answer_accepted"
+msgstr "răspuns_acceptat"
+
+#: const/__init__.py:188
+msgid "[closed]"
+msgstr "[închis]"
+
+#: const/__init__.py:189
+msgid "[deleted]"
+msgstr "[șters]"
+
+#: const/__init__.py:190 views/readers.py:578
+msgid "initial version"
+msgstr "versiune inițială"
+
+#: const/__init__.py:191
+msgid "retagged"
+msgstr "reetichetat"
+
+#: const/__init__.py:199
+msgid "off"
+msgstr "dezactivat"
+
+#: const/__init__.py:200
+msgid "exclude ignored"
+msgstr "exclude cele ignorate"
+
+#: const/__init__.py:201
+msgid "only selected"
+msgstr "doar cele selectate"
+
+#: const/__init__.py:205
+msgid "instantly"
+msgstr "instant"
+
+#: const/__init__.py:206
+msgid "daily"
+msgstr "zilnic"
+
+#: const/__init__.py:207
+msgid "weekly"
+msgstr "săptămânal"
+
+#: const/__init__.py:208
+msgid "no email"
+msgstr "fără e-mail"
+
+#: const/__init__.py:245 skins/default/templates/badges.html:37
+msgid "gold"
+msgstr "aur"
+
+#: const/__init__.py:246 skins/default/templates/badges.html:46
+msgid "silver"
+msgstr "argint"
+
+#: const/__init__.py:247 skins/default/templates/badges.html:53
+msgid "bronze"
+msgstr "bronz"
+
+#: const/message_keys.py:19
+#, python-format
+msgid "First time here? Check out the <a href=\"%s\">FAQ</a>!"
+msgstr ""
+"Prima dată aici? Consultați <a href=\"%s\">Întrebările frecvente</a>!"
+
+#: const/message_keys.py:22 skins/default/templates/main_page/tab_bar.html:27
+msgid "most relevant questions"
+msgstr "cele mai relevante întrebări"
+
+#: const/message_keys.py:23 skins/default/templates/main_page/tab_bar.html:28
+msgid "click to see most relevant questions"
+msgstr "efectuați clic pentru a vedea cele mai relevante întrebări"
+
+#: const/message_keys.py:24
+msgid "by relevance"
+msgstr "după relevanță"
+
+#: const/message_keys.py:25
+msgid "click to see the oldest questions"
+msgstr "clic pentru a vedea cele mai vechi întrebări"
+
+#: const/message_keys.py:26
+msgid "by date"
+msgstr "după dată"
+
+#: const/message_keys.py:27
+msgid "click to see the newest questions"
+msgstr "efectuați clic pentru a vedea cele mai noi întrebări"
+
+#: const/message_keys.py:28
+msgid "click to see the least recently updated questions"
+msgstr "clic pentru a vedea cel mai puțin recent actualizate întrebări"
+
+#: const/message_keys.py:29
+msgid "by activity"
+msgstr "după activitate"
+
+#: const/message_keys.py:30
+msgid "click to see the most recently updated questions"
+msgstr "clic pentru a vedea cele mai recent actualizate întrebări"
+
+#: const/message_keys.py:31
+msgid "click to see the least answered questions"
+msgstr ""
+"efectuați clic pentru a vedea întrebările cu cele mai puține răspunsuri"
+
+#: const/message_keys.py:32
+msgid "by answers"
+msgstr "după răspunsuri"
+
+#: const/message_keys.py:33
+msgid "click to see the most answered questions"
+msgstr ""
+"efectuați clic pentru a vedea întrebările cu cele mai multe răspunsuri"
+
+#: const/message_keys.py:34
+msgid "click to see least voted questions"
+msgstr "efectuați clic pentru a vedea întrebările cu cele mai puține voturi"
+
+#: const/message_keys.py:35
+msgid "by votes"
+msgstr "după voturi"
+
+#: const/message_keys.py:36
+msgid "click to see most voted questions"
+msgstr "efectuați clic pentru a vedea întrebările cu cele mai multe voturi"
+
+#: deps/django_authopenid/forms.py:110 deps/django_authopenid/views.py:134
+msgid "i-names are not supported"
+msgstr ""
+
+#: deps/django_authopenid/forms.py:231
+#, python-format
+msgid "Please enter your %(username_token)s"
+msgstr "Introduceți %(username_token)s"
+
+#: deps/django_authopenid/forms.py:257
+msgid "Please, enter your user name"
+msgstr "Introduceți numele de utilizator"
+
+#: deps/django_authopenid/forms.py:261
+msgid "Please, enter your password"
+msgstr "Introduceți parola"
+
+#: deps/django_authopenid/forms.py:268 deps/django_authopenid/forms.py:272
+msgid "Please, enter your new password"
+msgstr "Introduceți noua parolă"
+
+#: deps/django_authopenid/forms.py:283
+msgid "Passwords did not match"
+msgstr "Parolele nu se potrivesc"
+
+#: deps/django_authopenid/forms.py:295
+#, python-format
+msgid "Please choose password > %(len)s characters"
+msgstr "Alegeți o parolă mai mare decât %(len)s caractere"
+
+#: deps/django_authopenid/forms.py:330
+msgid "Current password"
+msgstr "Parolă curentă"
+
+#: deps/django_authopenid/forms.py:341
+msgid ""
+"Old password is incorrect. Please enter the correct "
+"password."
+msgstr "Parola veche nu este corectă. Introduceți o parolă corectă."
+
+#: deps/django_authopenid/forms.py:394
+msgid "Sorry, we don't have this email address in the database"
+msgstr "Această adreasă de e-mail nu se regăsește în baza noastră de date"
+
+#: deps/django_authopenid/forms.py:430
+msgid "Your user name (<i>required</i>)"
+msgstr "Numele de utilizator este (<i>obligatoriu</i>)"
+
+#: deps/django_authopenid/forms.py:445
+msgid "Incorrect username."
+msgstr "Nume de utilizator incorect"
+
+#: deps/django_authopenid/urls.py:9 deps/django_authopenid/urls.py:10
+#: deps/django_authopenid/urls.py:11 deps/django_authopenid/urls.py:14
+#: deps/django_authopenid/urls.py:17 setup_templates/settings.py:188
+msgid "signin/"
+msgstr "autentificare/"
+
+#: deps/django_authopenid/urls.py:10
+msgid "newquestion/"
+msgstr ""
+
+#: deps/django_authopenid/urls.py:11
+msgid "newanswer/"
+msgstr ""
+
+#: deps/django_authopenid/urls.py:12
+msgid "signout/"
+msgstr ""
+
+#: deps/django_authopenid/urls.py:14
+msgid "complete/"
+msgstr ""
+
+#: deps/django_authopenid/urls.py:17
+msgid "complete-oauth/"
+msgstr ""
+
+#: deps/django_authopenid/urls.py:21
+msgid "register/"
+msgstr ""
+
+#: deps/django_authopenid/urls.py:23
+msgid "signup/"
+msgstr ""
+
+#: deps/django_authopenid/urls.py:31
+msgid "recover/"
+msgstr ""
+
+#: deps/django_authopenid/util.py:193
+#, python-format
+msgid "%(site)s user name and password"
+msgstr ""
+
+#: deps/django_authopenid/util.py:199
+#: skins/default/templates/authopenid/signin.html:99
+msgid "Create a password-protected account"
+msgstr "Creați un cont protejat prin parolă"
+
+#: deps/django_authopenid/util.py:200
+msgid "Change your password"
+msgstr "Schimbați parola"
+
+#: deps/django_authopenid/util.py:262
+msgid "Sign in with Yahoo"
+msgstr "Autentificare cu Yahoo"
+
+#: deps/django_authopenid/util.py:269
+msgid "AOL screen name"
+msgstr "nume utilizator AOL"
+
+#: deps/django_authopenid/util.py:277
+msgid "OpenID url"
+msgstr "URL OpenID"
+
+#: deps/django_authopenid/util.py:294
+msgid "MyOpenid user name"
+msgstr "nume utilizator MyOpenid"
+
+#: deps/django_authopenid/util.py:302
+msgid "Flickr user name"
+msgstr "nume utilizator Flickr"
+
+#: deps/django_authopenid/util.py:310
+msgid "Technorati user name"
+msgstr "nume utilizator Technorati"
+
+#: deps/django_authopenid/util.py:318
+msgid "WordPress blog name"
+msgstr "nume blog WordPress"
+
+#: deps/django_authopenid/util.py:326
+msgid "Blogger blog name"
+msgstr "nume blog Blogger"
+
+#: deps/django_authopenid/util.py:334
+msgid "LiveJournal blog name"
+msgstr "nume blog LiveJournal"
+
+#: deps/django_authopenid/util.py:342
+msgid "ClaimID user name"
+msgstr "nume utilizator ClaimID"
+
+#: deps/django_authopenid/util.py:350
+msgid "Vidoop user name"
+msgstr "nume utilizator Vidoop"
+
+#: deps/django_authopenid/util.py:358
+msgid "Verisign user name"
+msgstr "nume utilizator Verisign"
+
+#: deps/django_authopenid/util.py:382
+#, python-format
+msgid "Change your %(provider)s password"
+msgstr "Modificați parola pentru %(provider)s"
+
+#: deps/django_authopenid/util.py:386
+#, python-format
+msgid ""
+"Click to see if your %(provider)s signin still works for %(site_name)s"
+msgstr ""
+"Efectuați clic pentru a verifica dacă autentificarea pentru %(provider)s "
+"încă funcționează pe %(site_name)s"
+
+#: deps/django_authopenid/util.py:395
+#, python-format
+msgid "Create password for %(provider)s"
+msgstr "Creați parolă pentru %(provider)s"
+
+#: deps/django_authopenid/util.py:399
+#, python-format
+msgid "Connect your %(provider)s account to %(site_name)s"
+msgstr "Conectați contul %(provider)s la %(site_name)s"
+
+#: deps/django_authopenid/util.py:408
+#, python-format
+msgid "Signin with %(provider)s user name and password"
+msgstr "Autentificați-vă cu numele de utilizator și parola %(provider)s"
+
+#: deps/django_authopenid/util.py:415
+#, python-format
+msgid "Sign in with your %(provider)s account"
+msgstr "Autentificați-vă cu contul de %(provider)s"
+
+#: deps/django_authopenid/views.py:141
+#, python-format
+msgid "OpenID %(openid_url)s is invalid"
+msgstr "Legătura OpenID %(openid_url)s este nevalidă"
+
+#: deps/django_authopenid/views.py:253 deps/django_authopenid/views.py:395
+#: deps/django_authopenid/views.py:423
+#, python-format
+msgid ""
+"Unfortunately, there was some problem when connecting to %(provider)s, "
+"please try again or use another provider"
+msgstr ""
+"Din păcate există o problemă la conectarea la %(provider)s, reîncercați sau "
+"utilizați un alt furnizor"
+
+#: deps/django_authopenid/views.py:345
+msgid "Your new password saved"
+msgstr "Noua parolă a fost salvată"
+
+#: deps/django_authopenid/views.py:507
+msgid "Please click any of the icons below to sign in"
+msgstr ""
+"Pentru a vă autentifica efectuați clic pe oricare din iconițele de mai jos"
+
+#: deps/django_authopenid/views.py:509
+msgid "Account recovery email sent"
+msgstr "E-mail-ul pentru recuperarea contului a fost trimis"
+
+#: deps/django_authopenid/views.py:512
+msgid "Please add one or more login methods."
+msgstr "Adăugați una sau mai multe metode de autentificare"
+
+#: deps/django_authopenid/views.py:514
+msgid "If you wish, please add, remove or re-validate your login methods"
+msgstr ""
+"Dacă doriți, adăugați, ștergeți sau revalidați metodele de autentificare"
+
+#: deps/django_authopenid/views.py:516
+msgid "Please wait a second! Your account is recovered, but ..."
+msgstr "Așteptați puțin! Contul dumneavoastră este recuperat, dar..."
+
+#: deps/django_authopenid/views.py:518
+msgid "Sorry, this account recovery key has expired or is invalid"
+msgstr ""
+"Ne pare rău, cheia pentru recuperarea contului a expirat sau nu mai este "
+"validă"
+
+#: deps/django_authopenid/views.py:574
+#, python-format
+msgid "Login method %(provider_name)s does not exist"
+msgstr "Metoda de autentificare pentru %(provider_name)s nu există"
+
+#: deps/django_authopenid/views.py:580
+msgid "Oops, sorry - there was some error - please try again"
+msgstr "Oauu, scuze - a apărut o eroare - încercați mai târziu"
+
+#: deps/django_authopenid/views.py:671
+#, python-format
+msgid "Your %(provider)s login works fine"
+msgstr "Autentificarea pentru %(provider)s este funcțională"
+
+#: deps/django_authopenid/views.py:978 deps/django_authopenid/views.py:984
+#, python-format
+msgid "your email needs to be validated see %(details_url)s"
+msgstr ""
+"adresa dumneavoastră de e-mail trebuie validată, consultați %(details_url)s"
+
+#: deps/django_authopenid/views.py:1005
+#, python-format
+msgid "Recover your %(site)s account"
+msgstr "Recuperați contul %(site)s"
+
+#: deps/django_authopenid/views.py:1070
+msgid "Please check your email and visit the enclosed link."
+msgstr "Verificați-vă e-mail-ul și mergeți la legătura inclusă"
+
+#: deps/livesettings/models.py:101 deps/livesettings/models.py:140
+msgid "Site"
+msgstr "Pagină web"
+
+#: deps/livesettings/values.py:106
+msgid "Base Settings"
+msgstr "Configurări de bază"
+
+#: deps/livesettings/values.py:213
+msgid "Default value: \"\""
+msgstr "Valoare implicită: \"\""
+
+#: deps/livesettings/values.py:220
+msgid "Default value: "
+msgstr "Valoare implicită: "
+
+#: deps/livesettings/values.py:223
+#, python-format
+msgid "Default value: %s"
+msgstr "Valoare implicită: %s"
+
+#: deps/livesettings/values.py:588
+#, python-format
+msgid "Allowed image file types are %(types)s"
+msgstr "Tipurile de fișiere imagine permise sunt %(types)s"
+
+#: deps/livesettings/templates/livesettings/_admin_site_views.html:4
+msgid "Sites"
+msgstr "Pagini web"
+
+#: deps/livesettings/templates/livesettings/group_settings.html:11
+#: deps/livesettings/templates/livesettings/site_settings.html:23
+msgid "Documentation"
+msgstr "Documentație"
+
+#: deps/livesettings/templates/livesettings/group_settings.html:11
+#: deps/livesettings/templates/livesettings/site_settings.html:23
+#: skins/default/templates/authopenid/signin.html:117
+msgid "Change password"
+msgstr "Schimbă parola"
+
+#: deps/livesettings/templates/livesettings/group_settings.html:11
+#: deps/livesettings/templates/livesettings/site_settings.html:23
+msgid "Log out"
+msgstr "Ieșire"
+
+#: deps/livesettings/templates/livesettings/group_settings.html:14
+#: deps/livesettings/templates/livesettings/site_settings.html:26
+msgid "Home"
+msgstr "Acasă"
+
+#: deps/livesettings/templates/livesettings/group_settings.html:15
+msgid "Edit Group Settings"
+msgstr "Editare configurări de grup"
+
+#: deps/livesettings/templates/livesettings/group_settings.html:22
+#: deps/livesettings/templates/livesettings/site_settings.html:50
+msgid "Please correct the error below."
+msgid_plural "Please correct the errors below."
+msgstr[0] "Corectați eroarea de mai jos"
+msgstr[1] "Corectați erorile de mai jos"
+msgstr[2] "Corectați erorile de mai jos"
+
+#: deps/livesettings/templates/livesettings/group_settings.html:28
+#, python-format
+msgid "Settings included in %(name)s."
+msgstr "Configurări incluse în %(name)s."
+
+#: deps/livesettings/templates/livesettings/group_settings.html:62
+#: deps/livesettings/templates/livesettings/site_settings.html:97
+msgid "You don't have permission to edit values."
+msgstr "Nu aveți permisiunea de a edita valorile"
+
+#: deps/livesettings/templates/livesettings/group_settings.html:68
+msgid "Setting groups"
+msgstr "Configurare grup"
+
+#: deps/livesettings/templates/livesettings/site_settings.html:27
+msgid "Edit Site Settings"
+msgstr "Editați configurările site-ului"
+
+#: deps/livesettings/templates/livesettings/site_settings.html:43
+msgid "Livesettings are disabled for this site."
+msgstr "Configurările live sunt dezactivate pentru acest site"
+
+#: deps/livesettings/templates/livesettings/site_settings.html:44
+msgid "All configuration options must be edited in the site settings.py file"
+msgstr ""
+"Toate opțiunile de configurare trebuie editate în fișierul site-ului "
+"settings.py"
+
+#: deps/livesettings/templates/livesettings/site_settings.html:66
+#, python-format
+msgid "Group settings: %(name)s"
+msgstr "Configurări grup: %(name)s"
+
+#: deps/livesettings/templates/livesettings/site_settings.html:93
+msgid "Uncollapse all"
+msgstr "Restrânge tot"
+
+#: deps/recaptcha_django/__init__.py:19 deps/recaptcha_django/__init__.py:80
+msgid "Unknown error."
+msgstr "Eroare necunoscută."
+
+#: deps/recaptcha_django/__init__.py:20 deps/recaptcha_django/__init__.py:21
+msgid "ReCAPTCHA is wrongly configured."
+msgstr "ReCAPTCHA este configurat greșit."
+
+#: deps/recaptcha_django/__init__.py:22
+msgid "Bad reCAPTCHA challenge parameter."
+msgstr "Parametru șir reCAPTCHA eronat."
+
+#: deps/recaptcha_django/__init__.py:23
+msgid "The CAPTCHA solution was incorrect."
+msgstr "Soluția CAPTCHA a fost incorectă."
+
+#: deps/recaptcha_django/__init__.py:24
+msgid "Bad reCAPTCHA verification parameters."
+msgstr "Parametri verificare reCAPTCHA eronați."
+
+#: deps/recaptcha_django/__init__.py:25
+msgid "Provided reCAPTCHA API keys are not valid for this domain."
+msgstr "Cheile reCAPTCHA API furnizate nu sunt valide pentru acest domeniu."
+
+#: deps/recaptcha_django/__init__.py:26
+msgid "ReCAPTCHA could not be reached."
+msgstr "ReCAPTCHA nu poate fi lansat."
+
+#: deps/recaptcha_django/__init__.py:73
+msgid "Invalid request"
+msgstr "Cerere nevalidă"
+
+#: importers/stackexchange/management/commands/load_stackexchange.py:128
+msgid "Congratulations, you are now an Administrator"
+msgstr "Felicitări, de acum sunteți un administrator"
+
+#: management/commands/send_email_alerts.py:103
+#, python-format
+msgid "\" and \"%s\""
+msgstr "\" și \"%s\""
+
+#: management/commands/send_email_alerts.py:106
+msgid "\" and more"
+msgstr "\" și în plus"
+
+#: management/commands/send_email_alerts.py:111
+#, python-format
+msgid "%(question_count)d updated question about %(topics)s"
+msgid_plural "%(question_count)d updated questions about %(topics)s"
+msgstr[0] "%(question_count)d întrebare actualizată despre %(topics)s"
+msgstr[1] "%(question_count)d întrebări actualizate despre %(topics)s"
+msgstr[2] "%(question_count)d de întrebări actualizate despre %(topics)s"
+
+#: management/commands/send_email_alerts.py:484
+#, 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"
+msgstr[0] ""
+"%(name)s, acesta este un antet de mesaj actualizat pentru %(num)d întrebare"
+msgstr[1] ""
+"%(name)s, acesta este un antet de mesaj actualizat pentru %(num)d întrebări"
+msgstr[2] ""
+"%(name)s, acesta este un antet de mesaj actualizat pentru %(num)d de "
+"întrebări"
+
+#: management/commands/send_email_alerts.py:501
+msgid "new question"
+msgstr "întrebare nouă"
+
+#: management/commands/send_email_alerts.py:518
+msgid ""
+"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?"
+msgstr ""
+"Vizitați pagina askbot pentru a afla noutățile! Puteți duce vestea mai "
+"departe - poate că cineva cunoscut are răspunsuri pentru aceste întrebări "
+"sau dorește să posteze o întrebare."
+
+#: management/commands/send_email_alerts.py:530
+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 askbot administrator."
+msgstr ""
+"Frecvența aleasă de dumneavoastră pentru a primi întrebările selectate este "
+"„zilnic”. Dacă primiți mai mult de un e-mail pe zi, adresați-vă "
+"administratorului paginii askbot pentru a raporta problema."
+
+#: management/commands/send_email_alerts.py:536
+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 askbot "
+"administrator."
+msgstr ""
+"Frecvența aleasă de dumneavoastră pentru a primi întrebările selectate este "
+"„săptămânal”. Dacă primiți mai mult de un e-mail pe săptămână, adresați-vă "
+"administratorului paginii askbot pentru a raporta problema."
+
+#: management/commands/send_email_alerts.py:542
+msgid ""
+"There is a chance that you may be receiving links seen before - due to a "
+"technicality that will eventually go away. "
+msgstr ""
+"Există posibilitatea unele legături pe care le-ați primit deja să vă fie din "
+"nou trimise - cauza este de natură tehnică și va fi remediată. "
+
+#: management/commands/send_email_alerts.py:548
+#, python-format
+msgid ""
+"go to %(email_settings_link)s to change frequency of email updates or "
+"%(admin_email)s administrator"
+msgstr ""
+"mergeți la %(email_settings_link)s pentru a modifica frecvența e-mail-urilor "
+"cu actualizări sau %(admin_email)s de administrare"
+
+#: models/__init__.py:299
+msgid ""
+"Sorry, you cannot accept or unaccept best answers because your account is "
+"blocked"
+msgstr ""
+"Nu puteți accepta sau refuza cele mai bune răspunsuri deoarece contul "
+"dumneavoastră este blocat"
+
+#: models/__init__.py:304
+msgid ""
+"Sorry, you cannot accept or unaccept best answers because your account is "
+"suspended"
+msgstr ""
+"Nu puteți accepta sau refuza cele mai bune răspunsuri deoarece contul "
+"dumneavoastră este suspendat"
+
+#: models/__init__.py:310
+msgid ""
+"Sorry, you cannot accept or unaccept your own answer to your own question"
+msgstr ""
+"Nu se poate accepta sau revoca acceptarea pentru propriul răspuns la propria "
+"întrebare"
+
+#: models/__init__.py:317
+#, python-format
+msgid ""
+"Sorry, only original author of the question - %(username)s - can accept the "
+"best answer"
+msgstr ""
+"Numai autorul original al întrebării - %(username)s - poate accepta cel mai "
+"bun răspuns"
+
+#: models/__init__.py:340
+msgid "cannot vote for own posts"
+msgstr "nu se pot vota mesajele proprii"
+
+#: models/__init__.py:343
+msgid "Sorry your account appears to be blocked "
+msgstr "Contul dumneavoastră pare a fi blocat "
+
+#: models/__init__.py:348
+msgid "Sorry your account appears to be suspended "
+msgstr "Contul dumneavoastră pare a fi suspendat "
+
+#: models/__init__.py:358
+#, python-format
+msgid ">%(points)s points required to upvote"
+msgstr "Sunt necesare >%(points)s puncte pentru a vota pozitiv"
+
+#: models/__init__.py:364
+#, python-format
+msgid ">%(points)s points required to downvote"
+msgstr "sunt necesare %(points)s puncte pentru a dezaprova"
+
+#: models/__init__.py:379
+msgid "Sorry, blocked users cannot upload files"
+msgstr "Utilizatorii blocați nu pot încărca fișiere"
+
+#: models/__init__.py:380
+msgid "Sorry, suspended users cannot upload files"
+msgstr "Utilizatorii suspendați nu pot încărca fișiere"
+
+#: models/__init__.py:382
+#, python-format
+msgid ""
+"uploading images is limited to users with >%(min_rep)s reputation points"
+msgstr ""
+"încărcarea de imagini este limitată utilizatorilor cu mai mult de "
+"%(min_rep)s puncte de reputație"
+
+#: models/__init__.py:401 models/__init__.py:468 models/__init__.py:2320
+msgid "blocked users cannot post"
+msgstr "utilizatorii blocați nu pot introduce postări"
+
+#: models/__init__.py:402 models/__init__.py:2323
+msgid "suspended users cannot post"
+msgstr "utilizatorii suspendați nu pot introduce postări"
+
+#: models/__init__.py:429
+#, python-format
+msgid ""
+"Sorry, comments (except the last one) are editable only within %(minutes)s "
+"minute from posting"
+msgid_plural ""
+"Sorry, comments (except the last one) are editable only within %(minutes)s "
+"minutes from posting"
+msgstr[0] ""
+"Comentariile (cu excepția ultimului) pot fi modificate numai într-un "
+"interval de %(minutes)s minut de la postare"
+msgstr[1] ""
+"Comentariile (cu excepția ultimului) pot fi modificate numai într-un "
+"interval de %(minutes)s minute de la postare"
+msgstr[2] ""
+"Comentariile (cu excepția ultimului) pot fi modificate numai într-un "
+"interval de %(minutes)s de minute de la postare"
+
+#: models/__init__.py:441
+msgid "Sorry, but only post owners or moderators can edit comments"
+msgstr ""
+"Doar cel care a adăugat mesajul și moderatorii pot modifica comentariile"
+
+#: models/__init__.py:454
+msgid ""
+"Sorry, since your account is suspended you can comment only your own posts"
+msgstr ""
+"Deoarece contul dumneavoastră este suspendat, puteți comenta numai postările "
+"proprii"
+
+#: models/__init__.py:458
+#, python-format
+msgid ""
+"Sorry, to comment any post a minimum reputation of %(min_rep)s points is "
+"required. You can still comment your own posts and answers to your questions"
+msgstr ""
+"Ne pare rău, pentru a comenta la un mesaj este necesar un minim de "
+"%(min_rep)s puncte de reputație. Puteți în continuare să comentați mesajele "
+"și răspunsurile pentru întrebările proprii"
+
+#: models/__init__.py:486
+msgid ""
+"This post has been deleted and can be seen only by post owners, site "
+"administrators and moderators"
+msgstr ""
+"Această postare a fost ștearsă și poate fi văzută numai de către "
+"proprietari, administratorii site-ului și moderatori"
+
+#: models/__init__.py:503
+msgid ""
+"Sorry, only moderators, site administrators and post owners can edit deleted "
+"posts"
+msgstr ""
+"Numai moderatorii, administratorii site-ului și proprietarii postării pot "
+"modifica postările șterse"
+
+#: models/__init__.py:518
+msgid "Sorry, since your account is blocked you cannot edit posts"
+msgstr ""
+"Deoarece contul dumneavoastră este blocat, nu puteți modifica postările"
+
+#: models/__init__.py:522
+msgid ""
+"Sorry, since your account is suspended you can edit only your own posts"
+msgstr ""
+"Deoarece contul dumneavoastră este suspendat, puteți modifica numai "
+"postările proprii"
+
+#: models/__init__.py:527
+#, python-format
+msgid ""
+"Sorry, to edit wiki posts, a minimum reputation of %(min_rep)s is required"
+msgstr ""
+"Pentru a modifica wiki-ul, este necesar un minim de %(min_rep)s puncte de "
+"reputație"
+
+#: models/__init__.py:534
+#, python-format
+msgid ""
+"Sorry, to edit other people's posts, a minimum reputation of %(min_rep)s is "
+"required"
+msgstr ""
+"Ne pare rău, pentru a modifica mesajele altor utilizatori este nevoie de un "
+"minim de %(min_rep)s puncte de reputație"
+
+#: models/__init__.py:597
+msgid ""
+"Sorry, cannot delete your question since it has an upvoted answer posted by "
+"someone else"
+msgid_plural ""
+"Sorry, cannot delete your question since it has some upvoted answers posted "
+"by other users"
+msgstr[0] ""
+"Nu puteți șterge întrebarea deoarece beneficiază de un răspuns votat pozitiv "
+"de altcineva."
+msgstr[1] ""
+"Nu puteți șterge întrebarea deoarece beneficiază de răspunsuri votate "
+"pozitiv de alți utilizatori."
+msgstr[2] ""
+"Nu puteți șterge întrebarea deoarece beneficiază de răspunsuri votate "
+"pozitiv de alți utilizatori."
+
+#: models/__init__.py:612
+msgid "Sorry, since your account is blocked you cannot delete posts"
+msgstr "Deoarece contul dumneavoastră este blocat, nu puteți șterge postări"
+
+#: models/__init__.py:616
+msgid ""
+"Sorry, since your account is suspended you can delete only your own posts"
+msgstr ""
+"Deoarece contul dumneavoastră este suspendat, puteți șterge numai postările "
+"proprii"
+
+#: models/__init__.py:620
+#, python-format
+msgid ""
+"Sorry, to deleted other people' posts, a minimum reputation of %(min_rep)s "
+"is required"
+msgstr ""
+"Ne pare rău, pentru a șterge mesajele altor utilizatori este nevoie de un "
+"minim de %(min_rep)s puncte de reputație"
+
+#: models/__init__.py:640
+msgid "Sorry, since your account is blocked you cannot close questions"
+msgstr ""
+"Deoarece contul dumneavoastră este blocat, nu puteți închide întrebări"
+
+#: models/__init__.py:644
+msgid "Sorry, since your account is suspended you cannot close questions"
+msgstr ""
+"Deoarece contul dumneavoastră este suspendat, nu puteți închide întrebări"
+
+#: models/__init__.py:648
+#, python-format
+msgid ""
+"Sorry, to close other people' posts, a minimum reputation of %(min_rep)s is "
+"required"
+msgstr ""
+"Ne pare rău, pentru a închide mesajele altor utilizatori este nevoie de un "
+"minim de %(min_rep)s puncte de reputație"
+
+#: models/__init__.py:657
+#, python-format
+msgid ""
+"Sorry, to close own question a minimum reputation of %(min_rep)s is required"
+msgstr ""
+"Ne pare rău, pentru a închide propria întrebare este nevoie de un minim de "
+"%(min_rep)s puncte de reputație"
+
+#: models/__init__.py:681
+#, python-format
+msgid ""
+"Sorry, only administrators, moderators or post owners with reputation > "
+"%(min_rep)s can reopen questions."
+msgstr ""
+"Ne pare rău, doar administratorii, moderatorii și proprietarii mesajelor cu "
+"o reputație de minim %(min_rep)s puncte de reputație pot redeschide "
+"întrebări."
+
+#: models/__init__.py:687
+#, python-format
+msgid ""
+"Sorry, to reopen own question a minimum reputation of %(min_rep)s is required"
+msgstr ""
+"Ne pare rău, pentru a redesche propria întrebare este nevoie de un minim de "
+"%(min_rep)s puncte de reputație"
+
+#: models/__init__.py:707
+msgid "cannot flag message as offensive twice"
+msgstr "nu se poate marca ofensiv de mai multe ori"
+
+#: models/__init__.py:712
+msgid "blocked users cannot flag posts"
+msgstr "utilizatorii blocați nu pot marca postări"
+
+#: models/__init__.py:714
+msgid "suspended users cannot flag posts"
+msgstr "utilizatorii suspendați nu pot marca postări"
+
+#: models/__init__.py:716
+#, python-format
+msgid "need > %(min_rep)s points to flag spam"
+msgstr ""
+"este nevoie de mai mult de %(min_rep)s puncte pentru a marca drept spam"
+
+#: models/__init__.py:735
+#, python-format
+msgid "%(max_flags_per_day)s exceeded"
+msgstr "ați depășit %(max_flags_per_day)s"
+
+#: models/__init__.py:750
+msgid ""
+"Sorry, only question owners, site administrators and moderators can retag "
+"deleted questions"
+msgstr ""
+"Numai proprietarii întrebării, administratorii site-ului și moderatorii pot "
+"reeticheta întrebările șterse"
+
+#: models/__init__.py:757
+msgid "Sorry, since your account is blocked you cannot retag questions"
+msgstr ""
+"Deoarece contul dumneavoastră este blocat, nu puteți reeticheta întrebări"
+
+#: models/__init__.py:761
+msgid ""
+"Sorry, since your account is suspended you can retag only your own questions"
+msgstr ""
+"Deoarece contul dumneavoastră este suspendat, puteți reeticheta numai "
+"întrebările proprii"
+
+#: models/__init__.py:765
+#, python-format
+msgid ""
+"Sorry, to retag questions a minimum reputation of %(min_rep)s is required"
+msgstr ""
+"Ne pare rău, pentru a reeticheta întrebări este nevoie de un minim de "
+"%(min_rep)s puncte de reputație"
+
+#: models/__init__.py:784
+msgid "Sorry, since your account is blocked you cannot delete comment"
+msgstr ""
+"Deoarece contul dumneavoastră este blocat, nu puteți șterge comentarii"
+
+#: models/__init__.py:788
+msgid ""
+"Sorry, since your account is suspended you can delete only your own comments"
+msgstr ""
+"Deoarece contul dumneavoastră este suspendat, puteți șterge numai propriile "
+"comentarii"
+
+#: models/__init__.py:792
+#, python-format
+msgid "Sorry, to delete comments reputation of %(min_rep)s is required"
+msgstr ""
+"Ne pare rău, pentru a șterge un comentariu este nevoie de un minim de "
+"%(min_rep)s puncte de reputație"
+
+#: models/__init__.py:815
+msgid "cannot revoke old vote"
+msgstr "voturile vechi nu pot fi revocate"
+
+#: models/__init__.py:1354
+msgid "Anonymous"
+msgstr "Anonim"
+
+#: models/__init__.py:1440 views/users.py:362
+msgid "Site Adminstrator"
+msgstr "Administrator"
+
+#: models/__init__.py:1442 views/users.py:364
+msgid "Forum Moderator"
+msgstr "Moderator"
+
+#: models/__init__.py:1444 views/users.py:366
+msgid "Suspended User"
+msgstr "Utilizator suspendat"
+
+#: models/__init__.py:1446 views/users.py:368
+msgid "Blocked User"
+msgstr "Utilizator blocat"
+
+#: models/__init__.py:1448 views/users.py:370
+msgid "Registered User"
+msgstr "Utilizator înregistrat"
+
+#: models/__init__.py:1450
+msgid "Watched User"
+msgstr "Utilizator urmărit"
+
+#: models/__init__.py:1452
+msgid "Approved User"
+msgstr "Utilizator aprobat"
+
+#: models/__init__.py:1508
+#, python-format
+msgid "%(username)s karma is %(reputation)s"
+msgstr "%(username)s are %(reputation)s puncte de reputație"
+
+#: models/__init__.py:1518
+#, python-format
+msgid "one gold badge"
+msgid_plural "%(count)d gold badges"
+msgstr[0] "o insignă de aur"
+msgstr[1] "%(count)d insigne de aur"
+msgstr[2] "%(count)d de insigne de aur"
+
+#: models/__init__.py:1525
+#, python-format
+msgid "one silver badge"
+msgid_plural "%(count)d silver badges"
+msgstr[0] "o insignă de argint"
+msgstr[1] "%(count)d insigne de argint"
+msgstr[2] "%(count)d de insigne de argint"
+
+#: models/__init__.py:1532
+#, python-format
+msgid "one bronze badge"
+msgid_plural "%(count)d bronze badges"
+msgstr[0] "o insignă de bronz"
+msgstr[1] "%(count)d insigne de bronz"
+msgstr[2] "%(count)d de insigne de bronz"
+
+#: models/__init__.py:1543
+#, python-format
+msgid "%(item1)s and %(item2)s"
+msgstr "%(item1)s și %(item2)s"
+
+#: models/__init__.py:1547
+#, python-format
+msgid "%(user)s has %(badges)s"
+msgstr "%(user)s are %(badges)s"
+
+#: models/__init__.py:1920 models/__init__.py:1926 models/__init__.py:1931
+#: models/__init__.py:1936
+#, python-format
+msgid "Re: \"%(title)s\""
+msgstr "Re: \"%(title)s\""
+
+#: models/__init__.py:1941 models/__init__.py:1946
+#, python-format
+msgid "Question: \"%(title)s\""
+msgstr "Întrebare: „%(title)s”"
+
+#: models/__init__.py:2116
+#, python-format
+msgid ""
+"Congratulations, you have received a badge '%(badge_name)s'. Check out <a "
+"href=\"%(user_profile)s\">your profile</a>."
+msgstr ""
+"Felicitări, ați obținut o insignă „%(badge_name)s”. Verificați <a "
+"href=\"%(user_profile)s\">profilul propriu</a>."
+
+#: models/__init__.py:2295 views/commands.py:396
+msgid "Your tag subscription was saved, thanks!"
+msgstr "Abonarea la etichetă a fost salvată!"
+
+#: models/answer.py:105
+msgid ""
+"Sorry, the answer you are looking for is no longer available, because the "
+"parent question has been removed"
+msgstr ""
+"Ne pare rău, răspunsul pe care îl cautați nu mai etse disponibil deoarece "
+"întrebarea asociată a fost ștearsă"
+
+#: models/answer.py:112
+msgid "Sorry, this answer has been removed and is no longer accessible"
+msgstr ""
+"Ne pară rău, această întrebarea a fost ștearsă și nu mai este accesibilă"
+
+#: models/badges.py:129
+#, python-format
+msgid "Deleted own post with %(votes)s or more upvotes"
+msgstr "A șters mesajul propriu cu %(votes)s sau mai multe voturi"
+
+#: models/badges.py:133
+msgid "Disciplined"
+msgstr "Disciplinat"
+
+#: models/badges.py:151
+#, python-format
+msgid "Deleted own post with %(votes)s or more downvotes"
+msgstr "A șters propriul mesaj cu %(votes)s sau mai multe voturi negative"
+
+#: models/badges.py:155
+msgid "Peer Pressure"
+msgstr "Presat de colegi"
+
+#: models/badges.py:174
+#, python-format
+msgid "Received at least %(votes)s upvote for an answer for the first time"
+msgstr ""
+"A primit cel puțin %(votes)s voturi pozitive pentru un răspuns pentru prima "
+"dată"
+
+#: models/badges.py:178
+msgid "Teacher"
+msgstr "Profesor"
+
+#: models/badges.py:218
+msgid "Supporter"
+msgstr "Suporter"
+
+#: models/badges.py:219
+msgid "First upvote"
+msgstr "Primul vot pozitiv"
+
+#: models/badges.py:227
+msgid "Critic"
+msgstr "Critic"
+
+#: models/badges.py:228
+msgid "First downvote"
+msgstr "Primul vot negativ"
+
+#: models/badges.py:237
+msgid "Civic Duty"
+msgstr "Datoria civică"
+
+#: models/badges.py:238
+#, python-format
+msgid "Voted %(num)s times"
+msgstr "A votat de %(num)s de ori"
+
+#: models/badges.py:252
+#, python-format
+msgid "Answered own question with at least %(num)s up votes"
+msgstr "A răspuns proprieri întrebări cu cel puțin %(num)s voturi pozitive"
+
+#: models/badges.py:256
+msgid "Self-Learner"
+msgstr "Autodidact"
+
+#: models/badges.py:304
+msgid "Nice Answer"
+msgstr "Răspuns frumos"
+
+#: models/badges.py:309 models/badges.py:321 models/badges.py:333
+#, python-format
+msgid "Answer voted up %(num)s times"
+msgstr "Răspuns votat pozitiv de %(num)s de ori"
+
+#: models/badges.py:316
+msgid "Good Answer"
+msgstr "Răspuns bun"
+
+#: models/badges.py:328
+msgid "Great Answer"
+msgstr "Răspuns grozav"
+
+#: models/badges.py:340
+msgid "Nice Question"
+msgstr "Întrebare frumoasă"
+
+#: models/badges.py:345 models/badges.py:357 models/badges.py:369
+#, python-format
+msgid "Question voted up %(num)s times"
+msgstr "Întrebare votată pozitiv de %(num)s de ori"
+
+#: models/badges.py:352
+msgid "Good Question"
+msgstr "Întrebare bună"
+
+#: models/badges.py:364
+msgid "Great Question"
+msgstr "Întrebare grozavă"
+
+#: models/badges.py:376
+msgid "Student"
+msgstr "Student"
+
+#: models/badges.py:381
+msgid "Asked first question with at least one up vote"
+msgstr "A întrebat prima întrebare cu cel puțin un vot pozitiv"
+
+#: models/badges.py:414
+msgid "Popular Question"
+msgstr "Întrebare populară"
+
+#: models/badges.py:418 models/badges.py:429 models/badges.py:441
+#, python-format
+msgid "Asked a question with %(views)s views"
+msgstr "A pus o întrebare cu %(views)s vizualizări"
+
+#: models/badges.py:425
+msgid "Notable Question"
+msgstr "Întrebare notabilă"
+
+#: models/badges.py:436
+msgid "Famous Question"
+msgstr "Întrebare faimoasă"
+
+#: models/badges.py:450
+msgid "Asked a question and accepted an answer"
+msgstr "A pus o întrebare și a acceptat răspunsul"
+
+#: models/badges.py:453
+msgid "Scholar"
+msgstr "Elev"
+
+#: models/badges.py:495
+msgid "Enlightened"
+msgstr "Luminat"
+
+#: models/badges.py:499
+#, python-format
+msgid "First answer was accepted with %(num)s or more votes"
+msgstr "Primul răspuns a fost acceptat cu %(num)s sau mai multe voturi"
+
+#: models/badges.py:507
+msgid "Guru"
+msgstr "Guru"
+
+#: models/badges.py:510
+#, python-format
+msgid "Answer accepted with %(num)s or more votes"
+msgstr "Răspuns acceptat cu %(num)s sau mai multe voturi"
+
+#: models/badges.py:518
+#, python-format
+msgid ""
+"Answered a question more than %(days)s days later with at least %(votes)s "
+"votes"
+msgstr ""
+"A răspuns unei întrebări mai mult de %(days)s zile mai târziu cu cel puțin "
+"%(votes)s voturi"
+
+#: models/badges.py:525
+msgid "Necromancer"
+msgstr ""
+
+#: models/badges.py:548
+msgid "Citizen Patrol"
+msgstr "Patrula comunitară"
+
+#: models/badges.py:551
+msgid "First flagged post"
+msgstr "Primul mesaj marcat ca ofensiv"
+
+#: models/badges.py:563
+msgid "Cleanup"
+msgstr "Curățenie"
+
+#: models/badges.py:566
+msgid "First rollback"
+msgstr "Prima revenire la o versiune anterioară"
+
+#: models/badges.py:577
+msgid "Pundit"
+msgstr "Cărturar"
+
+#: models/badges.py:580
+msgid "Left 10 comments with score of 10 or more"
+msgstr "A lăsat 10 comentarii cu scorul de 10 sau mai mult"
+
+#: models/badges.py:612
+msgid "Editor"
+msgstr "Editor"
+
+#: models/badges.py:615
+msgid "First edit"
+msgstr "Prima modificare"
+
+#: models/badges.py:623
+msgid "Associate Editor"
+msgstr "Editor asociat"
+
+#: models/badges.py:627
+#, python-format
+msgid "Edited %(num)s entries"
+msgstr "A modificat %(num)s intrări"
+
+#: models/badges.py:634
+msgid "Organizer"
+msgstr "Organizator"
+
+#: models/badges.py:637
+msgid "First retag"
+msgstr "Prima reetichetare"
+
+#: models/badges.py:644
+msgid "Autobiographer"
+msgstr "Autobiograf"
+
+#: models/badges.py:647
+msgid "Completed all user profile fields"
+msgstr "A completat toate câmpurile din profil"
+
+#: models/badges.py:663
+#, python-format
+msgid "Question favorited by %(num)s users"
+msgstr "Întrebare favorită pentru %(num)s utilizatori"
+
+#: models/badges.py:689
+msgid "Stellar Question"
+msgstr "Întrebare stelară"
+
+#: models/badges.py:698
+msgid "Favorite Question"
+msgstr "Întrebare favorită"
+
+#: models/badges.py:710
+msgid "Enthusiast"
+msgstr "Entuziast"
+
+#: models/badges.py:714
+#, python-format
+msgid "Visited site every day for %(num)s days in a row"
+msgstr "A vizitat siteul în fiecare zi pentru %(num)s zile consecutive"
+
+#: models/badges.py:732
+msgid "Commentator"
+msgstr "Comentator"
+
+#: models/badges.py:736
+#, python-format
+msgid "Posted %(num_comments)s comments"
+msgstr "A adăugat %(num_comments)s comentarii"
+
+#: models/badges.py:752
+msgid "Taxonomist"
+msgstr "Taxonomist"
+
+#: models/badges.py:756
+#, python-format
+msgid "Created a tag used by %(num)s questions"
+msgstr "A creat o etichetă folosită în %(num)s întrebări"
+
+#: models/badges.py:776
+msgid "Expert"
+msgstr "Expert"
+
+#: models/badges.py:779
+msgid "Very active in one tag"
+msgstr "Foarte activ pe o anumită etichetă"
+
+#: models/meta.py:111
+msgid ""
+"Sorry, the comment you are looking for is no longer accessible, because the "
+"parent question has been removed"
+msgstr ""
+"Ne pare rău, comentariu pe care îl cautați nu mai este accesibil deoarece "
+"întrebarea asociată a fost ștearsă"
+
+#: models/meta.py:118
+msgid ""
+"Sorry, the comment you are looking for is no longer accessible, because the "
+"parent answer has been removed"
+msgstr ""
+"Ne pare rău, comentariul pe care îl cautați nu mai este accesibil deoarece "
+"răspunsul asociat a fost șters"
+
+#: models/question.py:387
+msgid "Sorry, this question has been deleted and is no longer accessible"
+msgstr ""
+"Ne pare rău, această întrebare a fost ștearsă și nu mai este accesibilă"
+
+#: models/question.py:815
+#, python-format
+msgid "%(author)s modified the question"
+msgstr "%(author)s a modificat întrebarea"
+
+#: models/question.py:819
+#, python-format
+msgid "%(people)s posted %(new_answer_count)s new answers"
+msgstr "%(people)s au adăugat %(new_answer_count)s întrebări noi"
+
+#: models/question.py:824
+#, python-format
+msgid "%(people)s commented the question"
+msgstr "%(people)s au comentat întrebările"
+
+#: models/question.py:829
+#, python-format
+msgid "%(people)s commented answers"
+msgstr "%(people)s au comentat răspunsurile"
+
+#: models/question.py:831
+#, python-format
+msgid "%(people)s commented an answer"
+msgstr "%(people)s au comentat un răspuns"
+
+#: models/repute.py:142
+#, python-format
+msgid "<em>Changed by moderator. Reason:</em> %(reason)s"
+msgstr "<em>Schimbat de moderator. Motiv:</em> %(reason)s"
+
+#: models/repute.py:153
+#, python-format
+msgid ""
+"%(points)s points were added for %(username)s's contribution to question "
+"%(question_title)s"
+msgstr ""
+"%(points)s puncte au fost adăugate pentru contribuția utilizatorului "
+"%(username)s la întrebarea %(question_title)s"
+
+#: models/repute.py:158
+#, python-format
+msgid ""
+"%(points)s points were subtracted for %(username)s's contribution to "
+"question %(question_title)s"
+msgstr ""
+"%(points)s puncte au fost retrase pentru contribuția utilizatorului "
+"%(username)s la întrebarea %(question_title)s"
+
+#: models/tag.py:105
+msgid "interesting"
+msgstr "interesant"
+
+#: models/tag.py:105
+msgid "ignored"
+msgstr "ignorat"
+
+#: models/user.py:261
+msgid "Entire forum"
+msgstr "Toate întrebările"
+
+#: models/user.py:262
+msgid "Questions that I asked"
+msgstr "Întrebările pe care le-am pus"
+
+#: models/user.py:263
+msgid "Questions that I answered"
+msgstr "Întrebările la care am răspuns"
+
+#: models/user.py:264
+msgid "Individually selected questions"
+msgstr "Întrebări selectate individual"
+
+#: models/user.py:265
+msgid "Mentions and comment responses"
+msgstr "Mențiuni și răspunsuri la comentarii"
+
+#: models/user.py:268
+msgid "Instantly"
+msgstr "Imediat"
+
+#: models/user.py:269
+msgid "Daily"
+msgstr "Zilnic"
+
+#: models/user.py:270
+msgid "Weekly"
+msgstr "Săptămânal"
+
+#: models/user.py:271
+msgid "No email"
+msgstr "Fără email"
+
+#: skins/default/templates/404.jinja.html:3
+#: skins/default/templates/404.jinja.html:10
+msgid "Page not found"
+msgstr "Pagina nu a fost găsită"
+
+#: skins/default/templates/404.jinja.html:13
+msgid "Sorry, could not find the page you requested."
+msgstr "Ne pare rău, pagina cerută nu a putut fi găsită."
+
+#: skins/default/templates/404.jinja.html:15
+msgid "This might have happened for the following reasons:"
+msgstr "Acest lucru s-a întâmplat probabil din următoarele motive:"
+
+#: skins/default/templates/404.jinja.html:17
+msgid "this question or answer has been deleted;"
+msgstr "acestă întrebare sau răspuns a fost ștearsă;"
+
+#: skins/default/templates/404.jinja.html:18
+msgid "url has error - please check it;"
+msgstr "legătura conține erori - verificați;"
+
+#: skins/default/templates/404.jinja.html:19
+msgid ""
+"the page you tried to visit is protected or you don't have sufficient "
+"points, see"
+msgstr ""
+"pagina pe care ați încercat să o vizitați este protejată și nu aveți "
+"suficiente puncte, vezi"
+
+#: skins/default/templates/404.jinja.html:19
+#: skins/default/templates/blocks/footer.html:6
+#: skins/default/templates/blocks/header_meta_links.html:13
+#: skins/default/templates/blocks/question_edit_tips.html:15
+msgid "faq"
+msgstr "întrebări frecvente"
+
+#: skins/default/templates/404.jinja.html:20
+msgid "if you believe this error 404 should not have occured, please"
+msgstr ""
+"în cazul în care considerați că acestă eroare 404 nu ar trebui să apară, vă "
+"rugăm"
+
+#: skins/default/templates/404.jinja.html:21
+msgid "report this problem"
+msgstr "raportați acestă problemă"
+
+#: skins/default/templates/404.jinja.html:30
+#: skins/default/templates/500.jinja.html:11
+msgid "back to previous page"
+msgstr "mergeți înapoi la pagina anterioară"
+
+#: skins/default/templates/404.jinja.html:31
+#: skins/default/templates/main_page/tab_bar.html:9
+msgid "see all questions"
+msgstr "vezi toate întrebările"
+
+#: skins/default/templates/404.jinja.html:32
+msgid "see all tags"
+msgstr "vezi toate etichetele"
+
+#: skins/default/templates/500.jinja.html:3
+#: skins/default/templates/500.jinja.html:5
+msgid "Internal server error"
+msgstr "Eroare server internă"
+
+#: skins/default/templates/500.jinja.html:8
+msgid "system error log is recorded, error will be fixed as soon as possible"
+msgstr "eroarea a fost înregistrată și va fi rezolvată cât de curând posibil"
+
+#: skins/default/templates/500.jinja.html:9
+msgid "please report the error to the site administrators if you wish"
+msgstr "puteți raporta eroarea administratorilor acestui site"
+
+#: skins/default/templates/500.jinja.html:12
+msgid "see latest questions"
+msgstr "vezi cele mai recente întrebări"
+
+#: skins/default/templates/500.jinja.html:13
+msgid "see tags"
+msgstr "vezi etichetele"
+
+#: skins/default/templates/about.html:3 skins/default/templates/about.html:5
+#, python-format
+msgid "About %(site_name)s"
+msgstr "Despre %(site_name)s"
+
+#: skins/default/templates/answer_edit.html:4
+#: skins/default/templates/answer_edit.html:10
+msgid "Edit answer"
+msgstr "Modifică răspuns"
+
+#: skins/default/templates/answer_edit.html:10
+#: skins/default/templates/question_edit.html:9
+#: skins/default/templates/question_retag.html:5
+#: skins/default/templates/revisions.html:7
+msgid "back"
+msgstr "înapoi"
+
+#: skins/default/templates/answer_edit.html:15
+#: skins/default/templates/question_edit.html:11
+msgid "revision"
+msgstr "revizie"
+
+#: skins/default/templates/answer_edit.html:18
+#: skins/default/templates/question_edit.html:16
+msgid "select revision"
+msgstr "alege revizia"
+
+#: skins/default/templates/answer_edit.html:22
+#: skins/default/templates/question_edit.html:20
+msgid "Save edit"
+msgstr "Salvează modificările"
+
+#: skins/default/templates/answer_edit.html:23
+#: skins/default/templates/close.html:16
+#: skins/default/templates/feedback.html:42
+#: skins/default/templates/question_edit.html:21
+#: skins/default/templates/question_retag.html:23
+#: skins/default/templates/reopen.html:27
+#: skins/default/templates/subscribe_for_tags.html:16
+#: skins/default/templates/authopenid/changeemail.html:38
+#: skins/default/templates/user_profile/user_edit.html:84
+msgid "Cancel"
+msgstr "Anulează"
+
+#: skins/default/templates/answer_edit.html:62
+#: skins/default/templates/answer_edit.html:65
+#: skins/default/templates/ask.html:43 skins/default/templates/ask.html:46
+#: skins/default/templates/macros.html:592
+#: skins/default/templates/question.html:477
+#: skins/default/templates/question.html:480
+#: skins/default/templates/question_edit.html:62
+#: skins/default/templates/question_edit.html:65
+msgid "hide preview"
+msgstr "ascunde previzualizarea"
+
+#: skins/default/templates/answer_edit.html:65
+#: skins/default/templates/ask.html:46
+#: skins/default/templates/question.html:480
+#: skins/default/templates/question_edit.html:65
+msgid "show preview"
+msgstr "arată previzualizarea"
+
+#: skins/default/templates/ask.html:3
+msgid "Ask a question"
+msgstr "Puneți o întrebare"
+
+#: skins/default/templates/badge.html:4 skins/default/templates/badge.html:8
+#: skins/default/templates/user_profile/user_recent.html:16
+#: skins/default/templates/user_profile/user_stats.html:106
+#, python-format
+msgid "%(name)s"
+msgstr "%(name)s"
+
+#: skins/default/templates/badge.html:4
+msgid "Badge"
+msgstr "Insignă"
+
+#: skins/default/templates/badge.html:6
+#, python-format
+msgid "Badge \"%(name)s\""
+msgstr "Insigna „%(name)s”"
+
+#: skins/default/templates/badge.html:8
+#: skins/default/templates/user_profile/user_recent.html:16
+#: skins/default/templates/user_profile/user_stats.html:106
+#, python-format
+msgid "%(description)s"
+msgstr "%(description)s"
+
+#: skins/default/templates/badge.html:13
+msgid "user received this badge:"
+msgid_plural "users received this badge:"
+msgstr[0] "utilizator care a primit această insignă:"
+msgstr[1] "utilizatorii care au primit acestă insignă:"
+msgstr[2] "utilizatorii care au primit acestă insignă:"
+
+#: skins/default/templates/badges.html:3
+msgid "Badges summary"
+msgstr "Sumar insigne"
+
+#: skins/default/templates/badges.html:5
+msgid "Badges"
+msgstr "Insigne"
+
+#: skins/default/templates/badges.html:7
+msgid "Community gives you awards for your questions, answers and votes."
+msgstr ""
+"Comunitatea vă recompensează pentru întrebările, răspunsurile și voturile "
+"dumneavoastră."
+
+#: skins/default/templates/badges.html:8
+#, python-format
+msgid ""
+"Below is the list of available badges and number \n"
+"of times each type of badge has been awarded. Give us feedback at "
+"%(feedback_faq_url)s.\n"
+msgstr ""
+"Mai jos este lista insignelor disponibile și numărul \n"
+"de ori fiecare dintre ele a fost obținuntă. Puteți trimite sugestiile "
+"voastre la %(feedback_faq_url)s.\n"
+
+#: skins/default/templates/badges.html:35
+msgid "Community badges"
+msgstr "Insigne ale comunității"
+
+#: skins/default/templates/badges.html:37
+msgid "gold badge: the highest honor and is very rare"
+msgstr "insignă de aur: cea mai înaltă onoare ... și foarte rară"
+
+#: skins/default/templates/badges.html:40
+msgid "gold badge description"
+msgstr "descriere insignă de aur"
+
+#: skins/default/templates/badges.html:45
+msgid ""
+"silver badge: occasionally awarded for the very high quality contributions"
+msgstr ""
+"insignă de argint: acordată ocazional pentru contribuții de cea mai bună "
+"calitate"
+
+#: skins/default/templates/badges.html:49
+msgid "silver badge description"
+msgstr "descriere insignă de argint"
+
+#: skins/default/templates/badges.html:52
+msgid "bronze badge: often given as a special honor"
+msgstr ""
+"insignă de argint: acordată adesea pentru a onora pe cineva într-un mod "
+"special"
+
+#: skins/default/templates/badges.html:56
+msgid "bronze badge description"
+msgstr "descriere insignă de bronz"
+
+#: skins/default/templates/close.html:3 skins/default/templates/close.html:5
+msgid "Close question"
+msgstr "Închide întrebarea"
+
+#: skins/default/templates/close.html:6
+msgid "Close the question"
+msgstr "Închide întrebarea"
+
+#: skins/default/templates/close.html:11
+msgid "Reasons"
+msgstr "Motive"
+
+#: skins/default/templates/close.html:15
+msgid "OK to close"
+msgstr "Ok pentru închidere"
+
+#: skins/default/templates/faq.html:3 skins/default/templates/faq.html.py:5
+msgid "FAQ"
+msgstr "Întrebări frecvente"
+
+#: skins/default/templates/faq.html:5
+msgid "Frequently Asked Questions "
+msgstr "Întrebări frecvente "
+
+#: skins/default/templates/faq.html:6
+msgid "What kinds of questions can I ask here?"
+msgstr "Ce fel de întrebări pot întreba aici?"
+
+#: skins/default/templates/faq.html:7
+msgid ""
+"Most importanly - questions should be <strong>relevant</strong> to this "
+"community."
+msgstr ""
+"Cel mai important - întrebările trebuie să fie <strong>relevante</strong> "
+"pentru această comunitate."
+
+#: skins/default/templates/faq.html:8
+msgid ""
+"Before asking the question - please make sure to use search to see whether "
+"your question has alredy been answered."
+msgstr ""
+"Înainte de a pune o întrebare vă rugăm să căutați acestă întrebare pentru a "
+"vă asigura că nu are deja un răspuns."
+
+#: skins/default/templates/faq.html:10
+msgid "What questions should I avoid asking?"
+msgstr "Ce întrebări ar trebui să evit a pune?"
+
+#: skins/default/templates/faq.html:11
+msgid ""
+"Please avoid asking questions that are not relevant to this community, too "
+"subjective and argumentative."
+msgstr ""
+"Vă rugăm să evitați a pune întrebări care nu sunt relevante pentru această "
+"comunitate, prea subiective și argumentative."
+
+#: skins/default/templates/faq.html:13
+msgid "What should I avoid in my answers?"
+msgstr "Ce ar trebui să evit în răspunsurile mele?"
+
+#: skins/default/templates/faq.html:14
+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 "
+"discussions."
+msgstr ""
+"Este un site pentru întrebări și răspunsuri, nu un grup de discuții. De "
+"aceea evitați purtarea unor discuții în răspunsurile dumneavoastră, mai ales "
+"că funcția pentru comentarii permite ceva spațiu pentru discuții scurte."
+
+#: skins/default/templates/faq.html:15
+msgid "Who moderates this community?"
+msgstr "Cine moderează această comunitate?"
+
+#: skins/default/templates/faq.html:16
+msgid "The short answer is: <strong>you</strong>."
+msgstr "Răspunsul scurt este: <strong>dumneavoastră</strong>."
+
+#: skins/default/templates/faq.html:17
+msgid "This website is moderated by the users."
+msgstr "Acest site web este moderat de utilizatori."
+
+#: skins/default/templates/faq.html:18
+msgid ""
+"The reputation system allows users earn the authorization to perform a "
+"variety of moderation tasks."
+msgstr ""
+"Sistemul de reputație permite utilizatorilor să câștige autoritate pe care o "
+"folosesc la realizarea mai multor sarcini de moderare."
+
+#: skins/default/templates/faq.html:20
+msgid "How does reputation system work?"
+msgstr "Cum funcționează sistemul de reputație?"
+
+#: skins/default/templates/faq.html:21
+msgid "Rep system summary"
+msgstr "Sumar al sistemului de reputație"
+
+#: skins/default/templates/faq.html:22
+#, 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>%(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 ""
+"De exemplu, dacă puneți o întrebare interesantă sau dacă oferiți un răspuns "
+"util, veți fi apreciat cu voturi pozitive. Pe de altă parte, dacă răspunsul "
+"este greșit, va fi votat negativ. Fiecare vot pozitiv va genera puncte "
+"<strong>%(REP_GAIN_FOR_RECEIVING_UPVOTE)s</strong> points, fiecare vot "
+"negativ va șterge puncte "
+"<strong>%(REP_LOSS_FOR_RECEIVING_DOWNVOTE)s</strong>. Există o limită a "
+"punctelor <strong>%(MAX_REP_GAIN_PER_USER_PER_DAY)s</strong> pe care le "
+"puteți acumula pentru o întrebare sau un răspuns în decursul unei zile. "
+"Tabelul de mai jos explică necesarul de puncte de reputație necesare pentru "
+"fiecare tip de sarcină de moderare."
+
+#: skins/default/templates/faq.html:32
+#: skins/default/templates/user_profile/user_votes.html:13
+msgid "upvote"
+msgstr "vot pozitiv"
+
+#: skins/default/templates/faq.html:37
+msgid "use tags"
+msgstr "utilizează etichete"
+
+#: skins/default/templates/faq.html:42
+msgid "add comments"
+msgstr "adaugă comentarii"
+
+#: skins/default/templates/faq.html:46
+#: skins/default/templates/user_profile/user_votes.html:15
+msgid "downvote"
+msgstr "vot negativ"
+
+#: skins/default/templates/faq.html:49
+msgid "open and close own questions"
+msgstr "deschide și închide propriile întrebări"
+
+#: skins/default/templates/faq.html:53
+msgid "retag other's questions"
+msgstr "reetichetează întrebările altora"
+
+#: skins/default/templates/faq.html:58
+msgid "edit community wiki questions"
+msgstr "modifică întrebările wiki-ului comunității"
+
+#: skins/default/templates/faq.html:63
+msgid "\"edit any answer"
+msgstr "\"modifică orice răspuns"
+
+#: skins/default/templates/faq.html:67
+msgid "\"delete any comment"
+msgstr "\"șterge orice comentariu"
+
+#: skins/default/templates/faq.html:70
+msgid "what is gravatar"
+msgstr "ce este gravatarul"
+
+#: skins/default/templates/faq.html:71
+msgid "gravatar faq info"
+msgstr "informații utile despre gravatar"
+
+#: skins/default/templates/faq.html:72
+msgid "To register, do I need to create new password?"
+msgstr "Pentru a mă înregistra trebuie să creez o parolă nouă?"
+
+#: skins/default/templates/faq.html:73
+msgid ""
+"No, you don't have to. You can login through any service that supports "
+"OpenID, e.g. Google, Yahoo, AOL, etc.\""
+msgstr ""
+"Nu, nu trebuie neapărat. Vă puteți autentifica prin orice serviciu care "
+"recunoaște OpenID, de ex. Google, Yahoo, AOL, etc.\""
+
+#: skins/default/templates/faq.html:74
+msgid "\"Login now!\""
+msgstr "\"Autentifică acum!\""
+
+#: skins/default/templates/faq.html:76
+msgid "Why other people can edit my questions/answers?"
+msgstr "De ce alții pot modifica întrebările/răspunsurile mele?"
+
+#: skins/default/templates/faq.html:77
+msgid "Goal of this site is..."
+msgstr "Scopul acestui site este..."
+
+#: skins/default/templates/faq.html:77
+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 ""
+"Întrebările și răspunsurile pot fi modifica asemănător paginilor wiki de "
+"către utilizatori cu experineță în acest fel îmbunătățindu-se calitatea "
+"bazei de cunoștințe."
+
+#: skins/default/templates/faq.html:78
+msgid "If this approach is not for you, we respect your choice."
+msgstr ""
+"Dacă această abordare nu este pe placul dumneavoastră, vă respectăm alegerea."
+
+#: skins/default/templates/faq.html:80
+msgid "Still have questions?"
+msgstr "Aveți și alte întrebări?"
+
+#: skins/default/templates/faq.html:81
+#, python-format
+msgid ""
+"Please ask your question at %(ask_question_url)s, help make our community "
+"better!"
+msgstr ""
+"Răspundeți întrebărilor la %(ask_question_url)s, ajutând astfel comunitatea "
+"să devină mai bună!"
+
+#: skins/default/templates/feedback.html:3
+msgid "Feedback"
+msgstr "Sugestii"
+
+#: skins/default/templates/feedback.html:5
+msgid "Give us your feedback!"
+msgstr "Trimite sugestia ta!"
+
+#: skins/default/templates/feedback.html:9
+#, python-format
+msgid ""
+"\n"
+" <span class='big strong'>Dear %(user_name)s</span>, we look forward "
+"to hearing your feedback. \n"
+" Please type and send us your message below.\n"
+" "
+msgstr ""
+"\n"
+" <span class='big strong'>%(user_name)s</span> așteptăm cu intereset "
+"sugestiile tale. \n"
+"Introduceți mai jos mesajul sugestiei.\n"
+" "
+
+#: skins/default/templates/feedback.html:16
+msgid ""
+"\n"
+" <span class='big strong'>Dear visitor</span>, we look forward to "
+"hearing your feedback.\n"
+" Please type and send us your message below.\n"
+" "
+msgstr ""
+"\n"
+" <span class='big strong'>Stimate vizitator(user_name)s</span> "
+"așteptăm cu intereset sugestiile tale. \n"
+"Introduceți mai jos mesajul sugestiei.\n"
+" "
+
+#: skins/default/templates/feedback.html:25
+msgid "(please enter a valid email)"
+msgstr "(introduceți o adresă de e-mail validă)"
+
+#: skins/default/templates/feedback.html:33
+msgid "(this field is required)"
+msgstr "(acest câmp este obligatoriu)"
+
+#: skins/default/templates/feedback.html:41
+msgid "Send Feedback"
+msgstr "Trimite sugestia"
+
+#: skins/default/templates/feedback_email.txt:3
+#, python-format
+msgid ""
+"\n"
+"Hello, this is a %(site_title)s forum feedback message\n"
+msgstr ""
+"\n"
+"Salut, acesta este un mesaj de sugestii pentru %(site_title)s\n"
+
+#: skins/default/templates/feedback_email.txt:9
+msgid "Sender is"
+msgstr "Expenditorul este"
+
+#: skins/default/templates/feedback_email.txt:11
+#: skins/default/templates/feedback_email.txt:14
+msgid "email"
+msgstr "email"
+
+#: skins/default/templates/feedback_email.txt:13
+msgid "anonymous"
+msgstr "anonim"
+
+#: skins/default/templates/feedback_email.txt:19
+msgid "Message body:"
+msgstr "Corp mesaj:"
+
+#: skins/default/templates/import_data.html:2
+#: skins/default/templates/import_data.html:4
+msgid "Import StackExchange data"
+msgstr "Importă date StackExchange"
+
+#: skins/default/templates/import_data.html:13
+msgid ""
+"<em>Warning:</em> if your database is not empty, please back it up\n"
+" before attempting this operation."
+msgstr ""
+"<em>Avertisment:</em> dacă baza de date nu este goală, creați o copie de "
+"siguranță\n"
+" înainte de a începe această operație."
+
+#: skins/default/templates/import_data.html:16
+msgid ""
+"Upload your stackexchange dump .zip file, then wait until\n"
+" the data import completes. This process may take several minutes.\n"
+" Please note that feedback will be printed in plain text.\n"
+" "
+msgstr ""
+"Încărcați fișierul dump .zip stackexchange, apoi așteptați până ce\n"
+" se termină importul datelor. Procesul poate dura câteva minute.\n"
+" Rețineți că feedback-ul va fi afișat în text simplu.\n"
+" "
+
+#: skins/default/templates/import_data.html:25
+msgid "Import data"
+msgstr "Import date"
+
+#: skins/default/templates/import_data.html:27
+msgid ""
+"In the case you experience any difficulties in using this import tool,\n"
+" please try importing your data via command line: <code>python "
+"manage.py load_stackexchange path/to/your-data.zip</code>"
+msgstr ""
+"În cazul în care întâmpinați dificultăți în utilizarea acestei unelte pentru "
+"import,\n"
+" încercați să importați datele utilizând linia de comandă : "
+"<code>python manage.py load_stackexchange calea/către/datele-"
+"dumneavoastră.zip</code>"
+
+#: skins/default/templates/instant_notification.html:1
+#, python-format
+msgid "<p>Dear %(receiving_user_name)s,</p>"
+msgstr "<p>%(receiving_user_name)s,</p>"
+
+#: skins/default/templates/instant_notification.html:3
+#, python-format
+msgid ""
+"\n"
+"<p>%(update_author_name)s left a <a href=\"%(post_url)s\">new "
+"comment</a>:</p>\n"
+msgstr ""
+"\n"
+"<p>%(update_author_name)s a lăsat un <a href=\"%(post_url)s\">comentariu "
+"nou</a>:</p>\n"
+
+#: skins/default/templates/instant_notification.html:8
+#, python-format
+msgid ""
+"\n"
+"<p>%(update_author_name)s left a <a href=\"%(post_url)s\">new "
+"comment</a></p>\n"
+msgstr ""
+"\n"
+"<p>%(update_author_name)s a lăsat un <a href=\"%(post_url)s\">comentariu "
+"nou</a></p>\n"
+
+#: skins/default/templates/instant_notification.html:13
+#, 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 ""
+"\n"
+"<p>%(update_author_name)s a răspuns unei întrebări \n"
+"<a href=\"%(post_url)s\">%(origin_post_title)s</a></p>\n"
+
+#: skins/default/templates/instant_notification.html:19
+#, python-format
+msgid ""
+"\n"
+"<p>%(update_author_name)s posted a new question \n"
+"<a href=\"%(post_url)s\">%(origin_post_title)s</a></p>\n"
+msgstr ""
+"\n"
+"<p>%(update_author_name)s a postat o întrebare nouă \n"
+"<a href=\"%(post_url)s\">%(origin_post_title)s</a></p>\n"
+
+#: skins/default/templates/instant_notification.html:25
+#, 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 ""
+"\n"
+"<p>%(update_author_name)s a actualizat un răspuns la întrebarea\n"
+"<a href=\"%(post_url)s\">%(origin_post_title)s</a></p>\n"
+
+#: skins/default/templates/instant_notification.html:31
+#, 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 ""
+"\n"
+"<p>%(update_author_name)s a actualizat o întrebare \n"
+"<a href=\"%(post_url)s\">%(origin_post_title)s</a></p>\n"
+
+#: skins/default/templates/instant_notification.html:37
+#, python-format
+msgid ""
+"\n"
+"<div>%(content_preview)s</div>\n"
+"<p>Please note - you can easily <a "
+"href=\"%(user_subscriptions_url)s\">change</a>\n"
+"how often you receive these notifications or unsubscribe. Thank you for your "
+"interest in our forum!</p>\n"
+msgstr ""
+"\n"
+"<div>%(content_preview)s</div>\n"
+"<p>Rețineți că puteți <a href=\"%(user_subscriptions_url)s\">modifica</a> cu "
+"ușurință\n"
+"frecvența cu care primiți aceste notificări sau chiar anula abonamentul. Vă "
+"mulțumim pentru interesul acordat forumului nostru!</p>\n"
+
+#: skins/default/templates/instant_notification.html:42
+msgid "<p>Sincerely,<br/>Forum Administrator</p>"
+msgstr "<p>Cu stimă,<br/>Administrator forum</p>"
+
+#: skins/default/templates/logout.html:3 skins/default/templates/logout.html:5
+msgid "Logout"
+msgstr "Ieșire"
+
+#: skins/default/templates/logout.html:6
+msgid ""
+"As a registered user you can login with your OpenID, log out of the site or "
+"permanently remove your account."
+msgstr ""
+"Ca utilizator înregistrat vă puteți autentifica cu OpenID-ul dumneavoastră, "
+"vă puteți deautentifica sau vă puteți șterge contul definitiv."
+
+#: skins/default/templates/logout.html:7
+msgid "Logout now"
+msgstr "Ieșiți acum"
+
+#: skins/default/templates/macros.html:26
+msgid "karma:"
+msgstr "reputație:"
+
+#: skins/default/templates/macros.html:30
+msgid "badges:"
+msgstr "insigne:"
+
+#: skins/default/templates/macros.html:82
+#: skins/default/templates/macros.html:83
+msgid "previous"
+msgstr "precedentă"
+
+#: skins/default/templates/macros.html:94
+msgid "current page"
+msgstr "pagiona curentă"
+
+#: skins/default/templates/macros.html:96
+#: skins/default/templates/macros.html:103
+#, python-format
+msgid "page number %(num)s"
+msgstr "număr pagină %(num)s"
+
+#: skins/default/templates/macros.html:107
+msgid "next page"
+msgstr "pagina următoare"
+
+#: skins/default/templates/macros.html:118
+msgid "posts per page"
+msgstr "postări pe pagină"
+
+#: skins/default/templates/macros.html:150 templatetags/extra_tags.py:43
+#, python-format
+msgid "%(username)s gravatar image"
+msgstr "imagine gravatat %(username)s"
+
+#: skins/default/templates/macros.html:159
+#, python-format
+msgid "%(username)s's website is %(url)s"
+msgstr "Pagina web pentru %(username)s este %(url)s"
+
+#: skins/default/templates/macros.html:171
+msgid "anonymous user"
+msgstr "utilizator anonim"
+
+#: skins/default/templates/macros.html:199
+msgid "this post is marked as community wiki"
+msgstr "acest text este marca drep un wiki al comunității"
+
+#: skins/default/templates/macros.html:202
+#, python-format
+msgid ""
+"This post is a wiki.\n"
+" Anyone with karma &gt;%(wiki_min_rep)s is welcome to improve it."
+msgstr ""
+"Acesta este o pagină wiki.\n"
+" Oricine cu o reputație mai mare decât %(wiki_min_rep)s este binevenit "
+"să o imbunătățească."
+
+#: skins/default/templates/macros.html:208
+msgid "asked"
+msgstr "întrebat"
+
+#: skins/default/templates/macros.html:210
+msgid "answered"
+msgstr "răspuns"
+
+#: skins/default/templates/macros.html:212
+msgid "posted"
+msgstr "adăugat"
+
+#: skins/default/templates/macros.html:242
+msgid "updated"
+msgstr "actualizat"
+
+#: skins/default/templates/macros.html:309
+#, python-format
+msgid "see questions tagged '%(tag)s'"
+msgstr "afișează întrebările etichetate „%(tag)s”"
+
+#: skins/default/templates/macros.html:352 views/readers.py:231
+msgid "vote"
+msgid_plural "votes"
+msgstr[0] "vot"
+msgstr[1] "voturi"
+msgstr[2] "de voturi"
+
+#: skins/default/templates/macros.html:369 views/readers.py:234
+msgid "answer"
+msgid_plural "answers"
+msgstr[0] "răspuns"
+msgstr[1] "răspunsuri"
+msgstr[2] "de răspunsuri"
+
+#: skins/default/templates/macros.html:380 views/readers.py:237
+msgid "view"
+msgid_plural "views"
+msgstr[0] "afișare"
+msgstr[1] "afișări"
+msgstr[2] "de afișări"
+
+#: skins/default/templates/macros.html:409
+#: skins/default/templates/question.html:93
+#: skins/default/templates/question.html:249
+#: skins/default/templates/revisions.html:37
+msgid "edit"
+msgstr "modifică"
+
+#: skins/default/templates/macros.html:413
+msgid "delete this comment"
+msgstr "șterge acest comentariu"
+
+#: skins/default/templates/macros.html:431
+#: skins/default/templates/macros.html:439
+#: skins/default/templates/question.html:439
+msgid "add comment"
+msgstr "adaugă comentariu"
+
+#: skins/default/templates/macros.html:432
+#, python-format
+msgid "see <strong>%(counter)s</strong> more"
+msgid_plural "see <strong>%(counter)s</strong> more"
+msgstr[0] "afișează încă <strong>%(counter)s</strong>"
+msgstr[1] "afișează încă <strong>%(counter)s</strong>"
+msgstr[2] "afișează încă <strong>%(counter)s</strong>"
+
+#: skins/default/templates/macros.html:434
+#, python-format
+msgid "see <strong>%(counter)s</strong> more comment"
+msgid_plural ""
+"see <strong>%(counter)s</strong> more comments\n"
+" "
+msgstr[0] "afișează încă <strong>%(counter)s</strong> comentariu"
+msgstr[1] "afișează încă <strong>%(counter)s</strong> comentarii"
+msgstr[2] "afișează încă <strong>%(counter)s</strong> de comentarii"
+
+#: skins/default/templates/macros.html:569
+msgid "(required)"
+msgstr "(obligatoriu)"
+
+#: skins/default/templates/macros.html:590
+msgid "Toggle the real time Markdown editor preview"
+msgstr "Comută previzualizare în timp real pentru textul Markdown"
+
+#: skins/default/templates/macros.html:602
+#, python-format
+msgid "responses for %(username)s"
+msgstr "răspunsuri pentru %(username)s"
+
+#: skins/default/templates/macros.html:605
+#, python-format
+msgid "you have a new response"
+msgid_plural "you have %(response_count)s new responses"
+msgstr[0] "ai un răspuns nou"
+msgstr[1] "ai %(response_count)s răspunsuri noi"
+msgstr[2] "ai %(response_count)s de răspunsuri noi"
+
+#: skins/default/templates/macros.html:608
+msgid "no new responses yet"
+msgstr "încă nici un răspuns nou"
+
+#: skins/default/templates/macros.html:623
+#: skins/default/templates/macros.html:624
+#, python-format
+msgid "%(new)s new flagged posts and %(seen)s previous"
+msgstr "%(new)s postări noi marcate și %(seen)s anterioare"
+
+#: skins/default/templates/macros.html:626
+#: skins/default/templates/macros.html:627
+#, python-format
+msgid "%(new)s new flagged posts"
+msgstr "%(new)s postări noi marcate"
+
+#: skins/default/templates/macros.html:632
+#: skins/default/templates/macros.html:633
+#, python-format
+msgid "%(seen)s flagged posts"
+msgstr "%(seen)s (de) postări marcate"
+
+#: skins/default/templates/main_page.html:11
+msgid "Questions"
+msgstr "Întrebări"
+
+#: skins/default/templates/privacy.html:3
+#: skins/default/templates/privacy.html:5
+msgid "Privacy policy"
+msgstr "Politica de confidențialitate"
+
+#: skins/default/templates/question.html:27
+#: skins/default/templates/question.html:28
+#: skins/default/templates/question.html:43
+#: skins/default/templates/question.html:45
+msgid "i like this post (click again to cancel)"
+msgstr "îmi place această postare (efectuați clic din nou pentru a anula)"
+
+#: skins/default/templates/question.html:30
+#: skins/default/templates/question.html:47
+#: skins/default/templates/question.html:200
+msgid "current number of votes"
+msgstr "număr actual de voturi"
+
+#: skins/default/templates/question.html:39
+#: skins/default/templates/question.html:40
+#: skins/default/templates/question.html:52
+#: skins/default/templates/question.html:53
+msgid "i dont like this post (click again to cancel)"
+msgstr "nu îmi place această postare (efectuați clic din nou pentru a anula)"
+
+#: skins/default/templates/question.html:57
+#: skins/default/templates/question.html:58
+msgid "mark this question as favorite (click again to cancel)"
+msgstr ""
+"marchează această întrebare ca favorită (efectuați clic din nou pentru a "
+"anula)"
+
+#: skins/default/templates/question.html:64
+#: skins/default/templates/question.html:65
+msgid "remove favorite mark from this question (click again to restore mark)"
+msgstr ""
+"șterge această întrebare din grupul favoritelor (efectuați clic din nou "
+"pentru a anula)"
+
+#: skins/default/templates/question.html:71
+msgid "Share this question on twitter"
+msgstr "Partajează această întrebare pe twitter"
+
+#: skins/default/templates/question.html:72
+msgid "Share this question on facebook"
+msgstr "Partajează această întrebare pe facebook"
+
+#: skins/default/templates/question.html:96
+msgid "retag"
+msgstr "reetichetează"
+
+#: skins/default/templates/question.html:103
+msgid "reopen"
+msgstr "redeschide"
+
+#: skins/default/templates/question.html:107
+msgid "close"
+msgstr "închide"
+
+#: skins/default/templates/question.html:112
+#: skins/default/templates/question.html:253
+msgid ""
+"report as offensive (i.e containing spam, advertising, malicious text, etc.)"
+msgstr ""
+"raportează ca ofensatoare (de ex. conține spam, reclame, texte rău-voitoare, "
+"etc.)"
+
+#: skins/default/templates/question.html:113
+#: skins/default/templates/question.html:254
+msgid "flag offensive"
+msgstr "marchează ofensiv"
+
+#: skins/default/templates/question.html:120
+#: skins/default/templates/question.html:264
+msgid "undelete"
+msgstr "recuperează"
+
+#: skins/default/templates/question.html:120
+#: skins/default/templates/question.html:264
+#: skins/default/templates/authopenid/signin.html:149
+msgid "delete"
+msgstr "șterge"
+
+#: skins/default/templates/question.html:157
+#, python-format
+msgid ""
+"The question has been closed for the following reason \"%(close_reason)s\" by"
+msgstr ""
+"Această întrebare a fost închisă din următoarele motive \"%(close_reason)s\" "
+"de către"
+
+#: skins/default/templates/question.html:159
+#, python-format
+msgid "close date %(closed_at)s"
+msgstr "data închiderii %(closed_at)s"
+
+#: skins/default/templates/question.html:165
+#, python-format
+msgid ""
+"\n"
+" %(counter)s Answer:\n"
+" "
+msgid_plural ""
+"\n"
+" %(counter)s Answers:\n"
+" "
+msgstr[0] ""
+"\n"
+" %(counter)s răspuns:\n"
+" "
+msgstr[1] ""
+"\n"
+" %(counter)s răspunsuri:\n"
+" "
+msgstr[2] ""
+"\n"
+" %(counter)s de răspunsuri:\n"
+" "
+
+#: skins/default/templates/question.html:173
+msgid "oldest answers will be shown first"
+msgstr "răspunsurile mai vechi vor fi afișate întâi"
+
+#: skins/default/templates/question.html:174
+msgid "oldest answers"
+msgstr "cele mai vechi întrebări"
+
+#: skins/default/templates/question.html:176
+msgid "newest answers will be shown first"
+msgstr "răspunsurile mai noi vor fi afișate întâi"
+
+#: skins/default/templates/question.html:177
+msgid "newest answers"
+msgstr "cele mai noi răspunsuri"
+
+#: skins/default/templates/question.html:179
+msgid "most voted answers will be shown first"
+msgstr "cele mai votate răspunsuri vor fi afișate întâi"
+
+#: skins/default/templates/question.html:180
+msgid "popular answers"
+msgstr "răspunsuri populare"
+
+#: skins/default/templates/question.html:198
+#: skins/default/templates/question.html:199
+msgid "i like this answer (click again to cancel)"
+msgstr "îmi place acest răspuns (efectuați clic din nou pentru a anula)"
+
+#: skins/default/templates/question.html:209
+#: skins/default/templates/question.html:210
+msgid "i dont like this answer (click again to cancel)"
+msgstr "nu îmi place acest răspuns (efectuați clic din nou pentru a anula)"
+
+#: skins/default/templates/question.html:218
+#: skins/default/templates/question.html:219
+msgid "mark this answer as favorite (click again to undo)"
+msgstr ""
+"marchează acest răspuns ca favorit (efectuați clic din nou pentru a anula)"
+
+#: skins/default/templates/question.html:228
+#: skins/default/templates/question.html:229
+#, python-format
+msgid "%(question_author)s has selected this answer as correct"
+msgstr "%(question_author)s a ales acest răspuns ca fiind cel corect"
+
+#: skins/default/templates/question.html:244
+msgid "answer permanent link"
+msgstr "legătură permanentă întrebare"
+
+#: skins/default/templates/question.html:245
+msgid "permanent link"
+msgstr "legătură permanentă"
+
+#: skins/default/templates/question.html:314
+#: skins/default/templates/question.html:316
+msgid "Notify me once a day when there are any new answers"
+msgstr "Notifică-mă o dată pe zi când apar răspunsuri noi"
+
+#: skins/default/templates/question.html:318
+msgid "Notify me weekly when there are any new answers"
+msgstr "Notifică-mă o dată pe săptămână când apar răspunsuri noi"
+
+#: skins/default/templates/question.html:320
+msgid "Notify me immediately when there are any new answers"
+msgstr "Notifică-mă imediat ce apar răspunsuri noi"
+
+#: skins/default/templates/question.html:323
+#, python-format
+msgid ""
+"You can always adjust frequency of email updates from your %(profile_url)s"
+msgstr ""
+"Puteți oricând să modificați frecvența notificărilor mergând la pagina "
+"%(profile_url)s"
+
+#: skins/default/templates/question.html:328
+msgid "once you sign in you will be able to subscribe for any updates here"
+msgstr ""
+"odată ce vă veți autentifica, aici vă veți putea abona la orice actualizare"
+
+#: skins/default/templates/question.html:338
+msgid "Your answer"
+msgstr "Răspunsul tău"
+
+#: skins/default/templates/question.html:340
+msgid "Be the first one to answer this question!"
+msgstr "Fi primul care răspunde acestei întrebări!"
+
+#: skins/default/templates/question.html:346
+msgid "you can answer anonymously and then login"
+msgstr "puteți răspunde anonim și vă puteți autentifica după aceea"
+
+#: skins/default/templates/question.html:350
+msgid "answer your own question only to give an answer"
+msgstr "răspunde propriei întrebări doar pentru a oferi un răspuns"
+
+#: skins/default/templates/question.html:352
+msgid "please only give an answer, no discussions"
+msgstr "vă rugăm să dați doar răspunsul, fără discuții"
+
+#: skins/default/templates/question.html:359
+msgid "Login/Signup to Post Your Answer"
+msgstr "Autentifică-te / înregistrează-te pentru a adăuga răspunsul"
+
+#: skins/default/templates/question.html:362
+msgid "Answer Your Own Question"
+msgstr "Răspunde propriei întrebări"
+
+#: skins/default/templates/question.html:364
+msgid "Answer the question"
+msgstr "Răspunde întrebării"
+
+#: skins/default/templates/question.html:380
+msgid "Question tags"
+msgstr "Etichete întrebare"
+
+#: skins/default/templates/question.html:397
+msgid "question asked"
+msgstr "întrebare cu răspuns"
+
+#: skins/default/templates/question.html:400
+msgid "question was seen"
+msgstr "întrebarea a fost văzută de"
+
+#: skins/default/templates/question.html:400
+msgid "times"
+msgstr "ori"
+
+#: skins/default/templates/question.html:403
+msgid "last updated"
+msgstr "ultima actualizare"
+
+#: skins/default/templates/question.html:410
+msgid "Related questions"
+msgstr "Întrebări similare"
+
+#: skins/default/templates/question_edit.html:4
+#: skins/default/templates/question_edit.html:9
+msgid "Edit question"
+msgstr "Modifică întrebarea"
+
+#: skins/default/templates/question_retag.html:3
+#: skins/default/templates/question_retag.html:5
+msgid "Change tags"
+msgstr "Schimbă etichetele"
+
+#: skins/default/templates/question_retag.html:22
+msgid "Retag"
+msgstr "Reetichetează"
+
+#: skins/default/templates/question_retag.html:30
+msgid "Why use and modify tags?"
+msgstr "De ce să folosiți și să modificați etichetele?"
+
+#: skins/default/templates/question_retag.html:32
+msgid "Tags help to keep the content better organized and searchable"
+msgstr "Etichetele ajută la organizarea și căutarea conținutului"
+
+#: skins/default/templates/question_retag.html:34
+msgid "tag editors receive special awards from the community"
+msgstr ""
+"cei care modifică etichetele primesc recompense speciale din partea "
+"comunității"
+
+#: skins/default/templates/question_retag.html:75
+msgid "up to 5 tags, less than 20 characters each"
+msgstr "până la 5 etichete, mai puțin de 20 de caractere pentru fiecare"
+
+#: skins/default/templates/reopen.html:3 skins/default/templates/reopen.html:5
+msgid "Reopen question"
+msgstr "Redeschide întrebarea"
+
+#: skins/default/templates/reopen.html:6
+msgid "Title"
+msgstr "Titlu"
+
+#: skins/default/templates/reopen.html:11
+#, python-format
+msgid ""
+"This question has been closed by \n"
+" <a href=\"%(closed_by_profile_url)s\">%(closed_by_username)s</a>\n"
+msgstr ""
+"Această întrebare a fost închisă de \n"
+" <a href=\"%(closed_by_profile_url)s\">%(closed_by_username)s</a>\n"
+
+#: skins/default/templates/reopen.html:16
+msgid "Close reason:"
+msgstr "Motiv închidere:"
+
+#: skins/default/templates/reopen.html:19
+msgid "When:"
+msgstr "Când:"
+
+#: skins/default/templates/reopen.html:22
+msgid "Reopen this question?"
+msgstr "Redeschide această întrebare?"
+
+#: skins/default/templates/reopen.html:26
+msgid "Reopen this question"
+msgstr "Redeschide această întrebare"
+
+#: skins/default/templates/revisions.html:4
+#: skins/default/templates/revisions.html:7
+msgid "Revision history"
+msgstr "Istoric revizii"
+
+#: skins/default/templates/revisions.html:23
+msgid "click to hide/show revision"
+msgstr "clic pentru a arătă/a ascunde revizia"
+
+#: skins/default/templates/revisions.html:29
+#, python-format
+msgid "revision %(number)s"
+msgstr "revizia %(number)s"
+
+#: skins/default/templates/subscribe_for_tags.html:3
+#: skins/default/templates/subscribe_for_tags.html:5
+msgid "Subscribe for tags"
+msgstr "Abonare etichete"
+
+#: skins/default/templates/subscribe_for_tags.html:6
+msgid "Please, subscribe for the following tags:"
+msgstr "Abonați-vă la următoarele etichete:"
+
+#: skins/default/templates/subscribe_for_tags.html:15
+msgid "Subscribe"
+msgstr "Abonare"
+
+#: skins/default/templates/tags.html:4 skins/default/templates/tags.html:8
+msgid "Tag list"
+msgstr "Listă etichete"
+
+#: skins/default/templates/tags.html:14
+msgid "sorted alphabetically"
+msgstr "ordonate alfabetic"
+
+#: skins/default/templates/tags.html:15
+msgid "by name"
+msgstr "după nume"
+
+#: skins/default/templates/tags.html:20
+msgid "sorted by frequency of tag use"
+msgstr "ordonate după frecvența folosirii etichetei"
+
+#: skins/default/templates/tags.html:21
+msgid "by popularity"
+msgstr "după popularitate"
+
+#: skins/default/templates/tags.html:26
+#, python-format
+msgid ""
+"All tags matching '<span class=\"darkred\"><strong>%(stag)s</strong></span>'"
+msgstr ""
+"Toate etichetele echivalente cu '<span "
+"class=\"darkred\"><strong>%(stag)s</strong></span>'"
+
+#: skins/default/templates/tags.html:29
+msgid "Nothing found"
+msgstr "Nu a fost găsit nimic"
+
+#: skins/default/templates/users.html:4 skins/default/templates/users.html:7
+msgid "Users"
+msgstr "Utilizatori"
+
+#: skins/default/templates/users.html:13 skins/default/templates/users.html:14
+#: skins/default/templates/user_profile/user_info.html:25
+msgid "reputation"
+msgstr "reputație"
+
+#: skins/default/templates/users.html:19 skins/default/templates/users.html:20
+msgid "recent"
+msgstr "recent"
+
+#: skins/default/templates/users.html:31 skins/default/templates/users.html:32
+msgid "by username"
+msgstr "după nume de utilizator"
+
+#: skins/default/templates/users.html:37
+#, python-format
+msgid "users matching query %(suser)s:"
+msgstr ""
+
+#: skins/default/templates/users.html:40
+msgid "Nothing found."
+msgstr "Nu s-a găsit nimic."
+
+#: skins/default/templates/authopenid/changeemail.html:2
+#: skins/default/templates/authopenid/changeemail.html:8
+#: skins/default/templates/authopenid/changeemail.html:36
+msgid "Change email"
+msgstr "Schimbare email"
+
+#: skins/default/templates/authopenid/changeemail.html:10
+msgid "Save your email address"
+msgstr "Salvați adresa de email"
+
+#: skins/default/templates/authopenid/changeemail.html:15
+#, python-format
+msgid "change %(email)s info"
+msgstr "modifică informațiile despre %(email)s"
+
+#: skins/default/templates/authopenid/changeemail.html:17
+#, python-format
+msgid "here is why email is required, see %(gravatar_faq_url)s"
+msgstr ""
+"pentru a afla de ce este necesară o adresă de e-mail, consultați "
+"%(gravatar_faq_url)s"
+
+#: skins/default/templates/authopenid/changeemail.html:29
+msgid "Your new Email"
+msgstr "Adresa nouă de e-mail"
+
+#: skins/default/templates/authopenid/changeemail.html:29
+msgid "Your Email"
+msgstr "Adresa dumneavoastră de e-mail"
+
+#: skins/default/templates/authopenid/changeemail.html:36
+msgid "Save Email"
+msgstr "Salvează adresa de e-mail"
+
+#: skins/default/templates/authopenid/changeemail.html:45
+msgid "Validate email"
+msgstr "Validează adresa de e-mail"
+
+#: skins/default/templates/authopenid/changeemail.html:48
+#, python-format
+msgid "validate %(email)s info or go to %(change_email_url)s"
+msgstr ""
+"validați informațiile despre %(email)s sau mergeți la %(change_email_url)s"
+
+#: skins/default/templates/authopenid/changeemail.html:52
+msgid "Email not changed"
+msgstr "Adresa de e-mail nu a fost schimbată"
+
+#: skins/default/templates/authopenid/changeemail.html:55
+#, python-format
+msgid "old %(email)s kept, if you like go to %(change_email_url)s"
+msgstr ""
+"vechea adresă %(email)s a fost păstrată, puteți merge, dacă doriți, la "
+"%(change_email_url)s"
+
+#: skins/default/templates/authopenid/changeemail.html:59
+msgid "Email changed"
+msgstr "Adresa de e-mail a fost schimbată"
+
+#: skins/default/templates/authopenid/changeemail.html:62
+#, python-format
+msgid "your current %(email)s can be used for this"
+msgstr "adresa curentă %(email)s poate fi utilizată pentru acest lucru"
+
+#: skins/default/templates/authopenid/changeemail.html:66
+msgid "Email verified"
+msgstr "Adresa de e-mail a fost verificată"
+
+#: skins/default/templates/authopenid/changeemail.html:69
+msgid "thanks for verifying email"
+msgstr "Mulțumim pentru verificarea adresei de e-mail"
+
+#: skins/default/templates/authopenid/changeemail.html:73
+msgid "email key not sent"
+msgstr "cheia pentru adresa de e-mail nu a fost trimisă"
+
+#: skins/default/templates/authopenid/changeemail.html:76
+#, python-format
+msgid "email key not sent %(email)s change email here %(change_link)s"
+msgstr ""
+"cheia pentru adresa de e-mail nu a fost trimisă %(email)s modificați adresa "
+"de e-mail aici %(change_link)s"
+
+#: skins/default/templates/authopenid/complete.html:21
+#: skins/default/templates/authopenid/complete.html:23
+msgid "Registration"
+msgstr "Înregistrare"
+
+#: skins/default/templates/authopenid/complete.html:27
+#, python-format
+msgid "register new %(provider)s account info, see %(gravatar_faq_url)s"
+msgstr ""
+"înregistrați informații noi pentru contul %(provider)s, consultați "
+"%(gravatar_faq_url)s"
+
+#: skins/default/templates/authopenid/complete.html:30
+#, python-format
+msgid ""
+"%(username)s already exists, choose another name for \n"
+" %(provider)s. Email is required too, see "
+"%(gravatar_faq_url)s\n"
+" "
+msgstr ""
+"%(username)s există deja, alegeți un alt nume pentru \n"
+" %(provider)s. Este necesară și o adresă de e-"
+"mail, consultați %(gravatar_faq_url)s\n"
+" "
+
+#: skins/default/templates/authopenid/complete.html:34
+#, python-format
+msgid ""
+"register new external %(provider)s account info, see %(gravatar_faq_url)s"
+msgstr ""
+"înregistrați informații noi pentru contul %(provider)s extern, consultați "
+"%(gravatar_faq_url)s"
+
+#: skins/default/templates/authopenid/complete.html:37
+#, python-format
+msgid "register new Facebook connect account info, see %(gravatar_faq_url)s"
+msgstr ""
+"înregistrați informații noi pentru conectarea prin contul Facebook, "
+"consultați %(gravatar_faq_url)s"
+
+#: skins/default/templates/authopenid/complete.html:40
+msgid "This account already exists, please use another."
+msgstr "Acest cont există deja, vă rugăm să utilizați un altul."
+
+#: skins/default/templates/authopenid/complete.html:59
+msgid "Screen name label"
+msgstr ""
+
+#: skins/default/templates/authopenid/complete.html:66
+msgid "Email address label"
+msgstr ""
+
+#: skins/default/templates/authopenid/complete.html:72
+#: skins/default/templates/authopenid/signup_with_password.html:36
+msgid "receive updates motivational blurb"
+msgstr ""
+
+#: skins/default/templates/authopenid/complete.html:76
+#: skins/default/templates/authopenid/signup_with_password.html:40
+msgid "please select one of the options above"
+msgstr ""
+
+#: skins/default/templates/authopenid/complete.html:79
+msgid "Tag filter tool will be your right panel, once you log in."
+msgstr ""
+
+#: skins/default/templates/authopenid/complete.html:80
+msgid "create account"
+msgstr "creaţi un cont"
+
+#: skins/default/templates/authopenid/confirm_email.txt:1
+msgid "Thank you for registering at our Q&A forum!"
+msgstr ""
+
+#: skins/default/templates/authopenid/confirm_email.txt:3
+msgid "Your account details are:"
+msgstr "Detaliile contului sunt:"
+
+#: skins/default/templates/authopenid/confirm_email.txt:5
+msgid "Username:"
+msgstr "Nume utilizator:"
+
+#: skins/default/templates/authopenid/confirm_email.txt:6
+msgid "Password:"
+msgstr "Parolă:"
+
+#: skins/default/templates/authopenid/confirm_email.txt:8
+msgid "Please sign in here:"
+msgstr ""
+
+#: skins/default/templates/authopenid/confirm_email.txt:11
+#: skins/default/templates/authopenid/email_validation.txt:13
+msgid ""
+"Sincerely,\n"
+"Forum Administrator"
+msgstr ""
+
+#: skins/default/templates/authopenid/email_validation.txt:1
+msgid "Greetings from the Q&A forum"
+msgstr ""
+
+#: skins/default/templates/authopenid/email_validation.txt:3
+msgid "To make use of the Forum, please follow the link below:"
+msgstr ""
+
+#: skins/default/templates/authopenid/email_validation.txt:7
+msgid "Following the link above will help us verify your email address."
+msgstr ""
+
+#: skins/default/templates/authopenid/email_validation.txt:9
+msgid ""
+"If you beleive that this message was sent in mistake - \n"
+"no further action is needed. Just ingore this email, we apologize\n"
+"for any inconvenience"
+msgstr ""
+
+#: skins/default/templates/authopenid/macros.html:50
+msgid "Please enter your <span>user name</span>, then sign in"
+msgstr ""
+
+#: skins/default/templates/authopenid/macros.html:51
+#: skins/default/templates/authopenid/signin.html:84
+msgid "(or select another login method above)"
+msgstr ""
+
+#: skins/default/templates/authopenid/macros.html:53
+msgid "Sign in"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:4
+msgid "User login"
+msgstr "Autentificare autilizator"
+
+#: skins/default/templates/authopenid/signin.html:12
+#, python-format
+msgid ""
+"\n"
+" Your answer to %(title)s %(summary)s will be posted once you log in\n"
+" "
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:19
+#, python-format
+msgid ""
+"Your question \n"
+" %(title)s %(summary)s will be posted once you log in\n"
+" "
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:26
+msgid ""
+"Take a pick of your favorite service below to sign in using secure OpenID or "
+"similar technology. Your external service password always stays confidential "
+"and you don't have to rememeber or create another one."
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:29
+msgid ""
+"It's a good idea to make sure that your existing login methods still work, "
+"or add a new one. Please click any of the icons below to check/change or add "
+"new login methods."
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:31
+msgid ""
+"Please add a more permanent login method by clicking one of the icons below, "
+"to avoid logging in via email each time."
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:35
+msgid ""
+"Click on one of the icons below to add a new login method or re-validate an "
+"existing one."
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:37
+msgid ""
+"You don't have a method to log in right now, please add one or more by "
+"clicking any of the icons below."
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:40
+msgid ""
+"Please check your email and visit the enclosed link to re-connect to your "
+"account"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:82
+msgid "Please enter your <span>user name and password</span>, then sign in"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:86
+msgid "Login failed, please try again"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:89
+msgid "Login name"
+msgstr "Nume cont"
+
+#: skins/default/templates/authopenid/signin.html:93
+msgid "Password"
+msgstr "Parolă"
+
+#: skins/default/templates/authopenid/signin.html:97
+msgid "Login"
+msgstr "Autentificare"
+
+#: skins/default/templates/authopenid/signin.html:104
+msgid "To change your password - please enter the new one twice, then submit"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:107
+msgid "New password"
+msgstr "Parolă nouă"
+
+#: skins/default/templates/authopenid/signin.html:112
+msgid "Please, retype"
+msgstr "introduceți din nou"
+
+#: skins/default/templates/authopenid/signin.html:130
+msgid "Here are your current login methods"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:134
+msgid "provider"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:135
+msgid "last used"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:136
+msgid "delete, if you like"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:162
+msgid "Still have trouble signing in?"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:167
+msgid "Please, enter your email address below and obtain a new key"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:169
+msgid "Please, enter your email address below to recover your account"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:172
+msgid "recover your account via email"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:183
+msgid "Send a new recovery key"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:185
+msgid "Recover your account via email"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:196
+msgid "Why use OpenID?"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:199
+msgid "with openid it is easier"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:202
+msgid "reuse openid"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:205
+msgid "openid is widely adopted"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:208
+msgid "openid is supported open standard"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:212
+msgid "Find out more"
+msgstr ""
+
+#: skins/default/templates/authopenid/signin.html:213
+msgid "Get OpenID"
+msgstr ""
+
+#: skins/default/templates/authopenid/signup_with_password.html:4
+msgid "Signup"
+msgstr ""
+
+#: skins/default/templates/authopenid/signup_with_password.html:10
+msgid "Please register by clicking on any of the icons below"
+msgstr ""
+
+#: skins/default/templates/authopenid/signup_with_password.html:23
+msgid "or create a new user name and password here"
+msgstr ""
+
+#: skins/default/templates/authopenid/signup_with_password.html:25
+msgid "Create login name and password"
+msgstr ""
+
+#: skins/default/templates/authopenid/signup_with_password.html:26
+msgid "Traditional signup info"
+msgstr ""
+
+#: skins/default/templates/authopenid/signup_with_password.html:44
+msgid ""
+"Please read and type in the two words below to help us prevent automated "
+"account creation."
+msgstr ""
+
+#: skins/default/templates/authopenid/signup_with_password.html:47
+msgid "Create Account"
+msgstr ""
+
+#: skins/default/templates/authopenid/signup_with_password.html:49
+msgid "or"
+msgstr "sau"
+
+#: skins/default/templates/authopenid/signup_with_password.html:50
+msgid "return to OpenID login"
+msgstr ""
+
+#: skins/default/templates/avatar/add.html:3
+msgid "add avatar"
+msgstr ""
+
+#: skins/default/templates/avatar/add.html:5
+msgid "Change avatar"
+msgstr ""
+
+#: skins/default/templates/avatar/add.html:6
+#: skins/default/templates/avatar/change.html:7
+msgid "Your current avatar: "
+msgstr ""
+
+#: skins/default/templates/avatar/add.html:9
+#: skins/default/templates/avatar/change.html:11
+msgid "You haven't uploaded an avatar yet. Please upload one now."
+msgstr ""
+
+#: skins/default/templates/avatar/add.html:13
+msgid "Upload New Image"
+msgstr ""
+
+#: skins/default/templates/avatar/change.html:4
+msgid "change avatar"
+msgstr ""
+
+#: skins/default/templates/avatar/change.html:17
+msgid "Choose new Default"
+msgstr ""
+
+#: skins/default/templates/avatar/change.html:22
+msgid "Upload"
+msgstr "Încarcă"
+
+#: skins/default/templates/avatar/confirm_delete.html:3
+msgid "delete avatar"
+msgstr "șterge avatar"
+
+#: skins/default/templates/avatar/confirm_delete.html:5
+msgid "Please select the avatars that you would like to delete."
+msgstr ""
+
+#: skins/default/templates/avatar/confirm_delete.html:7
+#, python-format
+msgid ""
+"You have no avatars to delete. Please <a "
+"href=\"%(avatar_change_url)s\">upload one</a> now."
+msgstr ""
+
+#: skins/default/templates/avatar/confirm_delete.html:13
+msgid "Delete These"
+msgstr ""
+
+#: skins/default/templates/blocks/answer_edit_tips.html:3
+msgid "answer tips"
+msgstr "indicații pentru răspunsuri"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:6
+msgid "please make your answer relevant to this community"
+msgstr "dați răspunsuri relevante pentru această comunitate"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:9
+msgid "try to give an answer, rather than engage into a discussion"
+msgstr "încercați să oferiți un răspuns, nu să vă angajați într-o discuție"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:12
+msgid "please try to provide details"
+msgstr "încercați să furnizați detalii"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:15
+#: skins/default/templates/blocks/question_edit_tips.html:11
+msgid "be clear and concise"
+msgstr "fiți clari și conciși"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:19
+#: skins/default/templates/blocks/question_edit_tips.html:15
+msgid "see frequently asked questions"
+msgstr "consultați secțiunea întrebărilor frecvente"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:25
+#: skins/default/templates/blocks/question_edit_tips.html:20
+msgid "Markdown tips"
+msgstr "indicii Markdown"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:29
+#: skins/default/templates/blocks/question_edit_tips.html:24
+msgid "*italic*"
+msgstr "*înclinat*"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:32
+#: skins/default/templates/blocks/question_edit_tips.html:27
+msgid "**bold**"
+msgstr "**îngroșat**"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:36
+#: skins/default/templates/blocks/question_edit_tips.html:31
+msgid "*italic* or _italic_"
+msgstr "*înclinat* sau __înclinat__"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:39
+#: skins/default/templates/blocks/question_edit_tips.html:34
+msgid "**bold** or __bold__"
+msgstr "**îngroșat** sau __îngroșat__"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:43
+#: skins/default/templates/blocks/question_edit_tips.html:38
+msgid "link"
+msgstr "legătură"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:43
+#: skins/default/templates/blocks/answer_edit_tips.html:47
+#: skins/default/templates/blocks/question_edit_tips.html:38
+#: skins/default/templates/blocks/question_edit_tips.html:43
+msgid "text"
+msgstr "text"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:47
+#: skins/default/templates/blocks/question_edit_tips.html:43
+msgid "image"
+msgstr "imagine"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:51
+#: skins/default/templates/blocks/question_edit_tips.html:47
+msgid "numbered list:"
+msgstr "listă numerotată:"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:56
+#: skins/default/templates/blocks/question_edit_tips.html:52
+msgid "basic HTML tags are also supported"
+msgstr "de asemenea sunt suportate tag-uri HTML simple"
+
+#: skins/default/templates/blocks/answer_edit_tips.html:60
+#: skins/default/templates/blocks/question_edit_tips.html:56
+msgid "learn more about Markdown"
+msgstr "află mai multe despre Markdown"
+
+#: skins/default/templates/blocks/ask_form.html:7
+msgid "login to post question info"
+msgstr "autentificați-vă pentru a pune o întrebare"
+
+#: skins/default/templates/blocks/ask_form.html:11
+#, python-format
+msgid ""
+"must have valid %(email)s to post, \n"
+" see %(email_validation_faq_url)s\n"
+" "
+msgstr ""
+"este necesar %(email)s valid pentru a posta, \n"
+" vezi %(email_validation_faq_url)s\n"
+" "
+
+#: skins/default/templates/blocks/ask_form.html:28
+msgid "Login/signup to post your question"
+msgstr ""
+
+#: skins/default/templates/blocks/ask_form.html:30
+msgid "Ask your question"
+msgstr "Puneți întrebarea"
+
+#: skins/default/templates/blocks/editor_data.html:5
+#, python-format
+msgid "each tag must be shorter that %(max_chars)s character"
+msgid_plural "each tag must be shorter than %(max_chars)s characters"
+msgstr[0] ""
+msgstr[1] ""
+
+#: skins/default/templates/blocks/editor_data.html:7
+#, python-format
+msgid "please use %(tag_count)s tag"
+msgid_plural "please use %(tag_count)s tags or less"
+msgstr[0] ""
+msgstr[1] ""
+
+#: skins/default/templates/blocks/editor_data.html:8
+#, python-format
+msgid ""
+"please use up to %(tag_count)s tags, less than %(max_chars)s characters each"
+msgstr ""
+
+#: skins/default/templates/blocks/footer.html:5
+#: skins/default/templates/blocks/header_meta_links.html:12
+msgid "about"
+msgstr "despre"
+
+#: skins/default/templates/blocks/footer.html:7
+msgid "privacy policy"
+msgstr "politica de confidențialitate"
+
+#: skins/default/templates/blocks/footer.html:16
+msgid "give feedback"
+msgstr "oferă o sugestie"
+
+#: skins/default/templates/blocks/header.html:8
+msgid "back to home page"
+msgstr "înapoi la pagina de start"
+
+#: skins/default/templates/blocks/header.html:9
+#, python-format
+msgid "%(site)s logo"
+msgstr "siglă %(site)s"
+
+#: skins/default/templates/blocks/header.html:17
+msgid "questions"
+msgstr "întrebări"
+
+#: skins/default/templates/blocks/header.html:27
+msgid "users"
+msgstr "utilizatori"
+
+#: skins/default/templates/blocks/header.html:32
+msgid "badges"
+msgstr "insigne"
+
+#: skins/default/templates/blocks/header.html:37
+msgid "ask a question"
+msgstr "pune o întrebare"
+
+#: skins/default/templates/blocks/header_meta_links.html:8
+msgid "logout"
+msgstr "ieșire"
+
+#: skins/default/templates/blocks/header_meta_links.html:10
+msgid "login"
+msgstr "autentificare"
+
+#: skins/default/templates/blocks/header_meta_links.html:15
+msgid "settings"
+msgstr "configurări"
+
+#: skins/default/templates/blocks/input_bar.html:34
+msgid "search"
+msgstr "caută"
+
+#: skins/default/templates/blocks/question_edit_tips.html:3
+msgid "question tips"
+msgstr "indicii căutare"
+
+#: skins/default/templates/blocks/question_edit_tips.html:5
+msgid "please ask a relevant question"
+msgstr "puneți o întrebare relevantă"
+
+#: skins/default/templates/blocks/question_edit_tips.html:8
+msgid "please try provide enough details"
+msgstr "încercați să oferiți suficiente detalii"
+
+#: skins/default/templates/blocks/tag_selector.html:4
+msgid "Interesting tags"
+msgstr "Etichete interesante"
+
+#: skins/default/templates/blocks/tag_selector.html:18
+#: skins/default/templates/blocks/tag_selector.html:34
+#: skins/default/templates/user_profile/user_moderate.html:38
+msgid "Add"
+msgstr "Adaugă"
+
+#: skins/default/templates/blocks/tag_selector.html:20
+msgid "Ignored tags"
+msgstr "Etichete ignorate"
+
+#: skins/default/templates/blocks/tag_selector.html:36
+msgid "Display tag filter"
+msgstr "Afișare filtre etichete"
+
+#: skins/default/templates/main_page/content.html:13
+msgid "Did not find what you were looking for?"
+msgstr "Nu ați găsit ceea ce căutați?"
+
+#: skins/default/templates/main_page/content.html:14
+msgid "Please, post your question!"
+msgstr "Vă rugăm să puneți o întrebare!"
+
+#: skins/default/templates/main_page/headline.html:7
+msgid "subscribe to the questions feed"
+msgstr "abonarea la fluxul de întrebări"
+
+#: skins/default/templates/main_page/headline.html:8
+msgid "rss feed"
+msgstr "flux fss"
+
+#: skins/default/templates/main_page/headline.html:12 views/readers.py:131
+#, python-format
+msgid "%(q_num)s question, tagged"
+msgid_plural "%(q_num)s questions, tagged"
+msgstr[0] ""
+msgstr[1] ""
+
+#: skins/default/templates/main_page/headline.html:14 views/readers.py:139
+#, python-format
+msgid "%(q_num)s question"
+msgid_plural "%(q_num)s questions"
+msgstr[0] ""
+msgstr[1] ""
+
+#: skins/default/templates/main_page/headline.html:17
+#, python-format
+msgid "with %(author_name)s's contributions"
+msgstr ""
+
+#: skins/default/templates/main_page/headline.html:28
+msgid "Search tips:"
+msgstr "Indicii de căutare:"
+
+#: skins/default/templates/main_page/headline.html:31
+msgid "reset author"
+msgstr ""
+
+#: skins/default/templates/main_page/headline.html:33
+#: skins/default/templates/main_page/headline.html:36
+#: skins/default/templates/main_page/nothing_found.html:18
+#: skins/default/templates/main_page/nothing_found.html:21
+msgid " or "
+msgstr " sau "
+
+#: skins/default/templates/main_page/headline.html:34
+msgid "reset tags"
+msgstr "resetare etichete"
+
+#: skins/default/templates/main_page/headline.html:37
+#: skins/default/templates/main_page/headline.html:40
+msgid "start over"
+msgstr "începeți din nou"
+
+#: skins/default/templates/main_page/headline.html:42
+msgid " - to expand, or dig in by adding more tags and revising the query."
+msgstr ""
+" pentru a lărgi sau a filtra prin adăugarea mai multor etichete sau a "
+"textului de căutat."
+
+#: skins/default/templates/main_page/headline.html:45
+msgid "Search tip:"
+msgstr "Indiciu de căutare:"
+
+#: skins/default/templates/main_page/headline.html:45
+msgid "add tags and a query to focus your search"
+msgstr "adăugarea de etichete și a mai multe cuvinte cheie pentru căutare"
+
+#: skins/default/templates/main_page/javascript.html:16
+#: skins/default/templates/main_page/javascript.html:17
+msgid "mark-tag/"
+msgstr ""
+
+#: skins/default/templates/main_page/javascript.html:16
+msgid "interesting/"
+msgstr ""
+
+#: skins/default/templates/main_page/javascript.html:17
+msgid "ignored/"
+msgstr ""
+
+#: skins/default/templates/main_page/javascript.html:18
+msgid "unmark-tag/"
+msgstr ""
+
+#: skins/default/templates/main_page/nothing_found.html:4
+msgid "There are no unanswered questions here"
+msgstr ""
+
+#: skins/default/templates/main_page/nothing_found.html:7
+msgid "No favorite questions here. "
+msgstr ""
+
+#: skins/default/templates/main_page/nothing_found.html:8
+msgid "Please start (bookmark) some questions when you visit them"
+msgstr ""
+
+#: skins/default/templates/main_page/nothing_found.html:13
+msgid "You can expand your search by "
+msgstr "Puteți extinde căutarea prin "
+
+#: skins/default/templates/main_page/nothing_found.html:16
+msgid "resetting author"
+msgstr ""
+
+#: skins/default/templates/main_page/nothing_found.html:19
+msgid "resetting tags"
+msgstr ""
+
+#: skins/default/templates/main_page/nothing_found.html:22
+#: skins/default/templates/main_page/nothing_found.html:25
+msgid "starting over"
+msgstr ""
+
+#: skins/default/templates/main_page/nothing_found.html:30
+msgid "Please always feel free to ask your question!"
+msgstr ""
+
+#: skins/default/templates/main_page/sidebar.html:5
+msgid "Contributors"
+msgstr "Contribuitori"
+
+#: skins/default/templates/main_page/sidebar.html:22
+msgid "Related tags"
+msgstr "Etichete asemămătoare"
+
+#: skins/default/templates/main_page/tab_bar.html:5
+msgid "In:"
+msgstr "În:"
+
+#: skins/default/templates/main_page/tab_bar.html:14
+msgid "see unanswered questions"
+msgstr "vezi întrebările fără răspuns"
+
+#: skins/default/templates/main_page/tab_bar.html:20
+msgid "see your favorite questions"
+msgstr "vezi întrebările tale favorite"
+
+#: skins/default/templates/main_page/tab_bar.html:25
+msgid "Sort by:"
+msgstr "Ordonează după:"
+
+#: skins/default/templates/user_profile/user.html:13
+#, python-format
+msgid "%(username)s's profile"
+msgstr "Profilul pentru %(username)s"
+
+#: skins/default/templates/user_profile/user_edit.html:4
+msgid "Edit user profile"
+msgstr "Modifică profilul de utilizator"
+
+#: skins/default/templates/user_profile/user_edit.html:7
+msgid "edit profile"
+msgstr "modifică profil"
+
+#: skins/default/templates/user_profile/user_edit.html:17
+#: skins/default/templates/user_profile/user_info.html:15
+msgid "change picture"
+msgstr "schimbă poza"
+
+#: skins/default/templates/user_profile/user_edit.html:20
+msgid "Registered user"
+msgstr "Utilizator înregistrat"
+
+#: skins/default/templates/user_profile/user_edit.html:27
+msgid "Screen Name"
+msgstr "Nume afișat"
+
+#: skins/default/templates/user_profile/user_edit.html:83
+#: skins/default/templates/user_profile/user_email_subscriptions.html:21
+msgid "Update"
+msgstr "Actualizează"
+
+#: skins/default/templates/user_profile/user_email_subscriptions.html:4
+#: skins/default/templates/user_profile/user_tabs.html:36
+msgid "subscriptions"
+msgstr "abonamente"
+
+#: skins/default/templates/user_profile/user_email_subscriptions.html:7
+msgid "Email subscription settings"
+msgstr "Configurări abonamente email"
+
+#: skins/default/templates/user_profile/user_email_subscriptions.html:8
+msgid "email subscription settings info"
+msgstr "informații configurări abonamente email"
+
+#: skins/default/templates/user_profile/user_email_subscriptions.html:22
+msgid "Stop sending email"
+msgstr "Nu mai trimite emailuri"
+
+#: skins/default/templates/user_profile/user_favorites.html:4
+#: skins/default/templates/user_profile/user_tabs.html:21
+msgid "favorites"
+msgstr "favorite"
+
+#: skins/default/templates/user_profile/user_inbox.html:18
+#: skins/default/templates/user_profile/user_tabs.html:12
+msgid "inbox"
+msgstr "inbox"
+
+#: skins/default/templates/user_profile/user_inbox.html:34
+msgid "Sections:"
+msgstr "Secțiuni:"
+
+#: skins/default/templates/user_profile/user_inbox.html:38
+#, python-format
+msgid "forum responses (%(re_count)s)"
+msgstr "răspunsuri site (%(re_count)s)"
+
+#: skins/default/templates/user_profile/user_inbox.html:43
+#, python-format
+msgid "flagged items (%(flag_count)s)"
+msgstr "elemente marcate (%(flag_count)s)"
+
+#: skins/default/templates/user_profile/user_inbox.html:49
+msgid "select:"
+msgstr "selectează:"
+
+#: skins/default/templates/user_profile/user_inbox.html:51
+msgid "seen"
+msgstr "văzut"
+
+#: skins/default/templates/user_profile/user_inbox.html:52
+msgid "new"
+msgstr "nou"
+
+#: skins/default/templates/user_profile/user_inbox.html:53
+msgid "none"
+msgstr "niciunul"
+
+#: skins/default/templates/user_profile/user_inbox.html:54
+msgid "mark as seen"
+msgstr "machează ca văzut"
+
+#: skins/default/templates/user_profile/user_inbox.html:55
+msgid "mark as new"
+msgstr "marcează ca nou"
+
+#: skins/default/templates/user_profile/user_inbox.html:56
+msgid "dismiss"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_info.html:19
+msgid "remove"
+msgstr "elimină"
+
+#: skins/default/templates/user_profile/user_info.html:33
+msgid "update profile"
+msgstr "actualizează profil"
+
+#: skins/default/templates/user_profile/user_info.html:37
+msgid "manage login methods"
+msgstr "administrează metodele de autentificare"
+
+#: skins/default/templates/user_profile/user_info.html:50
+msgid "real name"
+msgstr "nume real"
+
+#: skins/default/templates/user_profile/user_info.html:55
+msgid "member for"
+msgstr "membru de"
+
+#: skins/default/templates/user_profile/user_info.html:60
+msgid "last seen"
+msgstr "văzut ultima dată"
+
+#: skins/default/templates/user_profile/user_info.html:66
+msgid "user website"
+msgstr "pagină web utilizator"
+
+#: skins/default/templates/user_profile/user_info.html:72
+msgid "location"
+msgstr "locație"
+
+#: skins/default/templates/user_profile/user_info.html:79
+msgid "age"
+msgstr "vârstă"
+
+#: skins/default/templates/user_profile/user_info.html:80
+msgid "age unit"
+msgstr "ani"
+
+#: skins/default/templates/user_profile/user_info.html:87
+msgid "todays unused votes"
+msgstr "voturi nefolosite azi"
+
+#: skins/default/templates/user_profile/user_info.html:88
+msgid "votes left"
+msgstr "voturi rămase"
+
+#: skins/default/templates/user_profile/user_moderate.html:4
+#: skins/default/templates/user_profile/user_tabs.html:42
+msgid "moderation"
+msgstr "moderare"
+
+#: skins/default/templates/user_profile/user_moderate.html:8
+#, python-format
+msgid "%(username)s's current status is \"%(status)s\""
+msgstr "starea curentă a utilizatorului %(username)s este „%(status)s”"
+
+#: skins/default/templates/user_profile/user_moderate.html:11
+msgid "User status changed"
+msgstr "Starea utilizatorului a fost schimbată"
+
+#: skins/default/templates/user_profile/user_moderate.html:18
+msgid "Save"
+msgstr "Salvează"
+
+#: skins/default/templates/user_profile/user_moderate.html:24
+#, python-format
+msgid "Your current reputation is %(reputation)s points"
+msgstr "Reputația curentă este %(reputation)s puncte"
+
+#: skins/default/templates/user_profile/user_moderate.html:26
+#, python-format
+msgid "User's current reputation is %(reputation)s points"
+msgstr "Reputația curentă a utilizatorului este %(reputation)s puncte"
+
+#: skins/default/templates/user_profile/user_moderate.html:30
+msgid "User reputation changed"
+msgstr "Reputația utilizatorului a fost schimbată"
+
+#: skins/default/templates/user_profile/user_moderate.html:37
+msgid "Subtract"
+msgstr "Scade"
+
+#: skins/default/templates/user_profile/user_moderate.html:42
+#, python-format
+msgid "Send message to %(username)s"
+msgstr "Trimite mesaj către %(username)s"
+
+#: skins/default/templates/user_profile/user_moderate.html:43
+msgid ""
+"An email will be sent to the user with 'reply-to' field set to your email "
+"address. Please make sure that your address is entered correctly."
+msgstr ""
+"Un mesaj email va fi trimis către utilizator cu câmpul „reply-to” definit la "
+"adresa proprie de email. Verificați că adresa proprie este introdusă corect."
+
+#: skins/default/templates/user_profile/user_moderate.html:45
+msgid "Message sent"
+msgstr "Mesaj trimis"
+
+#: skins/default/templates/user_profile/user_moderate.html:63
+msgid "Send message"
+msgstr "Trimite mesaj"
+
+#: skins/default/templates/user_profile/user_recent.html:4
+#: skins/default/templates/user_profile/user_tabs.html:25
+msgid "activity"
+msgstr "activitate"
+
+#: skins/default/templates/user_profile/user_reputation.html:4
+msgid "karma"
+msgstr "reputație"
+
+#: skins/default/templates/user_profile/user_reputation.html:11
+msgid "Your karma change log."
+msgstr "Schimbările în reputație."
+
+#: skins/default/templates/user_profile/user_reputation.html:13
+#, python-format
+msgid "%(user_name)s's karma change log"
+msgstr "schimbăr în reputația utilizatorului %(user_name)s"
+
+#: skins/default/templates/user_profile/user_stats.html:5
+#: skins/default/templates/user_profile/user_tabs.html:7
+msgid "overview"
+msgstr "privire de ansamblu"
+
+#: skins/default/templates/user_profile/user_stats.html:11
+#, python-format
+msgid "<span class=\"count\">%(counter)s</span> Question"
+msgid_plural "<span class=\"count\">%(counter)s</span> Questions"
+msgstr[0] "<span class=\"count\">%(counter)s</span> întrebare"
+msgstr[1] "<span class=\"count\">%(counter)s</span> întrebări"
+msgstr[2] "<span class=\"count\">%(counter)s</span> de întrebări"
+
+#: skins/default/templates/user_profile/user_stats.html:16
+#, python-format
+msgid "<span class=\"count\">%(counter)s</span> Answer"
+msgid_plural "<span class=\"count\">%(counter)s</span> Answers"
+msgstr[0] "<span class=\"count\">%(counter)s</span> răspuns"
+msgstr[1] "<span class=\"count\">%(counter)s</span> răspunsuri"
+msgstr[2] "<span class=\"count\">%(counter)s</span> de răspunsuri"
+
+#: skins/default/templates/user_profile/user_stats.html:24
+#, python-format
+msgid "the answer has been voted for %(answer_score)s times"
+msgstr "răspunsul a fost votat de %(answer_score)s de ori"
+
+#: skins/default/templates/user_profile/user_stats.html:24
+msgid "this answer has been selected as correct"
+msgstr "acest răspuns a fost ales drept corect"
+
+#: skins/default/templates/user_profile/user_stats.html:34
+#, python-format
+msgid "(%(comment_count)s comment)"
+msgid_plural "the answer has been commented %(comment_count)s times"
+msgstr[0] "(%(comment_count)s comentariu)"
+msgstr[1] "răspunsul a fost comentat de %(comment_count)s ori"
+msgstr[2] "răspunsul a fost comentat de %(comment_count)s de ori"
+
+#: skins/default/templates/user_profile/user_stats.html:44
+#, python-format
+msgid "<span class=\"count\">%(cnt)s</span> Vote"
+msgid_plural "<span class=\"count\">%(cnt)s</span> Votes "
+msgstr[0] "<span class=\"count\">%(cnt)s</span> vot"
+msgstr[1] "<span class=\"count\">%(cnt)s</span> voturi"
+msgstr[2] "<span class=\"count\">%(cnt)s</span> de voturi"
+
+#: skins/default/templates/user_profile/user_stats.html:50
+msgid "thumb up"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_stats.html:51
+msgid "user has voted up this many times"
+msgstr "utilizatorul a votat pozitiv de atâtea ori"
+
+#: skins/default/templates/user_profile/user_stats.html:54
+msgid "thumb down"
+msgstr ""
+
+#: skins/default/templates/user_profile/user_stats.html:55
+msgid "user voted down this many times"
+msgstr "utilizatorul a votat negativ de atâtea ori"
+
+#: skins/default/templates/user_profile/user_stats.html:63
+#, python-format
+msgid "<span class=\"count\">%(counter)s</span> Tag"
+msgid_plural "<span class=\"count\">%(counter)s</span> Tags"
+msgstr[0] "<span class=\"count\">%(counter)s</span> etichetă"
+msgstr[1] "<span class=\"count\">%(counter)s</span> etichete"
+msgstr[2] "<span class=\"count\">%(counter)s</span> de etichete"
+
+#: skins/default/templates/user_profile/user_stats.html:99
+#, python-format
+msgid "<span class=\"count\">%(counter)s</span> Badge"
+msgid_plural "<span class=\"count\">%(counter)s</span> Badges"
+msgstr[0] "<span class=\"count\">%(counter)s</span> insignă"
+msgstr[1] "<span class=\"count\">%(counter)s</span> insigne"
+msgstr[2] "<span class=\"count\">%(counter)s</span> de insigne"
+
+#: skins/default/templates/user_profile/user_tabs.html:5
+msgid "User profile"
+msgstr "Profil utilizator"
+
+#: skins/default/templates/user_profile/user_tabs.html:10 views/users.py:728
+msgid "comments and answers to others questions"
+msgstr "comentarii și răspunsuri pentru întrebările altora"
+
+#: skins/default/templates/user_profile/user_tabs.html:15
+msgid "graph of user reputation"
+msgstr "graficul reputației utilizatorului"
+
+#: skins/default/templates/user_profile/user_tabs.html:17
+msgid "reputation history"
+msgstr "istorie reputație"
+
+#: skins/default/templates/user_profile/user_tabs.html:19
+msgid "questions that user selected as his/her favorite"
+msgstr "întrebări pe care utilizatorul le-a ales ca fiind favorite"
+
+#: skins/default/templates/user_profile/user_tabs.html:23
+msgid "recent activity"
+msgstr "activitate recentă"
+
+#: skins/default/templates/user_profile/user_tabs.html:28 views/users.py:792
+msgid "user vote record"
+msgstr "istoria voturilor utilizatorului"
+
+#: skins/default/templates/user_profile/user_tabs.html:30
+msgid "casted votes"
+msgstr "voturi date"
+
+#: skins/default/templates/user_profile/user_tabs.html:34 views/users.py:897
+msgid "email subscription settings"
+msgstr "configurări abonament email"
+
+#: skins/default/templates/user_profile/user_tabs.html:40 views/users.py:212
+msgid "moderate this user"
+msgstr "moderează acest utilizator"
+
+#: skins/default/templates/user_profile/user_votes.html:4
+msgid "votes"
+msgstr "voturi"
+
+#: skins/default/templates/user_profile/users_questions.html:9
+#: skins/default/templates/user_profile/users_questions.html:17
+#, python-format
+msgid "this questions was selected as favorite %(cnt)s time"
+msgid_plural "this questions was selected as favorite %(cnt)s times"
+msgstr[0] "aceste întrebări au fost alese ca favorite %(cnt)s dată"
+msgstr[1] "aceste întrebări au fost alese ca favorite de %(cnt)s ori"
+msgstr[2] "aceste întrebări au fost alese ca favorite de %(cnt)s de ori"
+
+#: skins/default/templates/user_profile/users_questions.html:10
+msgid "thumb-up on"
+msgstr ""
+
+#: skins/default/templates/user_profile/users_questions.html:18
+msgid "thumb-up off"
+msgstr ""
+
+#: templatetags/extra_filters.py:145 templatetags/extra_filters_jinja.py:227
+msgid "no items in counter"
+msgstr "nu sunt elemente în contor"
+
+#: utils/decorators.py:82 views/commands.py:128 views/commands.py:145
+msgid "Oops, apologies - there was some error"
+msgstr "Oops, ne cerem scuze - a apărut o eroare"
+
+#: utils/forms.py:32
+msgid "this field is required"
+msgstr "acest câmp este obligatoriu"
+
+#: utils/forms.py:46
+msgid "choose a username"
+msgstr "alegeți un nume de utilizator"
+
+#: utils/forms.py:52
+msgid "user name is required"
+msgstr "numele de utilizator este obligatoriu"
+
+#: utils/forms.py:53
+msgid "sorry, this name is taken, please choose another"
+msgstr "ne pare rău, acest nume este luat, alegeți un alt nume"
+
+#: utils/forms.py:54
+msgid "sorry, this name is not allowed, please choose another"
+msgstr "ne pare rău, acest nume nu este permis, alegeți un alt nume"
+
+#: utils/forms.py:55
+msgid "sorry, there is no user with this name"
+msgstr "ne pare rău, nu există nici un utilizator cu acest nume"
+
+#: utils/forms.py:56
+msgid "sorry, we have a serious error - user name is taken by several users"
+msgstr ""
+"ne pare rău, avem o problemă gravă, numele de utilizator este luat de mai "
+"mult utilizatori"
+
+#: utils/forms.py:57
+msgid "user name can only consist of letters, empty space and underscore"
+msgstr ""
+"numele de utilizator poate fi format doar din litere, spații și liniuță de "
+"subliniere"
+
+#: utils/forms.py:118
+msgid "your email address"
+msgstr "adresa de email"
+
+#: utils/forms.py:119
+msgid "email address is required"
+msgstr "adresa de email este obligatorie"
+
+#: utils/forms.py:120
+msgid "please enter a valid email address"
+msgstr "introduceți o adresă de email validă"
+
+#: utils/forms.py:121
+msgid "this email is already used by someone else, please choose another"
+msgstr ""
+"această adresă de email este deja folosită de un alt utilizator, folosiți o "
+"altă adresă"
+
+#: utils/forms.py:149
+msgid "choose password"
+msgstr "alegeți parola"
+
+#: utils/forms.py:150
+msgid "password is required"
+msgstr "parola este obligatorie"
+
+#: utils/forms.py:153
+msgid "retype password"
+msgstr "retastați parola"
+
+#: utils/forms.py:154
+msgid "please, retype your password"
+msgstr "retastați parola"
+
+#: utils/forms.py:155
+msgid "sorry, entered passwords did not match, please try again"
+msgstr "ne pare rău, parolele tastate nu sunt identice, încercați din nou"
+
+#: utils/functions.py:63
+#, python-format
+msgid "on %(date)s"
+msgstr "în %(date)s"
+
+#: utils/functions.py:67
+msgid "2 days ago"
+msgstr "acum 2 zile"
+
+#: utils/functions.py:69
+msgid "yesterday"
+msgstr "ieri"
+
+#: utils/functions.py:71
+#, python-format
+msgid "%(hr)d hour ago"
+msgid_plural "%(hr)d hours ago"
+msgstr[0] "acum %(hr)d oră"
+msgstr[1] "acum %(hr)d ore"
+msgstr[2] "acum %(hr)d de ore"
+
+#: utils/functions.py:73
+#, python-format
+msgid "%(min)d min ago"
+msgid_plural "%(min)d mins ago"
+msgstr[0] "acum %(min)d minut"
+msgstr[1] "acum %(min)d minute"
+msgstr[2] "acum %(min)d de minute"
+
+#: views/avatar_views.py:94
+msgid "Successfully uploaded a new avatar."
+msgstr "A încărcat cu succes un avatar nou."
+
+#: views/avatar_views.py:134
+msgid "Successfully updated your avatar."
+msgstr "Ați actualizat cu succes propriul avatar."
+
+#: views/avatar_views.py:173
+msgid "Successfully deleted the requested avatars."
+msgstr "Ați șters cu succes avatarele cerute."
+
+#: views/commands.py:38
+msgid "anonymous users cannot vote"
+msgstr "utilizatorii anonimi nu pot vota"
+
+#: views/commands.py:58
+msgid "Sorry you ran out of votes for today"
+msgstr ""
+"Ne pare rău, dar nu mai aveți voturi pentru azi... și mâine este o zi"
+
+#: views/commands.py:64
+#, python-format
+msgid "You have %(votes_left)s votes left for today"
+msgstr "Mai ai %(votes_left)s voturi pentru azi"
+
+#: views/commands.py:135
+msgid "Sorry, but anonymous users cannot access the inbox"
+msgstr "Ne pare rău dar utilizatorii anonimi nu pot accesa inboxul"
+
+#: views/commands.py:205
+msgid "Sorry, something is not right here..."
+msgstr "Ne pare rău dar ceva nu este în regulă aici"
+
+#: views/commands.py:220
+msgid "Sorry, but anonymous users cannot accept answers"
+msgstr "Ne pare rău dar utilizatorii anonimi nu pot accepta răspunsuri"
+
+#: views/commands.py:301
+#, python-format
+msgid "subscription saved, %(email)s needs validation, see %(details_url)s"
+msgstr "abonament salvat, %(email)s necesită validare, vezi %(details_url)s"
+
+#: views/commands.py:309
+msgid "email update frequency has been set to daily"
+msgstr "frecvența de actualizare a emailurilor a fost definită drept zilnic"
+
+#: views/commands.py:400
+#, python-format
+msgid "Tag subscription was canceled (<a href=\"%(url)s\">undo</a>)."
+msgstr ""
+"Abonomanetul la etichetă a fost anulat (<a href=\"%(url)s\">refă</a>)."
+
+#: views/commands.py:409
+#, python-format
+msgid "Please sign in to subscribe for: %(tags)s"
+msgstr "Vă rugăm să vă autentificați pentru a vă abona la: %(tags)s"
+
+#: views/meta.py:63
+msgid "Q&A forum feedback"
+msgstr "Sugestii pentru întrebări și răspunsuri"
+
+#: views/meta.py:64
+msgid "Thanks for the feedback!"
+msgstr "Vă mulțumim pentru sugestii!"
+
+#: views/meta.py:72
+msgid ""
+"We look forward to hearing your feedback! Please, give it next time :)"
+msgstr "Suntem interesați de sugestiile voastre!"
+
+#: views/readers.py:177
+#, python-format
+msgid "%(badge_count)d %(badge_level)s badge"
+msgid_plural "%(badge_count)d %(badge_level)s badges"
+msgstr[0] "%(badge_count)d %(badge_level)s insignă"
+msgstr[1] "%(badge_count)d %(badge_level)s insigne"
+msgstr[2] "%(badge_count)d %(badge_level)s de insigne"
+
+#: views/readers.py:403
+msgid ""
+"Sorry, the comment you are looking for has been deleted and is no longer "
+"accessible"
+msgstr ""
+"Ne pare rău, comentariul pe care îl căutați a fost șters nu mai este "
+"accesibil"
+
+#: views/users.py:213
+msgid "moderate user"
+msgstr "moderează utilizator"
+
+#: views/users.py:377
+msgid "user profile"
+msgstr "profil utilizator"
+
+#: views/users.py:378
+msgid "user profile overview"
+msgstr "privire de ansamblu profil utilizator"
+
+#: views/users.py:661
+msgid "recent user activity"
+msgstr "activitate recentă utilizator"
+
+#: views/users.py:662
+msgid "profile - recent activity"
+msgstr "profil - activitate recentă"
+
+#: views/users.py:729
+msgid "profile - responses"
+msgstr "profil - răspunsuri"
+
+#: views/users.py:793
+msgid "profile - votes"
+msgstr "profil - voturi"
+
+#: views/users.py:828
+msgid "user reputation in the community"
+msgstr "reputația utilizatorului în comunitate"
+
+#: views/users.py:829
+msgid "profile - user reputation"
+msgstr "profil - reputație utilizator"
+
+#: views/users.py:856
+msgid "users favorite questions"
+msgstr "întrebările favorite ale utilizatorului"
+
+#: views/users.py:857
+msgid "profile - favorite questions"
+msgstr "profile - întrebări favorite"
+
+#: views/users.py:876 views/users.py:880
+msgid "changes saved"
+msgstr "schimbările au fost salvate"
+
+#: views/users.py:886
+msgid "email updates canceled"
+msgstr "actualizările email au fost anulate"
+
+#: views/users.py:898
+msgid "profile - email subscriptions"
+msgstr "profil - abonamente email"
+
+#: views/writers.py:57
+msgid "Sorry, anonymous users cannot upload files"
+msgstr "Utilizatorii anonimi nu pot încărca fișiere"
+
+#: views/writers.py:67
+#, python-format
+msgid "allowed file types are '%(file_types)s'"
+msgstr "tipurile de fișiere permise sunt „%(file_types)s”"
+
+#: views/writers.py:90
+#, python-format
+msgid "maximum upload file size is %(file_size)sK"
+msgstr "mărimea maximă a fișierului încărcat este %(file_size)sK"
+
+#: views/writers.py:98
+msgid ""
+"Error uploading file. Please contact the site administrator. Thank you."
+msgstr ""
+"Eroare la încărcarea fișierului. Vă rugăm să contactați administratorii "
+"siteului. Vă mulțumim."
+
+#: views/writers.py:560
+#, python-format
+msgid ""
+"Sorry, you appear to be logged out and cannot post comments. Please <a "
+"href=\"%(sign_in_url)s\">sign in</a>."
+msgstr ""
+"Nu sunteți autentificat și nu puteți adăuga comentarii . Vă rugăm să vă <a "
+"href=\"%(sign_in_url)s\">autentificați</a>."
+
+#: views/writers.py:605
+msgid "Sorry, anonymous users cannot edit comments"
+msgstr "Utilizatorii anonimi nu pot modifica comentariile"
+
+#: views/writers.py:613
+#, python-format
+msgid ""
+"Sorry, you appear to be logged out and cannot delete comments. Please <a "
+"href=\"%(sign_in_url)s\">sign in</a>."
+msgstr ""
+"Nu sunteți autentificat și nu puteți șterge comentarii . Vă rugăm să vă <a "
+"href=\"%(sign_in_url)s\">autentificați</a>."
+
+#: views/writers.py:634
+msgid "sorry, we seem to have some technical difficulties"
+msgstr "ne pare rău dar se pare că avem unele dificultăți tehnice"
+
+msgid "Email verification subject line"
+msgstr "Linie subiect verificare email"
+
+msgid "how to validate email title"
+msgstr "cum să fie validat titlul email-ului"
+
+msgid ""
+"how to validate email info with %(send_email_key_url)s %(gravatar_faq_url)s"
+msgstr ""
+"cum să fie validate informațiile email cu %(send_email_key_url)s "
+"%(gravatar_faq_url)s"
+
+msgid "more answers"
+msgstr "mai multe răspunsuri"
+
+msgid "popular"
+msgstr "popular"
+
+msgid "reputation points"
+msgstr "puncte reputație"
diff --git a/askbot/locale/ru/LC_MESSAGES/djangojs.mo b/askbot/locale/ru/LC_MESSAGES/djangojs.mo
new file mode 100644
index 00000000..c2aa55bb
--- /dev/null
+++ b/askbot/locale/ru/LC_MESSAGES/djangojs.mo
Binary files differ
diff --git a/askbot/locale/ru/LC_MESSAGES/djangojs.po b/askbot/locale/ru/LC_MESSAGES/djangojs.po
new file mode 100644
index 00000000..a45910df
--- /dev/null
+++ b/askbot/locale/ru/LC_MESSAGES/djangojs.po
@@ -0,0 +1,26 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-01-20 17:36-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"
+"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"
+
+#: skins/default/media/js/live_search.js:278
+msgid "%(q_num)s question"
+msgid_plural "%(q_num)s questions"
+msgstr[0] "%(q_num)s вопрос"
+msgstr[1] "%(q_num)s вопроса"
+msgstr[2] "%(q_num)s вопросов"
diff --git a/askbot/management/__init__.py b/askbot/management/__init__.py
index e69de29b..1e2b2aaf 100644
--- a/askbot/management/__init__.py
+++ b/askbot/management/__init__.py
@@ -0,0 +1,82 @@
+import sys
+from django.core.management.base import NoArgsCommand
+from django.db import transaction
+from askbot.models import signals
+from askbot.utils import console
+
+FORMAT_STRING = '%6.2f%%'#to print progress in percent
+
+class NoArgsJob(NoArgsCommand):
+ """Base class for a job command -
+ the one that runs the same operation on
+ sets of items - each item operation in its own
+ transaction and prints progress in % of items
+ completed
+
+ The subclass must implement __init__() method
+ where self.batches data structure must be defined as follows
+ (#the whole thing is a tuple
+ {#batch is described by a dictionary
+ 'title': <string>,
+ 'query_set': <query set for the items>,
+ 'function': <function or callable that performs
+ an operation on a single item
+ and returns True if item was changed
+ False otherwise
+ item is given as argument
+ >,
+ 'items_changed_message': <string with one %d placeholder>,
+ 'nothing_changed_message': <string>
+ },
+ #more batch descriptions
+ )
+ """
+ batches = ()
+
+ def handle_noargs(self, **options):
+ """handler function that removes all signal listeners
+ then runs the job and finally restores the listerers
+ """
+ signal_data = signals.pop_all_db_signal_receivers()
+ self.run_command(**options)
+ signals.set_all_db_signal_receivers(signal_data)
+
+ def run_command(self, **options):
+ """runs the batches"""
+ for batch in self.batches:
+ self.run_batch(batch)
+
+ @transaction.commit_manually
+ def run_batch(self, batch):
+ """runs the single batch
+ prints batch title
+ then loops through the query set
+ and prints progress in %
+ afterwards there will be a short summary
+ """
+
+ sys.stdout.write(batch['title'])
+ changed_count = 0
+ checked_count = 0
+ total_count = batch['query_set'].count()
+
+ if total_count == 0:
+ return
+
+ for item in batch['query_set'].all():
+
+ item_changed = batch['function'](item)
+ transaction.commit()
+
+ if item_changed:
+ changed_count += 1
+ checked_count += 1
+
+ progress = 100*float(checked_count)/float(total_count)
+ console.print_progress(FORMAT_STRING, progress)
+ print FORMAT_STRING % 100
+
+ if changed_count:
+ print batch['changed_count_message'] % changed_count
+ else:
+ print batch['nothing_changed_message']
diff --git a/askbot/management/commands/add_admin.py b/askbot/management/commands/add_admin.py
index 8ff49193..6f7c7034 100644
--- a/askbot/management/commands/add_admin.py
+++ b/askbot/management/commands/add_admin.py
@@ -1,6 +1,6 @@
from django.core.management.base import NoArgsCommand
-from django.contrib.auth.models import User, Group
-from django.db.models.signals import pre_save, post_save, pre_delete, post_delete
+from django.contrib.auth.models import User
+from django.db.models.signals import pre_save, post_save
import sys
class Command(NoArgsCommand):
@@ -41,6 +41,5 @@ class Command(NoArgsCommand):
self.confirm_action()
self.remove_signals()
- self.user.is_superuser = True
- self.user.is_staff = True
+ self.user.set_admin_status()
self.user.save()
diff --git a/askbot/management/commands/delete_unused_tags.py b/askbot/management/commands/delete_unused_tags.py
index e5e340d0..acb28fa7 100644
--- a/askbot/management/commands/delete_unused_tags.py
+++ b/askbot/management/commands/delete_unused_tags.py
@@ -1,6 +1,7 @@
from django.core.management.base import NoArgsCommand
from django.db import transaction
from askbot import models
+from askbot.utils import console
import sys
class Command(NoArgsCommand):
@@ -17,10 +18,9 @@ class Command(NoArgsCommand):
tag.delete()
transaction.commit()
count += 1
- sys.stdout.write('%6.2f%%' % (100*float(count)/float(total)))
- sys.stdout.flush()
- sys.stdout.write('\b'*7)
- sys.stdout.write('\n')
+ progress = 100*float(count)/float(total)
+ console.print_progress('%6.2f%%', progress)
+ print '%6.2f%%' % 100
if deleted_tags:
found_count = len(deleted_tags)
diff --git a/askbot/management/commands/dump_forum.py b/askbot/management/commands/dump_forum.py
index 8047b2f6..cabc8ae8 100644
--- a/askbot/management/commands/dump_forum.py
+++ b/askbot/management/commands/dump_forum.py
@@ -26,7 +26,7 @@ The extension ".json" will be added automatically."""
sys.stdout = dump_file
management.call_command(
'dumpdata',
- exclude = ('contenttypes',),
+ #exclude = ('contenttypes',),
indent = 4
)
sys.stdout = stdout_orig
diff --git a/askbot/management/commands/fix_inbox_counts.py b/askbot/management/commands/fix_inbox_counts.py
new file mode 100644
index 00000000..c2ffffdc
--- /dev/null
+++ b/askbot/management/commands/fix_inbox_counts.py
@@ -0,0 +1,46 @@
+from askbot.management import NoArgsJob
+from askbot import models
+from askbot import const
+
+ACTIVITY_TYPES = const.RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY
+ACTIVITY_TYPES += (const.TYPE_ACTIVITY_MENTION,)
+
+def fix_inbox_counts(user):
+ old_new_count = user.new_response_count
+ old_seen_count = user.seen_response_count
+ new_new_count = models.ActivityAuditStatus.objects.filter(
+ user = user,
+ status = models.ActivityAuditStatus.STATUS_NEW,
+ activity__activity_type__in = ACTIVITY_TYPES
+ ).count()
+ new_seen_count = models.ActivityAuditStatus.objects.filter(
+ user = user,
+ status = models.ActivityAuditStatus.STATUS_SEEN,
+ activity__activity_type__in = ACTIVITY_TYPES
+ ).count()
+
+ (changed1, changed2) = (False, False)
+ if new_new_count != old_new_count:
+ user.new_response_count = new_new_count
+ changed1 = True
+ if new_seen_count != old_seen_count:
+ user.seen_response_count = new_seen_count
+ changed2 = True
+ if changed1 or changed2:
+ user.save()
+ return True
+ return False
+
+class Command(NoArgsJob):
+ """definition of the job that fixes response counts
+ destined for the user inboxes
+ """
+ def __init__(self, *args, **kwargs):
+ self.batches = ({
+ 'title': 'Checking inbox item counts for all users: ',
+ 'query_set': models.User.objects.all(),
+ 'function': fix_inbox_counts,
+ 'changed_count_message': 'Corrected records for %d users',
+ 'nothing_changed_message': 'No problems found'
+ },)
+ super(Command, self).__init__(*args, **kwargs)
diff --git a/askbot/management/commands/fix_question_tags.py b/askbot/management/commands/fix_question_tags.py
new file mode 100644
index 00000000..47fc4102
--- /dev/null
+++ b/askbot/management/commands/fix_question_tags.py
@@ -0,0 +1,79 @@
+import sys
+from django.core.management.base import NoArgsCommand
+from django.db import transaction
+from askbot import models
+from askbot import forms
+from askbot.utils import console
+from askbot.models import signals
+from askbot.conf import settings as askbot_settings
+
+FORMAT_STRING = '%6.2f%%'
+
+class Command(NoArgsCommand):
+ def handle_noargs(self, **options):
+ signal_data = signals.pop_all_db_signal_receivers()
+ self.run_command()
+ signals.set_all_db_signal_receivers(signal_data)
+
+ @transaction.commit_manually
+ def run_command(self):
+ """method that runs the actual command"""
+ #go through tags and find character case duplicates and eliminate them
+ tagnames = models.Tag.objects.values_list('name', flat = True)
+ for name in tagnames:
+ dupes = models.Tag.objects.filter(name__iexact = name)
+ first_tag = dupes[0]
+ if dupes.count() > 1:
+ line = 'Found duplicate tags for %s: ' % first_tag.name
+ print line,
+ for idx in xrange(1, dupes.count()):
+ print dupes[idx].name + ' ',
+ dupes[idx].delete()
+ print ''
+ if askbot_settings.FORCE_LOWERCASE_TAGS:
+ lowercased_name = first_tag.name.lower()
+ if first_tag.name != lowercased_name:
+ print 'Converting tag %s to lower case' % first_tag.name
+ first_tag.name = lowercased_name
+ first_tag.save()
+ transaction.commit()
+
+ #go through questions and fix tag records on each
+ questions = models.Question.objects.all()
+ checked_count = 0
+ found_count = 0
+ total_count = questions.count()
+ print "Searching for questions with inconsistent tag records:",
+ for question in questions:
+ tags = question.tags.all()
+ denorm_tag_set = set(question.get_tag_names())
+ norm_tag_set = set(question.tags.values_list('name', flat=True))
+ if norm_tag_set != denorm_tag_set:
+
+ if question.last_edited_by:
+ user = question.last_edited_by
+ timestamp = question.last_edited_at
+ else:
+ user = question.author
+ timestamp = question.added_at
+
+ tagnames = forms.TagNamesField().clean(question.tagnames)
+
+ question.update_tags(
+ tagnames = tagnames,
+ user = user,
+ timestamp = timestamp
+ )
+ question.tagnames = tagnames
+ question.save()
+ found_count += 1
+
+ transaction.commit()
+ checked_count += 1
+ progress = 100*float(checked_count)/float(total_count)
+ console.print_progress(FORMAT_STRING, progress)
+ print FORMAT_STRING % 100
+ if found_count:
+ print '%d problem questions found, tag records restored' % found_count
+ else:
+ print 'Did not find any problems'
diff --git a/askbot/management/commands/get_tag_stats.py b/askbot/management/commands/get_tag_stats.py
new file mode 100644
index 00000000..c30643b3
--- /dev/null
+++ b/askbot/management/commands/get_tag_stats.py
@@ -0,0 +1,218 @@
+import sys
+import optparse
+from django.core.management.base import BaseCommand, CommandError
+from askbot import models
+
+def get_tag_lines(tag_marks, width = 25):
+ output = list()
+ line = ''
+ for name in tag_marks:
+ if line == '':
+ line = name
+ elif len(line) + len(name) + 1 > width:
+ output.append(line)
+ line = name
+ else:
+ line += ' ' + name
+ output.append(line)
+ return output
+
+def get_empty_lines(num_lines):
+ output = list()
+ for idx in xrange(num_lines):
+ output.append('')
+ return output
+
+def pad_list(the_list, length):
+ if len(the_list) < length:
+ the_list.extend(get_empty_lines(length - len(the_list)))
+
+def format_table_row(*cols, **kwargs):
+ max_len = max(map(len, cols))
+ for col in cols:
+ pad_list(col, max_len)
+
+ output = list()
+ for idx in xrange(max_len):
+ bits = list()
+ for col in cols:
+ bits.append(col[idx])
+ line = kwargs['format_string'] % tuple(bits)
+ output.append(line)
+
+ return output
+
+
+class Command(BaseCommand):
+ help = 'Prints statistics of tag usage'
+
+ option_list = BaseCommand.option_list + (
+ optparse.make_option(
+ '-t',
+ '--sub-counts',
+ action = 'store_true',
+ default = False,
+ dest = 'sub_counts',
+ help = 'Print tag subscription statistics, for all tags, listed alphabetically'
+ ),
+ optparse.make_option(
+ '-u',
+ '--user-sub-counts',
+ action = 'store_true',
+ default = False,
+ dest = 'user_sub_counts',
+ help = 'Print tag subscription data per user, with users listed alphabetically'
+ ),
+ optparse.make_option(
+ '-e',
+ '--print-empty',
+ action = 'store_true',
+ default = False,
+ dest = 'print_empty',
+ help = 'Print empty records too (with zero counts)'
+ ),
+ )
+ def handle(self, *args, **options):
+ if not(options['sub_counts'] ^ options['user_sub_counts']):
+ raise CommandError('Please use either -u or -t (but not both)')
+
+ print ''
+ if options['sub_counts']:
+ self.print_sub_counts(options['print_empty'])
+
+ if options['user_sub_counts']:
+ self.print_user_sub_counts(options['print_empty'])
+ print ''
+
+ def print_user_sub_counts(self, print_empty):
+ """prints list of users and what tags they follow/ignore
+ """
+ users = models.User.objects.all().order_by('username')
+ item_count = 0
+ for user in users:
+ tag_marks = user.tag_selections
+
+ #add names of explicitly followed tags
+ followed_tags = list()
+ followed_tags.extend(
+ tag_marks.filter(
+ reason='good'
+ ).values_list(
+ 'tag__name', flat = True
+ )
+ )
+
+ #add wildcards to the list of interesting tags
+ followed_tags.extend(user.interesting_tags.split())
+
+ for good_tag in user.interesting_tags.split():
+ followed_tags.append(good_tag)
+
+ ignored_tags = list()
+ ignored_tags.extend(
+ tag_marks.filter(
+ reason='bad'
+ ).values_list(
+ 'tag__name', flat = True
+ )
+ )
+
+ for bad_tag in user.ignored_tags.split():
+ ignored_tags.append(bad_tag)
+
+ followed_count = len(followed_tags)
+ ignored_count = len(ignored_tags)
+ if followed_count == 0 and ignored_count == 0 and print_empty == False:
+ continue
+ if item_count == 0:
+ print '%-28s %25s %25s' % ('User (id)', 'Interesting tags', 'Ignored tags')
+ print '%-28s %25s %25s' % ('=========', '================', '============')
+ followed_lines = get_tag_lines(followed_tags, width = 25)
+ ignored_lines = get_tag_lines(ignored_tags, width = 25)
+
+ follow = '*'
+ if user.email_tag_filter_strategy == const.INCLUDE_INTERESTING:
+ follow = ''
+ user_string = '%s (%d)%s' % (user.username, user.id, follow)
+ output_lines = format_table_row(
+ [user_string,],
+ followed_lines,
+ ignored_lines,
+ format_string = '%-28s %25s %25s'
+ )
+ item_count += 1
+ for line in output_lines:
+ print line
+ print ''
+
+ self.print_postamble(item_count)
+
+ def get_wildcard_tag_stats(self):
+ """This method collects statistics on all tags
+ that are followed or ignored via a wildcard selection
+
+ The return value is a dictionary, where keys are tag names
+ and values are two element lists with whe first value - follow count
+ and the second value - ignore count
+ """
+ wild = dict()#the dict that is returned in the end
+
+ users = models.User.objects.all().order_by('username')
+ for user in users:
+ wk = user.interesting_tags.strip().split()
+ interesting_tags = models.Tag.objects.get_by_wildcards(wk)
+ for tag in interesting_tags:
+ if tag.name not in wild:
+ wild[tag.name] = [0, 0]
+ wild[tag.name][0] += 1
+
+ wk = user.ignored_tags.strip().split()
+ ignored_tags = models.Tag.objects.get_by_wildcards(wk)
+ for tag in ignored_tags:
+ if tag.name not in wild:
+ wild[tag.name] = [0, 0]
+ wild[tag.name][1] += 1
+
+ return wild
+
+ def print_sub_counts(self, print_empty):
+ """prints subscription counts for
+ each tag (ignored and favorite counts)
+ """
+ wild_tags = self.get_wildcard_tag_stats()
+ tags = models.Tag.objects.all().order_by('name')
+ item_count = 0
+ for tag in tags:
+ wild_follow = 0
+ wild_ignore = 0
+ if tag.name in wild_tags:
+ (wild_follow, wild_ignore) = wild_tags[tag.name]
+
+ tag_marks = tag.user_selections
+ follow_count = tag_marks.filter(reason='good').count() \
+ + wild_follow
+ ignore_count = tag_marks.filter(reason='bad').count() \
+ + wild_ignore
+ follow_str = '%d (%d)' % (follow_count, wild_follow)
+ ignore_str = '%d (%d)' % (ignore_count, wild_ignore)
+ counts = (11-len(follow_str)) * ' ' + follow_str + ' '
+ counts += (11-len(ignore_str)) * ' ' + ignore_str
+
+ if follow_count + ignore_count == 0 and print_empty == False:
+ continue
+ if item_count == 0:
+ print '%-32s %12s %12s' % ('', 'Interesting', 'Ignored ')
+ print '%-32s %12s %12s' % ('Tag name', 'Total(wild)', 'Total(wild)')
+ print '%-32s %12s %12s' % ('========', '===========', '===========')
+ print '%-32s %s' % (tag.name, counts)
+ item_count += 1
+
+ self.print_postamble(item_count)
+
+ def print_postamble(self, item_count):
+ print ''
+ if item_count == 0:
+ print 'Did not find anything'
+ else:
+ print '%d records shown' % item_count
+ print 'Since -e option was not selected, empty records were hidden'
diff --git a/askbot/management/commands/junk.py b/askbot/management/commands/junk.py
new file mode 100644
index 00000000..189ab361
--- /dev/null
+++ b/askbot/management/commands/junk.py
@@ -0,0 +1,36 @@
+import os
+import sys
+import tempfile
+import threading
+from django.core.management.base import NoArgsCommand
+from django.core import management
+
+class SEImporterThread(threading.Thread):
+ def __init__(self, stdout = None):
+ self.stdout = stdout
+ super(SEImporterThread, self).__init__()
+
+ def run(self):
+ management.call_command('load_stackexchange','/home/fadeev/personal/asksci/asksci.zip')
+
+class Command(NoArgsCommand):
+ def handle_noargs(self, **options):
+ fake_stdout = tempfile.NamedTemporaryFile()
+ real_stdout = sys.stdout
+ sys.stdout = fake_stdout
+ importer = SEImporterThread(stdout = fake_stdout)
+ importer.start()
+
+ read_stdout = open(fake_stdout.name, 'r')
+ file_pos = 0
+ fd = read_stdout.fileno()
+ while importer.isAlive():
+ c_size = os.fstat(fd).st_size
+ if c_size > file_pos:
+ line = read_stdout.readline()
+ real_stdout.write('Have line :' + line)
+ file_pos = read_stdout.tell()
+
+ fake_stdout.close()
+ read_stdout.close()
+ sys.stdout = real_stdout
diff --git a/askbot/management/commands/load_forum.py b/askbot/management/commands/load_forum.py
index f0b636df..65ac410f 100644
--- a/askbot/management/commands/load_forum.py
+++ b/askbot/management/commands/load_forum.py
@@ -1,5 +1,6 @@
from django.core import management
from django.db.models import signals
+from django.contrib.contenttypes.models import ContentType
from django.core.management.base import BaseCommand
from askbot import models
@@ -9,6 +10,7 @@ class Command(BaseCommand):
def handle(self, *args, **options):
#need to remove badge data b/c they are aslo in the dump
models.BadgeData.objects.all().delete()
+ ContentType.objects.all().delete()
#turn off the post_save signal so than Activity can be copied
signals.post_save.receivers = []
management.call_command('loaddata', args[0])
diff --git a/askbot/management/commands/pg_base_command.py b/askbot/management/commands/pg_base_command.py
deleted file mode 100644
index 3ff7853d..00000000
--- a/askbot/management/commands/pg_base_command.py
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python
-#encoding:utf-8
-#-------------------------------------------------------------------------------
-# Name: Award badges command
-# Purpose: This is a command file croning in background process regularly to
-# query database and award badges for user's special acitivities.
-#
-# Author: Mike, Sailing
-#
-# Created: 22/01/2009
-# Copyright: (c) Mike 2009
-# Licence: GPL V2
-#-------------------------------------------------------------------------------
-
-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 askbot.models import *
-from askbot.const import *
-
-class BaseCommand(NoArgsCommand):
- def update_activities_auditted(self, cursor, activity_ids):
- # update processed rows to auditted
- if len(activity_ids):
- query = "UPDATE activity SET is_auditted = TRUE WHERE id in (%s)"\
- % ','.join('%s' % item for item in activity_ids)
- cursor.execute(query)
-
-
-
-
-
diff --git a/askbot/management/commands/post_emailed_questions.py b/askbot/management/commands/post_emailed_questions.py
new file mode 100644
index 00000000..b80eb188
--- /dev/null
+++ b/askbot/management/commands/post_emailed_questions.py
@@ -0,0 +1,207 @@
+"""Copyright 2011 Askbot.org and Askbot project contributors.
+
+Custom management command that takes questions posted
+via email at the IMAP server
+Expects subject line of emails to have format:
+[Tag1, Tag2] Question title
+
+Tags can be entered as multiword, but the space character
+within the tag may be replaced with a dash, per live
+setting EMAIL_REPLACE_SPACE_IN_TAGS
+also, to make use of this command, the feature must
+be enabled via ALLOW_ASKING_BY_EMAIL
+and IMAP settings in the settings.py must be configured
+correctly
+
+todo: use templates for the email formatting
+"""
+import imaplib
+import email
+import quopri
+import base64
+from django.conf import settings as django_settings
+from django.core.management.base import NoArgsCommand, CommandError
+from django.core import exceptions
+from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import string_concat
+from django.core.urlresolvers import reverse
+from askbot.conf import settings as askbot_settings
+from askbot.utils import mail
+from askbot import models
+from askbot.forms import AskByEmailForm
+
+USAGE = _(
+"""<p>To ask by email, please:</p>
+<ul>
+ <li>Format the subject line as: [Tag1; Tag2] Question title</li>
+ <li>Type details of your question into the email body</li>
+</ul>
+<p>Note that tags may consist of more than one word, and tags
+may be separated by a semicolon or a comma</p>
+"""
+)
+
+def bounce_email(email, subject, reason = None, body_text = None):
+ """sends a bounce email at address ``email``, with the subject
+ line ``subject``, accepts several reasons for the bounce:
+
+ * ``'problem_posting'``, ``unknown_user`` and ``permission_denied``
+ * ``body_text`` in an optional parameter that allows to append
+ extra text to the message
+ """
+ if reason == 'problem_posting':
+ error_message = _(
+ '<p>Sorry, there was an error posting your question '
+ 'please contact the %(site)s administrator</p>'
+ ) % {'site': askbot_settings.APP_SHORT_NAME}
+ error_message = string_concat(error_message, USAGE)
+ elif reason == 'unknown_user':
+ error_message = _(
+ '<p>Sorry, in order to post questions on %(site)s '
+ 'by email, please <a href="%(url)s">register first</a></p>'
+ ) % {
+ 'site': askbot_settings.APP_SHORT_NAME,
+ 'url': askbot_settings.APP_URL + reverse('user_signin')
+ }
+ elif reason == 'permission_denied':
+ error_message = _(
+ '<p>Sorry, your question could not be posted '
+ 'due to insufficient privileges of your user account</p>'
+ )
+ else:
+ raise ValueError('unknown reason to bounce an email: "%s"' % reason)
+
+ if body_text != None:
+ error_message = string_concat(error_message, body_text)
+
+ #print 'sending email'
+ #print email
+ #print subject
+ #print error_message
+ mail.send_mail(
+ recipient_list = (email,),
+ subject_line = 'Re: ' + subject,
+ body_text = error_message
+ )
+
+class CannotParseEmail(Exception):
+ """This exception will bounce the email"""
+ def __init__(self, email, subject):
+ super(CannotParseEmail, self).__init__()
+ bounce_email(email, subject, reason = 'problem_posting')
+
+def parse_message(msg):
+ """returns a tuple
+ (<from email address>, <subject>, <body>)
+ the function will attempt to decode the email
+ supported encodings are "quoted-printable" and "base64"
+ not supported - emails using language - specific encodings
+ """
+ sender = msg.get('From')
+ subject = msg.get('Subject')
+ if msg.is_multipart():
+ msg = msg.get_payload()
+ if isinstance(msg, list):
+ raise CannotParseEmail(sender, subject)
+
+ ctype = msg.get_content_type()#text/plain only
+ raw_body = msg.get_payload()#text/plain only
+ encoding = msg.get('Content-Transfer-Encoding')
+ if encoding == 'base64':
+ body = base64.b64decode(raw_body)
+ elif encoding == 'quoted-printable':
+ body = quopri.decodestring(raw_body)
+ else:
+ body = raw_body
+ return (sender, subject, body)
+
+
+class Command(NoArgsCommand):
+ def handle_noargs(self, **options):
+ """reads all emails from the INBOX of
+ imap server and posts questions based on
+ those emails. Badly formatted questions are
+ bounced, as well as emails from unknown users
+
+ all messages are deleted thereafter
+ """
+ if askbot_settings.ALLOW_ASKING_BY_EMAIL:
+ raise CommandError('Asking by email is not enabled')
+
+ #open imap server and select the inbox
+ if django_settings.IMAP_USE_TLS:
+ imap_getter = imaplib.IMAP4_SSL
+ else:
+ imap_getter = imaplib.IMAP4
+ imap = imap_getter(
+ django_settings.IMAP_HOST,
+ django_settings.IMAP_PORT
+ )
+ imap.login(
+ django_settings.IMAP_HOST_USER,
+ django_settings.IMAP_HOST_PASSWORD
+ )
+ imap.select('INBOX')
+
+ #get message ids
+ status, ids = imap.search(None, 'ALL')
+
+ #for each id - read a message, parse it and post a question
+ for id in ids[0].split(' '):
+ t, data = imap.fetch(id, '(RFC822)')
+ message_body = data[0][1]
+ msg = email.message_from_string(data[0][1])
+ imap.store(id, '+FLAGS', '\\Deleted')
+ try:
+ (sender, subject, body) = parse_message(msg)
+ except CannotParseEmail, e:
+ continue
+ data = {
+ 'sender': sender,
+ 'subject': subject,
+ 'body_text': body
+ }
+ form = AskByEmailForm(data)
+ print data
+ if form.is_valid():
+ email_address = form.cleaned_data['email']
+ try:
+ print 'looking for ' + email_address
+ user = models.User.objects.get(email = email_address)
+ except models.User.DoesNotExist:
+ bounce_email(email_address, subject, reason = 'unknown_user')
+ except models.User.MultipleObjectsReturned:
+ bounce_email(email_address, subject, reason = 'problem_posting')
+
+ tagnames = form.cleaned_data['tagnames']
+ title = form.cleaned_data['title']
+ body_text = form.cleaned_data['body_text']
+
+ try:
+ print 'posting question'
+ print title
+ print tagnames
+ print body_text
+ user.post_question(
+ title = title,
+ tags = tagnames,
+ body_text = body_text
+ )
+ except exceptions.PermissionDenied, e:
+ bounce_email(
+ email_address,
+ subject,
+ reason = 'permission_denied',
+ body_text = unicode(e)
+ )
+ else:
+ email_address = mail.extract_first_email_address(sender)
+ if email_address:
+ bounce_email(
+ email_address,
+ subject,
+ reason = 'problem_posting'
+ )
+ imap.expunge()
+ imap.close()
+ imap.logout()
diff --git a/askbot/management/commands/remove_admin.py b/askbot/management/commands/remove_admin.py
index edc22f3d..2aa95c20 100644
--- a/askbot/management/commands/remove_admin.py
+++ b/askbot/management/commands/remove_admin.py
@@ -1,6 +1,6 @@
from django.core.management.base import NoArgsCommand
-from django.contrib.auth.models import User, Group
-from django.db.models.signals import pre_save, post_save, pre_delete, post_delete
+from django.contrib.auth.models import User
+from django.db.models.signals import pre_save, post_save
import sys
class Command(NoArgsCommand):
@@ -41,6 +41,5 @@ class Command(NoArgsCommand):
self.confirm_action()
self.remove_signals()
- self.user.is_superuser = False
- self.user.is_staff = False
+ self.user.remove_admin_status()
self.user.save()
diff --git a/askbot/management/commands/rename_tags.py b/askbot/management/commands/rename_tags.py
index bb7e54e2..bd15d685 100644
--- a/askbot/management/commands/rename_tags.py
+++ b/askbot/management/commands/rename_tags.py
@@ -4,7 +4,6 @@ retagged
"""
import sys
from optparse import make_option
-from django.db import transaction
from django.core import management
from django.core.management.base import BaseCommand, CommandError
from askbot import api, models
@@ -142,8 +141,6 @@ Also, you can try command "rename_tag_id"
)
except models.Tag.MultipleObjectsReturned:
raise CommandError(u'found more than one tag named %s' % tag_name)
- #transaction.commit()
-
options['user_id'] = admin.id
options['from'] = format_tag_ids(from_tags)
options['to'] = format_tag_ids(to_tags)
diff --git a/askbot/management/commands/send_email_alerts.py b/askbot/management/commands/send_email_alerts.py
index e3c9482f..56286981 100644
--- a/askbot/management/commands/send_email_alerts.py
+++ b/askbot/management/commands/send_email_alerts.py
@@ -1,20 +1,18 @@
-import logging
import datetime
from django.core.management.base import NoArgsCommand
from django.db import connection
from django.db.models import Q, F
-import askbot
from askbot.models import User, Question, Answer, Tag, QuestionRevision
from askbot.models import AnswerRevision, Activity, EmailFeedSetting
from askbot.models import Comment
from django.utils.translation import ugettext as _
from django.utils.translation import ungettext
-from django.conf import settings
+from django.conf import settings as django_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
-from askbot.utils.mail import send_mail
+from askbot.utils import mail
DEBUG_THIS_COMMAND = False
@@ -100,7 +98,7 @@ def get_update_subject_line(question_dict):
question_count = len(updated_questions)
#note that double quote placement is important here
if len(tag_list) == 1:
- last_topic = ''
+ last_topic = '"'
elif len(tag_list) <= 5:
last_topic = _('" and "%s"') % tag_list.pop()
else:
@@ -117,7 +115,8 @@ def get_update_subject_line(question_dict):
'question_count': question_count,
'topics': topics
}
- return subject_line
+
+ return mail.prefix_the_subject_line(subject_line)
class Command(NoArgsCommand):
def handle_noargs(self, **options):
@@ -245,23 +244,41 @@ class Command(NoArgsCommand):
q_ans_B.cutoff_time = cutoff_time
elif feed.feed_type == 'q_all':
- if user.tag_filter_setting == 'ignored':
+ if user.email_tag_filter_strategy == '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 )
+ wk = user.ignored_tags.strip().split()
+ ignored_by_wildcards = Tag.objects.get_by_wildcards(wk)
+
+ q_all_A = Q_set_A.exclude(
+ tags__in = ignored_tags
+ ).exclude(
+ tags__in = ignored_by_wildcards
+ )
- q_all_B = Q_set_B.exclude( tags__in=ignored_tags )
+ q_all_B = Q_set_B.exclude(
+ tags__in = ignored_tags
+ ).exclude(
+ tags__in = ignored_by_wildcards
+ )
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 )
+
+ wk = user.interesting_tags.strip().split()
+ selected_by_wildcards = Tag.objects.get_by_wildcards(wk)
+
+ tag_filter = Q(tags__in = list(selected_tags)) \
+ | Q(tags__in = list(selected_by_wildcards))
+
+ q_all_A = Q_set_A.filter( tag_filter )
+ q_all_B = Q_set_B.filter( tag_filter )
q_all_A = q_all_A[:askbot_settings.MAX_ALERTS_PER_EMAIL]
q_all_B = q_all_B[:askbot_settings.MAX_ALERTS_PER_EMAIL]
@@ -331,7 +348,7 @@ class Command(NoArgsCommand):
except EmailFeedSetting.DoesNotExist:
pass
- if user.tag_filter_setting == 'interesting':
+ if user.email_tag_filter_strategy == const.INCLUDE_INTERESTING:
extend_question_list(q_all_A, q_list)
extend_question_list(q_all_B, q_list)
@@ -341,7 +358,7 @@ class Command(NoArgsCommand):
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':
+ if user.email_tag_filter_strategy == const.EXCLUDE_IGNORED:
extend_question_list(q_all_A, q_list, limit=True)
extend_question_list(q_all_B, q_list, limit=True)
@@ -527,14 +544,20 @@ class Command(NoArgsCommand):
)
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]}
+ text += _(
+ 'go to %(email_settings_link)s to change '
+ 'frequency of email updates or '
+ '%(admin_email)s administrator'
+ ) % {
+ 'email_settings_link': link,
+ 'admin_email': django_settings.ADMINS[0][1]
+ }
if DEBUG_THIS_COMMAND == True:
- recipient_email = settings.ADMINS[0][1]
+ recipient_email = django_settings.ADMINS[0][1]
else:
recipient_email = user.email
- send_mail(
+ mail.send_mail(
subject_line = subject_line,
body_text = text,
recipient_list = [recipient_email]
diff --git a/askbot/management/commands/subscribe_everyone.py b/askbot/management/commands/subscribe_everyone.py
index 039fc1e3..12f7bed2 100644
--- a/askbot/management/commands/subscribe_everyone.py
+++ b/askbot/management/commands/subscribe_everyone.py
@@ -1,7 +1,6 @@
from django.core.management.base import NoArgsCommand
from django.db import connection
from askbot.models import EmailFeedSetting, User
-from django.core.mail import EmailMessage
class Command(NoArgsCommand):
def handle_noargs(self, **options):
diff --git a/askbot/middleware/cancel.py b/askbot/middleware/cancel.py
index 45764d82..f13d8d69 100644
--- a/askbot/middleware/cancel.py
+++ b/askbot/middleware/cancel.py
@@ -1,6 +1,5 @@
from django.http import HttpResponseRedirect
from askbot.utils.forms import get_next_url
-import logging
class CancelActionMiddleware(object):
def process_view(self, request, view_func, view_args, view_kwargs):
if 'cancel' in request.REQUEST:
diff --git a/askbot/middleware/pagesize.py b/askbot/middleware/pagesize.py
index d4bec017..f10607ad 100644
--- a/askbot/middleware/pagesize.py
+++ b/askbot/middleware/pagesize.py
@@ -4,6 +4,7 @@ import sys
from django.http import HttpResponse, Http404
from django.template import RequestContext
from django.conf import settings
+from askbot import utils
# used in questions
QUESTIONS_PAGE_SIZE = 10
@@ -49,6 +50,8 @@ class QuestionsPageSizeMiddleware(object):
else:
#todo - we have a strange requirement - maybe remove
#500.html needs RequestContext, while handler500 only receives Context
- from askbot.skins.loaders import ENV
- template = ENV.get_template('500.jinja.html')
+ #need to log some more details about the request
+ logging.critical(utils.http.get_request_info(request))
+ from askbot.skins.loaders import get_template
+ template = get_template('500.jinja.html', request)
return HttpResponse(template.render(RequestContext(request)))
diff --git a/askbot/middleware/view_log.py b/askbot/middleware/view_log.py
index 3dbbd4a8..8f036077 100644
--- a/askbot/middleware/view_log.py
+++ b/askbot/middleware/view_log.py
@@ -1,44 +1,40 @@
+"""This module records the site visits by the authenticaded
+users and heps maintain the state of the search (for all visitors).
+
+Included here is the ViewLogMiddleware
+"""
import logging
+import datetime
from django.conf import settings
+from django.views.static import serve
+from django.views.i18n import javascript_catalog
+from askbot.models import signals
from askbot.views.readers import questions as questions_view
from askbot.views.commands import vote
-from django.views.static import serve
from askbot.views.writers import delete_comment, post_comments, retag_question
from askbot.views.readers import revisions
+from askbot.views.meta import media
+from askbot.search.state_manager import ViewLog
#todo: the list is getting bigger and bigger - maybe there is a better way to
#trigger reset of sarch state?
-IGNORED_VIEWS = (serve, vote, delete_comment, post_comments,
- retag_question, revisions)
-
-class ViewLog(object):
- """must be modified only in this middlware
- however, can be read anywhere else
- """
- def __init__(self):
- self.views = []
- self.depth = 3 #todo maybe move this to const.py
-
- def get_previous(self, num):
- if num > self.depth - 1:
- raise Exception("view log depth exceeded")
- elif num < 0:
- raise Exception("num must be positive");
- elif num <= len(self.views) - 1:
- return self.views[num]
- else:
- return None
+IGNORED_VIEWS = (serve, vote, media, delete_comment, post_comments,
+ retag_question, revisions, javascript_catalog)
- def set_current(self, view_name):
- self.views.insert(0, view_name)
- if len(self.views) > self.depth:
- self.views.pop()
-
- def __str__(self):
- return str(self.views) + ' depth=%d' % self.depth
class ViewLogMiddleware(object):
+ """ViewLogMiddleware does two things: tracks visits of pages for the
+ stateful site search and sends the site_visited signal
+ """
def process_view(self, request, view_func, view_args, view_kwargs):
+ #send the site_visited signal for the authenticated users
+ if request.user.is_authenticated():
+ signals.site_visited.send(None, #this signal has no sender
+ user = request.user,
+ timestamp = datetime.datetime.now()
+ )
+
+ #remaining stuff is for the search state
if view_func == questions_view:
view_str = 'questions'
elif view_func in IGNORED_VIEWS:
@@ -57,10 +53,6 @@ class ViewLogMiddleware(object):
except ImportError:
pass
- if request.user.is_authenticated():
- user_name = request.user.username
- else:
- user_name = request.META['REMOTE_ADDR']
logging.debug('user %s, view %s' % (request.user.username, view_str))
logging.debug('next url is %s' % request.REQUEST.get('next','nothing'))
diff --git a/askbot/migrations/0025_transfer_flagged_items_to_activity.py b/askbot/migrations/0025_transfer_flagged_items_to_activity.py
index 6c40bbbe..0da59629 100644
--- a/askbot/migrations/0025_transfer_flagged_items_to_activity.py
+++ b/askbot/migrations/0025_transfer_flagged_items_to_activity.py
@@ -1,8 +1,6 @@
# encoding: utf-8
-import datetime
-from south.db import db
+#from south.db import db
from south.v2 import DataMigration
-from django.db import models
from askbot.migrations_api.version1 import API
from askbot import const
@@ -22,19 +20,19 @@ class Migration(DataMigration):
for flag in orm.FlaggedItem.objects.all():
activity_items = api.get_activity_items_for_object(flag)
if len(activity_items) == 0:#fix a glitch
- activity = orm.Activity(
- user = flag.user,
- active_at = flag.flagged_at,
- activity_type = OFFENSIVE
- )
+ activity = orm.Activity()
elif len(activity_items) == 1:
activity = activity_items[0]
else:
raise ValueError('cannot have >1 flagged items per activity')
- assert(activity.user==flag.user)
- assert(activity.content_type==flag.content_type)
- assert(activity.object_id==flag.object_id)
+
+ activity.user = flag.user
+ activity.active_at = flag.flagged_at
+ activity.activity_type = OFFENSIVE
+ activity.content_type = flag.content_type
+ activity.object_id = flag.object_id
activity.question = api.get_origin_post_from_content_object(flag)
+
activity.save()
api.add_recipients_to_activity(moderators, activity)
flag.delete()
@@ -44,7 +42,6 @@ class Migration(DataMigration):
question reference is not deleted either
"""
activity_items = orm.Activity.objects.filter(activity_type=OFFENSIVE)
- api = API(orm)
for activity in activity_items:
flag = orm.FlaggedItem(
user = activity.user,
diff --git a/askbot/migrations/0033_add__consecutive_days_visit_count__to__auth_user.py b/askbot/migrations/0033_add__consecutive_days_visit_count__to__auth_user.py
new file mode 100644
index 00000000..580c2f25
--- /dev/null
+++ b/askbot/migrations/0033_add__consecutive_days_visit_count__to__auth_user.py
@@ -0,0 +1,309 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding field 'User.consecutive_days_visit_count'
+ try:
+ db.add_column(
+ u'auth_user',
+ 'consecutive_days_visit_count',
+ self.gf('django.db.models.fields.IntegerField')(default = 0, max_length = 2),
+ keep_default=False
+ )
+ except:
+ pass
+
+
+ def backwards(self, orm):
+
+ # Deleting field 'User.consecutive_days_visit_count'
+ db.delete_column(u'auth_user', 'consecutive_days_visit_count')
+
+
+ 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', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'through': "'ActivityAuditStatus'", 'to': "orm['auth.User']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ '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.BadgeData']"}),
+ '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.badgedata': {
+ 'Meta': {'object_name': 'BadgeData'},
+ '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']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'})
+ },
+ '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', [], {}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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.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'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ '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']", 'null': 'True', 'blank': 'True'}),
+ '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.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']", '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'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'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_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'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ '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'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0034_auto__add_field_user_avatar_url.py b/askbot/migrations/0034_auto__add_field_user_avatar_url.py
new file mode 100644
index 00000000..fe50057b
--- /dev/null
+++ b/askbot/migrations/0034_auto__add_field_user_avatar_url.py
@@ -0,0 +1,305 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding field 'Tag.avatar_url'
+ try:
+ db.add_column(u'auth_user', 'has_custom_avatar', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False)
+ except:
+ pass
+
+
+ def backwards(self, orm):
+
+ # Deleting field 'Tag.avatar_url'
+ db.delete_column(u'auth_user', 'has_custom_avatar')
+
+ 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', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'through': "'ActivityAuditStatus'", 'to': "orm['auth.User']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ '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.BadgeData']"}),
+ '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.badgedata': {
+ 'Meta': {'object_name': 'BadgeData'},
+ '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']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'})
+ },
+ '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', [], {}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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.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'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ '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']", 'null': 'True', 'blank': 'True'}),
+ '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.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']", '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'}),
+ 'avatar_url': ('django.db.models.fields.URLField', [], {'default': "''", 'max_length': '200'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'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'}),
+ 'has_custom_avatar': ('django.db.models.fields.BooleanField', [], {'default': '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_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'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ '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'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0035_add_country_fields_to_user.py b/askbot/migrations/0035_add_country_fields_to_user.py
new file mode 100644
index 00000000..02dd404c
--- /dev/null
+++ b/askbot/migrations/0035_add_country_fields_to_user.py
@@ -0,0 +1,309 @@
+# 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 country fields to the model auth_user
+ try:
+ db.add_column(u'auth_user', 'country', self.gf('django_countries.fields.CountryField')(max_length=2, blank=True, null=True))
+ db.add_column(u'auth_user', 'show_country', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True))
+ except:
+ pass
+
+
+ def backwards(self, orm):
+
+ # Deleting country fields
+ db.delete_column(u'auth_user', 'country')
+ db.delete_column(u'auth_user', 'show_country')
+
+
+ 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', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'through': "'ActivityAuditStatus'", 'to': "orm['auth.User']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ '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.BadgeData']"}),
+ '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.badgedata': {
+ 'Meta': {'object_name': 'BadgeData'},
+ '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']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'})
+ },
+ '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', [], {}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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.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'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ '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']", 'null': 'True', 'blank': 'True'}),
+ '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.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']", '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'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True', 'null': 'True'}),
+ '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'}),
+ 'has_custom_avatar': ('django.db.models.fields.BooleanField', [], {'default': '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_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'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ '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'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0036_auto__add_field_anonymousquestion_is_anonymous__add_field_questionrevi.py b/askbot/migrations/0036_auto__add_field_anonymousquestion_is_anonymous__add_field_questionrevi.py
new file mode 100644
index 00000000..e515b402
--- /dev/null
+++ b/askbot/migrations/0036_auto__add_field_anonymousquestion_is_anonymous__add_field_questionrevi.py
@@ -0,0 +1,319 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding field 'AnonymousQuestion.is_anonymous'
+ db.add_column('askbot_anonymousquestion', 'is_anonymous', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)
+
+ # Adding field 'QuestionRevision.is_anonymous'
+ db.add_column(u'question_revision', 'is_anonymous', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)
+
+ # Adding field 'Question.is_anonymous'
+ db.add_column(u'question', 'is_anonymous', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)
+
+
+ def backwards(self, orm):
+
+ # Deleting field 'AnonymousQuestion.is_anonymous'
+ db.delete_column('askbot_anonymousquestion', 'is_anonymous')
+
+ # Deleting field 'QuestionRevision.is_anonymous'
+ db.delete_column(u'question_revision', 'is_anonymous')
+
+ # Deleting field 'Question.is_anonymous'
+ db.delete_column(u'question', 'is_anonymous')
+
+
+ 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', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'through': "'ActivityAuditStatus'", 'to': "orm['auth.User']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ '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'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ '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.BadgeData']"}),
+ '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.badgedata': {
+ 'Meta': {'object_name': 'BadgeData'},
+ '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']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'})
+ },
+ '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', [], {}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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.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'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': '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'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': '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'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ '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']", 'null': 'True', 'blank': 'True'}),
+ '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.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']", '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'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ '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'}),
+ 'has_custom_avatar': ('django.db.models.fields.BooleanField', [], {'default': '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_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'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ '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'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0037_add_marked_tags_to_user_profile.py b/askbot/migrations/0037_add_marked_tags_to_user_profile.py
new file mode 100644
index 00000000..f10f53be
--- /dev/null
+++ b/askbot/migrations/0037_add_marked_tags_to_user_profile.py
@@ -0,0 +1,315 @@
+# 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):
+
+ try:
+ # Adding field 'User.interesting_tags'
+ db.add_column(u'auth_user', 'interesting_tags', self.gf('django.db.models.fields.TextField')(blank=True, default = ''), keep_default=False)
+ # Adding field 'User.ignored_tags'
+ db.add_column(u'auth_user', 'ignored_tags', self.gf('django.db.models.fields.TextField')(blank=True, default = ''), keep_default=False)
+ except:
+ pass
+
+ def backwards(self, orm):
+
+ # Deleting field 'User.interesting_tags'
+ db.delete_column('auth_user', 'interesting_tags')
+ # Deleting field 'User.ignored_tags'
+ db.delete_column('auth_user', 'ignored_tags')
+
+
+ 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', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'through': "'ActivityAuditStatus'", 'to': "orm['auth.User']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ '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'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ '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.BadgeData']"}),
+ '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.badgedata': {
+ 'Meta': {'object_name': 'BadgeData'},
+ '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']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'})
+ },
+ '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', [], {}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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.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'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': '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'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': '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'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ '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']", 'null': 'True', 'blank': 'True'}),
+ '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.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']", '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'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ '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'}),
+ 'has_custom_avatar': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', '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'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ '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'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0038_add_tag_filter_strategies.py b/askbot/migrations/0038_add_tag_filter_strategies.py
new file mode 100644
index 00000000..c2596366
--- /dev/null
+++ b/askbot/migrations/0038_add_tag_filter_strategies.py
@@ -0,0 +1,321 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+from askbot import const
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model country fields to the model auth_user
+ try:
+ db.add_column(
+ u'auth_user',
+ 'email_tag_filter_strategy',
+ self.gf(
+ 'django.db.models.fields.SmallIntegerField'
+ )(default = const.EXCLUDE_IGNORED)
+ )
+ db.add_column(
+ u'auth_user',
+ 'display_tag_filter_strategy',
+ self.gf(
+ 'django.db.models.fields.SmallIntegerField'
+ )(default = const.INCLUDE_ALL)
+ )
+ except:
+ pass
+
+
+ def backwards(self, orm):
+
+ db.delete_column(u'auth_user', 'email_tag_filter_strategy')
+ db.delete_column(u'auth_user', 'display_tag_filter_strategy')
+
+
+ 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', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'through': "'ActivityAuditStatus'", 'to': "orm['auth.User']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ '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.BadgeData']"}),
+ '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.badgedata': {
+ 'Meta': {'object_name': 'BadgeData'},
+ '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']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'})
+ },
+ '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', [], {}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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.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'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ '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']", 'null': 'True', 'blank': 'True'}),
+ '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.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']", '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'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True', 'null': 'True'}),
+ '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'}),
+ 'has_custom_avatar': ('django.db.models.fields.BooleanField', [], {'default': '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_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'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ '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'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0039_populate_tag_filter_strategies.py b/askbot/migrations/0039_populate_tag_filter_strategies.py
new file mode 100644
index 00000000..6971cdc0
--- /dev/null
+++ b/askbot/migrations/0039_populate_tag_filter_strategies.py
@@ -0,0 +1,333 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from askbot import const
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ """populate email and display filter strategies"""
+ for user in orm['auth.User'].objects.all():
+ old_email_setting = user.tag_filter_setting
+ if old_email_setting == 'ignored':
+ user.email_tag_filter_strategy = const.EXCLUDE_IGNORED
+ elif old_email_setting == 'interesting':
+ user.email_tag_filter_strategy = const.INCLUDE_INTERESTING
+
+ hide_ignored = user.hide_ignored_questions
+ if hide_ignored == True:
+ user.display_tag_filter_strategy = const.EXCLUDE_IGNORED
+
+ user.save()
+
+ def backwards(self, orm):
+ """populate ``User.tag_filter_setting``
+ and
+ ``User.hide_ignored_questions
+ """
+ for user in orm['auth.User'].objects.all():
+ email_strategy = user.email_tag_filter_strategy
+ if email_strategy == const.EXCLUDE_IGNORED:
+ user.tag_filter_setting = 'ignored'
+ elif email_strategy == const.INCLUDE_INTERESTING:
+ user.tag_filter_setting = 'interesting'
+
+ if user.display_tag_filter_strategy == const.EXCLUDE_IGNORED:
+ user.hide_ignored_questions = True
+
+ user.save()
+
+
+ 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'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'through': "'ActivityAuditStatus'", 'to': "orm['auth.User']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ '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'})
+ },
+ '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'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ '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'})
+ },
+ 'askbot.answer': {
+ 'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},
+ 'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ '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'}),
+ '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'}),
+ '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'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.answerrevision': {
+ 'Meta': {'ordering': "('-revision',)", '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.BadgeData']"}),
+ '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'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ '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']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.comment': {
+ 'Meta': {'ordering': "('-added_at',)", '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', [], {}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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.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'}),
+ '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'}),
+ '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'}),
+ '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'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ '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'}),
+ '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'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.questionrevision': {
+ 'Meta': {'ordering': "('-revision',)", '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'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ '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'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ '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']", 'null': 'True', 'blank': 'True'}),
+ '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': {'ordering': "('-used_count', 'name')", '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'}),
+ '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.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']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'codename')", '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'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ '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'}),
+ 'has_custom_avatar': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ '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'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ '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': {'ordering': "('name',)", '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 = ['askbot']
diff --git a/askbot/migrations/0040_delete_old_tag_filter_strategies.py b/askbot/migrations/0040_delete_old_tag_filter_strategies.py
new file mode 100644
index 00000000..5743194e
--- /dev/null
+++ b/askbot/migrations/0040_delete_old_tag_filter_strategies.py
@@ -0,0 +1,317 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+from askbot import const
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model country fields to the model auth_user
+ db.delete_column(u'auth_user', 'hide_ignored_questions')
+ db.delete_column(u'auth_user', 'tag_filter_setting')
+
+
+ def backwards(self, orm):
+ db.add_column(
+ u'auth_user',
+ 'hide_ignored_questions',
+ self.gf(
+ 'django.db.models.fields.BooleanField'
+ )(default = False)
+ )
+ db.add_column(
+ u'auth_user',
+ 'tag_filter_setting',
+ self.gf(
+ 'django.db.models.fields.CharField'
+ )(default = 'ignored', max_length = 16)
+ )
+
+
+ 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', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'through': "'ActivityAuditStatus'", 'to': "orm['auth.User']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ '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.BadgeData']"}),
+ '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.badgedata': {
+ 'Meta': {'object_name': 'BadgeData'},
+ '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']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'})
+ },
+ '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', [], {}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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.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'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ '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']", 'null': 'True', 'blank': 'True'}),
+ '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.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']", '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'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True', 'null': 'True'}),
+ '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'}),
+ 'has_custom_avatar': ('django.db.models.fields.BooleanField', [], {'default': '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_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'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ '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'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py
index 098271e0..a4d21caa 100644
--- a/askbot/models/__init__.py
+++ b/askbot/models/__init__.py
@@ -2,8 +2,8 @@ import logging
import re
import hashlib
import datetime
-from django.core.urlresolvers import reverse
-from askbot.search.indexer import create_fulltext_indexes
+import urllib
+from django.core.urlresolvers import reverse, NoReverseMatch
from django.db.models import signals as django_signals
from django.template import Context
from django.utils.translation import ugettext as _
@@ -14,6 +14,7 @@ from django.db import models
from django.conf import settings as django_settings
from django.contrib.contenttypes.models import ContentType
from django.core import exceptions as django_exceptions
+from django_countries.fields import CountryField
import askbot
from askbot import exceptions as askbot_exceptions
from askbot import const
@@ -33,7 +34,7 @@ from askbot import auth
from askbot.utils.decorators import auto_now_timestamp
from askbot.utils.slug import slugify
from askbot.utils.diff import textDiff as htmldiff
-from askbot.utils.mail import send_mail
+from askbot.utils import mail
from askbot import startup_procedures
startup_procedures.run()
@@ -53,33 +54,104 @@ User.add_to_class(
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('reputation',
+ models.PositiveIntegerField(default=const.MIN_REPUTATION)
+)
User.add_to_class('gravatar', models.CharField(max_length=32))
+User.add_to_class('has_custom_avatar', models.BooleanField(default=False))
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(
+ '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))
+#location field is actually city
User.add_to_class('location', models.CharField(max_length=100, blank=True))
+User.add_to_class('country', CountryField(blank = True))
+User.add_to_class('show_country', models.BooleanField(default = False))
+
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'
- )
- )
+#interesting tags and ignored tags are to store wildcard tag selections only
+User.add_to_class('interesting_tags', models.TextField(blank = True))
+User.add_to_class('ignored_tags', models.TextField(blank = True))
+User.add_to_class(
+ 'email_tag_filter_strategy',
+ models.SmallIntegerField(
+ choices=const.TAG_FILTER_STRATEGY_CHOICES,
+ default=const.EXCLUDE_IGNORED
+ )
+)
+User.add_to_class(
+ 'display_tag_filter_strategy',
+ models.SmallIntegerField(
+ choices=const.TAG_FILTER_STRATEGY_CHOICES,
+ default=const.INCLUDE_ALL
+ )
+)
+
User.add_to_class('new_response_count', models.IntegerField(default=0))
User.add_to_class('seen_response_count', models.IntegerField(default=0))
+User.add_to_class('consecutive_days_visit_count', models.IntegerField(default = 0))
+
+GRAVATAR_TEMPLATE = "http://www.gravatar.com/avatar/%(gravatar)s?" + \
+ "s=%(size)d&amp;d=%(type)s&amp;r=PG"
+
+def user_get_gravatar_url(self, size):
+ """returns gravatar url
+ currently identicon is the only supported type
+ """
+ return GRAVATAR_TEMPLATE % {
+ 'gravatar': self.gravatar,
+ 'size': size,
+ 'type': 'identicon'
+ }
+
+def user_get_avatar_url(self, size):
+ """returns avatar url - by default - gravatar,
+ but if application django-avatar is installed
+ it will use avatar provided through that app
+ """
+ if 'avatar' in django_settings.INSTALLED_APPS:
+ if self.has_custom_avatar == False:
+ import avatar
+ if avatar.settings.AVATAR_GRAVATAR_BACKUP:
+ return self.get_gravatar_url(size)
+ else:
+ return avatar.utils.get_default_avatar_url()
+ kwargs = {'user': urllib.quote_plus(self.username), 'size': size}
+ try:
+ return reverse('avatar_render_primary', kwargs = kwargs)
+ except NoReverseMatch:
+ message = 'Please, make sure that avatar urls are in the urls.py '\
+ 'or update your django-avatar app, '\
+ 'currently it is impossible to serve avatars.'
+ logging.critical(message)
+ raise django_exceptions.ImproperlyConfigured(message)
+ else:
+ return self.get_gravatar_url(size)
+
+
+def user_update_has_custom_avatar(self):
+ """counts number of custom avatars
+ and if zero, sets has_custom_avatar to False,
+ True otherwise. The method is called only if
+ avatar application is installed.
+ Saves the object.
+ """
+ if self.avatar_set.count() > 0:
+ self.has_custom_avatar = True
+ else:
+ self.has_custom_avatar = False
+ self.save()
def user_get_old_vote_for_post(self, post):
@@ -103,6 +175,63 @@ def user_get_old_vote_for_post(self, post):
return old_votes[0]
+def user_has_affinity_to_question(self, question = None, affinity_type = None):
+ """returns True if number of tag overlap of the user tag
+ selection with the question is 0 and False otherwise
+ affinity_type can be either "like" or "dislike"
+ """
+ if affinity_type == 'like':
+ tag_selection_type = 'good'
+ wildcards = self.interesting_tags.split()
+ elif affinity_type == 'dislike':
+ tag_selection_type = 'bad'
+ wildcards = self.ignored_tags.split()
+ else:
+ raise ValueError('unexpected affinity type %s' % str(affinity_type))
+
+ question_tags = question.tags.all()
+ intersecting_tag_selections = self.tag_selections.filter(
+ tag__in = question_tags,
+ reason = tag_selection_type
+ )
+ #count number of overlapping tags
+ if intersecting_tag_selections.count() > 0:
+ return True
+ elif askbot_settings.USE_WILDCARD_TAGS == False:
+ return False
+
+ #match question tags against wildcards
+ for tag in question_tags:
+ for wildcard in wildcards:
+ if tag.name.startswith(wildcard[:-1]):
+ return True
+ return False
+
+
+def user_has_ignored_wildcard_tags(self):
+ """True if wildcard tags are on and
+ user has some"""
+ return (
+ askbot_settings.USE_WILDCARD_TAGS \
+ and self.ignored_tags != ''
+ )
+
+
+def user_has_interesting_wildcard_tags(self):
+ """True in wildcard tags aro on and
+ user has nome interesting wildcard tags selected
+ """
+ return (
+ askbot_settings.USE_WILDCARD_TAGS \
+ and self.interesting_tags != ''
+ )
+
+
+def user_can_have_strong_url(self):
+ """True if user's homepage url can be
+ followed by the search engine crawlers"""
+ return (self.reputation >= askbot_settings.MIN_REP_TO_HAVE_STRONG_URL)
+
def _assert_user_can(
user = None,
post = None, #related post (may be parent)
@@ -290,15 +419,23 @@ def user_assert_can_edit_comment(self, comment = None):
return
else:
if comment.user == self:
- now = datetime.datetime.now()
- if now - comment.added_at > datetime.timedelta(0, 600):
- if comment.is_last():
- return
- error_message = _(
- 'Sorry, comments (except the last one) are editable only within 10 minutes from posting'
- )
- raise django_exceptions.PermissionDenied(error_message)
- return
+ if askbot_settings.USE_TIME_LIMIT_TO_EDIT_COMMENT:
+ now = datetime.datetime.now()
+ delta_seconds = 60 * askbot_settings.MINUTES_TO_EDIT_COMMENT
+ if now - comment.added_at > datetime.timedelta(0, delta_seconds):
+ if comment.is_last():
+ return
+ error_message = ungettext(
+ 'Sorry, comments (except the last one) are editable only '
+ 'within %(minutes)s minute from posting',
+ 'Sorry, comments (except the last one) are editable only '
+ 'within %(minutes)s minutes from posting',
+ askbot_settings.MINUTES_TO_EDIT_COMMENT
+ ) % {'minutes': askbot_settings.MINUTES_TO_EDIT_COMMENT}
+ raise django_exceptions.PermissionDenied(error_message)
+ return
+ else:
+ return
error_message = _(
'Sorry, but only post owners or moderators can edit comments'
@@ -306,7 +443,6 @@ def user_assert_can_edit_comment(self, comment = None):
raise django_exceptions.PermissionDenied(error_message)
-
def user_assert_can_post_comment(self, parent_post = None):
"""raises exceptions.PermissionDenied if
user cannot post comment
@@ -717,8 +853,71 @@ def user_post_comment(
comment = body_text,
added_at = timestamp,
)
+ award_badges_signal.send(None,
+ event = 'post_comment',
+ actor = self,
+ context_object = comment,
+ timestamp = timestamp
+ )
return comment
+def user_mark_tags(
+ self,
+ tagnames = None,
+ wildcards = None,
+ reason = None,
+ action = None
+ ):
+ """subscribe for or ignore a list of tags
+
+ * ``tagnames`` and ``wildcards`` are lists of
+ pure tags and wildcard tags, respectively
+ * ``reason`` - either "good" or "bad"
+ * ``action`` - eitrer "add" or "remove"
+ """
+ cleaned_wildcards = list()
+ assert(reason in ('good', 'bad'))
+ assert(action in ('add', 'remove'))
+ if wildcards:
+ cleaned_wildcards = self.update_wildcard_tag_selections(
+ action = action,
+ reason = reason,
+ wildcards = wildcards
+ )
+ if tagnames is None:
+ tagnames = list()
+
+ #below we update normal tag selections
+ marked_ts = MarkedTag.objects.filter(
+ user = self,
+ tag__name__in = tagnames
+ )
+ #todo: use the user api methods here instead of the straight ORM
+ cleaned_tagnames = list() #those that were actually updated
+ if action == 'remove':
+ logging.debug('deleting tag marks: %s' % ','.join(tagnames))
+ marked_ts.delete()
+ else:
+ marked_names = marked_ts.values_list('tag__name', flat = True)
+ if len(marked_names) < len(tagnames):
+ unmarked_names = set(tagnames).difference(set(marked_names))
+ ts = Tag.objects.filter(name__in = unmarked_names)
+ new_marks = list()
+ for tag in ts:
+ MarkedTag(
+ user = self,
+ reason = reason,
+ tag = tag
+ ).save()
+ new_marks.append(tag.name)
+ cleaned_tagnames.extend(marked_names)
+ cleaned_tagnames.extend(new_marks)
+ else:
+ marked_ts.update(reason=reason)
+ cleaned_tagnames = tagnames
+
+ return cleaned_tagnames, cleaned_wildcards
+
@auto_now_timestamp
def user_retag_question(
self,
@@ -919,6 +1118,7 @@ def user_post_question(
body_text = None,
tags = None,
wiki = False,
+ is_anonymous = False,
timestamp = None
):
@@ -939,7 +1139,8 @@ def user_post_question(
text = body_text,
tagnames = tags,
added_at = timestamp,
- wiki = wiki
+ wiki = wiki,
+ is_anonymous = is_anonymous,
)
return question
@@ -960,7 +1161,8 @@ def user_edit_question(
revision_comment = None,
tags = None,
wiki = False,
- timestamp = None
+ edit_anonymously = False,
+ timestamp = None,
):
self.assert_can_edit_question(question)
question.apply_edit(
@@ -972,6 +1174,7 @@ def user_edit_question(
comment = revision_comment,
tags = tags,
wiki = wiki,
+ edit_anonymously = edit_anonymously,
)
award_badges_signal.send(None,
event = 'edit_question',
@@ -1116,8 +1319,20 @@ def user_is_username_taken(cls,username):
return False
def user_is_administrator(self):
- return (self.is_superuser or self.is_staff)
-
+ """checks whether user in the forum site administrator
+ the admin must be both superuser and staff member
+ the latter is because staff membership is required
+ to access the live settings"""
+ return (self.is_superuser and self.is_staff)
+
+def user_remove_admin_status(self):
+ self.is_staff = False
+ self.is_superuser = False
+
+def user_set_admin_status(self):
+ self.is_staff = True
+ self.is_superuser = True
+
def user_is_moderator(self):
return (self.status == 'm' and self.is_administrator() == False)
@@ -1133,6 +1348,34 @@ def user_is_watched(self):
def user_is_approved(self):
return (self.status == 'a')
+def user_is_owner_of(self, obj):
+ """True if user owns object
+ False otherwise
+ """
+ if isinstance(obj, Question):
+ return self == obj.author
+ else:
+ raise NotImplementedError()
+
+def get_name_of_anonymous_user():
+ """Returns name of the anonymous user
+ either comes from the live settyngs or the language
+ translation
+
+ very possible that this function does not belong here
+ """
+ if askbot_settings.NAME_OF_ANONYMOUS_USER:
+ return askbot_settings.NAME_OF_ANONYMOUS_USER
+ else:
+ return _('Anonymous')
+
+def user_get_anonymous_name(self):
+ """Returns name of anonymous user
+ - convinience method for use in the template
+ macros that accept user as parameter
+ """
+ return get_name_of_anonymous_user()
+
def user_set_status(self, new_status):
"""sets new status to user
@@ -1156,9 +1399,9 @@ def user_set_status(self, new_status):
return
#clear admin status if user was an administrator
- if self.is_administrator:
- self.is_superuser = False
- self.is_staff = False
+ #because this function is not dealing with the site admins
+ if self.is_administrator():
+ self.remove_admin_status()
self.status = new_status
self.save()
@@ -1521,12 +1764,59 @@ def user_clean_response_counts(user):
'seen response count wanted to go below zero form %s' % user.username
)
+def user_receive_reputation(self, num_points):
+ new_points = self.reputation + num_points
+ if new_points > 0:
+ self.reputation = new_points
+ else:
+ self.reputation = const.MIN_REPUTATION
+
+def user_update_wildcard_tag_selections(
+ self,
+ action = None,
+ reason = None,
+ wildcards = None,
+ ):
+ """updates the user selection of wildcard tags
+ and saves the user object to the database
+ """
+ new_tags = set(wildcards)
+ interesting = set(self.interesting_tags.split())
+ ignored = set(self.ignored_tags.split())
+
+ target_set = interesting
+ other_set = ignored
+ if reason == 'good':
+ pass
+ elif reason == 'bad':
+ target_set = ignored
+ other_set = interesting
+ else:
+ assert(action == 'remove')
+
+ if action == 'add':
+ target_set.update(new_tags)
+ other_set.difference_update(new_tags)
+ else:
+ target_set.difference_update(new_tags)
+ other_set.difference_update(new_tags)
+
+ self.interesting_tags = ' '.join(interesting)
+ self.ignored_tags = ' '.join(ignored)
+ self.save()
+ return new_tags
+
+
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('get_avatar_url', user_get_avatar_url)
+User.add_to_class('get_gravatar_url', user_get_gravatar_url)
+User.add_to_class('get_anonymous_name', user_get_anonymous_name)
+User.add_to_class('update_has_custom_avatar', user_update_has_custom_avatar)
User.add_to_class('post_question', user_post_question)
User.add_to_class('edit_question', user_edit_question)
User.add_to_class('retag_question', user_retag_question)
@@ -1539,6 +1829,7 @@ User.add_to_class('visit_question', user_visit_question)
User.add_to_class('upvote', upvote)
User.add_to_class('downvote', downvote)
User.add_to_class('flag_post', flag_post)
+User.add_to_class('receive_reputation', user_receive_reputation)
User.add_to_class('get_flags', user_get_flags)
User.add_to_class('get_flag_count_posted_today', user_get_flag_count_posted_today)
User.add_to_class('get_flags_for_post', user_get_flags_for_post)
@@ -1549,17 +1840,25 @@ User.add_to_class('delete_messages', delete_messages)
User.add_to_class('toggle_favorite_question', toggle_favorite_question)
User.add_to_class('follow_question', user_follow_question)
User.add_to_class('unfollow_question', user_unfollow_question)
+User.add_to_class('mark_tags', user_mark_tags)
User.add_to_class('is_following', user_is_following)
User.add_to_class('decrement_response_count', user_decrement_response_count)
User.add_to_class('increment_response_count', user_increment_response_count)
User.add_to_class('clean_response_counts', user_clean_response_counts)
+User.add_to_class('can_have_strong_url', user_can_have_strong_url)
User.add_to_class('is_administrator', user_is_administrator)
+User.add_to_class('set_admin_status', user_set_admin_status)
+User.add_to_class('remove_admin_status', user_remove_admin_status)
User.add_to_class('is_moderator', user_is_moderator)
User.add_to_class('is_approved', user_is_approved)
User.add_to_class('is_watched', user_is_watched)
User.add_to_class('is_suspended', user_is_suspended)
User.add_to_class('is_blocked', user_is_blocked)
+User.add_to_class('is_owner_of', user_is_owner_of)
+User.add_to_class('has_interesting_wildcard_tags', user_has_interesting_wildcard_tags)
+User.add_to_class('has_ignored_wildcard_tags', user_has_ignored_wildcard_tags)
User.add_to_class('can_moderate_user', user_can_moderate_user)
+User.add_to_class('has_affinity_to_question', user_has_affinity_to_question)
User.add_to_class('moderate_user_reputation', user_moderate_user_reputation)
User.add_to_class('set_status', user_set_status)
User.add_to_class('get_status_display', user_get_status_display)
@@ -1573,6 +1872,10 @@ User.add_to_class('close_question', user_close_question)
User.add_to_class('reopen_question', user_reopen_question)
User.add_to_class('accept_best_answer', user_accept_best_answer)
User.add_to_class('unaccept_best_answer', user_unaccept_best_answer)
+User.add_to_class(
+ 'update_wildcard_tag_selections',
+ user_update_wildcard_tag_selections
+)
#assertions
User.add_to_class('assert_can_vote_for_post', user_assert_can_vote_for_post)
@@ -1676,6 +1979,20 @@ def format_instant_notification_email(
#todo: remove hardcoded style
else:
content_preview = post.html
+ tag_style = "white-space: nowrap; " \
+ + "font-size: 11px; color: #333;" \
+ + "background-color: #EEE;" \
+ + "border-left: 3px solid #777;" \
+ + "border-top: 1px solid #EEE;" \
+ + "border-bottom: 1px solid #CCC;" \
+ + "border-right: 1px solid #CCC;" \
+ + "padding: 1px 8px 1px 8px;" \
+ + "margin-right:3px;"
+ if post.post_type == 'question':#add tags to the question
+ content_preview += '<div>'
+ for tag_name in post.get_tag_names():
+ content_preview += '<span style="%s">%s</span>' % (tag_style, tag_name)
+ content_preview += '</div>'
update_data = {
'update_author_name': from_user.username,
@@ -1686,6 +2003,7 @@ def format_instant_notification_email(
'origin_post_title': origin_post.title,
'user_subscriptions_url': user_subscriptions_url,
}
+ subject_line = mail.prefix_the_subject_line(subject_line)
return subject_line, template.render(Context(update_data))
#todo: action
@@ -1708,8 +2026,8 @@ def send_instant_notifications_about_activity_in_post(
if update_activity.activity_type not in acceptable_types:
return
- from askbot.skins.loaders import ENV
- template = ENV.get_template('instant_notification.html')
+ from askbot.skins.loaders import get_template
+ template = get_template('instant_notification.html')
update_type_map = const.RESPONSE_ACTIVITY_TYPE_MAP_FOR_TEMPLATES
update_type = update_type_map[update_activity.activity_type]
@@ -1717,22 +2035,22 @@ def send_instant_notifications_about_activity_in_post(
origin_post = post.get_origin_post()
for user in recipients:
- subject_line, body_text = format_instant_notification_email(
- 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
- send_mail(
- subject_line = subject_line,
- body_text = body_text,
- recipient_list = [user.email],
- related_object = origin_post,
- activity_type = const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT
- )
+ subject_line, body_text = format_instant_notification_email(
+ 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
+ mail.send_mail(
+ subject_line = subject_line,
+ body_text = body_text,
+ recipient_list = [user.email],
+ related_object = origin_post,
+ activity_type = const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT
+ )
#todo: move to utils
@@ -1746,7 +2064,7 @@ def calculate_gravatar_hash(instance, **kwargs):
def record_post_update_activity(
post,
- newly_mentioned_users = list(),
+ newly_mentioned_users = None,
updated_by = None,
timestamp = None,
created = False,
@@ -1757,49 +2075,27 @@ def record_post_update_activity(
"""
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,
- question = post.get_origin_post()
- )
- 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
- recipients = post.get_response_receivers(
- exclude_list = [updated_by, ]
- )
-
- update_activity.add_recipients(recipients)
-
- assert(updated_by not in recipients)
-
- for user in set(recipients) | set(newly_mentioned_users):
- user.increment_response_count()
- user.save()
-
- #todo: weird thing is that only comments need the recipients
- #todo: debug these calls and then uncomment in the repo
- #argument to this call
- notification_subscribers = post.get_instant_notification_subscribers(
- potential_subscribers = recipients,
- mentioned_users = newly_mentioned_users,
- exclude_list = [updated_by, ]
- )
-
- send_instant_notifications_about_activity_in_post(
- update_activity = update_activity,
- post = post,
- recipients = notification_subscribers,
- )
+ if newly_mentioned_users is None:
+ newly_mentioned_users = list()
+
+ from askbot import tasks
+
+ tasks.record_post_update_celery_task.delay(
+ post_id = post.id,
+ post_content_type_id = ContentType.objects.get_for_model(post).id,
+ newly_mentioned_user_id_list = [u.id for u in newly_mentioned_users],
+ updated_by_id = updated_by.id,
+ timestamp = timestamp,
+ created = created,
+ )
+ #non-celery version
+ #tasks.record_post_update(
+ # post = post,
+ # newly_mentioned_users = newly_mentioned_users,
+ # updated_by = updated_by,
+ # timestamp = timestamp,
+ # created = created,
+ #)
def record_award_event(instance, created, **kwargs):
@@ -1869,18 +2165,21 @@ def record_answer_accepted(instance, created, **kwargs):
)
activity.add_recipients(recipients)
-
-def update_last_seen(instance, created, **kwargs):
+def record_user_visit(user, timestamp, **kwargs):
"""
- when user has activities, we update 'last_seen' time stamp for him
+ when user visits any pages, we update the last_seen and
+ consecutive_days_visit_count
"""
- #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 = instance.active_at
+ prev_last_seen = user.last_seen
+ user.last_seen = timestamp
+ if (user.last_seen - prev_last_seen).days == 1:
+ user.consecutive_days_visit_count += 1
+ award_badges_signal.send(None,
+ event = 'site_visit',
+ actor = user,
+ context_object = user,
+ timestamp = timestamp
+ )
user.save()
@@ -1957,12 +2256,21 @@ def record_flag_offensive(instance, mark_by, **kwargs):
)
activity.add_recipients(recipients)
-def record_update_tags(question, **kwargs):
+def record_update_tags(question, tags, user, timestamp, **kwargs):
"""
- when user updated tags of the question
+ This function sends award badges signal on each updated tag
+ the badges that respond to the 'ta
"""
+ for tag in tags:
+ award_badges_signal.send(None,
+ event = 'update_tag',
+ actor = user,
+ context_object = tag,
+ timestamp = timestamp
+ )
+
activity = Activity(
- user=question.author,
+ user=user,
active_at=datetime.datetime.now(),
content_object=question,
activity_type=const.TYPE_ACTIVITY_UPDATE_TAGS,
@@ -1997,8 +2305,23 @@ def record_user_full_updated(instance, **kwargs):
)
activity.save()
+def complete_pending_tag_subscriptions(sender, request, *args, **kwargs):
+ """save pending tag subscriptions saved in the session"""
+ if 'subscribe_for_tags' in request.session:
+ (pure_tag_names, wildcards) = request.session.pop('subscribe_for_tags')
+ request.user.mark_tags(
+ pure_tag_names,
+ wildcards,
+ reason = 'good',
+ action = 'add'
+ )
+ request.user.message_set.create(
+ message = _('Your tag subscription was saved, thanks!')
+ )
+
def post_stored_anonymous_content(
sender,
+ request,
user,
session_key,
signal,
@@ -2029,17 +2352,33 @@ def post_stored_anonymous_content(
for aa in aa_list:
aa.publish(user)
+def set_user_has_custom_avatar_flag(instance, created, **kwargs):
+ instance.user.update_has_custom_avatar()
+
+def update_user_has_custom_avatar_flag(instance, **kwargs):
+ instance.user.update_has_custom_avatar()
+
#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
)
+if 'avatar' in django_settings.INSTALLED_APPS:
+ from avatar.models import Avatar
+ django_signals.post_save.connect(
+ set_user_has_custom_avatar_flag,
+ sender=Avatar
+ )
+ django_signals.post_delete.connect(
+ update_user_has_custom_avatar_flag,
+ sender=Avatar
+ )
+
django_signals.post_delete.connect(record_cancel_vote, sender=Vote)
#change this to real m2m_changed with Django1.2
@@ -2047,9 +2386,10 @@ signals.delete_question_or_answer.connect(record_delete_question, sender=Questio
signals.delete_question_or_answer.connect(record_delete_question, sender=Answer)
signals.flag_offensive.connect(record_flag_offensive, sender=Question)
signals.flag_offensive.connect(record_flag_offensive, sender=Answer)
-signals.tags_updated.connect(record_update_tags, sender=Question)
+signals.tags_updated.connect(record_update_tags)
signals.user_updated.connect(record_user_full_updated, sender=User)
signals.user_logged_in.connect(post_stored_anonymous_content)
+signals.user_logged_in.connect(complete_pending_tag_subscriptions)
signals.post_updated.connect(
record_post_update_activity,
sender=Comment
@@ -2062,10 +2402,9 @@ signals.post_updated.connect(
record_post_update_activity,
sender=Question
)
-#post_syncdb.connect(create_fulltext_indexes)
+signals.site_visited.connect(record_user_visit)
#todo: wtf??? what is x=x about?
-signals = signals
Question = Question
QuestionRevision = QuestionRevision
@@ -2077,10 +2416,6 @@ Answer = Answer
AnswerRevision = AnswerRevision
AnonymousAnswer = AnonymousAnswer
-Tag = Tag
-Comment = Comment
-Vote = Vote
-MarkedTag = MarkedTag
BadgeData = BadgeData
Award = Award
diff --git a/askbot/models/answer.py b/askbot/models/answer.py
index 885b0e73..c268551d 100644
--- a/askbot/models/answer.py
+++ b/askbot/models/answer.py
@@ -10,7 +10,6 @@ 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 askbot.utils.slug import slugify
from askbot.utils import markup
@@ -95,6 +94,7 @@ class Answer(content.Content, DeletableContent):
parse = parse_post_text
parse_and_save = parse_and_save_post
+ is_anonymous = False #answers are never anonymous - may change
def assert_is_visible_to(self, user):
"""raises QuestionHidden or AnswerHidden"""
@@ -128,6 +128,10 @@ class Answer(content.Content, DeletableContent):
latest_revision = self.get_latest_revision()
return const.TYPE_ACTIVITY_UPDATE_ANSWER, latest_revision
+ def get_tag_names(self):
+ """return tag names on the question"""
+ return self.question.get_tag_names()
+
def apply_edit(self, edited_at=None, edited_by=None, text=None, comment=None, wiki=False):
if text is None:
diff --git a/askbot/models/badges.py b/askbot/models/badges.py
index 37477530..77d4e0ab 100644
--- a/askbot/models/badges.py
+++ b/askbot/models/badges.py
@@ -24,6 +24,7 @@ from django.utils.translation import ugettext as _
from django.dispatch import Signal
from askbot.models.repute import BadgeData, Award
from askbot.models.user import Activity
+from askbot.models.meta import Comment
from askbot.models.question import FavoriteQuestion as Fave#name collision
from askbot import const
from askbot.conf import settings as askbot_settings
@@ -700,25 +701,82 @@ class FavoriteQuestion(FavoriteTypeBadge):
return self
class Enthusiast(Badge):
- """Unimplemented stub badge"""
+ """Awarded to a user who visits the site
+ for a certain number of days in a row
+ """
def __init__(self):
super(Enthusiast, self).__init__(
key = 'enthusiast',
name = _('Enthusiast'),
level = const.SILVER_BADGE,
multiple = False,
- description = _('Visited site every day for 30 days in a row')
+ description = _(
+ 'Visited site every day for %(num)s days in a row'
+ ) % {'num': askbot_settings.ENTHUSIAST_BADGE_MIN_DAYS}
)
+ def consider_award(self, actor = None,
+ context_object = None, timestamp = None):
+ min_days = askbot_settings.ENTHUSIAST_BADGE_MIN_DAYS
+ if actor.consecutive_days_visit_count == min_days:
+ return self.award(actor, context_object, timestamp)
+ return False
+
class Commentator(Badge):
- """Unimplemented stub badge"""
+ """Commentator is a bronze badge that is
+ awarded once when user posts a certain number of
+ comments"""
def __init__(self):
super(Commentator, self).__init__(
key = 'commentator',
name = _('Commentator'),
level = const.BRONZE_BADGE,
multiple = False,
- description = _('Posted 10 comments')
+ description = _(
+ 'Posted %(num_comments)s comments'
+ ) % {'num_comments': askbot_settings.COMMENTATOR_BADGE_MIN_COMMENTS}
+ )
+
+ def consider_award(self, actor = None,
+ context_object = None, timestamp = None):
+ num_comments = Comment.objects.filter(user = actor).count()
+ if num_comments >= askbot_settings.COMMENTATOR_BADGE_MIN_COMMENTS:
+ return self.award(actor, context_object, timestamp)
+ return False
+
+class Taxonomist(Badge):
+ """Stub badge"""
+ def __init__(self):
+ super(Taxonomist, self).__init__(
+ key = 'taxonomist',
+ name = _('Taxonomist'),
+ level = const.SILVER_BADGE,
+ multiple = False,
+ description = _(
+ 'Created a tag used by %(num)s questions'
+ ) % {'num': askbot_settings.TAXONOMIST_BADGE_MIN_USE_COUNT}
+ )
+
+ def consider_award(self, actor = None,
+ context_object = None, timestamp = None):
+
+ tag = context_object
+ taxonomist_threshold = askbot_settings.TAXONOMIST_BADGE_MIN_USE_COUNT
+ #the "-1" is used because tag counts are updated in a bulk query
+ #that does not update the value in the python object
+ if tag.used_count == taxonomist_threshold - 1:
+ return self.award(tag.created_by, tag, timestamp)
+ return False
+
+class Expert(Badge):
+ """Stub badge"""
+ def __init__(self):
+ super(Expert, self).__init__(
+ key = 'expert',
+ name = _('Expert'),
+ level = const.SILVER_BADGE,
+ multiple = False,
+ description = _('Very active in one tag')
)
ORIGINAL_DATA = """
@@ -730,12 +788,10 @@ extra badges from stackexchange
* mortarboard - hit the daily reputation cap for the first time (s)
* populist - provided an answer that outscored an accepted answer two-fold or by n points, whichever is higher (m)
* reversal - provided an answer with +n points to a question of -m points
- (_('Taxonomist'), 2, _('taxonomist'), _('Created a tag used by 50 questions'), True, 0)
(_('Yearling'), 2, _('yearling'), _('Active member for a year'), False, 0),
(_('Generalist'), 2, _('generalist'), _('Active in many different tags'), False, 0),
- (_('Expert'), 2, _('expert'), _('Very active in one tag'), False, 0),
(_('Beta'), 2, _('beta'), _('Actively participated in the private beta'), False, 0),
(_('Alpha'), 2, _('alpha'), _('Actively participated in the private alpha'), False, 0),
"""
@@ -752,6 +808,7 @@ BADGES = {
'editor': Editor,
'enlightened': Enlightened,
'enthusiast': Enthusiast,
+ 'expert': Expert,
'famous-question': FamousQuestion,
'favorite-question': FavoriteQuestion,
'good-answer': GoodAnswer,
@@ -773,6 +830,7 @@ BADGES = {
'student': Student,
'supporter': Supporter,
'teacher': Teacher,
+ 'taxonomist': Taxonomist,
}
#events are sent as a parameter via signal award_badges_signal
@@ -786,8 +844,11 @@ EVENTS_TO_BADGES = {
'edit_question': (Editor, AssociateEditor),
'flag_post': (CitizenPatrol,),
'post_answer': (Necromancer,),
+ 'post_comment': (Commentator,),
'retag_question': (Organizer,),
'select_favorite_question': (FavoriteQuestion, StellarQuestion,),
+ 'site_visit': (Enthusiast,),
+ 'update_tag': (Taxonomist,),
'update_user_profile': (Autobiographer,),
'upvote_answer': (
Teacher, NiceAnswer, GoodAnswer,
@@ -802,7 +863,7 @@ EVENTS_TO_BADGES = {
}
def get_badge(name = None):
- """Get badge object by name, if none mathes the name
+ """Get badge object by name, if none matches the name
raise KeyError
"""
key = slugify(name)
diff --git a/askbot/models/base.py b/askbot/models/base.py
index af8f5a77..361ae5df 100644
--- a/askbot/models/base.py
+++ b/askbot/models/base.py
@@ -5,6 +5,7 @@ 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
+from django.contrib.sitemaps import ping_google
#todo: maybe merge askbot.utils.markup and forum.utils.html
from askbot.utils import markup
from askbot.utils.html import sanitize_html
@@ -45,8 +46,6 @@ def parse_post_text(post):
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,
@@ -73,6 +72,7 @@ def parse_post_text(post):
#find mentions that were removed and identify any previously
#entered mentions so that we can send alerts on only new ones
+ from askbot.models.user import Activity
if post.pk is not None:
#only look for previous mentions if post was already saved before
prev_mention_qs = Activity.objects.get_mentions(
@@ -157,6 +157,37 @@ def parse_and_save_post(post, author = None, **kwargs):
except Exception:
logging.debug('cannot ping google - did you register with them?')
+class BaseQuerySetManager(models.Manager):
+ """a base class that allows chainable qustom filters
+ on the query sets
+
+ pattern from http://djangosnippets.org/snippets/562/
+
+ Usage (the most basic example, all imports explicit for clarity):
+
+ >>>import django.db.models.QuerySet
+ >>>import django.db.models.Model
+ >>>import askbot.models.base.BaseQuerySetManager
+ >>>
+ >>>class SomeQuerySet(django.db.models.QuerySet):
+ >>> def some_custom_filter(self, *args, **kwargs):
+ >>> return self #or any custom code
+ >>> #add more custom filters here
+ >>>
+ >>>class SomeManager(askbot.models.base.BaseQuerySetManager)
+ >>> def get_query_set(self):
+ >>> return SomeQuerySet(self.model)
+ >>>
+ >>>class SomeModel(django.db.models.Model)
+ >>> #add fields here
+ >>> objects = SomeManager()
+ """
+ def __getattr__(self, attr, *args):
+ try:
+ return getattr(self.__class__, attr, *args)
+ except AttributeError:
+ return getattr(self.get_query_set(), attr, *args)
+
class UserContent(models.Model):
user = models.ForeignKey(User, related_name='%(class)ss')
diff --git a/askbot/models/content.py b/askbot/models/content.py
index 87c3087d..84bd2421 100644
--- a/askbot/models/content.py
+++ b/askbot/models/content.py
@@ -1,12 +1,13 @@
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 django.utils import html as html_utils
+from askbot import const
from askbot.models.meta import Comment, Vote
from askbot.models.user import EmailFeedSetting
-from django.utils import html as html_utils
+from askbot.models.tag import Tag, MarkedTag, tags_match_some_wildcard
+from askbot.conf import settings as askbot_settings
class Content(models.Model):
"""
@@ -93,6 +94,117 @@ class Content(models.Model):
return comment
+ def get_global_tag_based_subscribers(
+ self,
+ tag_mark_reason = None,
+ subscription_records = None
+ ):
+ """returns a list of users who either follow or "do not ignore"
+ the given set of tags, depending on the tag_mark_reason
+
+ ``subscription_records`` - query set of ``~askbot.models.EmailFeedSetting``
+ this argument is used to reduce number of database queries
+ """
+ if tag_mark_reason == 'good':
+ email_tag_filter_strategy = const.INCLUDE_INTERESTING
+ user_set_getter = User.objects.filter
+ elif tag_mark_reason == 'bad':
+ email_tag_filter_strategy = const.EXCLUDE_IGNORED
+ user_set_getter = User.objects.exclude
+ else:
+ raise ValueError('Uknown value of tag mark reason %s' % tag_mark_reason)
+
+ #part 1 - find users who follow or not ignore the set of tags
+ tag_names = self.get_tag_names()
+ tag_selections = MarkedTag.objects.filter(
+ tag__name__in = tag_names,
+ reason = tag_mark_reason
+ )
+ subscribers = set(
+ user_set_getter(
+ tag_selections__in = tag_selections
+ ).filter(
+ notification_subscriptions__in = subscription_records
+ ).filter(
+ email_tag_filter_strategy = email_tag_filter_strategy
+ )
+ )
+
+ #part 2 - find users who follow or not ignore tags via wildcard selections
+ #inside there is a potentially time consuming loop
+ if askbot_settings.USE_WILDCARD_TAGS:
+ #todo: fix this
+ #this branch will not scale well
+ #because we have to loop through the list of users
+ #in python
+ if tag_mark_reason == 'good':
+ empty_wildcard_filter = {'interesting_tags__exact': ''}
+ wildcard_tags_attribute = 'interesting_tags'
+ update_subscribers = lambda the_set, item: the_set.add(item)
+ elif tag_mark_reason == 'bad':
+ empty_wildcard_filter = {'ignored_tags__exact': ''}
+ wildcard_tags_attribute = 'ignored_tags'
+ update_subscribers = lambda the_set, item: the_set.discard(item)
+
+ potential_wildcard_subscribers = User.objects.filter(
+ notification_subscriptions__in = subscription_records
+ ).filter(
+ email_tag_filter_strategy = email_tag_filter_strategy
+ ).exclude(
+ **empty_wildcard_filter #need this to limit size of the loop
+ )
+ for potential_subscriber in potential_wildcard_subscribers:
+ wildcard_tags = getattr(
+ potential_subscriber,
+ wildcard_tags_attribute
+ ).split(' ')
+
+ if tags_match_some_wildcard(tag_names, wildcard_tags):
+ update_subscribers(subscribers, potential_subscriber)
+
+ return subscribers
+
+ def get_global_instant_notification_subscribers(self):
+ """returns a set of subscribers to post according to tag filters
+ both - subscribers who ignore tags or who follow only
+ specific tags
+
+ this method in turn calls several more specialized
+ subscriber retrieval functions
+ todo: retrieval of wildcard tag followers ignorers
+ won't scale at all
+ """
+ subscriber_set = set()
+
+ global_subscriptions = EmailFeedSetting.objects.filter(
+ feed_type = 'q_all',
+ frequency = 'i'
+ )
+
+ #segment of users who have tag filter turned off
+ global_subscribers = User.objects.filter(
+ email_tag_filter_strategy = const.INCLUDE_ALL
+ )
+ subscriber_set.update(global_subscribers)
+
+ #segment of users who want emails on selected questions only
+ subscriber_set.update(
+ self.get_global_tag_based_subscribers(
+ subscription_records = global_subscriptions,
+ tag_mark_reason = 'good'
+ )
+ )
+
+ #segment of users who want to exclude ignored tags
+ subscriber_set.update(
+ self.get_global_tag_based_subscribers(
+ subscription_records = global_subscriptions,
+ tag_mark_reason = 'bad'
+ )
+ )
+ return subscriber_set
+
+
def get_instant_notification_subscribers(
self,
potential_subscribers = None,
@@ -103,11 +215,28 @@ class Content(models.Model):
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
+ Arguments:
+
+ * ``potential_subscribers`` is not used here! todo: why? - clean this out
+ parameter is left for the uniformity of the interface
+ (Comment method does use it)
+ normally these methods would determine the list
+ :meth:`~askbot.models.question.Question.get_response_recipients`
+ :meth:`~askbot.models.question.Answer.get_response_recipients`
+ - depending on the type of the post
+ * ``mentioned_users`` - users, mentioned in the post for the first time
+ * ``exclude_list`` - users who must be excluded from the subscription
+
+ Users who receive notifications are:
+
+ * of ``mentioned_users`` - those who subscribe for the instant
+ updates on the @name mentions
+ * those who follow the parent question
+ * global subscribers (any personalized tag filters are applied)
+ * author of the question who subscribe to instant updates
+ on questions that they asked
+ * authors or any answers who subsribe to instant updates
+ on the questions which they answered
"""
#print '------------------'
#print 'in content function'
@@ -140,19 +269,9 @@ class Content(models.Model):
subscriber_set.update(selective_subscribers)
#print 'selective subscribers: ', selective_subscribers
-
- #3) whole forum subscibers
- global_subscribers = EmailFeedSetting.objects.filter_subscribers(
- feed_type = 'q_all',
- frequency = 'i'
- )
- for subscriber in global_subscribers:
- if origin_post.passes_tag_filter_for_user(subscriber):
- #print subscriber, ' passes tag filter'
- subscriber_set.add(subscriber)
- else:
- #print 'does not pass tag filter'
- pass
+ #3) whole forum subscribers
+ global_subscribers = origin_post.get_global_instant_notification_subscribers()
+ subscriber_set.update(global_subscribers)
#4) question asked by me (todo: not "edited_by_me" ???)
question_author = origin_post.author
@@ -186,23 +305,6 @@ class Content(models.Model):
#print 'final subscriber set is ', subscriber_set
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]
@@ -238,34 +340,25 @@ class Content(models.Model):
return list(authors)
def passes_tag_filter_for_user(self, user):
- tags = self.get_origin_post().tags.all()
- if user.tag_filter_setting == 'interesting':
+ question = self.get_origin_post()
+ if user.email_tag_filter_strategy == const.INCLUDE_INTERESTING:
#at least some of the tags must be marked interesting
- interesting_selections = user.tag_selections.filter(
- tag__in = tags,
- reason = 'good'
- )
- if interesting_selections.count() > 0:
- return True
- else:
- return False
-
- elif user.tag_filter_setting == 'ignored':
- #at least one tag must be ignored
- ignored_selections = user.tag_selections.filter(
- tag__in = tags,
- reason = 'bad'
- )
- if ignored_selections.count() > 0:
- return False
- else:
- return True
-
+ return user.has_affinity_to_question(
+ question,
+ affinity_type = 'like'
+ )
+ elif user.email_tag_filter_strategy == const.EXCLUDE_IGNORED:
+ return not user.has_affinity_to_question(
+ question,
+ affinity_type = 'dislike'
+ )
+ elif user.email_tag_filter_strategy == const.INCLUDE_ALL:
+ return True
else:
raise ValueError(
- 'unexpected User.tag_filter_setting %s' \
- % user.tag_filter_setting
+ 'unexpected User.email_tag_filter_strategy %s' \
+ % user.email_tag_filter_strategy
)
def post_get_last_update_info(self):#todo: rename this subroutine
diff --git a/askbot/models/meta.py b/askbot/models/meta.py
index 9f94a45d..290f5ef0 100644
--- a/askbot/models/meta.py
+++ b/askbot/models/meta.py
@@ -92,6 +92,7 @@ class Comment(base.MetaContent, base.UserContent):
_urlize = True
_use_markdown = False
_escape_html = True
+ is_anonymous = False #comments are never anonymous - may change
class Meta(base.MetaContent.Meta):
ordering = ('-added_at',)
@@ -123,6 +124,10 @@ class Comment(base.MetaContent, base.UserContent):
def get_origin_post(self):
return self.content_object.get_origin_post()
+ def get_tag_names(self):
+ """return tag names of the origin question"""
+ return self.get_origin_post().get_tag_names()
+
def get_page_number(self, answers = None):
"""return page number whithin the page
where the comment is going to appear
@@ -159,17 +164,17 @@ class Comment(base.MetaContent, base.UserContent):
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
+ """Response receivers are commenters of the
+ same post and the authors of the post itself.
"""
assert(exclude_list is not None)
users = set()
+ #get authors of parent object and all associated comments
users.update(
- #get authors of parent object and all associated comments
- self.content_object.get_author_list(
- include_comments = True,
- )
+ self.content_object.get_author_list(
+ include_comments = True,
)
+ )
users -= set(exclude_list)
return list(users)
@@ -179,10 +184,20 @@ class Comment(base.MetaContent, base.UserContent):
mentioned_users = None,
exclude_list = None
):
- """get list of users who want instant notifications
- about this comment
+ """get list of users who want instant notifications about comments
argument potential_subscribers is required as it saves on db hits
+
+ Here is the list of people who will receive the notifications:
+
+ * mentioned users
+ * of response receivers
+ (see :meth:`~askbot.models.meta.Comment.get_response_receivers`) -
+ those who subscribe for the instant
+ updates on comments and @mentions
+ * all who follow the question explicitly
+ * all global subscribers
+ (tag filtered, and subject to personalized settings)
"""
#print 'in meta function'
#print 'potential subscribers: ', potential_subscribers
@@ -221,10 +236,7 @@ class Comment(base.MetaContent, base.UserContent):
subscriber_set.update(selective_subscribers)
#print 'selective subscribers: ', selective_subscribers
- global_subscribers = EmailFeedSetting.objects.filter_subscribers(
- feed_type = 'q_all',
- frequency = 'i'
- )
+ global_subscribers = origin_post.get_global_instant_notification_subscribers()
#print 'global subscribers: ', global_subscribers
subscriber_set.update(global_subscribers)
@@ -245,9 +257,6 @@ class Comment(base.MetaContent, base.UserContent):
records, as well as mention records, while preserving
integrity or response counts for the users
"""
- #todo: not very good import in models of other models
- #todo: potentially a circular import
- from askbot.models.user import Activity
comment_content_type = ContentType.objects.get_for_model(self)
comment_id = self.id
@@ -256,6 +265,9 @@ class Comment(base.MetaContent, base.UserContent):
#all this should pack into Activity.responses.filter( somehow ).delete()
activity_types = const.RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY
activity_types += (const.TYPE_ACTIVITY_MENTION,)
+ #todo: not very good import in models of other models
+ #todo: potentially a circular import
+ from askbot.models.user import Activity
activities = Activity.objects.filter(
content_type = comment_content_type,
object_id = comment_id,
diff --git a/askbot/models/question.py b/askbot/models/question.py
index d8d60c6e..d1570877 100644
--- a/askbot/models/question.py
+++ b/askbot/models/question.py
@@ -1,4 +1,3 @@
-import random
import logging
import datetime
from django.conf import settings
@@ -13,10 +12,15 @@ from django.utils.translation import ugettext as _
import askbot
import askbot.conf
from askbot import exceptions
-from askbot.models.tag import Tag, MarkedTag
-from askbot.models.base import AnonymousContent, DeletableContent, ContentRevision
-from askbot.models.base import parse_post_text, parse_and_save_post
+from askbot.models.tag import Tag
+from askbot.models.base import AnonymousContent
+from askbot.models.base import DeletableContent
+from askbot.models.base import ContentRevision
+from askbot.models.base import BaseQuerySetManager
+from askbot.models.base import parse_post_text
+from askbot.models.base import parse_and_save_post
from askbot.models import content
+from askbot.models import signals
from askbot import const
from askbot.utils.lists import LazyList
from askbot.utils.slug import slugify
@@ -36,8 +40,19 @@ QUESTION_ORDER_BY_MAP = {
'relevance-desc': None#this is a special case for postges only
}
-class QuestionManager(models.Manager):
- def create_new(self, title=None,author=None,added_at=None, wiki=False,tagnames=None, text=None):
+class QuestionQuerySet(models.query.QuerySet):
+ """Custom query set subclass for :class:`~askbot.models.Question`
+ """
+ def create_new(
+ self,
+ title = None,
+ author = None,
+ added_at = None,
+ wiki = False,
+ is_anonymous = False,
+ tagnames = None,
+ text = None
+ ):
question = Question(
title = title,
@@ -46,6 +61,7 @@ class QuestionManager(models.Manager):
last_activity_at = added_at,
last_activity_by = author,
wiki = wiki,
+ is_anonymous = is_anonymous,
tagnames = tagnames,
#html field is denormalized in .save() call
text = text,
@@ -55,7 +71,6 @@ class QuestionManager(models.Manager):
#DATED COMMENT
#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
@@ -65,13 +80,43 @@ class QuestionManager(models.Manager):
question.update_tags(tagnames = tagnames, user = author, timestamp = added_at)
question.add_revision(
- author=author,
- text=text,
- comment=const.POST_STATUS['default_version'],
- revised_at=added_at,
+ author = author,
+ is_anonymous = is_anonymous,
+ text = text,
+ comment = const.POST_STATUS['default_version'],
+ revised_at = added_at,
)
return question
+ def get_by_text_query(self, search_query):
+ """returns a query set of questions,
+ matching the full text query
+ """
+ if settings.DATABASE_ENGINE == 'mysql':
+ return self.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)
+ )
+ elif settings.DATABASE_ENGINE == 'postgresql_psycopg2':
+ rank_clause = "ts_rank(question.text_search_vector, to_tsquery(%s))";
+ search_query = '&'.join(search_query.split())
+ extra_params = ("'" + search_query + "'",)
+ extra_kwargs = {
+ 'select': {'relevance': rank_clause},
+ 'where': ['text_search_vector @@ to_tsquery(%s)'],
+ 'params': extra_params,
+ 'select_params': extra_params,
+ }
+ return self.extra(**extra_kwargs)
+ else:
+ #fallback to dumb title match search
+ return extra(
+ where=['title like %s'],
+ params=['%' + search_query + '%']
+ )
+
def run_advanced_search(
self,
request_user = None,
@@ -107,32 +152,12 @@ class QuestionManager(models.Manager):
qs = qs.filter(tags__name = tag)
if search_query:
- if settings.DATABASE_ENGINE == 'mysql':
- 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)
- )
- elif settings.DATABASE_ENGINE == 'postgresql_psycopg2':
- rank_clause = "ts_rank(question.text_search_vector, to_tsquery('%s'))";
- search_query = '&'.join(search_query.split())
- extra_kwargs = {
- 'select': {'relevance': rank_clause % search_query},
- 'where': ['text_search_vector @@ to_tsquery(%s)'],
- 'params': ["'" + search_query + "'"]
- }
- if askbot.conf.should_show_sort_by_relevance():
- if sort_method == 'relevance-desc':
- extra_kwargs['order_by'] = ['-relevance',]
-
- qs = qs.extra(**extra_kwargs)
- else:
- #fallback to dumb title match search
- qs = qs.extra(
- where=['title like %s'],
- params=['%' + search_query + '%']
- )
+ qs = qs.get_by_text_query(search_query)
+ #a patch for postgres search sort method
+ if askbot.conf.should_show_sort_by_relevance():
+ if sort_method == 'relevance-desc':
+ qs= qs.extra(order_by = ['-relevance',])
+
#have to import this at run time, otherwise there
#a circular import dependency...
@@ -183,27 +208,47 @@ class QuestionManager(models.Manager):
ignored_tag_names = [tag.name for tag in ignored_tags]
meta_data['ignored_tag_names'] = ignored_tag_names
- if interesting_tags:
+ if interesting_tags or request_user.has_interesting_wildcard_tags():
#expensive query
- qs = qs.extra(
- 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.display_tag_filter_strategy == \
+ const.INCLUDE_INTERESTING:
+ #filter by interesting tags only
+ interesting_tag_filter = models.Q(tags__in = interesting_tags)
+ if request_user.has_interesting_wildcard_tags():
+ interesting_wildcards = request_user.interesting_tags.split()
+ extra_interesting_tags = Tag.objects.get_by_wildcards(
+ interesting_wildcards
+ )
+ interesting_tag_filter |= models.Q(tags__in = extra_interesting_tags)
+
+ qs = qs.filter(interesting_tag_filter)
+ else:
+ #simply annotate interesting questions
+ qs = qs.extra(
+ 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,),
+ )
# get the list of interesting and ignored tags (interesting_tag_names, ignored_tag_names) = (None, None)
- if ignored_tags:
- if request_user.hide_ignored_questions:
+ if ignored_tags or request_user.has_ignored_wildcard_tags():
+ if request_user.display_tag_filter_strategy == const.EXCLUDE_IGNORED:
#exclude ignored tags if the user wants to
qs = qs.exclude(tags__in=ignored_tags)
+ if request_user.has_ignored_wildcard_tags():
+ ignored_wildcards = request_user.ignored_tags.split()
+ extra_ignored_tags = Tag.objects.get_by_wildcards(
+ ignored_wildcards
+ )
+ qs = qs.exclude(tags__in = extra_ignored_tags)
else:
#annotate questions tagged with ignored tags
#expensive query
@@ -235,7 +280,9 @@ class QuestionManager(models.Manager):
'last_activity_by__reputation',
'last_activity_by__gold',
'last_activity_by__silver',
- 'last_activity_by__bronze'
+ 'last_activity_by__bronze',
+ 'last_activity_by__country',
+ 'last_activity_by__show_country',
)
related_tags = Tag.objects.get_related_to_search(
@@ -243,6 +290,12 @@ class QuestionManager(models.Manager):
search_state = search_state,
ignored_tag_names = ignored_tag_names
)
+ if askbot_settings.USE_WILDCARD_TAGS == True \
+ and request_user.is_authenticated() == True:
+ tagnames = request_user.interesting_tags
+ meta_data['interesting_tag_names'].extend(tagnames.split())
+ tagnames = request_user.ignored_tags
+ meta_data['ignored_tag_names'].extend(tagnames.split())
return qs, meta_data, related_tags
#todo: this function is similar to get_response_receivers
@@ -284,6 +337,14 @@ class QuestionManager(models.Manager):
self.filter(id=question.id).update(view_count = question.view_count + 1)
+class QuestionManager(BaseQuerySetManager):
+ """chainable custom query set manager for
+ questions
+ """
+ def get_query_set(self):
+ return QuestionQuerySet(self.model)
+
+
class Question(content.Content, DeletableContent):
post_type = 'question'
title = models.CharField(max_length=300)
@@ -309,6 +370,7 @@ class Question(content.Content, DeletableContent):
summary = models.CharField(max_length=180)
favorited_by = models.ManyToManyField(User, through='FavoriteQuestion', related_name='favorite_questions')
+ is_anonymous = models.BooleanField(default=False)
objects = QuestionManager()
@@ -332,6 +394,17 @@ class Question(content.Content, DeletableContent):
except django_exceptions.PermissionDenied:
raise exceptions.QuestionHidden(message)
+ def remove_author_anonymity(self):
+ """removes anonymous flag from the question
+ and all its revisions
+ the function calls update method to make sure that
+ signals are not called
+ """
+ #it is important that update method is called - not save,
+ #because we do not want the signals to fire here
+ Question.objects.filter(id = self.id).update(is_anonymous = False)
+ self.revisions.all().update(is_anonymous = False)
+
def update_answer_count(self, save = True):
"""updates the denormalized field 'answer_count'
on the question
@@ -407,6 +480,15 @@ class Question(content.Content, DeletableContent):
"""
Updates Tag associations for a question to match the given
tagname string.
+
+ When tags are removed and their use count hits 0 - the tag is
+ automatically deleted.
+
+ When an added tag does not exist - it is created
+
+ Tag use counts are recalculated
+
+ A signal tags updated is sent
"""
previous_tags = list(self.tags.all())
@@ -428,6 +510,7 @@ class Question(content.Content, DeletableContent):
if tag.used_count == 1:
#we won't modify used count b/c it's done below anyway
removed_tags.remove(tag)
+ #todo - do we need to use fields deleted_by and deleted_at?
tag.delete()#auto-delete tags whose use count dwindled
#remember modified tags, we'll need to update use counts on them
@@ -466,6 +549,12 @@ class Question(content.Content, DeletableContent):
#if there are any modified tags, update their use counts
if modified_tags:
Tag.objects.update_use_counts(modified_tags)
+ signals.tags_updated.send(None,
+ question = self,
+ tags = modified_tags,
+ user = user,
+ timestamp = timestamp
+ )
return True
return False
@@ -531,9 +620,9 @@ class Question(content.Content, DeletableContent):
self.tagnames = tagnames
if silent == False:
self.last_edited_at = retagged_at
- self.last_activity_at = retagged_at
+ #self.last_activity_at = retagged_at
self.last_edited_by = retagged_by
- self.last_activity_by = retagged_by
+ #self.last_activity_by = retagged_by
self.save()
# Update the Question's tag associations
@@ -555,7 +644,8 @@ class Question(content.Content, DeletableContent):
return self
def apply_edit(self, edited_at=None, edited_by=None, title=None,\
- text=None, comment=None, tags=None, wiki=False):
+ text=None, comment=None, tags=None, wiki=False, \
+ edit_anonymously = False):
latest_revision = self.get_latest_revision()
#a hack to allow partial edits - important for SE loader
@@ -580,6 +670,7 @@ class Question(content.Content, DeletableContent):
self.last_activity_by = edited_by
self.tagnames = tags
self.text = text
+ self.is_anonymous = edit_anonymously
#wiki is an eternal trap whence there is no exit
if self.wiki == False and wiki == True:
@@ -594,12 +685,20 @@ class Question(content.Content, DeletableContent):
author = edited_by,
text = text,
revised_at = edited_at,
+ is_anonymous = edit_anonymously,
comment = comment,
)
self.parse_and_save(author = edited_by)
- def add_revision(self,author=None, text=None, comment=None, revised_at=None):
+ def add_revision(
+ self,
+ author = None,
+ is_anonymous = False,
+ text = None,
+ comment = None,
+ revised_at = None
+ ):
if None in (author, text, comment):
raise Exception('author, text and comment are required arguments')
rev_no = self.revisions.all().count() + 1
@@ -614,6 +713,7 @@ class Question(content.Content, DeletableContent):
revision = rev_no,
title = self.title,
author = author,
+ is_anonymous = is_anonymous,
revised_at = revised_at,
tagnames = self.tagnames,
summary = comment,
@@ -634,11 +734,12 @@ class Question(content.Content, DeletableContent):
def tagname_meta_generator(self):
return u','.join([unicode(tag) for tag in self.get_tag_names()])
- def get_absolute_url(self):
- return '%s%s' % (
- reverse('question', args=[self.id]),
- django_urlquote(slugify(self.title))
- )
+ def get_absolute_url(self, no_slug = False):
+ url = reverse('question', args=[self.id])
+ if no_slug == True:
+ return url
+ else:
+ return url + django_urlquote(slugify(self.title))
def has_favorite_by_user(self, user):
if not user.is_authenticated():
@@ -768,6 +869,7 @@ class QuestionRevision(ContentRevision):
question = models.ForeignKey(Question, related_name='revisions')
title = models.CharField(max_length=300)
tagnames = models.CharField(max_length=125)
+ is_anonymous = models.BooleanField(default=False)
class Meta(ContentRevision.Meta):
db_table = u'question_revision'
@@ -801,17 +903,24 @@ class QuestionRevision(ContentRevision):
return u'revision %s of %s' % (self.revision, self.title)
class AnonymousQuestion(AnonymousContent):
+ """question that was asked before logging in
+ maybe the name is a little misleading, the user still
+ may or may not want to stay anonymous after the question
+ is published
+ """
title = models.CharField(max_length=300)
tagnames = models.CharField(max_length=125)
+ is_anonymous = models.BooleanField(default=False)
def publish(self,user):
added_at = datetime.datetime.now()
Question.objects.create_new(
- title=self.title,
- author=user,
- added_at=added_at,
- wiki=self.wiki,
- tagnames=self.tagnames,
- text=self.text,
+ title = self.title,
+ added_at = added_at,
+ author = user,
+ wiki = self.wiki,
+ is_anonymous = self.is_anonymous,
+ tagnames = self.tagnames,
+ text = self.text,
)
self.delete()
diff --git a/askbot/models/signals.py b/askbot/models/signals.py
index 825f72e7..d28cd4a5 100644
--- a/askbot/models/signals.py
+++ b/askbot/models/signals.py
@@ -1,6 +1,15 @@
+"""Custom django signals defined for the askbot forum application.
+"""
import django.dispatch
+from django.db.models.signals import pre_save, post_save, pre_delete, post_delete, post_syncdb
+try:
+ from django.db.models.signals import m2m_changed
+except ImportError:
+ pass
-tags_updated = django.dispatch.Signal(providing_args=['question'])
+tags_updated = django.dispatch.Signal(
+ providing_args=['tags', 'user', 'timestamp']
+ )
#todo: this one seems to be unused
edit_question_or_answer = django.dispatch.Signal(
@@ -21,3 +30,62 @@ post_updated = django.dispatch.Signal(
'newly_mentioned_users'
]
)
+site_visited = django.dispatch.Signal(providing_args=['user', 'timestamp'])
+
+def pop_signal_receivers(signal):
+ """disables a given signal by removing listener functions
+ and returns the list
+ """
+ receivers = signal.receivers
+ signal.receivers = list()
+ return receivers
+
+def set_signal_receivers(signal, receiver_list):
+ """assigns a value of the receiver_list
+ to the signal receivers
+ """
+ signal.receivers = receiver_list
+
+def pop_all_db_signal_receivers():
+ """loops through all relevant signals
+ pops their receivers and returns a
+ dictionary where signals are keys
+ and lists of receivers are values
+ """
+ #this is the only askbot signal that is not defined here
+ #must use this to avoid a circular import
+ from askbot.models.badges import award_badges_signal
+ signals = (
+ #askbot signals
+ tags_updated,
+ edit_question_or_answer,
+ delete_question_or_answer,
+ flag_offensive,
+ user_updated,
+ user_logged_in,
+ post_updated,
+ award_badges_signal,
+ #django signals
+ pre_save,
+ post_save,
+ pre_delete,
+ post_delete,
+ post_syncdb,
+ )
+ if 'm2m_changed' in globals():
+ signals += m2m_changed
+
+ receiver_data = dict()
+ for signal in signals:
+ receiver_data[signal] = pop_signal_receivers(signal)
+
+ return receiver_data
+
+def set_all_db_signal_receivers(receiver_data):
+ """takes receiver data as an argument
+ where the argument is as returned by the
+ pop_all_db_signal_receivers() call
+ and sets the receivers back to the signals
+ """
+ for (signal, receivers) in receiver_data.items():
+ signal.receivers = receivers
diff --git a/askbot/models/tag.py b/askbot/models/tag.py
index 473c3cd7..73aa328f 100644
--- a/askbot/models/tag.py
+++ b/askbot/models/tag.py
@@ -3,10 +3,21 @@ 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
+from askbot.models.base import BaseQuerySetManager
-
-class TagManager(models.Manager):
- UPDATE_USED_COUNTS_QUERY ="""
+def tags_match_some_wildcard(tag_names, wildcard_tags):
+ """Same as
+ :meth:`~askbot.models.tag.TagQuerySet.tags_match_some_wildcard`
+ except it works on tag name strings
+ """
+ for tag_name in tag_names:
+ for wildcard_tag in sorted(wildcard_tags):
+ if tag_name.startswith(wildcard_tag[:-1]):
+ return True
+ return False
+
+class TagQuerySet(models.query.QuerySet):
+ UPDATE_USED_COUNTS_QUERY = """
UPDATE tag
SET used_count = (
SELECT COUNT(*) FROM question_tags
@@ -27,20 +38,48 @@ class TagManager(models.Manager):
cursor = connection.cursor()
query = self.UPDATE_USED_COUNTS_QUERY % ','.join(['%s'] * len(tags))
cursor.execute(query, [tag.id for tag in tags])
- transaction.commit_unless_managed()
+
+ transaction.commit_unless_managed()
+
+ def tags_match_some_wildcard(self, wildcard_tags = None):
+ """True if any one of the tags in the query set
+ matches a wildcard
+
+ :arg:`wildcard_tags` is an iterable of wildcard tag strings
+
+ todo: refactor to use :func:`tags_match_some_wildcard`
+ """
+ for tag in self.all():
+ for wildcard_tag in sorted(wildcard_tags):
+ if tag.name.startswith(wildcard_tag[:-1]):
+ return True
+ return False
+
+ def get_by_wildcards(self, wildcards = None):
+ """returns query set of tags that match the wildcard tags
+ wildcard tag is guaranteed to end with an asterisk and has
+ at least one character preceding the the asterisk. and there
+ is only one asterisk in the entire name
+ """
+ if wildcards is None or len(wildcards) == 0:
+ return self.none()
+ first_tag = wildcards.pop()
+ tag_filter = models.Q(name__startswith = first_tag[:-1])
+ for next_tag in wildcards:
+ tag_filter |= models.Q(name__startswith = next_tag[:-1])
+ return self.filter(tag_filter)
def get_related_to_search(
self,
- questions=None,
- search_state=None,
- ignored_tag_names=None
+ questions = None,
+ search_state = None,
+ ignored_tag_names = None
):
"""must return at least tag names, along with use counts
handle several cases to optimize the query performance
"""
- if search_state.is_default() or \
- questions.count() > search_state.page_size * 3:
+ if questions.count() > search_state.page_size * 3:
"""if we have too many questions or
search query is the most common - just return a list
of top tags"""
@@ -72,6 +111,14 @@ class TagManager(models.Manager):
return tags
+
+class TagManager(BaseQuerySetManager):
+ """chainable custom filter query set manager
+ for :class:``~askbot.models.Tag`` objects
+ """
+ def get_query_set(self):
+ return TagQuerySet(self.model)
+
class Tag(DeletableContent):
name = models.CharField(max_length=255, unique=True)
created_by = models.ForeignKey(User, related_name='created_tags')
@@ -88,7 +135,7 @@ class Tag(DeletableContent):
return self.name
class MarkedTag(models.Model):
- TAG_MARK_REASONS = (('good',_('interesting')),('bad',_('ignored')))
+ TAG_MARK_REASONS = (('good', _('interesting')), ('bad', _('ignored')))
tag = models.ForeignKey('Tag', related_name='user_selections')
user = models.ForeignKey(User, related_name='tag_selections')
reason = models.CharField(max_length=16, choices=TAG_MARK_REASONS)
diff --git a/askbot/models/user.py b/askbot/models/user.py
index 078feca3..09e7ebee 100644
--- a/askbot/models/user.py
+++ b/askbot/models/user.py
@@ -1,6 +1,3 @@
-from hashlib import md5
-import string
-from random import Random
import datetime
import logging
from django.db import models
@@ -227,7 +224,7 @@ class EmailFeedSettingManager(models.Manager):
frequency = frequency
)
if potential_subscribers is not None:
- matching_feeds.filter(
+ matching_feeds = matching_feeds.filter(
subscriber__in = potential_subscribers
)
subscriber_set = set()
@@ -327,12 +324,3 @@ class EmailFeedSetting(models.Model):
class Meta:
app_label = 'askbot'
-
-#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/askbot/patches/__init__.py b/askbot/patches/__init__.py
new file mode 100644
index 00000000..3c5e0d28
--- /dev/null
+++ b/askbot/patches/__init__.py
@@ -0,0 +1,28 @@
+"""module for monkey patching that is
+necessary for interoperability of different
+versions of various components used in askbot
+"""
+import django
+from askbot.patches import django_patches
+from askbot.deployment import package_utils
+
+def patch_django():
+ """earlier versions of Django do not have
+ csrf token and function called import_library
+ (the latter is needed by coffin)
+ """
+ (major, minor, micro) = package_utils.get_django_version()
+ if major == 1 and minor < 2:
+ django_patches.add_import_library_function()
+ django_patches.add_csrf_protection()
+
+def patch_coffin():
+ """coffin before version 0.3.4
+ does not have csrf_token template tag.
+ This patch must be applied after the django patches
+ """
+ from askbot.patches import coffin_patches
+
+ (major, minor, micro) = package_utils.get_coffin_version()
+ if major == 0 and minor == 3 and micro < 4:
+ coffin_patches.add_csrf_token_tag()
diff --git a/askbot/patches/coffin_patches.py b/askbot/patches/coffin_patches.py
new file mode 100644
index 00000000..92e3bc09
--- /dev/null
+++ b/askbot/patches/coffin_patches.py
@@ -0,0 +1,34 @@
+"""patches for the coffin module"""
+from jinja2 import nodes
+from jinja2 import Markup
+from jinja2.ext import Extension
+
+class CsrfTokenExtension(Extension):
+ """Jinja2-version of the ``csrf_token`` tag.
+
+ Adapted from a snippet by Jason Green:
+ http://www.djangosnippets.org/snippets/1847/
+
+ This tag is a bit stricter than the Django tag in that it doesn't
+ simply ignore any invalid arguments passed in.
+ """
+
+ tags = set(['csrf_token'])
+
+ def parse(self, parser):
+ lineno = parser.stream.next().lineno
+ return nodes.Output([
+ self.call_method('_render', [nodes.Name('csrf_token', 'load')])
+ ]).set_lineno(lineno)
+
+ def _render(self, csrf_token):
+ from django.template.defaulttags import CsrfTokenNode
+ return Markup(CsrfTokenNode().render({'csrf_token': csrf_token}))
+
+def add_csrf_token_tag():
+ """adds csrf token tag to the default library"""
+ import coffin.template.defaulttags
+ coffin.template.defaulttags.CsrfTokenExtension = CsrfTokenExtension
+ csrf_token = CsrfTokenExtension
+ coffin.template.defaulttags.csrf_token = csrf_token
+ coffin.template.defaulttags.register.tag(csrf_token)
diff --git a/askbot/patches/django_patches.py b/askbot/patches/django_patches.py
new file mode 100644
index 00000000..baab64af
--- /dev/null
+++ b/askbot/patches/django_patches.py
@@ -0,0 +1,327 @@
+"""a module for patching django"""
+import imp
+import os
+import sys
+from django.utils.safestring import mark_safe
+from django.utils.functional import lazy
+from django.template import Node
+
+def module_has_submodule(package, module_name):
+ """See if 'module' is in 'package'."""
+ name = ".".join([package.__name__, module_name])
+ if name in sys.modules:
+ return True
+ for finder in sys.meta_path:
+ if finder.find_module(name):
+ return True
+ for entry in package.__path__: # No __path__, then not a package.
+ try:
+ # Try the cached finder.
+ finder = sys.path_importer_cache[entry]
+ if finder is None:
+ # Implicit import machinery should be used.
+ try:
+ file_, _, _ = imp.find_module(module_name, [entry])
+ if file_:
+ file_.close()
+ return True
+ except ImportError:
+ continue
+ # Else see if the finder knows of a loader.
+ elif finder.find_module(name):
+ return True
+ else:
+ continue
+ except KeyError:
+ # No cached finder, so try and make one.
+ for hook in sys.path_hooks:
+ try:
+ finder = hook(entry)
+ # XXX Could cache in sys.path_importer_cache
+ if finder.find_module(name):
+ return True
+ else:
+ # Once a finder is found, stop the search.
+ break
+ except ImportError:
+ # Continue the search for a finder.
+ continue
+ else:
+ # No finder found.
+ # Try the implicit import machinery if searching a directory.
+ if os.path.isdir(entry):
+ try:
+ file_, _, _ = imp.find_module(module_name, [entry])
+ if file_:
+ file_.close()
+ return True
+ except ImportError:
+ pass
+ # XXX Could insert None or NullImporter
+ else:
+ # Exhausted the search, so the module cannot be found.
+ return False
+
+class CsrfTokenNode(Node):
+ def render(self, context):
+ csrf_token = context.get('csrf_token', None)
+ if csrf_token:
+ if csrf_token == 'NOTPROVIDED':
+ return mark_safe(u"")
+ else:
+ return mark_safe(u"<div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='%s' /></div>" % csrf_token)
+ else:
+ # It's very probable that the token is missing because of
+ # misconfiguration, so we raise a warning
+ from django.conf import settings
+ if settings.DEBUG:
+ import warnings
+ warnings.warn("A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext.")
+ return u''
+
+def get_token(request):
+ """
+ Returns the the CSRF token required for a POST form.
+ A side effect of calling this function is to make the the csrf_protect
+ decorator and the CsrfViewMiddleware add a CSRF cookie and a 'Vary: Cookie'
+ header to the outgoing response. For this reason, you may need to use this
+ function lazily, as is done by the csrf context processor.
+ """
+ request.META["CSRF_COOKIE_USED"] = True
+ return request.META.get("CSRF_COOKIE", None)
+
+def csrf(request):
+ """
+ Context processor that provides a CSRF token, or the string 'NOTPROVIDED' if
+ it has not been provided by either a view decorator or the middleware
+ """
+ def _get_val():
+ token = get_token(request)
+ if token is None:
+ # In order to be able to provide debugging info in the
+ # case of misconfiguration, we use a sentinel value
+ # instead of returning an empty dict.
+ return 'NOTPROVIDED'
+ else:
+ return token
+ _get_val = lazy(_get_val, str)
+ return {'csrf_token': _get_val() }
+
+"""
+Cross Site Request Forgery Middleware.
+This module provides a middleware that implements protection
+against request forgeries from other sites.
+"""
+import itertools
+import re
+import random
+from django.conf import settings
+from django.core.urlresolvers import get_callable
+from django.utils.hashcompat import md5_constructor
+from django.utils.safestring import mark_safe
+_POST_FORM_RE = \
+ re.compile(r'(<form\W[^>]*\bmethod\s*=\s*(\'|"|)POST(\'|"|)\b[^>]*>)', re.IGNORECASE)
+_HTML_TYPES = ('text/html', 'application/xhtml+xml')
+# Use the system (hardware-based) random number generator if it exists.
+if hasattr(random, 'SystemRandom'):
+ randrange = random.SystemRandom().randrange
+else:
+ randrange = random.randrange
+_MAX_CSRF_KEY = 18446744073709551616L # 2 << 63
+def _get_failure_view():
+ """
+ Returns the view to be used for CSRF rejections
+ """
+ return get_callable(settings.CSRF_FAILURE_VIEW)
+
+def _get_new_csrf_key():
+ return md5_constructor("%s%s"
+ % (randrange(0, _MAX_CSRF_KEY), settings.SECRET_KEY)).hexdigest()
+
+def _make_legacy_session_token(session_id):
+ return md5_constructor(settings.SECRET_KEY + session_id).hexdigest()
+
+class CsrfViewMiddleware(object):
+ """
+ Middleware that requires a present and correct csrfmiddlewaretoken
+ for POST requests that have a CSRF cookie, and sets an outgoing
+ CSRF cookie.
+ This middleware should be used in conjunction with the csrf_token template
+ tag.
+ """
+ def process_view(self, request, callback, callback_args, callback_kwargs):
+ if getattr(callback, 'csrf_exempt', False):
+ return None
+ if getattr(request, 'csrf_processing_done', False):
+ return None
+ reject = lambda s: _get_failure_view()(request, reason=s)
+ def accept():
+ # Avoid checking the request twice by adding a custom attribute to
+ # request. This will be relevant when both decorator and middleware
+ # are used.
+ request.csrf_processing_done = True
+ return None
+ # If the user doesn't have a CSRF cookie, generate one and store it in the
+ # request, so it's available to the view. We'll store it in a cookie when
+ # we reach the response.
+ try:
+ request.META["CSRF_COOKIE"] = request.COOKIES[settings.CSRF_COOKIE_NAME]
+ cookie_is_new = False
+ except KeyError:
+ # No cookie, so create one. This will be sent with the next
+ # response.
+ request.META["CSRF_COOKIE"] = _get_new_csrf_key()
+ # Set a flag to allow us to fall back and allow the session id in
+ # place of a CSRF cookie for this request only.
+ cookie_is_new = True
+ if request.method == 'POST':
+ if getattr(request, '_dont_enforce_csrf_checks', False):
+ # Mechanism to turn off CSRF checks for test suite. It comes after
+ # the creation of CSRF cookies, so that everything else continues to
+ # work exactly the same (e.g. cookies are sent etc), but before the
+ # any branches that call reject()
+ return accept()
+ if request.is_ajax():
+ # .is_ajax() is based on the presence of X-Requested-With. In
+ # the context of a browser, this can only be sent if using
+ # XmlHttpRequest. Browsers implement careful policies for
+ # XmlHttpRequest:
+ #
+ # * Normally, only same-domain requests are allowed.
+ #
+ # * Some browsers (e.g. Firefox 3.5 and later) relax this
+ # carefully:
+ #
+ # * if it is a 'simple' GET or POST request (which can
+ # include no custom headers), it is allowed to be cross
+ # domain. These requests will not be recognized as AJAX.
+ #
+ # * if a 'preflight' check with the server confirms that the
+ # server is expecting and allows the request, cross domain
+ # requests even with custom headers are allowed. These
+ # requests will be recognized as AJAX, but can only get
+ # through when the developer has specifically opted in to
+ # allowing the cross-domain POST request.
+ #
+ # So in all cases, it is safe to allow these requests through.
+ return accept()
+ if request.is_secure():
+ # Strict referer checking for HTTPS
+ referer = request.META.get('HTTP_REFERER')
+ if referer is None:
+ return reject("Referer checking failed - no Referer.")
+ # The following check ensures that the referer is HTTPS,
+ # the domains match and the ports match. This might be too strict.
+ good_referer = 'https://%s/' % request.get_host()
+ if not referer.startswith(good_referer):
+ return reject("Referer checking failed - %s does not match %s." %
+ (referer, good_referer))
+ # If the user didn't already have a CSRF cookie, then fall back to
+ # the Django 1.1 method (hash of session ID), so a request is not
+ # rejected if the form was sent to the user before upgrading to the
+ # Django 1.2 method (session independent nonce)
+ if cookie_is_new:
+ try:
+ session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
+ csrf_token = _make_legacy_session_token(session_id)
+ except KeyError:
+ # No CSRF cookie and no session cookie. For POST requests,
+ # we insist on a CSRF cookie, and in this way we can avoid
+ # all CSRF attacks, including login CSRF.
+ return reject("No CSRF or session cookie.")
+ else:
+ csrf_token = request.META["CSRF_COOKIE"]
+ # check incoming token
+ request_csrf_token = request.POST.get('csrfmiddlewaretoken', None)
+ if request_csrf_token != csrf_token:
+ if cookie_is_new:
+ # probably a problem setting the CSRF cookie
+ return reject("CSRF cookie not set.")
+ else:
+ return reject("CSRF token missing or incorrect.")
+ return accept()
+ def process_response(self, request, response):
+ if getattr(response, 'csrf_processing_done', False):
+ return response
+ # If CSRF_COOKIE is unset, then CsrfViewMiddleware.process_view was
+ # never called, probaby because a request middleware returned a response
+ # (for example, contrib.auth redirecting to a login page).
+ if request.META.get("CSRF_COOKIE") is None:
+ return response
+ if not request.META.get("CSRF_COOKIE_USED", False):
+ return response
+ # Set the CSRF cookie even if it's already set, so we renew the expiry timer.
+ response.set_cookie(settings.CSRF_COOKIE_NAME,
+ request.META["CSRF_COOKIE"], max_age = 60 * 60 * 24 * 7 * 52,
+ domain=settings.CSRF_COOKIE_DOMAIN)
+ # Content varies with the CSRF cookie, so set the Vary header.
+ from django.utils.cache import patch_vary_headers
+ patch_vary_headers(response, ('Cookie',))
+ response.csrf_processing_done = True
+ return response
+
+from django.utils.decorators import decorator_from_middleware
+from functools import wraps
+
+csrf_protect = decorator_from_middleware(CsrfViewMiddleware)
+csrf_protect.__name__ = "csrf_protect"
+csrf_protect.__doc__ = """
+This decorator adds CSRF protection in exactly the same way as
+CsrfViewMiddleware, but it can be used on a per view basis. Using both, or
+using the decorator multiple times, is harmless and efficient.
+"""
+
+def add_import_library_function():
+
+ #this definition is copy/pasted from django 1.2 source code
+ #it is necessary to make Coffin library happy
+ from django.utils.importlib import import_module
+ class InvalidTemplateLibrary(Exception):
+ pass
+
+ def import_library(taglib_module):
+ """Load a template tag library module.
+ Verifies that the library contains a 'register' attribute, and
+ returns that attribute as the representation of the library
+ """
+ app_path, taglib = taglib_module.rsplit('.',1)
+ app_module = import_module(app_path)
+ try:
+ mod = import_module(taglib_module)
+ except ImportError, e:
+ # If the ImportError is because the taglib submodule does not exist, that's not
+ # an error that should be raised. If the submodule exists and raised an ImportError
+ # on the attempt to load it, that we want to raise.
+ if not module_has_submodule(app_module, taglib):
+ return None
+ else:
+ raise InvalidTemplateLibrary("ImportError raised loading %s: %s" % (taglib_module, e))
+ try:
+ return mod.register
+ except AttributeError:
+ raise InvalidTemplateLibrary("Template library %s does not have a variable named 'register'" % taglib_module)
+
+ import django.template
+ django.template.import_library = import_library
+
+def add_csrf_protection():
+ """adds csrf_token template tag to django
+ Must be used if version of django is < 1.2
+
+ Also adds csrf function to the context processor
+ and the csrf_protect decorator for the views
+ """
+ import django.template.defaulttags
+ def csrf_token(parser, token):
+ return CsrfTokenNode()
+ django.template.defaulttags.CsrfTokenNode = CsrfTokenNode
+ django.template.defaulttags.register.tag(csrf_token)
+
+ #add csrf context processor
+ import django.core.context_processors
+ django.core.context_processors.csrf = csrf
+
+ #add csrf_protect decorator
+ import django.views.decorators
+ django.views.decorators.csrf = imp.new_module('csrf')
+ django.views.decorators.csrf.csrf_protect = csrf_protect
diff --git a/askbot/search/indexer.py b/askbot/search/indexer.py
deleted file mode 100644
index c7c45c59..00000000
--- a/askbot/search/indexer.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from django.conf import settings
-from django.db import connection
-
-def create_fulltext_indexes():
- if settings.DATABASE_ENGINE == 'mysql':
- cursor = connection.cursor()
- cursor.execute('ALTER TABLE question ADD FULLTEXT (title, text, tagnames)')
- cursor.execute('ALTER TABLE answer ADD FULLTEXT (title, text, tagnames)')
-
diff --git a/askbot/search/state_manager.py b/askbot/search/state_manager.py
index b50a0405..f45f4bcc 100644
--- a/askbot/search/state_manager.py
+++ b/askbot/search/state_manager.py
@@ -9,7 +9,7 @@ import logging
ACTIVE_COMMANDS = (
'sort', 'search', 'query',
- 'reset_query', 'reset_author', 'reset_tags',
+ 'reset_query', 'reset_author', 'reset_tags', 'remove_tag',
'tags', 'scope', 'page_size', 'start_over',
'page'
)
@@ -24,6 +24,7 @@ class SearchState(object):
def __init__(self):
self.scope = const.DEFAULT_POST_SCOPE
self.query = None
+ self.search = None
self.tags = None
self.author = None
self.sort = const.DEFAULT_POST_SORT_METHOD
@@ -35,6 +36,9 @@ class SearchState(object):
def __str__(self):
out = 'scope=%s\n' % self.scope
out += 'query=%s\n' % self.query
+ if hasattr(self, 'search'):
+ manual_search = (self.search == 'search')
+ out += 'manual_search = %s\n' % str(manual_search)
if self.tags:
out += 'tags=%s\n' % ','.join(self.tags)
out += 'author=%s\n' % self.author
@@ -87,7 +91,7 @@ class SearchState(object):
self.reset()
#todo also relax if 'all' scope was clicked twice
- def update_from_user_input(self, input_dict, unprocessed_input = {}):
+ def update_from_user_input(self, input_dict):
#todo: this function will probably not
#fit the case of multiple parameters entered at the same tiem
if 'start_over' in input_dict:
@@ -119,6 +123,11 @@ class SearchState(object):
else:
self.tags = input_dict['tags']
+ if 'remove_tag' in input_dict and self.tags:
+ rm_set = set([input_dict['remove_tag']])
+ self.tags -= rm_set
+ return
+
#all resets just return
if 'reset_tags' in input_dict:
if self.tags:
@@ -135,6 +144,8 @@ class SearchState(object):
if 'reset_query' in input_dict:
self.reset_query()
+ if input_dict.get('sort', None) == 'relevance-desc':
+ self.reset_sort()
return
self.update_value('author', input_dict)
@@ -142,9 +153,16 @@ class SearchState(object):
if 'query' in input_dict:
self.update_value('query', input_dict)
self.sort = 'relevance-desc'
- elif 'search' in unprocessed_input:#a case of use nulling search query by hand
+ elif 'search' in input_dict:
+ #a case of use nulling search query by hand
+ #this branch corresponds to hitting search button manually
+ #when the search query is empty
self.reset_query()
return
+ elif askbot_settings.DECOUPLE_TEXT_QUERY_FROM_SEARCH_STATE:
+ #no query in the request and the setting instructs to
+ #not have the text search query sticky
+ self.reset_query()
if 'sort' in input_dict:
if input_dict['sort'] == 'relevance-desc' and self.query is None:
@@ -157,10 +175,29 @@ class SearchState(object):
if self.sort == 'relevance-desc':
self.reset_sort()
+ def update(self, input_dict, view_log, user):
+ """update the search state according to the
+ user input and the queue of the page hits that
+ user made"""
+ if 'preserve_state' in input_dict:
+ return
+
+ if view_log.should_reset_search_state():
+ self.reset()
+
+ if user.is_authenticated():
+ self.set_logged_in()
+
+ self.update_from_user_input(input_dict)
+ self.relax_stickiness(input_dict, view_log)
+
def reset_page(self):
self.page = 1
def reset_query(self):
+ """reset the search query string and
+ the associated "sort by relevance command"
+ """
if self.query:
self.query = None
self.reset_page()
@@ -172,3 +209,45 @@ class SearchState(object):
def reset_scope(self):
self.scope = const.DEFAULT_POST_SCOPE
+
+class ViewLog(object):
+ """The ViewLog helper obejcts store the trail of the page visits for a
+ given user. The trail is recorded only up to a certain depth.
+
+ The purpose to record this info is to reset the search state
+ when the user walks "too far away" from the search page.
+
+ These objects must be modified only in this middlware.
+ """
+ def __init__(self):
+ self.views = []
+ self.depth = 3 #todo maybe move this to const.py
+
+ def get_previous(self, num):
+ """get a previous record from a certain depth"""
+ if num > self.depth - 1:
+ raise Exception("view log depth exceeded")
+ elif num < 0:
+ raise Exception("num must be positive")
+ elif num <= len(self.views) - 1:
+ return self.views[num]
+ else:
+ return None
+
+ def should_reset_search_state(self):
+ """return True if user stepped too far from the home page
+ and False otherwise"""
+ return False
+ if self.get_previous(1) != 'questions':
+ if self.get_previous(2) != 'questions':
+ return True
+ return False
+
+ def set_current(self, view_name):
+ """insert a new record"""
+ self.views.insert(0, view_name)
+ if len(self.views) > self.depth:
+ self.views.pop()
+
+ def __str__(self):
+ return str(self.views) + ' depth=%d' % self.depth
diff --git a/askbot/setup_templates/settings.py b/askbot/setup_templates/settings.py
index 9b745f81..5ded3e17 100644
--- a/askbot/setup_templates/settings.py
+++ b/askbot/setup_templates/settings.py
@@ -1,4 +1,4 @@
-# Django settings for ASKBOT enabled project.
+## Django settings for ASKBOT enabled project.
import os.path
import logging
import sys
@@ -24,7 +24,7 @@ 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
+#outgoing mail server settings
SERVER_EMAIL = ''
DEFAULT_FROM_EMAIL = ''
EMAIL_HOST_USER = ''
@@ -35,6 +35,21 @@ EMAIL_PORT=''
EMAIL_USE_TLS=False
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
+#incoming mail settings
+#after filling out these settings - please
+#go to the site's live settings and enable the feature
+#"Email settings" -> "allow asking by email"
+#
+# WARNING: command post_emailed_questions DELETES all
+# emails from the mailbox each time
+# do not use your personal mail box here!!!
+#
+IMAP_HOST = ''
+IMAP_HOST_USER = ''
+IMAP_HOST_PASSWORD = ''
+IMAP_PORT = ''
+IMAP_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.
@@ -115,7 +130,7 @@ DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
#TEMPLATE_DIRS = (,) #template have no effect in askbot, use the variable below
-#ASKBOT_EXTRA_SKIN_DIRS = (,)#path to your skin collection
+#ASKBOT_EXTRA_SKIN_DIR = #path to your private skin collection
#take a look here http://askbot.org/en/question/207/
TEMPLATE_CONTEXT_PROCESSORS = (
@@ -145,6 +160,11 @@ INSTALLED_APPS = (
'askbot.deps.livesettings',
'keyedcache',
'robots',
+ 'django_countries',
+ 'djcelery',
+ 'djkombu',
+ #'avatar',#experimental use git clone git://github.com/ericflo/django-avatar.git$
+ #requires setting of MEDIA_ROOT and MEDIA_URL
)
@@ -183,3 +203,10 @@ LOGIN_URL = '/%s%s%s' % (ASKBOT_URL,_('account/'),_('signin/'))
#also, this url must not have the leading slash
ASKBOT_UPLOADED_FILES_URL = '%s%s' % (ASKBOT_URL, 'upfiles/')
ALLOW_UNICODE_SLUGS = False
+
+#Celery Settings
+BROKER_BACKEND = "djkombu.transport.DatabaseTransport"
+CELERY_ALWAYS_EAGER = True
+
+import djcelery
+djcelery.setup_loader()
diff --git a/askbot/skins/README b/askbot/skins/README
index 01ef0a9d..3fbc8c33 100755
--- a/askbot/skins/README
+++ b/askbot/skins/README
@@ -1,22 +1,71 @@
-this directory contains available skins
+=============================
+Customization of Askbot skins
+=============================
-1) default - default skin with templates
-2) common - this directory is to media directory common to all or many templates
+The default skin at the moment is in the development, however
+it is already possible to start customizing your site without
+incurring much maintenance overhead.
-to create a new skin just create another directory under skins/
-and start populating it with the directory structure as in
-default/templates - templates must be named the same way
+Current status of templates
+===========================
+The two busiest templates are - the "main" page and the "question" page,
+the main page is more or less complete. "Question" page will be significantly
+refactored in the near future.
-NO NEED TO CREATE ALL TEMPLATES/MEDIA FILES AT ONCE
+How skins work in Askbot
+========================
-templates are resolved in the following way:
+The skins reside in up to two directories:
+
+* `askbot/skins` in the source code (contains any stock skins)
+* directory pointed to by a ASKBOT_EXTRA_SKINS_DIR in your settings.py
+ with any other skins
+
+Currently, the skin is selected by the site administrator in the live settings.
+Also, at the moment skin default is special - it serves any resources
+absent in other skins. In a way - all other skins inherit from the "default".
+
+Templates and media are resolved in the following way:
* check in skin named as in settings.ASKBOT_DEFAULT_SKIN
* then skin named 'default'
-media is resolved with one extra option
-* settings.ASKBOT_DEFAULT_SKIN
-* 'default'
-* 'common'
+How to customize a skin
+=======================
+
+There are three options:
+
+* edit custom css via the settings interface - good for small tweaks
+ (no need to directly log in to the server)
+* create a new skin in separate files (need direct access to the server
+ files, more maintenance overhead)
+* directly modify the "default" skin (as in the previous option - need
+ direct access to the server, less maintenance overhead, some
+ knowledge of git system is required)
+
+The first option only allows to modify css and add custom javascript.
+The latter two options allow changing the templates as well.
+
+If you wish to follow the second option, create a directory named the same
+way as the skin you are building and start adding files with the same names
+and relative locations as those in the "default" skin.
+
+NO NEED TO CREATE ALL TEMPLATES/MEDIA FILES AT ONCE as your skin will inherit
+pieces from the "default".
+
+The disadvantage of thil second approach is that you will be on your own maintaining
+the synchrony of your template, stylesheet and the core code.
+
+Third approach is the best, but it requires (the most basic) use of
+git source code management software. With git you will easily merge the updates
+from the development repository.
+
+Structure of the skin directories
+=================================
+Todo.
+
+To simplify maintenance of the css as the skin is being developed,
+populate css file `media/style/extra.css` with any rules that will
+override those in the `media/style/style.css` file. If you do that
media does not have to be composed of files named the same way as in default skin
whatever media you link to from your templates - will be in operation
diff --git a/askbot/skins/common/media/README b/askbot/skins/common/media/README
deleted file mode 100755
index 3376e754..00000000
--- a/askbot/skins/common/media/README
+++ /dev/null
@@ -1 +0,0 @@
-directory for media common to all or many templates
diff --git a/askbot/skins/default/media/images/anon.png b/askbot/skins/default/media/images/anon.png
new file mode 100644
index 00000000..a2041590
--- /dev/null
+++ b/askbot/skins/default/media/images/anon.png
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/.DS_Store b/askbot/skins/default/media/images/flags/.DS_Store
new file mode 100644
index 00000000..eb96b838
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/.DS_Store
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ad.gif b/askbot/skins/default/media/images/flags/ad.gif
new file mode 100755
index 00000000..57b49973
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ad.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ae.gif b/askbot/skins/default/media/images/flags/ae.gif
new file mode 100755
index 00000000..78d15b67
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ae.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/af.gif b/askbot/skins/default/media/images/flags/af.gif
new file mode 100755
index 00000000..98894082
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/af.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ag.gif b/askbot/skins/default/media/images/flags/ag.gif
new file mode 100755
index 00000000..48f8e7bc
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ag.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ai.gif b/askbot/skins/default/media/images/flags/ai.gif
new file mode 100755
index 00000000..1cbc5795
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ai.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/al.gif b/askbot/skins/default/media/images/flags/al.gif
new file mode 100755
index 00000000..c44fe0a0
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/al.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/am.gif b/askbot/skins/default/media/images/flags/am.gif
new file mode 100755
index 00000000..2915e30c
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/am.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/an.gif b/askbot/skins/default/media/images/flags/an.gif
new file mode 100755
index 00000000..cb570c67
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/an.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ao.gif b/askbot/skins/default/media/images/flags/ao.gif
new file mode 100644
index 00000000..8c854fa1
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ao.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ar.gif b/askbot/skins/default/media/images/flags/ar.gif
new file mode 100755
index 00000000..a9f71f7d
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ar.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/as.gif b/askbot/skins/default/media/images/flags/as.gif
new file mode 100755
index 00000000..d776ec27
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/as.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/at.gif b/askbot/skins/default/media/images/flags/at.gif
new file mode 100755
index 00000000..87e12173
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/at.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/au.gif b/askbot/skins/default/media/images/flags/au.gif
new file mode 100755
index 00000000..5269c6a0
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/au.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/aw.gif b/askbot/skins/default/media/images/flags/aw.gif
new file mode 100755
index 00000000..27fdb4d1
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/aw.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ax.gif b/askbot/skins/default/media/images/flags/ax.gif
new file mode 100755
index 00000000..0ceb6849
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ax.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/az.gif b/askbot/skins/default/media/images/flags/az.gif
new file mode 100755
index 00000000..d7716184
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/az.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ba.gif b/askbot/skins/default/media/images/flags/ba.gif
new file mode 100755
index 00000000..9bf5f0ac
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ba.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/bb.gif b/askbot/skins/default/media/images/flags/bb.gif
new file mode 100755
index 00000000..b7d08e57
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/bb.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/bd.gif b/askbot/skins/default/media/images/flags/bd.gif
new file mode 100755
index 00000000..0fd27eca
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/bd.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/be.gif b/askbot/skins/default/media/images/flags/be.gif
new file mode 100755
index 00000000..ae09bfbe
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/be.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/bf.gif b/askbot/skins/default/media/images/flags/bf.gif
new file mode 100755
index 00000000..9d6772cd
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/bf.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/bg.gif b/askbot/skins/default/media/images/flags/bg.gif
new file mode 100755
index 00000000..11cf8ff3
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/bg.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/bh.gif b/askbot/skins/default/media/images/flags/bh.gif
new file mode 100755
index 00000000..56aa72b2
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/bh.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/bi.gif b/askbot/skins/default/media/images/flags/bi.gif
new file mode 100755
index 00000000..6e2cbe12
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/bi.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/bj.gif b/askbot/skins/default/media/images/flags/bj.gif
new file mode 100755
index 00000000..e676116f
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/bj.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/bm.gif b/askbot/skins/default/media/images/flags/bm.gif
new file mode 100755
index 00000000..9feb87bc
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/bm.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/bn.gif b/askbot/skins/default/media/images/flags/bn.gif
new file mode 100755
index 00000000..b7b6b0f9
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/bn.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/bo.gif b/askbot/skins/default/media/images/flags/bo.gif
new file mode 100755
index 00000000..4844f856
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/bo.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/br.gif b/askbot/skins/default/media/images/flags/br.gif
new file mode 100755
index 00000000..8c866162
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/br.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/bs.gif b/askbot/skins/default/media/images/flags/bs.gif
new file mode 100755
index 00000000..c0a741e5
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/bs.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/bt.gif b/askbot/skins/default/media/images/flags/bt.gif
new file mode 100755
index 00000000..abe2f3cc
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/bt.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/bv.gif b/askbot/skins/default/media/images/flags/bv.gif
new file mode 100755
index 00000000..6202d1f3
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/bv.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/bw.gif b/askbot/skins/default/media/images/flags/bw.gif
new file mode 100755
index 00000000..986ab63c
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/bw.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/by.gif b/askbot/skins/default/media/images/flags/by.gif
new file mode 100755
index 00000000..43ffcd4c
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/by.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/bz.gif b/askbot/skins/default/media/images/flags/bz.gif
new file mode 100755
index 00000000..791737f0
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/bz.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ca.gif b/askbot/skins/default/media/images/flags/ca.gif
new file mode 100755
index 00000000..457d9662
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ca.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/catalonia.gif b/askbot/skins/default/media/images/flags/catalonia.gif
new file mode 100644
index 00000000..73df9a04
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/catalonia.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/cc.gif b/askbot/skins/default/media/images/flags/cc.gif
new file mode 100755
index 00000000..3f783270
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/cc.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/cd.gif b/askbot/skins/default/media/images/flags/cd.gif
new file mode 100644
index 00000000..1df717ae
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/cd.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/cf.gif b/askbot/skins/default/media/images/flags/cf.gif
new file mode 100755
index 00000000..35787ca4
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/cf.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/cg.gif b/askbot/skins/default/media/images/flags/cg.gif
new file mode 100755
index 00000000..e0a62a51
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/cg.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ch.gif b/askbot/skins/default/media/images/flags/ch.gif
new file mode 100755
index 00000000..d5c0e5b7
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ch.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ci.gif b/askbot/skins/default/media/images/flags/ci.gif
new file mode 100755
index 00000000..844120a5
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ci.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ck.gif b/askbot/skins/default/media/images/flags/ck.gif
new file mode 100755
index 00000000..2edb7399
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ck.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/cl.gif b/askbot/skins/default/media/images/flags/cl.gif
new file mode 100755
index 00000000..cbc370e6
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/cl.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/cm.gif b/askbot/skins/default/media/images/flags/cm.gif
new file mode 100755
index 00000000..1fb102b2
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/cm.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/cn.gif b/askbot/skins/default/media/images/flags/cn.gif
new file mode 100755
index 00000000..b0525309
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/cn.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/co.gif b/askbot/skins/default/media/images/flags/co.gif
new file mode 100755
index 00000000..d0e15caf
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/co.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/cr.gif b/askbot/skins/default/media/images/flags/cr.gif
new file mode 100755
index 00000000..0728dd6a
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/cr.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/cs.gif b/askbot/skins/default/media/images/flags/cs.gif
new file mode 100755
index 00000000..101db649
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/cs.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/cu.gif b/askbot/skins/default/media/images/flags/cu.gif
new file mode 100755
index 00000000..291255ca
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/cu.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/cv.gif b/askbot/skins/default/media/images/flags/cv.gif
new file mode 100755
index 00000000..43c6c6cb
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/cv.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/cx.gif b/askbot/skins/default/media/images/flags/cx.gif
new file mode 100755
index 00000000..a5b43089
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/cx.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/cy.gif b/askbot/skins/default/media/images/flags/cy.gif
new file mode 100755
index 00000000..35c661e1
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/cy.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/cz.gif b/askbot/skins/default/media/images/flags/cz.gif
new file mode 100755
index 00000000..0a605e58
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/cz.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/de.gif b/askbot/skins/default/media/images/flags/de.gif
new file mode 100755
index 00000000..75728ddf
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/de.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/dj.gif b/askbot/skins/default/media/images/flags/dj.gif
new file mode 100755
index 00000000..212406d9
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/dj.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/dk.gif b/askbot/skins/default/media/images/flags/dk.gif
new file mode 100755
index 00000000..03e75bd2
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/dk.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/dm.gif b/askbot/skins/default/media/images/flags/dm.gif
new file mode 100755
index 00000000..2f87f3ca
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/dm.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/do.gif b/askbot/skins/default/media/images/flags/do.gif
new file mode 100755
index 00000000..f7d0bad3
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/do.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/dz.gif b/askbot/skins/default/media/images/flags/dz.gif
new file mode 100755
index 00000000..ed580a7c
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/dz.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ec.gif b/askbot/skins/default/media/images/flags/ec.gif
new file mode 100755
index 00000000..9e41e0ec
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ec.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ee.gif b/askbot/skins/default/media/images/flags/ee.gif
new file mode 100755
index 00000000..9397a2d0
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ee.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/eg.gif b/askbot/skins/default/media/images/flags/eg.gif
new file mode 100755
index 00000000..6857c7dd
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/eg.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/eh.gif b/askbot/skins/default/media/images/flags/eh.gif
new file mode 100755
index 00000000..dd0391c2
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/eh.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/england.gif b/askbot/skins/default/media/images/flags/england.gif
new file mode 100755
index 00000000..933a4f0b
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/england.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/er.gif b/askbot/skins/default/media/images/flags/er.gif
new file mode 100755
index 00000000..3d4d612c
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/er.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/es.gif b/askbot/skins/default/media/images/flags/es.gif
new file mode 100755
index 00000000..c27d65e5
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/es.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/et.gif b/askbot/skins/default/media/images/flags/et.gif
new file mode 100755
index 00000000..f77995d0
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/et.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/europeanunion.gif b/askbot/skins/default/media/images/flags/europeanunion.gif
new file mode 100644
index 00000000..28a762a5
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/europeanunion.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/fam.gif b/askbot/skins/default/media/images/flags/fam.gif
new file mode 100755
index 00000000..7d528852
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/fam.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/fi.gif b/askbot/skins/default/media/images/flags/fi.gif
new file mode 100755
index 00000000..8d3a1918
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/fi.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/fj.gif b/askbot/skins/default/media/images/flags/fj.gif
new file mode 100755
index 00000000..486151cb
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/fj.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/fk.gif b/askbot/skins/default/media/images/flags/fk.gif
new file mode 100755
index 00000000..37b5ecf3
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/fk.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/fm.gif b/askbot/skins/default/media/images/flags/fm.gif
new file mode 100755
index 00000000..7f8723b7
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/fm.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/fo.gif b/askbot/skins/default/media/images/flags/fo.gif
new file mode 100755
index 00000000..4a90fc04
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/fo.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/fr.gif b/askbot/skins/default/media/images/flags/fr.gif
new file mode 100755
index 00000000..43d0b801
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/fr.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ga.gif b/askbot/skins/default/media/images/flags/ga.gif
new file mode 100755
index 00000000..23fd5f0d
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ga.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/gb.gif b/askbot/skins/default/media/images/flags/gb.gif
new file mode 100644
index 00000000..3c6bce15
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/gb.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/gd.gif b/askbot/skins/default/media/images/flags/gd.gif
new file mode 100755
index 00000000..25ea3123
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/gd.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ge.gif b/askbot/skins/default/media/images/flags/ge.gif
new file mode 100755
index 00000000..faa7f126
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ge.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/gf.gif b/askbot/skins/default/media/images/flags/gf.gif
new file mode 100755
index 00000000..43d0b801
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/gf.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/gh.gif b/askbot/skins/default/media/images/flags/gh.gif
new file mode 100755
index 00000000..273fb7d1
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/gh.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/gi.gif b/askbot/skins/default/media/images/flags/gi.gif
new file mode 100755
index 00000000..7b1984bc
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/gi.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/gl.gif b/askbot/skins/default/media/images/flags/gl.gif
new file mode 100755
index 00000000..ef445be0
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/gl.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/gm.gif b/askbot/skins/default/media/images/flags/gm.gif
new file mode 100755
index 00000000..6847c5a8
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/gm.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/gn.gif b/askbot/skins/default/media/images/flags/gn.gif
new file mode 100755
index 00000000..a982ac6f
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/gn.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/gp.gif b/askbot/skins/default/media/images/flags/gp.gif
new file mode 100755
index 00000000..31166db6
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/gp.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/gq.gif b/askbot/skins/default/media/images/flags/gq.gif
new file mode 100755
index 00000000..8b4e0cc4
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/gq.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/gr.gif b/askbot/skins/default/media/images/flags/gr.gif
new file mode 100755
index 00000000..b4c8c04e
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/gr.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/gs.gif b/askbot/skins/default/media/images/flags/gs.gif
new file mode 100755
index 00000000..ccc96ec0
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/gs.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/gt.gif b/askbot/skins/default/media/images/flags/gt.gif
new file mode 100755
index 00000000..7e94d1dd
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/gt.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/gu.gif b/askbot/skins/default/media/images/flags/gu.gif
new file mode 100755
index 00000000..eafef683
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/gu.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/gw.gif b/askbot/skins/default/media/images/flags/gw.gif
new file mode 100755
index 00000000..55f75711
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/gw.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/gy.gif b/askbot/skins/default/media/images/flags/gy.gif
new file mode 100755
index 00000000..1cb4cd71
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/gy.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/hk.gif b/askbot/skins/default/media/images/flags/hk.gif
new file mode 100755
index 00000000..798af96d
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/hk.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/hm.gif b/askbot/skins/default/media/images/flags/hm.gif
new file mode 100755
index 00000000..5269c6a0
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/hm.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/hn.gif b/askbot/skins/default/media/images/flags/hn.gif
new file mode 100755
index 00000000..6c4ffe8e
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/hn.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/hr.gif b/askbot/skins/default/media/images/flags/hr.gif
new file mode 100755
index 00000000..557c6602
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/hr.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ht.gif b/askbot/skins/default/media/images/flags/ht.gif
new file mode 100755
index 00000000..059604ab
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ht.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/hu.gif b/askbot/skins/default/media/images/flags/hu.gif
new file mode 100755
index 00000000..6142d868
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/hu.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/id.gif b/askbot/skins/default/media/images/flags/id.gif
new file mode 100755
index 00000000..865161b0
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/id.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ie.gif b/askbot/skins/default/media/images/flags/ie.gif
new file mode 100755
index 00000000..506ad285
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ie.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/il.gif b/askbot/skins/default/media/images/flags/il.gif
new file mode 100755
index 00000000..c8483ae5
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/il.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/in.gif b/askbot/skins/default/media/images/flags/in.gif
new file mode 100755
index 00000000..1cd80272
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/in.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/io.gif b/askbot/skins/default/media/images/flags/io.gif
new file mode 100755
index 00000000..de7e7ab3
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/io.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/iq.gif b/askbot/skins/default/media/images/flags/iq.gif
new file mode 100755
index 00000000..c34fe3c4
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/iq.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ir.gif b/askbot/skins/default/media/images/flags/ir.gif
new file mode 100755
index 00000000..156040fc
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ir.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/is.gif b/askbot/skins/default/media/images/flags/is.gif
new file mode 100755
index 00000000..b42502de
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/is.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/it.gif b/askbot/skins/default/media/images/flags/it.gif
new file mode 100755
index 00000000..d79e90e9
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/it.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/jm.gif b/askbot/skins/default/media/images/flags/jm.gif
new file mode 100755
index 00000000..0bed67c2
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/jm.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/jo.gif b/askbot/skins/default/media/images/flags/jo.gif
new file mode 100755
index 00000000..03daf8af
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/jo.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/jp.gif b/askbot/skins/default/media/images/flags/jp.gif
new file mode 100755
index 00000000..444c1d05
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/jp.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ke.gif b/askbot/skins/default/media/images/flags/ke.gif
new file mode 100755
index 00000000..c2b5d45c
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ke.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/kg.gif b/askbot/skins/default/media/images/flags/kg.gif
new file mode 100755
index 00000000..72a4d412
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/kg.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/kh.gif b/askbot/skins/default/media/images/flags/kh.gif
new file mode 100755
index 00000000..30a18315
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/kh.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ki.gif b/askbot/skins/default/media/images/flags/ki.gif
new file mode 100755
index 00000000..4a0751a2
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ki.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/km.gif b/askbot/skins/default/media/images/flags/km.gif
new file mode 100755
index 00000000..5859595e
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/km.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/kn.gif b/askbot/skins/default/media/images/flags/kn.gif
new file mode 100755
index 00000000..bb9cc34a
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/kn.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/kp.gif b/askbot/skins/default/media/images/flags/kp.gif
new file mode 100755
index 00000000..6e0ca09e
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/kp.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/kr.gif b/askbot/skins/default/media/images/flags/kr.gif
new file mode 100755
index 00000000..1cddbe75
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/kr.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/kw.gif b/askbot/skins/default/media/images/flags/kw.gif
new file mode 100755
index 00000000..1efc7347
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/kw.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ky.gif b/askbot/skins/default/media/images/flags/ky.gif
new file mode 100755
index 00000000..d3d02ee4
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ky.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/kz.gif b/askbot/skins/default/media/images/flags/kz.gif
new file mode 100755
index 00000000..24baebe0
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/kz.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/la.gif b/askbot/skins/default/media/images/flags/la.gif
new file mode 100755
index 00000000..d14cf4d8
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/la.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/lb.gif b/askbot/skins/default/media/images/flags/lb.gif
new file mode 100755
index 00000000..003d83af
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/lb.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/lc.gif b/askbot/skins/default/media/images/flags/lc.gif
new file mode 100644
index 00000000..f5fe5bff
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/lc.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/li.gif b/askbot/skins/default/media/images/flags/li.gif
new file mode 100755
index 00000000..713c58e1
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/li.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/lk.gif b/askbot/skins/default/media/images/flags/lk.gif
new file mode 100755
index 00000000..1b3ee7f5
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/lk.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/lr.gif b/askbot/skins/default/media/images/flags/lr.gif
new file mode 100755
index 00000000..435af9e5
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/lr.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ls.gif b/askbot/skins/default/media/images/flags/ls.gif
new file mode 100755
index 00000000..427ae957
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ls.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/lt.gif b/askbot/skins/default/media/images/flags/lt.gif
new file mode 100755
index 00000000..dee9c601
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/lt.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/lu.gif b/askbot/skins/default/media/images/flags/lu.gif
new file mode 100755
index 00000000..7d7293ed
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/lu.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/lv.gif b/askbot/skins/default/media/images/flags/lv.gif
new file mode 100755
index 00000000..17e71b7e
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/lv.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ly.gif b/askbot/skins/default/media/images/flags/ly.gif
new file mode 100755
index 00000000..a654c30a
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ly.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ma.gif b/askbot/skins/default/media/images/flags/ma.gif
new file mode 100755
index 00000000..fc784119
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ma.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/mc.gif b/askbot/skins/default/media/images/flags/mc.gif
new file mode 100755
index 00000000..02a7c8e1
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/mc.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/md.gif b/askbot/skins/default/media/images/flags/md.gif
new file mode 100755
index 00000000..e4b8a7e3
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/md.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/me.gif b/askbot/skins/default/media/images/flags/me.gif
new file mode 100644
index 00000000..a260453c
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/me.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/mg.gif b/askbot/skins/default/media/images/flags/mg.gif
new file mode 100755
index 00000000..a91b577d
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/mg.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/mh.gif b/askbot/skins/default/media/images/flags/mh.gif
new file mode 100755
index 00000000..92f5f485
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/mh.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/mk.gif b/askbot/skins/default/media/images/flags/mk.gif
new file mode 100755
index 00000000..7aeb8311
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/mk.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ml.gif b/askbot/skins/default/media/images/flags/ml.gif
new file mode 100755
index 00000000..53d6f490
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ml.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/mm.gif b/askbot/skins/default/media/images/flags/mm.gif
new file mode 100755
index 00000000..9e0a2756
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/mm.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/mn.gif b/askbot/skins/default/media/images/flags/mn.gif
new file mode 100755
index 00000000..dff8ea5a
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/mn.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/mo.gif b/askbot/skins/default/media/images/flags/mo.gif
new file mode 100755
index 00000000..66cf5b4f
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/mo.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/mp.gif b/askbot/skins/default/media/images/flags/mp.gif
new file mode 100755
index 00000000..73b7147e
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/mp.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/mq.gif b/askbot/skins/default/media/images/flags/mq.gif
new file mode 100755
index 00000000..570bc5dd
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/mq.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/mr.gif b/askbot/skins/default/media/images/flags/mr.gif
new file mode 100755
index 00000000..f52fcf09
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/mr.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ms.gif b/askbot/skins/default/media/images/flags/ms.gif
new file mode 100755
index 00000000..5e5a67aa
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ms.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/mt.gif b/askbot/skins/default/media/images/flags/mt.gif
new file mode 100755
index 00000000..45c709f2
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/mt.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/mu.gif b/askbot/skins/default/media/images/flags/mu.gif
new file mode 100755
index 00000000..081ab453
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/mu.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/mv.gif b/askbot/skins/default/media/images/flags/mv.gif
new file mode 100755
index 00000000..46b63875
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/mv.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/mw.gif b/askbot/skins/default/media/images/flags/mw.gif
new file mode 100755
index 00000000..ad045a09
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/mw.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/mx.gif b/askbot/skins/default/media/images/flags/mx.gif
new file mode 100755
index 00000000..ddc75d04
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/mx.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/my.gif b/askbot/skins/default/media/images/flags/my.gif
new file mode 100755
index 00000000..fc7d5236
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/my.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/mz.gif b/askbot/skins/default/media/images/flags/mz.gif
new file mode 100755
index 00000000..7d635082
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/mz.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/na.gif b/askbot/skins/default/media/images/flags/na.gif
new file mode 100755
index 00000000..c0babe72
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/na.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/nc.gif b/askbot/skins/default/media/images/flags/nc.gif
new file mode 100755
index 00000000..b1e91b9a
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/nc.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ne.gif b/askbot/skins/default/media/images/flags/ne.gif
new file mode 100755
index 00000000..ff4eaf07
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ne.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/nf.gif b/askbot/skins/default/media/images/flags/nf.gif
new file mode 100755
index 00000000..c83424c2
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/nf.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ng.gif b/askbot/skins/default/media/images/flags/ng.gif
new file mode 100755
index 00000000..bdde7cb3
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ng.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ni.gif b/askbot/skins/default/media/images/flags/ni.gif
new file mode 100755
index 00000000..d05894d0
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ni.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/nl.gif b/askbot/skins/default/media/images/flags/nl.gif
new file mode 100755
index 00000000..c1c8f46d
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/nl.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/no.gif b/askbot/skins/default/media/images/flags/no.gif
new file mode 100755
index 00000000..6202d1f3
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/no.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/np.gif b/askbot/skins/default/media/images/flags/np.gif
new file mode 100755
index 00000000..1096893a
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/np.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/nr.gif b/askbot/skins/default/media/images/flags/nr.gif
new file mode 100755
index 00000000..2e4c0c5c
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/nr.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/nu.gif b/askbot/skins/default/media/images/flags/nu.gif
new file mode 100755
index 00000000..618210a7
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/nu.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/nz.gif b/askbot/skins/default/media/images/flags/nz.gif
new file mode 100755
index 00000000..028a5dc6
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/nz.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/om.gif b/askbot/skins/default/media/images/flags/om.gif
new file mode 100755
index 00000000..2b8c7750
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/om.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/pa.gif b/askbot/skins/default/media/images/flags/pa.gif
new file mode 100755
index 00000000..d518b2f9
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/pa.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/pe.gif b/askbot/skins/default/media/images/flags/pe.gif
new file mode 100755
index 00000000..3bc76390
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/pe.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/pf.gif b/askbot/skins/default/media/images/flags/pf.gif
new file mode 100755
index 00000000..849297a5
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/pf.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/pg.gif b/askbot/skins/default/media/images/flags/pg.gif
new file mode 100755
index 00000000..2d20b078
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/pg.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ph.gif b/askbot/skins/default/media/images/flags/ph.gif
new file mode 100755
index 00000000..12b380ac
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ph.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/pk.gif b/askbot/skins/default/media/images/flags/pk.gif
new file mode 100755
index 00000000..f3f62c2e
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/pk.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/pl.gif b/askbot/skins/default/media/images/flags/pl.gif
new file mode 100755
index 00000000..bf106463
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/pl.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/pm.gif b/askbot/skins/default/media/images/flags/pm.gif
new file mode 100755
index 00000000..99bf6fdb
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/pm.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/pn.gif b/askbot/skins/default/media/images/flags/pn.gif
new file mode 100755
index 00000000..4bc86a1d
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/pn.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/pr.gif b/askbot/skins/default/media/images/flags/pr.gif
new file mode 100755
index 00000000..6d5d5896
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/pr.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ps.gif b/askbot/skins/default/media/images/flags/ps.gif
new file mode 100755
index 00000000..6afa3b71
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ps.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/pt.gif b/askbot/skins/default/media/images/flags/pt.gif
new file mode 100755
index 00000000..e735f740
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/pt.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/pw.gif b/askbot/skins/default/media/images/flags/pw.gif
new file mode 100755
index 00000000..5854510f
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/pw.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/py.gif b/askbot/skins/default/media/images/flags/py.gif
new file mode 100755
index 00000000..f2e66af7
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/py.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/qa.gif b/askbot/skins/default/media/images/flags/qa.gif
new file mode 100755
index 00000000..2e843ff9
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/qa.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/re.gif b/askbot/skins/default/media/images/flags/re.gif
new file mode 100755
index 00000000..43d0b801
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/re.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ro.gif b/askbot/skins/default/media/images/flags/ro.gif
new file mode 100755
index 00000000..f5d5f125
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ro.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/rs.gif b/askbot/skins/default/media/images/flags/rs.gif
new file mode 100644
index 00000000..3bd1fb2f
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/rs.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ru.gif b/askbot/skins/default/media/images/flags/ru.gif
new file mode 100755
index 00000000..b525c462
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ru.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/rw.gif b/askbot/skins/default/media/images/flags/rw.gif
new file mode 100755
index 00000000..0d095f7a
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/rw.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/sa.gif b/askbot/skins/default/media/images/flags/sa.gif
new file mode 100755
index 00000000..179961b6
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/sa.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/sb.gif b/askbot/skins/default/media/images/flags/sb.gif
new file mode 100755
index 00000000..8f5ff837
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/sb.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/sc.gif b/askbot/skins/default/media/images/flags/sc.gif
new file mode 100755
index 00000000..31b47677
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/sc.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/scotland.gif b/askbot/skins/default/media/images/flags/scotland.gif
new file mode 100755
index 00000000..03f3f1de
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/scotland.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/sd.gif b/askbot/skins/default/media/images/flags/sd.gif
new file mode 100755
index 00000000..53ae214f
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/sd.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/se.gif b/askbot/skins/default/media/images/flags/se.gif
new file mode 100755
index 00000000..80f62852
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/se.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/sg.gif b/askbot/skins/default/media/images/flags/sg.gif
new file mode 100755
index 00000000..5663d39f
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/sg.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/sh.gif b/askbot/skins/default/media/images/flags/sh.gif
new file mode 100755
index 00000000..dcc7f3bc
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/sh.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/si.gif b/askbot/skins/default/media/images/flags/si.gif
new file mode 100755
index 00000000..23852b50
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/si.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/sj.gif b/askbot/skins/default/media/images/flags/sj.gif
new file mode 100755
index 00000000..6202d1f3
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/sj.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/sk.gif b/askbot/skins/default/media/images/flags/sk.gif
new file mode 100755
index 00000000..1b3f22ba
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/sk.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/sl.gif b/askbot/skins/default/media/images/flags/sl.gif
new file mode 100755
index 00000000..f0f34923
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/sl.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/sm.gif b/askbot/skins/default/media/images/flags/sm.gif
new file mode 100755
index 00000000..04d98de5
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/sm.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/sn.gif b/askbot/skins/default/media/images/flags/sn.gif
new file mode 100755
index 00000000..6dac8709
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/sn.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/so.gif b/askbot/skins/default/media/images/flags/so.gif
new file mode 100755
index 00000000..f1961694
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/so.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/sr.gif b/askbot/skins/default/media/images/flags/sr.gif
new file mode 100755
index 00000000..0f7499ad
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/sr.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/st.gif b/askbot/skins/default/media/images/flags/st.gif
new file mode 100755
index 00000000..4f1e6e09
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/st.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/sv.gif b/askbot/skins/default/media/images/flags/sv.gif
new file mode 100755
index 00000000..2d7b159a
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/sv.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/sy.gif b/askbot/skins/default/media/images/flags/sy.gif
new file mode 100755
index 00000000..dc8bd509
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/sy.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/sz.gif b/askbot/skins/default/media/images/flags/sz.gif
new file mode 100755
index 00000000..f37aaf80
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/sz.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/tc.gif b/askbot/skins/default/media/images/flags/tc.gif
new file mode 100755
index 00000000..11a8c232
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/tc.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/td.gif b/askbot/skins/default/media/images/flags/td.gif
new file mode 100755
index 00000000..7aa8a10d
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/td.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/tf.gif b/askbot/skins/default/media/images/flags/tf.gif
new file mode 100755
index 00000000..51a43250
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/tf.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/tg.gif b/askbot/skins/default/media/images/flags/tg.gif
new file mode 100755
index 00000000..ca6b4e77
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/tg.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/th.gif b/askbot/skins/default/media/images/flags/th.gif
new file mode 100755
index 00000000..01307924
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/th.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/tj.gif b/askbot/skins/default/media/images/flags/tj.gif
new file mode 100755
index 00000000..2fe38d4a
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/tj.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/tk.gif b/askbot/skins/default/media/images/flags/tk.gif
new file mode 100755
index 00000000..3d3a727f
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/tk.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/tl.gif b/askbot/skins/default/media/images/flags/tl.gif
new file mode 100755
index 00000000..df22d582
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/tl.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/tm.gif b/askbot/skins/default/media/images/flags/tm.gif
new file mode 100755
index 00000000..36d0994f
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/tm.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/tn.gif b/askbot/skins/default/media/images/flags/tn.gif
new file mode 100755
index 00000000..917d4288
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/tn.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/to.gif b/askbot/skins/default/media/images/flags/to.gif
new file mode 100755
index 00000000..d7ed4d11
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/to.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/tr.gif b/askbot/skins/default/media/images/flags/tr.gif
new file mode 100755
index 00000000..e407d553
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/tr.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/tt.gif b/askbot/skins/default/media/images/flags/tt.gif
new file mode 100755
index 00000000..47d3b806
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/tt.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/tv.gif b/askbot/skins/default/media/images/flags/tv.gif
new file mode 100755
index 00000000..3c338277
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/tv.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/tw.gif b/askbot/skins/default/media/images/flags/tw.gif
new file mode 100755
index 00000000..cacfd9b7
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/tw.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/tz.gif b/askbot/skins/default/media/images/flags/tz.gif
new file mode 100755
index 00000000..82b52ca2
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/tz.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ua.gif b/askbot/skins/default/media/images/flags/ua.gif
new file mode 100755
index 00000000..5d6cd83f
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ua.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ug.gif b/askbot/skins/default/media/images/flags/ug.gif
new file mode 100755
index 00000000..58b731ad
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ug.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/um.gif b/askbot/skins/default/media/images/flags/um.gif
new file mode 100755
index 00000000..3b4c8483
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/um.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/us.gif b/askbot/skins/default/media/images/flags/us.gif
new file mode 100755
index 00000000..8f198f73
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/us.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/uy.gif b/askbot/skins/default/media/images/flags/uy.gif
new file mode 100755
index 00000000..12848c74
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/uy.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/uz.gif b/askbot/skins/default/media/images/flags/uz.gif
new file mode 100755
index 00000000..dc9daeca
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/uz.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/va.gif b/askbot/skins/default/media/images/flags/va.gif
new file mode 100755
index 00000000..2bd74468
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/va.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/vc.gif b/askbot/skins/default/media/images/flags/vc.gif
new file mode 100755
index 00000000..48213816
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/vc.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ve.gif b/askbot/skins/default/media/images/flags/ve.gif
new file mode 100755
index 00000000..19ce6c14
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ve.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/vg.gif b/askbot/skins/default/media/images/flags/vg.gif
new file mode 100755
index 00000000..1fc0f96e
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/vg.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/vi.gif b/askbot/skins/default/media/images/flags/vi.gif
new file mode 100755
index 00000000..66f9e746
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/vi.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/vn.gif b/askbot/skins/default/media/images/flags/vn.gif
new file mode 100755
index 00000000..f1e20c94
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/vn.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/vu.gif b/askbot/skins/default/media/images/flags/vu.gif
new file mode 100755
index 00000000..8a8b2b06
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/vu.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/wales.gif b/askbot/skins/default/media/images/flags/wales.gif
new file mode 100755
index 00000000..901d1750
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/wales.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/wf.gif b/askbot/skins/default/media/images/flags/wf.gif
new file mode 100755
index 00000000..eaa954b1
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/wf.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ws.gif b/askbot/skins/default/media/images/flags/ws.gif
new file mode 100755
index 00000000..a51f939e
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ws.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/ye.gif b/askbot/skins/default/media/images/flags/ye.gif
new file mode 100755
index 00000000..7b0183d0
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/ye.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/yt.gif b/askbot/skins/default/media/images/flags/yt.gif
new file mode 100755
index 00000000..a2267c05
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/yt.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/za.gif b/askbot/skins/default/media/images/flags/za.gif
new file mode 100755
index 00000000..ede52589
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/za.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/zm.gif b/askbot/skins/default/media/images/flags/zm.gif
new file mode 100755
index 00000000..b2851d2b
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/zm.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/flags/zw.gif b/askbot/skins/default/media/images/flags/zw.gif
new file mode 100755
index 00000000..02901f62
--- /dev/null
+++ b/askbot/skins/default/media/images/flags/zw.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/tag-left.png b/askbot/skins/default/media/images/tag-left.png
new file mode 100644
index 00000000..5a9d8a0d
--- /dev/null
+++ b/askbot/skins/default/media/images/tag-left.png
Binary files differ
diff --git a/askbot/skins/default/media/images/tag-right.png b/askbot/skins/default/media/images/tag-right.png
new file mode 100644
index 00000000..871664c3
--- /dev/null
+++ b/askbot/skins/default/media/images/tag-right.png
Binary files differ
diff --git a/askbot/skins/default/media/jquery-openid/jquery.openid.js b/askbot/skins/default/media/jquery-openid/jquery.openid.js
index b3b06d40..273d9264 100755
--- a/askbot/skins/default/media/jquery-openid/jquery.openid.js
+++ b/askbot/skins/default/media/jquery-openid/jquery.openid.js
@@ -170,7 +170,9 @@ $.fn.authenticator = function() {
setup_event_handlers(
enabler,
function(){
- password_input_fields.hide();
+ if (askbot['settings']['signin_always_show_local_login'] === false){
+ password_input_fields.hide();
+ }
openid_login_token_input_fields.hide();
enabler.hide();
existing_login_methods_div.show();
@@ -193,7 +195,9 @@ $.fn.authenticator = function() {
var reset_form = function(){
openid_login_token_input_fields.hide();
- password_input_fields.hide();
+ if (askbot['settings']['signin_always_show_local_login'] === false){
+ password_input_fields.hide();
+ }
reset_password_input_fields();
$('.error').remove();
if (userIsAuthenticated === false){
diff --git a/askbot/skins/default/media/js/autocompleter.js b/askbot/skins/default/media/js/autocompleter.js
new file mode 100644
index 00000000..a7c54315
--- /dev/null
+++ b/askbot/skins/default/media/js/autocompleter.js
@@ -0,0 +1,766 @@
+/**
+ * AutoCompleter Object, refactored closure style from
+ * jQuery autocomplete plugin
+ * @param {Object=} options Settings
+ * @constructor
+ */
+var AutoCompleter = function(options) {
+
+ /**
+ * Default options for autocomplete plugin
+ */
+ var defaults = {
+ autocompleteMultiple: true,
+ multipleSeparator: ' ',//a single character
+ inputClass: 'acInput',
+ loadingClass: 'acLoading',
+ resultsClass: 'acResults',
+ selectClass: 'acSelect',
+ queryParamName: 'q',
+ limitParamName: 'limit',
+ extraParams: {},
+ lineSeparator: '\n',
+ cellSeparator: '|',
+ minChars: 2,
+ maxItemsToShow: 10,
+ delay: 400,
+ useCache: true,
+ maxCacheLength: 10,
+ matchSubset: true,
+ matchCase: false,
+ matchInside: true,
+ mustMatch: false,
+ preloadData: false,
+ selectFirst: false,
+ stopCharRegex: /\s+/,
+ selectOnly: false,
+ formatItem: null, // TBD
+ onItemSelect: false,
+ autoFill: false,
+ filterResults: true,
+ sortResults: true,
+ sortFunction: false,
+ onNoMatch: false
+ };
+
+ /**
+ * Options dictionary
+ * @type Object
+ * @private
+ */
+ this.options = $.extend({}, defaults, options);
+
+ /**
+ * Cached data
+ * @type Object
+ * @private
+ */
+ this.cacheData_ = {};
+
+ /**
+ * Number of cached data items
+ * @type number
+ * @private
+ */
+ this.cacheLength_ = 0;
+
+ /**
+ * Class name to mark selected item
+ * @type string
+ * @private
+ */
+ this.selectClass_ = 'jquery-autocomplete-selected-item';
+
+ /**
+ * Handler to activation timeout
+ * @type ?number
+ * @private
+ */
+ this.keyTimeout_ = null;
+
+ /**
+ * Last key pressed in the input field (store for behavior)
+ * @type ?number
+ * @private
+ */
+ this.lastKeyPressed_ = null;
+
+ /**
+ * Last value processed by the autocompleter
+ * @type ?string
+ * @private
+ */
+ this.lastProcessedValue_ = null;
+
+ /**
+ * Last value selected by the user
+ * @type ?string
+ * @private
+ */
+ this.lastSelectedValue_ = null;
+
+ /**
+ * Is this autocompleter active?
+ * @type boolean
+ * @private
+ */
+ this.active_ = false;
+
+ /**
+ * Is it OK to finish on blur?
+ * @type boolean
+ * @private
+ */
+ this.finishOnBlur_ = true;
+
+ this.options.minChars = parseInt(this.options.minChars, 10);
+ if (isNaN(this.options.minChars) || this.options.minChars < 1) {
+ this.options.minChars = 2;
+ }
+
+ this.options.maxItemsToShow = parseInt(this.options.maxItemsToShow, 10);
+ if (isNaN(this.options.maxItemsToShow) || this.options.maxItemsToShow < 1) {
+ this.options.maxItemsToShow = 10;
+ }
+
+ this.options.maxCacheLength = parseInt(this.options.maxCacheLength, 10);
+ if (isNaN(this.options.maxCacheLength) || this.options.maxCacheLength < 1) {
+ this.options.maxCacheLength = 10;
+ }
+
+ if (this.options['preloadData'] === true){
+ this.fetchRemoteData('', function(){});
+ }
+};
+inherits(AutoCompleter, WrappedElement);
+
+AutoCompleter.prototype.decorate = function(element){
+
+ /**
+ * Init DOM elements repository
+ */
+ this._element = element;
+
+ /**
+ * Switch off the native autocomplete
+ */
+ this._element.attr('autocomplete', 'off');
+
+ /**
+ * Create DOM element to hold results
+ */
+ this._results = $('<div></div>').hide();
+ if (this.options.resultsClass) {
+ this._results.addClass(this.options.resultsClass);
+ }
+ this._results.css({
+ position: 'absolute'
+ });
+ $('body').append(this._results);
+
+ this.setEventHandlers();
+};
+
+AutoCompleter.prototype.setEventHandlers = function(){
+ /**
+ * Shortcut to self
+ */
+ var self = this;
+
+ /**
+ * Attach keyboard monitoring to $elem
+ */
+ self._element.keydown(function(e) {
+ self.lastKeyPressed_ = e.keyCode;
+ switch(self.lastKeyPressed_) {
+
+ case 38: // up
+ e.preventDefault();
+ if (self.active_) {
+ self.focusPrev();
+ } else {
+ self.activate();
+ }
+ return false;
+ break;
+
+ case 40: // down
+ e.preventDefault();
+ if (self.active_) {
+ self.focusNext();
+ } else {
+ self.activate();
+ }
+ return false;
+ break;
+
+ case 9: // tab
+ case 13: // return
+ if (self.active_) {
+ e.preventDefault();
+ self.selectCurrent();
+ return false;
+ }
+ break;
+
+ case 27: // escape
+ if (self.active_) {
+ e.preventDefault();
+ self.finish();
+ return false;
+ }
+ break;
+
+ default:
+ self.activate();
+
+ }
+ });
+ self._element.blur(function() {
+ if (self.finishOnBlur_) {
+ setTimeout(function() { self.finish(); }, 200);
+ }
+ });
+};
+
+AutoCompleter.prototype.position = function() {
+ var offset = this._element.offset();
+ this._results.css({
+ top: offset.top + this._element.outerHeight(),
+ left: offset.left
+ });
+};
+
+AutoCompleter.prototype.cacheRead = function(filter) {
+ var filterLength, searchLength, search, maxPos, pos;
+ if (this.options.useCache) {
+ filter = String(filter);
+ filterLength = filter.length;
+ if (this.options.matchSubset) {
+ searchLength = 1;
+ } else {
+ searchLength = filterLength;
+ }
+ while (searchLength <= filterLength) {
+ if (this.options.matchInside) {
+ maxPos = filterLength - searchLength;
+ } else {
+ maxPos = 0;
+ }
+ pos = 0;
+ while (pos <= maxPos) {
+ search = filter.substr(0, searchLength);
+ if (this.cacheData_[search] !== undefined) {
+ return this.cacheData_[search];
+ }
+ pos++;
+ }
+ searchLength++;
+ }
+ }
+ return false;
+};
+
+AutoCompleter.prototype.cacheWrite = function(filter, data) {
+ if (this.options.useCache) {
+ if (this.cacheLength_ >= this.options.maxCacheLength) {
+ this.cacheFlush();
+ }
+ filter = String(filter);
+ if (this.cacheData_[filter] !== undefined) {
+ this.cacheLength_++;
+ }
+ return this.cacheData_[filter] = data;
+ }
+ return false;
+};
+
+AutoCompleter.prototype.cacheFlush = function() {
+ this.cacheData_ = {};
+ this.cacheLength_ = 0;
+};
+
+AutoCompleter.prototype.callHook = function(hook, data) {
+ var f = this.options[hook];
+ if (f && $.isFunction(f)) {
+ return f(data, this);
+ }
+ return false;
+};
+
+AutoCompleter.prototype.activate = function() {
+ var self = this;
+ var activateNow = function() {
+ self.activateNow();
+ };
+ var delay = parseInt(this.options.delay, 10);
+ if (isNaN(delay) || delay <= 0) {
+ delay = 250;
+ }
+ if (this.keyTimeout_) {
+ clearTimeout(this.keyTimeout_);
+ }
+ this.keyTimeout_ = setTimeout(activateNow, delay);
+};
+
+AutoCompleter.prototype.activateNow = function() {
+ var value = this.getValue();
+ if (value !== this.lastProcessedValue_ && value !== this.lastSelectedValue_) {
+ if (value.length >= this.options.minChars) {
+ this.active_ = true;
+ this.lastProcessedValue_ = value;
+ this.fetchData(value);
+ }
+ }
+};
+
+AutoCompleter.prototype.fetchData = function(value) {
+ if (this.options.data) {
+ this.filterAndShowResults(this.options.data, value);
+ } else {
+ var self = this;
+ this.fetchRemoteData(value, function(remoteData) {
+ self.filterAndShowResults(remoteData, value);
+ });
+ }
+};
+
+AutoCompleter.prototype.fetchRemoteData = function(filter, callback) {
+ var data = this.cacheRead(filter);
+ if (data) {
+ callback(data);
+ } else {
+ var self = this;
+ if (this._element){
+ this._element.addClass(this.options.loadingClass);
+ }
+ var ajaxCallback = function(data) {
+ var parsed = false;
+ if (data !== false) {
+ parsed = self.parseRemoteData(data);
+ self.options.data = parsed;//cache data forever - E.F.
+ self.cacheWrite(filter, parsed);
+ }
+ if (self._element){
+ self._element.removeClass(self.options.loadingClass);
+ }
+ callback(parsed);
+ };
+ $.ajax({
+ url: this.makeUrl(filter),
+ success: ajaxCallback,
+ error: function() {
+ ajaxCallback(false);
+ }
+ });
+ }
+};
+
+AutoCompleter.prototype.setOption = function(name, value){
+ this.options[name] = value;
+};
+
+AutoCompleter.prototype.setExtraParam = function(name, value) {
+ var index = $.trim(String(name));
+ if (index) {
+ if (!this.options.extraParams) {
+ this.options.extraParams = {};
+ }
+ if (this.options.extraParams[index] !== value) {
+ this.options.extraParams[index] = value;
+ this.cacheFlush();
+ }
+ }
+};
+
+AutoCompleter.prototype.makeUrl = function(param) {
+ var self = this;
+ var url = this.options.url;
+ var params = $.extend({}, this.options.extraParams);
+ // If options.queryParamName === false, append query to url
+ // instead of using a GET parameter
+ if (this.options.queryParamName === false) {
+ url += encodeURIComponent(param);
+ } else {
+ params[this.options.queryParamName] = param;
+ }
+
+ if (this.options.limitParamName && this.options.maxItemsToShow) {
+ params[this.options.limitParamName] = this.options.maxItemsToShow;
+ }
+
+ var urlAppend = [];
+ $.each(params, function(index, value) {
+ urlAppend.push(self.makeUrlParam(index, value));
+ });
+ if (urlAppend.length) {
+ url += url.indexOf('?') == -1 ? '?' : '&';
+ url += urlAppend.join('&');
+ }
+ return url;
+};
+
+AutoCompleter.prototype.makeUrlParam = function(name, value) {
+ return String(name) + '=' + encodeURIComponent(value);
+};
+
+/**
+ * Sanitize CR and LF, then split into lines
+ */
+AutoCompleter.prototype.splitText = function(text) {
+ return String(text).replace(/(\r\n|\r|\n)/g, '\n').split(this.options.lineSeparator);
+};
+
+AutoCompleter.prototype.parseRemoteData = function(remoteData) {
+ var value, lines, i, j, data;
+ var results = [];
+ var lines = this.splitText(remoteData);
+ for (i = 0; i < lines.length; i++) {
+ var line = lines[i].split(this.options.cellSeparator);
+ data = [];
+ for (j = 0; j < line.length; j++) {
+ data.push(unescape(line[j]));
+ }
+ value = data.shift();
+ results.push({ value: unescape(value), data: data });
+ }
+ return results;
+};
+
+AutoCompleter.prototype.filterAndShowResults = function(results, filter) {
+ this.showResults(this.filterResults(results, filter), filter);
+};
+
+AutoCompleter.prototype.filterResults = function(results, filter) {
+
+ var filtered = [];
+ var value, data, i, result, type, include;
+ var regex, pattern, testValue;
+
+ for (i = 0; i < results.length; i++) {
+ result = results[i];
+ type = typeof result;
+ if (type === 'string') {
+ value = result;
+ data = {};
+ } else if ($.isArray(result)) {
+ value = result[0];
+ data = result.slice(1);
+ } else if (type === 'object') {
+ value = result.value;
+ data = result.data;
+ }
+ value = String(value);
+ if (value > '') {
+ if (typeof data !== 'object') {
+ data = {};
+ }
+ if (this.options.filterResults) {
+ pattern = String(filter);
+ testValue = String(value);
+ if (!this.options.matchCase) {
+ pattern = pattern.toLowerCase();
+ testValue = testValue.toLowerCase();
+ }
+ include = testValue.indexOf(pattern);
+ if (this.options.matchInside) {
+ include = include > -1;
+ } else {
+ include = include === 0;
+ }
+ } else {
+ include = true;
+ }
+ if (include) {
+ filtered.push({ value: value, data: data });
+ }
+ }
+ }
+
+ if (this.options.sortResults) {
+ filtered = this.sortResults(filtered, filter);
+ }
+
+ if (this.options.maxItemsToShow > 0 && this.options.maxItemsToShow < filtered.length) {
+ filtered.length = this.options.maxItemsToShow;
+ }
+
+ return filtered;
+
+};
+
+AutoCompleter.prototype.sortResults = function(results, filter) {
+ var self = this;
+ var sortFunction = this.options.sortFunction;
+ if (!$.isFunction(sortFunction)) {
+ sortFunction = function(a, b, f) {
+ return self.sortValueAlpha(a, b, f);
+ };
+ }
+ results.sort(function(a, b) {
+ return sortFunction(a, b, filter);
+ });
+ return results;
+};
+
+AutoCompleter.prototype.sortValueAlpha = function(a, b, filter) {
+ a = String(a.value);
+ b = String(b.value);
+ if (!this.options.matchCase) {
+ a = a.toLowerCase();
+ b = b.toLowerCase();
+ }
+ if (a > b) {
+ return 1;
+ }
+ if (a < b) {
+ return -1;
+ }
+ return 0;
+};
+
+AutoCompleter.prototype.showResults = function(results, filter) {
+ var self = this;
+ var $ul = $('<ul></ul>');
+ var i, result, $li, extraWidth, first = false, $first = false;
+ var numResults = results.length;
+ for (i = 0; i < numResults; i++) {
+ result = results[i];
+ $li = $('<li>' + this.showResult(result.value, result.data) + '</li>');
+ $li.data('value', result.value);
+ $li.data('data', result.data);
+ $li.click(function() {
+ var $this = $(this);
+ self.selectItem($this);
+ }).mousedown(function() {
+ self.finishOnBlur_ = false;
+ }).mouseup(function() {
+ self.finishOnBlur_ = true;
+ });
+ $ul.append($li);
+ if (first === false) {
+ first = String(result.value);
+ $first = $li;
+ $li.addClass(this.options.firstItemClass);
+ }
+ if (i == numResults - 1) {
+ $li.addClass(this.options.lastItemClass);
+ }
+ }
+
+ // Alway recalculate position before showing since window size or
+ // input element location may have changed. This fixes #14
+ this.position();
+
+ this._results.html($ul).show();
+ extraWidth = this._results.outerWidth() - this._results.width();
+ this._results.width(this._element.outerWidth() - extraWidth);
+ $('li', this._results).hover(
+ function() { self.focusItem(this); },
+ function() { /* void */ }
+ );
+ if (this.autoFill(first, filter)) {
+ this.focusItem($first);
+ }
+};
+
+AutoCompleter.prototype.showResult = function(value, data) {
+ if ($.isFunction(this.options.showResult)) {
+ return this.options.showResult(value, data);
+ } else {
+ return value;
+ }
+};
+
+AutoCompleter.prototype.autoFill = function(value, filter) {
+ var lcValue, lcFilter, valueLength, filterLength;
+ if (this.options.autoFill && this.lastKeyPressed_ != 8) {
+ lcValue = String(value).toLowerCase();
+ lcFilter = String(filter).toLowerCase();
+ valueLength = value.length;
+ filterLength = filter.length;
+ if (lcValue.substr(0, filterLength) === lcFilter) {
+ this._element.val(value);
+ this.selectRange(filterLength, valueLength);
+ return true;
+ }
+ }
+ return false;
+};
+
+AutoCompleter.prototype.focusNext = function() {
+ this.focusMove(+1);
+};
+
+AutoCompleter.prototype.focusPrev = function() {
+ this.focusMove(-1);
+};
+
+AutoCompleter.prototype.focusMove = function(modifier) {
+ var i, $items = $('li', this._results);
+ modifier = parseInt(modifier, 10);
+ for (var i = 0; i < $items.length; i++) {
+ if ($($items[i]).hasClass(this.selectClass_)) {
+ this.focusItem(i + modifier);
+ return;
+ }
+ }
+ this.focusItem(0);
+};
+
+AutoCompleter.prototype.focusItem = function(item) {
+ var $item, $items = $('li', this._results);
+ if ($items.length) {
+ $items.removeClass(this.selectClass_).removeClass(this.options.selectClass);
+ if (typeof item === 'number') {
+ item = parseInt(item, 10);
+ if (item < 0) {
+ item = 0;
+ } else if (item >= $items.length) {
+ item = $items.length - 1;
+ }
+ $item = $($items[item]);
+ } else {
+ $item = $(item);
+ }
+ if ($item) {
+ $item.addClass(this.selectClass_).addClass(this.options.selectClass);
+ }
+ }
+};
+
+AutoCompleter.prototype.selectCurrent = function() {
+ var $item = $('li.' + this.selectClass_, this._results);
+ if ($item.length == 1) {
+ this.selectItem($item);
+ } else {
+ this.finish();
+ }
+};
+
+AutoCompleter.prototype.selectItem = function($li) {
+ var value = $li.data('value');
+ var data = $li.data('data');
+ var displayValue = this.displayValue(value, data);
+ this.lastProcessedValue_ = displayValue;
+ this.lastSelectedValue_ = displayValue;
+
+ this.setValue(displayValue);
+
+ this.setCaret(displayValue.length);
+ this.callHook('onItemSelect', { value: value, data: data });
+ this.finish();
+};
+
+/**
+ * @return {boolean} true if the symbol matches something that is
+ * considered content and false otherwise
+ * @param {string} symbol - a single char string
+ */
+AutoCompleter.prototype.isContentChar = function(symbol){
+ if (symbol.match(this.options['stopCharRegex'])){
+ return false;
+ } else if (symbol === this.options['multipleSeparator']){
+ return false;
+ } else {
+ return true;
+ }
+};
+
+/**
+ * takes value from the input box
+ * and saves _selection_start and _selection_end coordinates
+ * respects settings autocompleteMultiple and
+ * multipleSeparator
+ * @return {string} the current word in the
+ * autocompletable word
+ */
+AutoCompleter.prototype.getValue = function(){
+ var sel = this._element.getSelection();
+ var text = this._element.val();
+ var pos = sel.start;//estimated start
+ //find real start
+ var start = pos;
+ for (cpos = pos; cpos >= 0; cpos = cpos - 1){
+ if (cpos === text.length){
+ continue;
+ }
+ var symbol = text.charAt(cpos);
+ if (!this.isContentChar(symbol)){
+ break;
+ }
+ start = cpos;
+ }
+ //find real end
+ var end = pos;
+ for (cpos = pos; cpos < text.length; cpos = cpos + 1){
+ if (cpos === 0){
+ continue;
+ }
+ var symbol = text.charAt(cpos);
+ if (!this.isContentChar(symbol)){
+ break;
+ }
+ end = cpos;
+ }
+ this._selection_start = start;
+ this._selection_end = end;
+ return text.substring(start, end);
+}
+
+/**
+ * sets value of the input box
+ * by replacing the previous selection
+ * with the value from the autocompleter
+ */
+AutoCompleter.prototype.setValue = function(val){
+ var prefix = this._element.val().substring(0, this._selection_start);
+ var postfix = this._element.val().substring(this._selection_end + 1);
+ this._element.val(prefix + val + postfix);
+};
+
+AutoCompleter.prototype.displayValue = function(value, data) {
+ if ($.isFunction(this.options.displayValue)) {
+ return this.options.displayValue(value, data);
+ } else {
+ return value;
+ }
+};
+
+AutoCompleter.prototype.finish = function() {
+ if (this.keyTimeout_) {
+ clearTimeout(this.keyTimeout_);
+ }
+ if (this._element.val() !== this.lastSelectedValue_) {
+ if (this.options.mustMatch) {
+ this._element.val('');
+ }
+ this.callHook('onNoMatch');
+ }
+ this._results.hide();
+ this.lastKeyPressed_ = null;
+ this.lastProcessedValue_ = null;
+ if (this.active_) {
+ this.callHook('onFinish');
+ }
+ this.active_ = false;
+};
+
+AutoCompleter.prototype.selectRange = function(start, end) {
+ var input = this._element.get(0);
+ if (input.setSelectionRange) {
+ input.focus();
+ input.setSelectionRange(start, end);
+ } else if (this.createTextRange) {
+ var range = this.createTextRange();
+ range.collapse(true);
+ range.moveEnd('character', end);
+ range.moveStart('character', start);
+ range.select();
+ }
+};
+
+AutoCompleter.prototype.setCaret = function(pos) {
+ this.selectRange(pos, pos);
+};
+
diff --git a/askbot/skins/default/media/js/editor.js b/askbot/skins/default/media/js/editor.js
index f69639cf..1c936a80 100644
--- a/askbot/skins/default/media/js/editor.js
+++ b/askbot/skins/default/media/js/editor.js
@@ -4,16 +4,6 @@
Version 1.0.4
*/(function($){var textarea,staticOffset;var iLastMousePos=0;var iMin=32;var grip;$.fn.TextAreaResizer=function(){return this.each(function(){textarea=$(this).addClass('processed'),staticOffset=null;$(this).wrap('<div class="resizable-textarea"><span></span></div>').parent().append($('<div class="grippie"></div>').bind("mousedown",{el:this},startDrag));var grippie=$('div.grippie',$(this).parent())[0];grippie.style.marginRight=(grippie.offsetWidth-$(this)[0].offsetWidth)+'px'})};function startDrag(e){textarea=$(e.data.el);textarea.blur();iLastMousePos=mousePosition(e).y;staticOffset=textarea.height()-iLastMousePos;textarea.css('opacity',0.25);$(document).mousemove(performDrag).mouseup(endDrag);return false}function performDrag(e){var iThisMousePos=mousePosition(e).y;var iMousePos=staticOffset+iThisMousePos;if(iLastMousePos>=(iThisMousePos)){iMousePos-=5}iLastMousePos=iThisMousePos;iMousePos=Math.max(iMin,iMousePos);textarea.height(iMousePos+'px');if(iMousePos<iMin){endDrag(e)}return false}function endDrag(e){$(document).unbind('mousemove',performDrag).unbind('mouseup',endDrag);textarea.css('opacity',1);textarea.focus();textarea=null;staticOffset=null;iLastMousePos=0}function mousePosition(e){return{x:e.clientX+document.documentElement.scrollLeft,y:e.clientY+document.documentElement.scrollTop}}})(jQuery);
/*
- * Autocomplete - jQuery plugin 1.0.2
- * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
- * Dual licensed under the MIT and GPL licenses:
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
- */;(function($){$.fn.extend({autocomplete:function(urlOrData,options){var isUrl=typeof urlOrData=="string";options=$.extend({},$.Autocompleter.defaults,{url:isUrl?urlOrData:null,data:isUrl?null:urlOrData,delay:isUrl?$.Autocompleter.defaults.delay:10,max:options&&!options.scroll?10:150},options);options.highlight=options.highlight||function(value){return value;};options.formatMatch=options.formatMatch||options.formatItem;return this.each(function(){new $.Autocompleter(this,options);});},result:function(handler){return this.bind("result",handler);},search:function(handler){return this.trigger("search",[handler]);},flushCache:function(){return this.trigger("flushCache");},setOptions:function(options){return this.trigger("setOptions",[options]);},unautocomplete:function(){return this.trigger("unautocomplete");}});$.Autocompleter=function(input,options){var KEY={UP:38,DOWN:40,DEL:46,TAB:9,RETURN:13,ESC:27,COMMA:188,PAGEUP:33,PAGEDOWN:34,BACKSPACE:8};var $input=$(input).attr("autocomplete","off").addClass(options.inputClass);var timeout;var previousValue="";var cache=$.Autocompleter.Cache(options);var hasFocus=0;var lastKeyPressCode;var config={mouseDownOnSelect:false};var select=$.Autocompleter.Select(options,input,selectCurrent,config);var blockSubmit;$.browser.opera&&$(input.form).bind("submit.autocomplete",function(){if(blockSubmit){blockSubmit=false;return false;}});$input.bind(($.browser.opera?"keypress":"keydown")+".autocomplete",function(event){lastKeyPressCode=event.keyCode;switch(event.keyCode){case KEY.UP:event.preventDefault();if(select.visible()){select.prev();}else{onChange(0,true);}break;case KEY.DOWN:event.preventDefault();if(select.visible()){select.next();}else{onChange(0,true);}break;case KEY.PAGEUP:event.preventDefault();if(select.visible()){select.pageUp();}else{onChange(0,true);}break;case KEY.PAGEDOWN:event.preventDefault();if(select.visible()){select.pageDown();}else{onChange(0,true);}break;case options.multiple&&$.trim(options.multipleSeparator)==","&&KEY.COMMA:case KEY.TAB:case KEY.RETURN:if(selectCurrent()){event.preventDefault();blockSubmit=true;return false;}break;case KEY.ESC:select.hide();break;default:clearTimeout(timeout);timeout=setTimeout(onChange,options.delay);break;}}).focus(function(){hasFocus++;}).blur(function(){hasFocus=0;if(!config.mouseDownOnSelect){hideResults();}}).click(function(){if(hasFocus++>1&&!select.visible()){onChange(0,true);}}).bind("search",function(){var fn=(arguments.length>1)?arguments[1]:null;function findValueCallback(q,data){var result;if(data&&data.length){for(var i=0;i<data.length;i++){if(data[i].result.toLowerCase()==q.toLowerCase()){result=data[i];break;}}}if(typeof fn=="function")fn(result);else $input.trigger("result",result&&[result.data,result.value]);}$.each(trimWords($input.val()),function(i,value){request(value,findValueCallback,findValueCallback);});}).bind("flushCache",function(){cache.flush();}).bind("setOptions",function(){$.extend(options,arguments[1]);if("data"in arguments[1])cache.populate();}).bind("unautocomplete",function(){select.unbind();$input.unbind();$(input.form).unbind(".autocomplete");});function selectCurrent(){var selected=select.selected();if(!selected)return false;var v=selected.result;previousValue=v;if(options.multiple){var words=trimWords($input.val());if(words.length>1){v=words.slice(0,words.length-1).join(options.multipleSeparator)+options.multipleSeparator+v;}v+=options.multipleSeparator;}$input.val(v);hideResultsNow();$input.trigger("result",[selected.data,selected.value]);return true;}function onChange(crap,skipPrevCheck){if(lastKeyPressCode==KEY.DEL){select.hide();return;}var currentValue=$input.val();if(!skipPrevCheck&&currentValue==previousValue)return;previousValue=currentValue;currentValue=lastWord(currentValue);if(currentValue.length>=options.minChars){$input.addClass(options.loadingClass);if(!options.matchCase)currentValue=currentValue.toLowerCase();request(currentValue,receiveData,hideResultsNow);}else{stopLoading();select.hide();}};function trimWords(value){if(!value){return[""];}var words=value.split(options.multipleSeparator);var result=[];$.each(words,function(i,value){if($.trim(value))result[i]=$.trim(value);});return result;}function lastWord(value){if(!options.multiple)return value;var words=trimWords(value);return words[words.length-1];}function autoFill(q,sValue){if(options.autoFill&&(lastWord($input.val()).toLowerCase()==q.toLowerCase())&&lastKeyPressCode!=KEY.BACKSPACE){$input.val($input.val()+sValue.substring(lastWord(previousValue).length));$.Autocompleter.Selection(input,previousValue.length,previousValue.length+sValue.length);}};function hideResults(){clearTimeout(timeout);timeout=setTimeout(hideResultsNow,200);};function hideResultsNow(){var wasVisible=select.visible();select.hide();clearTimeout(timeout);stopLoading();if(options.mustMatch){$input.search(function(result){if(!result){if(options.multiple){var words=trimWords($input.val()).slice(0,-1);$input.val(words.join(options.multipleSeparator)+(words.length?options.multipleSeparator:""));}else
-$input.val("");}});}if(wasVisible)$.Autocompleter.Selection(input,input.value.length,input.value.length);};function receiveData(q,data){if(data&&data.length&&hasFocus){stopLoading();select.display(data,q);autoFill(q,data[0].value);select.show();}else{hideResultsNow();}};function request(term,success,failure){if(!options.matchCase)term=term.toLowerCase();var data=cache.load(term);if(data&&data.length){success(term,data);}else if((typeof options.url=="string")&&(options.url.length>0)){var extraParams={timestamp:+new Date()};$.each(options.extraParams,function(key,param){extraParams[key]=typeof param=="function"?param():param;});$.ajax({mode:"abort",port:"autocomplete"+input.name,dataType:options.dataType,url:options.url,data:$.extend({q:lastWord(term),limit:options.max},extraParams),success:function(data){var parsed=options.parse&&options.parse(data)||parse(data);cache.add(term,parsed);success(term,parsed);}});}else{select.emptyList();failure(term);}};function parse(data){var parsed=[];var rows=data.split("\n");for(var i=0;i<rows.length;i++){var row=$.trim(rows[i]);if(row){row=row.split("|");parsed[parsed.length]={data:row,value:row[0],result:options.formatResult&&options.formatResult(row,row[0])||row[0]};}}return parsed;};function stopLoading(){$input.removeClass(options.loadingClass);};};$.Autocompleter.defaults={inputClass:"ac_input",resultsClass:"ac_results",loadingClass:"ac_loading",minChars:1,delay:400,matchCase:false,matchSubset:true,matchContains:false,cacheLength:10,max:100,mustMatch:false,extraParams:{},selectFirst:true,formatItem:function(row){return row[0];},formatMatch:null,autoFill:false,width:0,multiple:false,multipleSeparator:", ",highlight:function(value,term){return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"<strong>$1</strong>");},scroll:true,scrollHeight:180};$.Autocompleter.Cache=function(options){var data={};var length=0;function matchSubset(s,sub){if(!options.matchCase)s=s.toLowerCase();var i=s.indexOf(sub);if(i==-1)return false;return i==0||options.matchContains;};function add(q,value){if(length>options.cacheLength){flush();}if(!data[q]){length++;}data[q]=value;}function populate(){if(!options.data)return false;var stMatchSets={},nullData=0;if(!options.url)options.cacheLength=1;stMatchSets[""]=[];for(var i=0,ol=options.data.length;i<ol;i++){var rawValue=options.data[i];rawValue=(typeof rawValue=="string")?[rawValue]:rawValue;var value=options.formatMatch(rawValue,i+1,options.data.length);if(value===false)continue;var firstChar=value.charAt(0).toLowerCase();if(!stMatchSets[firstChar])stMatchSets[firstChar]=[];var row={value:value,data:rawValue,result:options.formatResult&&options.formatResult(rawValue)||value};stMatchSets[firstChar].push(row);if(nullData++<options.max){stMatchSets[""].push(row);}};$.each(stMatchSets,function(i,value){options.cacheLength++;add(i,value);});}setTimeout(populate,25);function flush(){data={};length=0;}return{flush:flush,add:add,populate:populate,load:function(q){if(!options.cacheLength||!length)return null;if(!options.url&&options.matchContains){var csub=[];for(var k in data){if(k.length>0){var c=data[k];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub.push(x);}});}}return csub;}else
-if(data[q]){return data[q];}else
-if(options.matchSubset){for(var i=q.length-1;i>=options.minChars;i--){var c=data[q.substr(0,i)];if(c){var csub=[];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub[csub.length]=x;}});return csub;}}}return null;}};};$.Autocompleter.Select=function(options,input,select,config){var CLASSES={ACTIVE:"ac_over"};var listItems,active=-1,data,term="",needsInit=true,element,list;function init(){if(!needsInit)return;element=$("<div/>").hide().addClass(options.resultsClass).css("position","absolute").appendTo(document.body);list=$("<ul/>").appendTo(element).mouseover(function(event){if(target(event).nodeName&&target(event).nodeName.toUpperCase()=='LI'){active=$("li",list).removeClass(CLASSES.ACTIVE).index(target(event));$(target(event)).addClass(CLASSES.ACTIVE);}}).click(function(event){$(target(event)).addClass(CLASSES.ACTIVE);select();input.focus();return false;}).mousedown(function(){config.mouseDownOnSelect=true;}).mouseup(function(){config.mouseDownOnSelect=false;});if(options.width>0)element.css("width",options.width);needsInit=false;}function target(event){var element=event.target;while(element&&element.tagName!="LI")element=element.parentNode;if(!element)return[];return element;}function moveSelect(step){listItems.slice(active,active+1).removeClass(CLASSES.ACTIVE);movePosition(step);var activeItem=listItems.slice(active,active+1).addClass(CLASSES.ACTIVE);if(options.scroll){var offset=0;listItems.slice(0,active).each(function(){offset+=this.offsetHeight;});if((offset+activeItem[0].offsetHeight-list.scrollTop())>list[0].clientHeight){list.scrollTop(offset+activeItem[0].offsetHeight-list.innerHeight());}else if(offset<list.scrollTop()){list.scrollTop(offset);}}};function movePosition(step){active+=step;if(active<0){active=listItems.size()-1;}else if(active>=listItems.size()){active=0;}}function limitNumberOfItems(available){return options.max&&options.max<available?options.max:available;}function fillList(){list.empty();var max=limitNumberOfItems(data.length);for(var i=0;i<max;i++){if(!data[i])continue;var formatted=options.formatItem(data[i].data,i+1,max,data[i].value,term);if(formatted===false)continue;var li=$("<li/>").html(options.highlight(formatted,term)).addClass(i%2==0?"ac_even":"ac_odd").appendTo(list)[0];$.data(li,"ac_data",data[i]);}listItems=list.find("li");if(options.selectFirst){listItems.slice(0,1).addClass(CLASSES.ACTIVE);active=0;}if($.fn.bgiframe)list.bgiframe();}return{display:function(d,q){init();data=d;term=q;fillList();},next:function(){moveSelect(1);},prev:function(){moveSelect(-1);},pageUp:function(){if(active!=0&&active-8<0){moveSelect(-active);}else{moveSelect(-8);}},pageDown:function(){if(active!=listItems.size()-1&&active+8>listItems.size()){moveSelect(listItems.size()-1-active);}else{moveSelect(8);}},hide:function(){element&&element.hide();listItems&&listItems.removeClass(CLASSES.ACTIVE);active=-1;},visible:function(){return element&&element.is(":visible");},current:function(){return this.visible()&&(listItems.filter("."+CLASSES.ACTIVE)[0]||options.selectFirst&&listItems[0]);},show:function(){var offset=$(input).offset();element.css({width:typeof options.width=="string"||options.width>0?options.width:$(input).width(),top:offset.top+input.offsetHeight,left:offset.left}).show();if(options.scroll){list.scrollTop(0);list.css({maxHeight:options.scrollHeight,overflow:'auto'});if($.browser.msie&&typeof document.body.style.maxHeight==="undefined"){var listHeight=0;listItems.each(function(){listHeight+=this.offsetHeight;});var scrollbarsVisible=listHeight>options.scrollHeight;list.css('height',scrollbarsVisible?options.scrollHeight:listHeight);if(!scrollbarsVisible){listItems.width(list.width()-parseInt(listItems.css("padding-left"))-parseInt(listItems.css("padding-right")));}}}},selected:function(){var selected=listItems&&listItems.filter("."+CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);return selected&&selected.length&&$.data(selected[0],"ac_data");},emptyList:function(){list&&list.empty();},unbind:function(){element&&element.remove();}};};$.Autocompleter.Selection=function(field,start,end){if(field.createTextRange){var selRange=field.createTextRange();selRange.collapse(true);selRange.moveStart("character",start);selRange.moveEnd("character",end);selRange.select();}else if(field.setSelectionRange){field.setSelectionRange(start,end);}else{if(field.selectionStart){field.selectionStart=start;field.selectionEnd=end;}}field.focus();};})(jQuery);
-/*
* TypeWatch 2.0 - Original by Denny Ferrassoli / Refactored by Charles Christolini
* Copyright(c) 2007 Denny Ferrassoli - DennyDotNet.com
* Coprright(c) 2008 Charles Christolini - BinaryPie.com
diff --git a/askbot/skins/default/media/js/jquery-fieldselection.js b/askbot/skins/default/media/js/jquery-fieldselection.js
new file mode 100644
index 00000000..47f25a98
--- /dev/null
+++ b/askbot/skins/default/media/js/jquery-fieldselection.js
@@ -0,0 +1,83 @@
+/*
+ * jQuery plugin: fieldSelection - v0.1.0 - last change: 2006-12-16
+ * (c) 2006 Alex Brem <alex@0xab.cd> - http://blog.0xab.cd
+ */
+
+(function() {
+
+ var fieldSelection = {
+
+ getSelection: function() {
+
+ var e = this.jquery ? this[0] : this;
+
+ return (
+
+ /* mozilla / dom 3.0 */
+ ('selectionStart' in e && function() {
+ var l = e.selectionEnd - e.selectionStart;
+ return { start: e.selectionStart, end: e.selectionEnd, length: l, text: e.value.substr(e.selectionStart, l) };
+ }) ||
+
+ /* exploder */
+ (document.selection && function() {
+
+ e.focus();
+
+ var r = document.selection.createRange();
+ if (r == null) {
+ return { start: 0, end: e.value.length, length: 0 }
+ }
+
+ var re = e.createTextRange();
+ var rc = re.duplicate();
+ re.moveToBookmark(r.getBookmark());
+ rc.setEndPoint('EndToStart', re);
+
+ return { start: rc.text.length, end: rc.text.length + r.text.length, length: r.text.length, text: r.text };
+ }) ||
+
+ /* browser not supported */
+ function() {
+ return { start: 0, end: e.value.length, length: 0 };
+ }
+
+ )();
+
+ },
+
+ replaceSelection: function() {
+
+ var e = this.jquery ? this[0] : this;
+ var text = arguments[0] || '';
+
+ return (
+
+ /* mozilla / dom 3.0 */
+ ('selectionStart' in e && function() {
+ e.value = e.value.substr(0, e.selectionStart) + text + e.value.substr(e.selectionEnd, e.value.length);
+ return this;
+ }) ||
+
+ /* exploder */
+ (document.selection && function() {
+ e.focus();
+ document.selection.createRange().text = text;
+ return this;
+ }) ||
+
+ /* browser not supported */
+ function() {
+ e.value += text;
+ return this;
+ }
+
+ )();
+
+ }
+
+ };
+
+ jQuery.each(fieldSelection, function(i) { jQuery.fn[i] = this; });
+
+})();
diff --git a/askbot/skins/default/media/js/jquery-fieldselection.min.js b/askbot/skins/default/media/js/jquery-fieldselection.min.js
new file mode 100644
index 00000000..c2abde0b
--- /dev/null
+++ b/askbot/skins/default/media/js/jquery-fieldselection.min.js
@@ -0,0 +1 @@
+(function(){var a={getSelection:function(){var b=this.jquery?this[0]:this;return(("selectionStart" in b&&function(){var c=b.selectionEnd-b.selectionStart;return{start:b.selectionStart,end:b.selectionEnd,length:c,text:b.value.substr(b.selectionStart,c)}})||(document.selection&&function(){b.focus();var d=document.selection.createRange();if(d==null){return{start:0,end:b.value.length,length:0}}var c=b.createTextRange();var e=c.duplicate();c.moveToBookmark(d.getBookmark());e.setEndPoint("EndToStart",c);return{start:e.text.length,end:e.text.length+d.text.length,length:d.text.length,text:d.text}})||function(){return{start:0,end:b.value.length,length:0}})()},replaceSelection:function(){var b=this.jquery?this[0]:this;var c=arguments[0]||"";return(("selectionStart" in b&&function(){b.value=b.value.substr(0,b.selectionStart)+c+b.value.substr(b.selectionEnd,b.value.length);return this})||(document.selection&&function(){b.focus();document.selection.createRange().text=c;return this})||function(){b.value+=c;return this})()}};jQuery.each(a,function(b){jQuery.fn[b]=this})})(); \ No newline at end of file
diff --git a/askbot/skins/default/media/js/live_search.js b/askbot/skins/default/media/js/live_search.js
index cdd165d3..b94ecf07 100644
--- a/askbot/skins/default/media/js/live_search.js
+++ b/askbot/skins/default/media/js/live_search.js
@@ -1,13 +1,18 @@
var prevSortMethod = sortMethod;
-$(document).ready(function(){
- var query = $('input#keywords');
- var prev_text = $.trim(query.val());
+var liveSearch = function(){
+ var query = undefined;
+ var prev_text = undefined;
var running = false;
- var q_list_sel = 'listA';//id of question listing div
+ var q_list_sel = 'question-list';//id of question listing div
+ var search_url = undefined;
+ var restart_query = function(){};
+ var process_query = function(){};
+ var render_result = function(){};
+
var refresh_x_button = function(){
if ($.trim(query.val()).length > 0){
- if (query.attr('class') == 'searchInput'){
+ if (query.attr('class') === 'searchInput'){
query.attr('class', 'searchInputCancelable');
x_button = $('<input class="cancelSearchBtn" type="button" name="reset_query"/>');
//x_button.click(reset_query);
@@ -15,70 +20,81 @@ $(document).ready(function(){
x_button.click(
function(){
query.val('');
- if (sortMethod == 'relevance-desc'){
+ if (sortMethod === 'relevance-desc'){
sortMethod = prevSortMethod;
}
+ refresh_x_button();
reset_query(sortMethod);
}
);
query.after(x_button);
}
- }
- else {
+ } else {
$('input[name=reset_query]').remove();
query.attr('class', 'searchInput');
}
};
+ var reset_sort_method = function(){
+ if (sortMethod === 'relevance-desc'){
+ sortMethod = prevSortMethod;
+ if (sortMethod === 'relevance-desc'){
+ sortMethod = 'activity-desc';
+ }
+ } else {
+ sortMethod = 'activity-desc';
+ prevSortMethod = 'activity-desc';
+ }
+ };
+
var eval_query = function(){
cur_text = $.trim(query.val());
- if (cur_text != prev_text && running === false){
+ if (cur_text !== prev_text && running === false){
if (cur_text.length >= minSearchWordLength){
- if (prev_text.length === 0 && showSortByRelevance){
- if (sortMethod == 'activity-desc'){
- prevSortMethod = sortMethod;
- sortMethod = 'relevance-desc';
- }
- }
- send_query(cur_text, sortMethod);
- running = true;
- }
- else if (cur_text.length === 0){
- if (sortMethod == 'relevance-desc'){
- sortMethod = prevSortMethod;
- }
- reset_query(sortMethod);
+ process_query();
running = true;
+ } else if (cur_text.length === 0){
+ restart_query();
}
}
- }
+ };
- var listen = function(){
+ var ask_page_search_listen = function(){
running = false;
- refresh_x_button();
- query.keydown(function(e){
- refresh_x_button();
+ var ask_page_eval_handle;
+ query.keyup(function(e){
if (running === false){
- setTimeout(eval_query, 50);
+ clearTimeout(ask_page_eval_handle);
+ ask_page_eval_handle = setTimeout(eval_query, 400);
}
});
- query.keyup(function(){
+ };
+
+ var main_page_search_listen = function(){
+ running = false;
+ refresh_x_button();
+ var main_page_eval_handle;
+ query.keyup(function(e){
refresh_x_button();
+ if (running === false){
+ clearTimeout(main_page_eval_handle);
+ main_page_eval_handle = setTimeout(eval_query, 400);
+ }
});
- }
+ };
- var render_counter = function(count, word, counter_class){
- var output = '<div class="votes">' +
- '<span class="item-count ' + counter_class + '">' +
+ var render_counter = function(count, word, counter_class, counter_subclass){
+ var output = '<div class="' + counter_class + ' ' + counter_subclass + '">' +
+ '<span class="item-count">' +
count;
- if (counter_class == 'accepted'){
- output += '&#10003;'
+ if (counter_class === 'accepted'){
+ output += '&#10003;';
}
output += '</span>' +
'<div>' + word + '</div>' +
'</div>';
return output;
- }
+ };
var render_title = function(result){
return '<h2>' +
@@ -94,15 +110,21 @@ $(document).ready(function(){
var render_user_link = function(result){
if (result['u_id'] !== false){
- var u_slug = result['u_name'].toLowerCase().replace(/ +/g, '-');
- return '<a ' +
- 'href="' +
- askbot['urls']['user_url_template']
- .replace('{{user_id}}', result['u_id'])
- .replace('{{slug}}', u_slug) +
- '">' +
- result['u_name'] +
- '</a> ';
+ if (result['u_is_anonymous'] === true){
+ return '<span class="anonymous">' +
+ askbot['messages']['name_of_anonymous_user'] +
+ '</span>';
+ } else {
+ var u_slug = result['u_name'].toLowerCase().replace(/ +/g, '-');
+ return '<a ' +
+ 'href="' +
+ askbot['urls']['user_url_template']
+ .replace('{{user_id}}', result['u_id'])
+ .replace('{{slug}}', u_slug) +
+ '">' +
+ result['u_name'] +
+ '</a> ';
+ }
}
else {
return '';
@@ -137,6 +159,21 @@ $(document).ready(function(){
return html;
};
+ var render_user_flag = function(result){
+ var country_code = result['u_country_code'];
+ if (country_code) {
+ return '<img class="flag" src="'+
+ mediaUrl(
+ 'media/images/flags/' +
+ country_code.toLowerCase() +
+ '.gif'
+ ) +
+ '"/>';
+ } else {
+ return '';
+ }
+ };
+
var render_user_info = function(result){
var user_html =
'<div class="userinfo">' +
@@ -145,33 +182,29 @@ $(document).ready(function(){
'>' +
result['timesince'] +
'</span> ' +
- render_user_link(result) +
+ render_user_link(result);
+ if (result['u_is_anonymous'] === false){
+ user_html += render_user_flag(result);
//render_user_badge_and_karma(result) +
- '</div>';
+ }
+ user_html += '</div>';
return user_html;
};
- var render_tag = function(tag_name){
- var url = askbot['urls']['questions'] +
- '?tags=' + encodeURI(tag_name);
- var tag_title = $.i18n._(
- "see questions tagged '{tag}'"
- ).replace(
- '{tag}',
- tag_name
- );
- return '<a ' +
- 'href="' + url + '" ' +
- 'title="' + tag_title + '" rel="tag"' +
- '>' + tag_name + '</a>';
+ var render_tag = function(tag_name, linkable, deletable){
+ var tag = new Tag();
+ tag.setName(tag_name);
+ tag.setDeletable(deletable);
+ tag.setLinkable(linkable);
+ return tag.getElement().outerHTML();
};
- var render_tags = function(tags){
- var tags_html = '<div class="tags">';
- for (var i=0; i<tags.length; i++){
- tags_html += render_tag(tags[i]);
- }
- tags_html += '</div>';
+ var render_tags = function(tags, linkable, deletable){
+ var tags_html = '<ul class="tags">';
+ $.each(tags, function(idx, item){
+ tags_html += render_tag(item, linkable, deletable);
+ });
+ tags_html += '</ul>';
return tags_html;
};
@@ -182,22 +215,25 @@ $(document).ready(function(){
render_counter(
question['votes'],
question['votes_word'],
+ 'votes',
question['votes_class']
) +
render_counter(
question['answers'],
question['answers_word'],
+ 'answers',
question['answers_class']
) +
render_counter(
question['views'],
question['views_word'],
+ 'views',
question['views_class']
) +
+ render_user_info(question) +
'</div>' +
render_title(question) +
- render_user_info(question) +
- render_tags(question['tags']) +
+ render_tags(question['tags'], true, false) +
'</div>';
return entry_html;
};
@@ -228,7 +264,7 @@ $(document).ready(function(){
}
var html = '';
for (var i=0; i<tags.length; i++){
- html += render_tag(tags[i]['name']);
+ html += render_tag(tags[i]['name'], true, false);
html += '<span class="tag-number">&#215; ' +
tags[i]['used_count'] +
'</span>' +
@@ -253,11 +289,38 @@ $(document).ready(function(){
$('#question-count').html(count_html);
};
+ var get_old_tags = function(container){
+ var tag_elements = container.find('.tag');
+ var old_tags = [];
+ tag_elements.each(function(idx, element){
+ old_tags.push($(element).html());
+ });
+ return old_tags;
+ };
+
+ var render_search_tags = function(tags){
+ var search_tags = $('#search-tags');
+ search_tags.children().remove();
+ var tags_html = '';
+ $.each(tags, function(idx, tag_name){
+ var tag = new Tag();
+ tag.setName(tag_name);
+ tag.setDeletable(true);
+ tag.setLinkable(false);
+ tag.setDeleteHandler(
+ function(){
+ remove_search_tag(tag_name);
+ }
+ );
+ search_tags.append(tag.getElement());
+ });
+ };
+
var create_relevance_tab = function(){
relevance_tab = $('<a></a>');
relevance_tab.attr('href', '?sort=relevance-desc');
relevance_tab.attr('id', 'by_relevance');
- relevance_tab.html(sortButtonData['relevance']['label']);
+ relevance_tab.html('<span>' + sortButtonData['relevance']['label'] + '</span>');
return relevance_tab;
}
@@ -308,7 +371,60 @@ $(document).ready(function(){
}
};
- var render_result = function(data, text_status, xhr){
+ var remove_search_tag = function(tag_name){
+ $.ajax({
+ url: askbot['urls']['questions'],
+ data: {remove_tag: tag_name},
+ dataType: 'json',
+ success: render_result,
+ complete: try_again
+ });
+ };
+
+ var activate_search_tags = function(){
+ var search_tags = $('#search-tags .tag-left');
+ $.each(search_tags, function(idx, element){
+ var tag = new Tag();
+ tag.decorate($(element));
+ //todo: setDeleteHandler and setHandler
+ //must work after decorate & must have getName
+ tag.setDeleteHandler(
+ function(){
+ remove_search_tag(tag.getName());
+ }
+ );
+ });
+ };
+
+ var render_ask_page_result = function(data, text_status, xhr){
+ var container = $('#' + q_list_sel);
+ container.children().remove();
+ if (data.length > 5){
+ container.css('overflow-y', 'scroll');
+ container.css('height', '120px');
+ } else {
+ container.css('height', data.length * 24 + 'px');
+ container.css('overflow-y', 'hidden');
+ }
+ $.each(data, function(idx, question){
+ var url = question['url'];
+ var title = question['title'];
+ var answer_count = question['answer_count'];
+ var list_item = $('<h2></h2>');
+ var count_element = $('<span class="item-count"></span>');
+ count_element.html(answer_count);
+ list_item.append(count_element);
+ var link = $('<a></a>');
+ link.attr('href', url);
+ list_item.append(link);
+ title_element = $('<span class="title"></span>');
+ title_element.html(title);
+ link.append(title)
+ container.append(list_item);
+ });
+ };
+
+ var render_main_page_result = function(data, text_status, xhr){
var old_list = $('#' + q_list_sel);
var new_list = $('<div></div>');
if (data['questions'].length > 0){
@@ -320,6 +436,7 @@ $(document).ready(function(){
new_list.attr('id', q_list_sel);
render_paginator(data['paginator']);
set_question_count(data['question_counter']);
+ render_search_tags(data['query_data']['tags']);
render_faces(data['faces']);
render_related_tags(data['related_tags']);
render_relevance_sort_tab();
@@ -337,7 +454,7 @@ $(document).ready(function(){
var send_query = function(query_text, sort_method){
var post_data = {query: query_text};
$.ajax({
- url: askbot['urls']['questions'],
+ url: search_url,
data: {query: query_text, sort: sort_method},
dataType: 'json',
success: render_result,
@@ -347,9 +464,8 @@ $(document).ready(function(){
}
var reset_query = function(sort_method){
- refresh_x_button();
$.ajax({
- url: askbot['urls']['questions'],
+ url: search_url,
data: {reset_query: true, sort: sort_method},
dataType: 'json',
success: render_result,
@@ -358,5 +474,62 @@ $(document).ready(function(){
prev_text = '';
}
- listen();
-});
+ var refresh_main_page = function(){
+ $.ajax({
+ url: askbot['urls']['questions'],
+ data: {preserve_state: true},
+ dataType: 'json',
+ success: render_main_page_result
+ });
+ };
+
+ return {
+ refresh: function(){
+ refresh_main_page();
+ },
+ init: function(mode){
+ if (mode === 'main_page'){
+ //live search for the main page
+ query = $('input#keywords');
+ search_url = askbot['urls']['questions'];
+ render_result = render_main_page_result;
+
+ process_query = function(){
+ if (prev_text.length === 0 && showSortByRelevance){
+ if (sortMethod === 'activity-desc'){
+ prevSortMethod = sortMethod;
+ sortMethod = 'relevance-desc';
+ }
+ }
+ send_query(cur_text, sortMethod);
+ };
+ restart_query = function() {
+ reset_sort_method();
+ refresh_x_button();
+ reset_query(sortMethod);
+ running = true;
+ };
+
+ activate_search_tags();
+ main_page_search_listen();
+ } else {
+ query = $('input#id_title.questionTitleInput');
+ search_url = askbot['urls']['api_get_questions'];
+ render_result = render_ask_page_result;
+ process_query = function(){
+ send_query(cur_text);
+ };
+ restart_query = function(){
+ $('#' + q_list_sel).css('height',0).children().remove();
+ running = false;
+ prev_text = '';
+ //ask_page_search_listen();
+ };
+ ask_page_search_listen();
+ }
+ prev_text = $.trim(query.val());
+ running = false;
+ }
+ };
+
+};
diff --git a/askbot/skins/default/media/js/post.js b/askbot/skins/default/media/js/post.js
index 36a5f320..2c3609fd 100644
--- a/askbot/skins/default/media/js/post.js
+++ b/askbot/skins/default/media/js/post.js
@@ -24,10 +24,6 @@ var lanai =
}
};
-var getUniqueWords = function(value){
- return $.unique($.trim(value).split(/\s+/));
-};
-
function appendLoader(element) {
element.append('<img class="ajax-loader" ' +
'src="' + mediaUrl("media/images/indicator.gif") + '" title="' +
@@ -118,10 +114,10 @@ var CPValidator = function(){
required: true,
minlength: 10
},
- title: {
+ /*title: {
required: true,
minlength: 10
- }
+ }*/
};
},
getQuestionFormMessages: function(){
@@ -620,7 +616,6 @@ var questionRetagger = function(){
};
var cancelRetag = function(){
- tagInput.unautocomplete();//removes dropdown if open
tagsDiv.html(oldTagsHTML);
tagsDiv.removeClass('post-retag');
tagsDiv.addClass('post-tags');
@@ -630,30 +625,16 @@ var questionRetagger = function(){
var render_tag = function(tag_name){
//copy-paste from live search!!!
- var url = askbot['urls']['questions'] +
- '?tags=' + encodeURI(tag_name);
- var tag_title = $.i18n._(
- "see questions tagged '{tag}'"
- ).replace(
- '{tag}',
- tag_name
- );
- return '<a ' +
- 'href="' + url + '" ' +
- 'title="' + tag_title + '" rel="tag"' +
- '>' + tag_name + '</a>';
+ var tag = new Tag();
+ tag.setName(tag_name);
+ return tag.getElement().outerHTML();
};
var drawNewTags = function(new_tags){
new_tags = new_tags.split(/\s+/);
var tags_html = ''
$.each(new_tags, function(index, name){
- if (index === 0){
- tags_html = render_tag(name);
- }
- else {
- tags_html += ' ' + render_tag(name);
- }
+ tags_html += render_tag(name);
});
tagsDiv.html(tags_html);
};
@@ -666,7 +647,7 @@ var questionRetagger = function(){
data: { tags: getUniqueWords(tagInput.val()).join(' ') },
success: function(json) {
if (json['success'] === true){
- new_tags = getUniqueWords(tagInput.val());
+ new_tags = getUniqueWords(json['new_tags']);
oldTagsHtml = '';
cancelRetag();
drawNewTags(new_tags.join(' '));
@@ -700,22 +681,16 @@ var questionRetagger = function(){
//var tagLabel = $('<label for="retag_tags" class="error"></label>');
tagInput.val(old_tags_string);
//populate input
- //todo: make autocomplete work
- tagInput.autocomplete(tags_autocomplete, {
- minChars: 1,
- matchContains: true,
- selectFirst: false,
- max: 20,
- multiple: true,
- multipleSeparator: " ",
- formatItem: function(row, i, max) {
- return row.n + " ("+ row.c +")";
- },
- formatResult: function(row, i, max){
- return row.n;
- }
+ var tagAc = new AutoCompleter({
+ url: askbot['urls']['get_tag_list'],
+ preloadData: true,
+ minChars: 1,
+ useCache: true,
+ matchInside: true,
+ maxCacheLength: 100,
+ delay: 10,
});
-
+ tagAc.decorate(tagInput);
div.append(tagInput);
//div.append(tagLabel);
setupInputEventHandlers(tagInput);
@@ -807,90 +782,6 @@ var questionRetagger = function(){
};
}();
-inherits = function(childCtor, parentCtor) {
- /** @constructor taken from google closure */
- function tempCtor() {};
- tempCtor.prototype = parentCtor.prototype;
- childCtor.superClass_ = parentCtor.prototype;
- childCtor.prototype = new tempCtor();
- childCtor.prototype.constructor = childCtor;
-};
-
-/* wrapper around jQuery object */
-var WrappedElement = function(){
- this._element = null;
-};
-WrappedElement.prototype.setElement = function(element){
- this._element = element;
-};
-WrappedElement.prototype.createDom = function(){
- this._element = $('<div></div>');
-};
-WrappedElement.prototype.getElement = function(){
- if (this._element === null){
- this.createDom();
- }
- return this._element;
-};
-WrappedElement.prototype.dispose = function(){
- this._element.remove();
-};
-
-var SimpleControl = function(){
- WrappedElement.call(this);
- this._handler = null;
-};
-inherits(SimpleControl, WrappedElement);
-
-SimpleControl.prototype.setHandler = function(handler){
- this._handler = handler;
-};
-
-var EditLink = function(){
- SimpleControl.call(this)
-};
-inherits(EditLink, SimpleControl);
-
-EditLink.prototype.createDom = function(){
- var element = $('<a></a>');
- element.addClass('edit');
- this.decorate(element);
-};
-
-EditLink.prototype.decorate = function(element){
- this._element = element;
- this._element.attr('title', $.i18n._('click to edit this comment'));
- this._element.html($.i18n._('edit'));
- setupButtonEventHandlers(this._element, this._handler);
-};
-
-var DeleteIcon = function(title){
- SimpleControl.call(this);
- this._title = title;
-};
-inherits(DeleteIcon, SimpleControl);
-
-DeleteIcon.prototype.decorate = function(element){
- this._element = element;
- var img = mediaUrl("media/images/close-small.png");
- var imgHover = mediaUrl("media/images/close-small-hover.png");
- this._element.attr('class', 'delete-icon');
- this._element.attr('src', img);
- this._element.attr('title', this._title);
- setupButtonEventHandlers(this._element, this._handler);
- this._element.mouseover(function(e){
- $(this).attr('src', imgHover);
- });
- this._element.mouseout(function(e){
- $(this).attr('src', img);
- });
-};
-
-DeleteIcon.prototype.createDom = function(){
- this.decorate($('<img />'));
-};
-
-
//constructor for the form
var EditCommentForm = function(){
WrappedElement.call(this);
@@ -1023,7 +914,6 @@ EditCommentForm.prototype.createDom = function(){
var update_counter = this.getCounterUpdater();
var escape_handler = makeKeyHandler(27, this.getCancelHandler());
- var save_handler = makeKeyHandler(13, this.getSaveHandler());
this._textarea.attr('name', 'comment')
.attr('cols', 60)
.attr('rows', 5)
@@ -1031,8 +921,11 @@ EditCommentForm.prototype.createDom = function(){
.blur(update_counter)
.focus(update_counter)
.keyup(update_counter)
- .keyup(escape_handler)
- .keydown(save_handler);
+ .keyup(escape_handler);
+ if (askbot['settings']['saveCommentOnEnter']){
+ var save_handler = makeKeyHandler(13, this.getSaveHandler());
+ this._textarea.keydown(save_handler);
+ }
this._textarea.val(this._text);
};
@@ -1151,7 +1044,7 @@ Comment.prototype.decorate = function(element){
var parent_type = this._element.parent().parent().attr('id').split('-')[2];
var comment_id = this._element.attr('id').replace('comment-','');
this._data = {id: comment_id};
- var delete_img = this._element.find('img.delete-icon');
+ var delete_img = this._element.find('span.delete-icon');
if (delete_img.length > 0){
this._deletable = true;
this._delete_icon = new DeleteIcon(this.deletePrompt);
@@ -1490,7 +1383,7 @@ var socialSharing = function(){
return {
init: function(page_url, text_to_share){
URL = window.location.href;
- TEXT = escape($('div.headNormal > a').html());
+ TEXT = escape($('h1 > a').html());
var fb = $('a.fb-share')
var tw = $('a.twitter-share');
copyAltToTitle(fb);
diff --git a/askbot/skins/default/media/js/tag_selector.js b/askbot/skins/default/media/js/tag_selector.js
index 8df017d1..833accc0 100644
--- a/askbot/skins/default/media/js/tag_selector.js
+++ b/askbot/skins/default/media/js/tag_selector.js
@@ -1,7 +1,110 @@
-//var interestingTags, ignoredTags, tags, $;
+
+var TagDetailBox = function(box_type){
+ WrappedElement.call(this);
+ this.box_type = box_type;
+ this._is_blank = true;
+ this._tags = new Array();
+ this.wildcard = undefined;
+};
+inherits(TagDetailBox, WrappedElement);
+
+TagDetailBox.prototype.createDom = function(){
+ this._element = this.makeElement('div');
+ this._element.addClass('wildcard-tags');
+ this._headline = this.makeElement('p');
+ this._headline.html(gettext('Tag "<span></span>" matches:'));
+ this._element.append(this._headline);
+ this._tag_list_element = this.makeElement('ul');
+ this._tag_list_element.addClass('tags');
+ this._element.append(this._tag_list_element);
+ this._footer = this.makeElement('p');
+ this._footer.css('clear', 'left');
+ this._element.append(this._footer);
+ this._element.hide();
+};
+
+TagDetailBox.prototype.belongsTo = function(wildcard){
+ return (this.wildcard === wildcard);
+};
+
+TagDetailBox.prototype.isBlank = function(){
+ return this._is_blank;
+};
+
+TagDetailBox.prototype.clear = function(){
+ if (this.isBlank()){
+ return;
+ }
+ this._is_blank = true;
+ this.getElement().hide();
+ this.wildcard = null;
+ $.each(this._tags, function(idx, item){
+ item.dispose();
+ });
+ this._tags = new Array();
+};
+
+TagDetailBox.prototype.loadTags = function(wildcard, callback){
+ var me = this;
+ $.ajax({
+ type: 'GET',
+ dataType: 'json',
+ cache: false,
+ url: askbot['urls']['get_tags_by_wildcard'],
+ data: { wildcard: wildcard },
+ success: callback,
+ failure: function(){ me._loading = false; }
+ });
+};
+
+TagDetailBox.prototype.renderFor = function(wildcard){
+ var me = this;
+ if (this._loading === true){
+ return;
+ }
+ this._loading = true;
+ this.loadTags(
+ wildcard,
+ function(data, text_status, xhr){
+ me._tag_names = data['tag_names'];
+ if (data['tag_count'] > 0){
+ var wildcard_display = wildcard.replace(/\*$/, '&#10045;');
+ me._headline.find('span').html(wildcard_display);
+ $.each(me._tag_names, function(idx, name){
+ var tag = new Tag();
+ tag.setName(name);
+ //tag.setLinkable(false);
+ me._tags.push(tag);
+ me._tag_list_element.append(tag.getElement());
+ });
+ me._is_blank = false;
+ me.wildcard = wildcard;
+ var tag_count = data['tag_count'];
+ if (tag_count > 20){
+ var fmts = gettext('and %s more, not shown...');
+ var footer_text = interpolate(fmts, [tag_count - 20]);
+ me._footer.html(footer_text);
+ me._footer.show();
+ } else {
+ me._footer.hide();
+ }
+ me._element.show();
+ } else {
+ me.clear();
+ }
+ me._loading = false;
+ }
+ );
+}
+
function pickedTags(){
+
+ var interestingTags = {};
+ var ignoredTags = {};
+ var interestingTagDetailBox = new TagDetailBox('interesting');
+ var ignoredTagDetailBox = new TagDetailBox('ignored');
- var sendAjax = function(tagname, reason, action, callback){
+ var sendAjax = function(tagnames, reason, action, callback){
var url = '';
if (action == 'add'){
if (reason == 'good'){
@@ -14,11 +117,12 @@ function pickedTags(){
else {
url = askbot['urls']['unmark_tag'];
}
- url = url + tagname + '/';
var call_settings = {
type:'POST',
- url:url
+ url:url,
+ data: JSON.stringify({tagnames: tagnames}),
+ dataType: 'json'
};
if (callback !== false){
call_settings.success = callback;
@@ -26,140 +130,242 @@ function pickedTags(){
$.ajax(call_settings);
};
- var unpickTag = function(from_target ,tagname, reason, send_ajax){
+ var unpickTag = function(from_target, tagname, reason, send_ajax){
//send ajax request to delete tag
var deleteTagLocally = function(){
from_target[tagname].remove();
delete from_target[tagname];
};
if (send_ajax){
- sendAjax(tagname,reason,'remove',deleteTagLocally);
+ sendAjax(
+ [tagname],
+ reason,
+ 'remove',
+ function(){
+ deleteTagLocally();
+ liveSearch().refresh();
+ }
+ );
}
else {
deleteTagLocally();
}
};
- var setupTagDeleteEvents = function(obj,tag_store,tagname,reason,send_ajax){
- obj.unbind('mouseover').bind('mouseover', function(){
- $(this).attr('src', mediaUrl('media/images/close-small-hover.png'));
- });
- obj.unbind('mouseout').bind('mouseout', function(){
- $(this).attr('src', mediaUrl('media/images/close-small-dark.png'));
- });
- obj.click( function(){
- unpickTag(tag_store,tagname,reason,send_ajax);
+ var getTagList = function(reason){
+ var base_selector = '.marked-tags';
+ if (reason === 'good'){
+ var extra_selector = '.interesting';
+ } else {
+ var extra_selector = '.ignored';
+ }
+ return $(base_selector + extra_selector);
+ };
+
+ var getWildcardTagDetailBox = function(reason){
+ if (reason === 'good'){
+ return interestingTagDetailBox;
+ } else {
+ return ignoredTagDetailBox;
+ }
+ };
+
+ var handleWildcardTagClick = function(tag_name, reason){
+ var detail_box = getWildcardTagDetailBox(reason);
+ var tag_box = getTagList(reason);
+ if (detail_box.isBlank()){
+ detail_box.renderFor(tag_name);
+ } else if (detail_box.belongsTo(tag_name)){
+ detail_box.clear();//toggle off
+ } else {
+ detail_box.clear();//redraw with new data
+ detail_box.renderFor(tag_name);
+ }
+ if (!detail_box.inDocument()){
+ tag_box.after(detail_box.getElement());
+ detail_box.enterDocument();
+ }
+ };
+
+ var renderNewTags = function(
+ clean_tag_names,
+ reason,
+ to_target,
+ to_tag_container
+ ){
+ $.each(clean_tag_names, function(idx, tag_name){
+ var tag = new Tag();
+ tag.setName(tag_name);
+ tag.setDeletable(true);
+
+ if (/\*$/.test(tag_name)){
+ tag.setLinkable(false);
+ var detail_box = getWildcardTagDetailBox(reason);
+ tag.setHandler(function(){
+ handleWildcardTagClick(tag_name, reason);
+ if (detail_box.belongsTo(tag_name)){
+ detail_box.clear();
+ }
+ });
+ var delete_handler = function(){
+ unpickTag(to_target, tag_name, reason, true);
+ if (detail_box.belongsTo(tag_name)){
+ detail_box.clear();
+ }
+ }
+ } else {
+ var delete_handler = function(){
+ unpickTag(to_target, tag_name, reason, true);
+ }
+ }
+
+ tag.setDeleteHandler(delete_handler);
+ var tag_element = tag.getElement();
+ to_tag_container.append(tag_element);
+ to_target[tag_name] = tag_element;
});
};
- var handlePickedTag = function(obj,reason){
- var tagname = $.trim($(obj).prev().attr('value'));
+ var handlePickedTag = function(reason){
var to_target = interestingTags;
var from_target = ignoredTags;
var to_tag_container;
if (reason == 'bad'){
+ var input_sel = '#ignoredTagInput';
to_target = ignoredTags;
from_target = interestingTags;
to_tag_container = $('div .tags.ignored');
}
- else if (reason != 'good'){
- return;
+ else if (reason == 'good'){
+ var input_sel = '#interestingTagInput';
+ to_tag_container = $('div .tags.interesting');
}
else {
- to_tag_container = $('div .tags.interesting');
+ return;
}
- if (tagname in from_target){
- unpickTag(from_target,tagname,reason,false);
- }
+ var tagnames = getUniqueWords($(input_sel).attr('value'));
+
+ $.each(tagnames, function(idx, tagname){
+ if (tagname in from_target){
+ unpickTag(from_target,tagname,reason,false);
+ }
+ });
+
+ var clean_tagnames = [];
+ $.each(tagnames, function(idx, tagname){
+ if (!(tagname in to_target)){
+ clean_tagnames.push(tagname);
+ }
+ });
- if (!(tagname in to_target)){
+ if (clean_tagnames.length > 0){
//send ajax request to pick this tag
- sendAjax(tagname,reason,'add',function(){
- var new_tag = $('<span></span>');
- new_tag.addClass('deletable-tag');
- var tag_link = $('<a></a>');
- tag_link.attr('rel','tag');
- var tag_url = askbot['urls']['questions'] + '?tags=' + tagname;
- tag_link.attr('href', tag_url);
- tag_link.html(tagname);
- var del_link = $('<img></img>');
- del_link.addClass('delete-icon');
- del_link.attr('src', mediaUrl('/media/images/close-small-dark.png'));
-
- setupTagDeleteEvents(del_link, to_target, tagname, reason, true);
-
- new_tag.append(tag_link);
- new_tag.append(del_link);
- to_tag_container.append(new_tag);
-
- to_target[tagname] = new_tag;
- });
+ sendAjax(
+ clean_tagnames,
+ reason,
+ 'add',
+ function(){
+ renderNewTags(
+ clean_tagnames,
+ reason,
+ to_target,
+ to_tag_container
+ );
+ $(input_sel).val('');
+ liveSearch().refresh();
+ }
+ );
}
};
- var collectPickedTags = function(){
- var good_prefix = 'interesting-tag-';
- var bad_prefix = 'ignored-tag-';
- var good_re = RegExp('^' + good_prefix);
- var bad_re = RegExp('^' + bad_prefix);
- interestingTags = {};
- ignoredTags = {};
- $('.deletable-tag').each(
+ var collectPickedTags = function(section){
+ if (section === 'interesting'){
+ var reason = 'good';
+ var tag_store = interestingTags;
+ }
+ else if (section === 'ignored'){
+ var reason = 'bad';
+ var tag_store = ignoredTags;
+ }
+ else {
+ return;
+ }
+ $('.' + section + '.tags.marked-tags .tag-left').each(
function(i,item){
- var item_id = $(item).attr('id');
- var tag_name, tag_store;
- if (good_re.test(item_id)){
- tag_name = item_id.replace(good_prefix,'');
- tag_store = interestingTags;
- reason = 'good';
- }
- else if (bad_re.test(item_id)){
- tag_name = item_id.replace(bad_prefix,'');
- tag_store = ignoredTags;
- reason = 'bad';
- }
- else {
- return;
+ var tag = new Tag();
+ tag.decorate($(item));
+ tag.setDeleteHandler(function(){
+ unpickTag(
+ tag_store,
+ tag.getName(),
+ reason,
+ true
+ )
+ });
+ if (tag.isWildcard()){
+ tag.setHandler(function(){
+ handleWildcardTagClick(tag.getName(), reason)
+ });
}
- tag_store[tag_name] = $(item);
- setupTagDeleteEvents($(item).find('img'),tag_store,tag_name,reason,true);
+ tag_store[tag.getName()] = $(item);
}
);
};
- var setupHideIgnoredQuestionsControl = function(){
- $('#hideIgnoredTagsCb').unbind('click').click(function(){
+ var setupTagFilterControl = function(control_type){
+ $('#' + control_type + 'TagFilterControl input')
+ .unbind('click')
+ .click(function(){
$.ajax({
- type: 'POST',
- dataType: 'json',
- cache: false,
- url: askbot['urls']['command'],
- data: {command:'toggle-ignored-questions'}
- });
+ type: 'POST',
+ dataType: 'json',
+ cache: false,
+ url: askbot['urls']['set_tag_filter_strategy'],
+ data: {
+ filter_type: control_type,
+ filter_value: $(this).val()
+ },
+ success: function(){
+ liveSearch().refresh();
+ }
+ });
});
};
+
+ var getResultCallback = function(reason){
+ return function(){
+ handlePickedTag(reason);
+ };
+ };
+
return {
init: function(){
- collectPickedTags();
- setupHideIgnoredQuestionsControl();
- $("#interestingTagInput, #ignoredTagInput").autocomplete(tags, {
+ collectPickedTags('interesting');
+ collectPickedTags('ignored');
+ setupTagFilterControl('display');
+ var ac = new AutoCompleter({
+ url: askbot['urls']['get_tag_list'],
+ preloadData: true,
minChars: 1,
- matchContains: true,
- max: 20,
- multiple: true,
- multipleSeparator: " ",
- formatItem: function(row, i, max) {
- return row.n + " ("+ row.c +")";
- },
- formatResult: function(row, i, max){
- return row.n;
- }
-
+ useCache: true,
+ matchInside: true,
+ maxCacheLength: 100,
+ delay: 10,
});
- $("#interestingTagAdd").click(function(){handlePickedTag(this,'good');});
- $("#ignoredTagAdd").click(function(){handlePickedTag(this,'bad');});
+
+
+ var interestingTagAc = $.extend(true, {}, ac);
+ interestingTagAc.decorate($('#interestingTagInput'));
+ interestingTagAc.setOption('onItemSelect', getResultCallback('good'));
+
+ var ignoredTagAc = $.extend(true, {}, ac);
+ ignoredTagAc.decorate($('#ignoredTagInput'));
+ ignoredTagAc.setOption('onItemSelect', getResultCallback('bad'));
+
+ $("#interestingTagAdd").click(getResultCallback('good'));
+ $("#ignoredTagAdd").click(getResultCallback('bad'));
}
};
}
diff --git a/askbot/skins/default/media/js/utils.js b/askbot/skins/default/media/js/utils.js
index 2eed998a..9f1c3d9f 100644
--- a/askbot/skins/default/media/js/utils.js
+++ b/askbot/skins/default/media/js/utils.js
@@ -7,6 +7,19 @@ var copyAltToTitle = function(sel){
sel.attr('title', sel.attr('alt'));
};
+var getUniqueWords = function(value){
+ var words = $.trim(value).split(/\s+/);
+ var uniques = new Object();
+ var out = new Array();
+ $.each(words, function(idx, item){
+ if (!(item in uniques)){
+ uniques[item] = 1;
+ out.push(item);
+ };
+ });
+ return out;
+};
+
var showMessage = function(element, msg, where) {
var div = $('<div class="vote-notification"><h3>' + msg + '</h3>(' +
$.i18n._('click to close') + ')</div>');
@@ -27,6 +40,17 @@ var showMessage = function(element, msg, where) {
div.fadeIn("fast");
};
+//outer html hack - https://github.com/brandonaaron/jquery-outerhtml/
+(function($){
+ var div;
+ $.fn.outerHTML = function() {
+ var elem = this[0],
+ tmp;
+ return !elem ? null
+ : typeof ( tmp = elem.outerHTML ) === 'string' ? tmp
+ : ( div = div || $('<div/>') ).html( this.eq(0).clone() ).html();
+ };
+})(jQuery);
var makeKeyHandler = function(key, callback){
return function(e){
@@ -86,8 +110,275 @@ var notify = function() {
};
} ();
+/* some google closure-like code for the ui elements */
+var inherits = function(childCtor, parentCtor) {
+ /** @constructor taken from google closure */
+ function tempCtor() {};
+ tempCtor.prototype = parentCtor.prototype;
+ childCtor.superClass_ = parentCtor.prototype;
+ childCtor.prototype = new tempCtor();
+ childCtor.prototype.constructor = childCtor;
+};
+
+/* wrapper around jQuery object */
+var WrappedElement = function(){
+ this._element = null;
+ this._in_document = false;
+};
+WrappedElement.prototype.setElement = function(element){
+ this._element = element;
+};
+WrappedElement.prototype.createDom = function(){
+ this._element = $('<div></div>');
+};
+WrappedElement.prototype.getElement = function(){
+ if (this._element === null){
+ this.createDom();
+ }
+ return this._element;
+};
+WrappedElement.prototype.inDocument = function(){
+ return this._in_document;
+};
+WrappedElement.prototype.enterDocument = function(){
+ return this._in_document = true;
+};
+WrappedElement.prototype.hasElement = function(){
+ return (this._element !== null);
+};
+WrappedElement.prototype.makeElement = function(html_tag){
+ //makes jQuery element with tags
+ return $('<' + html_tag + '></' + html_tag + '>');
+};
+WrappedElement.prototype.dispose = function(){
+ this._element.remove();
+ this._in_document = false;
+};
+
+var SimpleControl = function(){
+ WrappedElement.call(this);
+ this._handler = null;
+ this._title = null;
+};
+inherits(SimpleControl, WrappedElement);
+
+SimpleControl.prototype.setHandler = function(handler){
+ this._handler = handler;
+ if (this.hasElement()){
+ this.setHandlerInternal();
+ }
+};
+
+SimpleControl.prototype.setHandlerInternal = function(){
+ //default internal setHandler behavior
+ setupButtonEventHandlers(this._element, this._handler);
+};
+
+SimpleControl.prototype.setTitle = function(title){
+ this._title = title;
+};
+
+var EditLink = function(){
+ SimpleControl.call(this)
+};
+inherits(EditLink, SimpleControl);
+
+EditLink.prototype.createDom = function(){
+ var element = $('<a></a>');
+ element.addClass('edit');
+ this.decorate(element);
+};
+
+EditLink.prototype.decorate = function(element){
+ this._element = element;
+ this._element.attr('title', $.i18n._('click to edit this comment'));
+ this._element.html($.i18n._('edit'));
+ this.setHandlerInternal();
+};
+
+var DeleteIcon = function(title){
+ SimpleControl.call(this);
+ this._title = title;
+};
+inherits(DeleteIcon, SimpleControl);
+
+DeleteIcon.prototype.decorate = function(element){
+ this._element = element;
+ this._element.attr('class', 'delete-icon');
+ this._element.attr('title', this._title);
+ if (this._handler !== null){
+ this.setHandlerInternal();
+ }
+};
+
+DeleteIcon.prototype.setHandlerInternal = function(){
+ setupButtonEventHandlers(this._element, this._handler);
+};
+
+DeleteIcon.prototype.createDom = function(){
+ this._element = this.makeElement('span');
+ this.decorate(this._element);
+};
+
+var Tag = function(){
+ SimpleControl.call(this);
+ this._deletable = false;
+ this._delete_handler = null;
+ this._delete_icon_title = null;
+ this._tag_title = null;
+ this._name = null;
+ this._url_params = null;
+ this._inner_html_tag = 'a';
+ this._html_tag = 'li';
+}
+inherits(Tag, SimpleControl);
+
+Tag.prototype.setName = function(name){
+ this._name = name;
+};
+
+Tag.prototype.getName = function(){
+ return this._name;
+};
+
+Tag.prototype.setHtmlTag = function(html_tag){
+ this._html_tag = html_tag;
+};
+
+Tag.prototype.setDeletable = function(is_deletable){
+ this._deletable = is_deletable;
+};
+
+Tag.prototype.setLinkable = function(is_linkable){
+ if (is_linkable === true){
+ this._inner_html_tag = 'a';
+ } else {
+ this._inner_html_tag = 'span';
+ }
+};
+
+Tag.prototype.isLinkable = function(){
+ return (this._inner_html_tag === 'a');
+};
+
+Tag.prototype.isDeletable = function(){
+ return this._deletable;
+};
+
+Tag.prototype.isWildcard = function(){
+ return (this.getName().substr(-1) === '*');
+};
+
+Tag.prototype.setUrlParams = function(url_params){
+ this._url_params = url_params;
+};
+
+Tag.prototype.setHandlerInternal = function(){
+ setupButtonEventHandlers(this._element.find('.tag'), this._handler);
+};
+
+/* delete handler will be specific to the task */
+Tag.prototype.setDeleteHandler = function(delete_handler){
+ this._delete_handler = delete_handler;
+ if (this.hasElement() && this.isDeletable()){
+ this._delete_icon.setHandler(delete_handler);
+ }
+};
+
+Tag.prototype.getDeleteHandler = function(){
+ return this._delete_handler;
+};
+
+Tag.prototype.setDeleteIconTitle = function(title){
+ this._delete_icon_title = title;
+};
+
+Tag.prototype.decorate = function(element){
+ this._element = element;
+ var del = element.find('.delete-icon');
+ if (del.length === 1){
+ this.setDeletable(true);
+ this._delete_icon = new DeleteIcon();
+ if (this._delete_icon_title != null){
+ this._delete_icon.setTitle(this._delete_icon_title);
+ }
+ //do not set the delete handler here
+ this._delete_icon.decorate(del);
+ }
+ this._inner_element = this._element.find('.tag');
+ this._name = this.decodeTagName($.trim(this._inner_element.html()));
+ if (this._title !== null){
+ this._inner_element.attr('title', this._title);
+ }
+ if (this._handler !== null){
+ this.setHandlerInternal();
+ }
+};
+
+Tag.prototype.getDisplayTagName = function(){
+ //replaces the trailing * symbol with the unicode asterisk
+ return this._name.replace(/\*$/, '&#10045;');
+};
+
+Tag.prototype.decodeTagName = function(encoded_name){
+ return encoded_name.replace('\u273d', '*');
+};
+
+Tag.prototype.createDom = function(){
+ this._element = this.makeElement(this._html_tag);
+ //render the outer element
+ if (this._deletable){
+ this._element.addClass('deletable-tag');
+ }
+ this._element.addClass('tag-left');
+
+ //render the inner element
+ this._inner_element = this.makeElement(this._inner_html_tag);
+ if (this.isLinkable()){
+ var url = askbot['urls']['questions'];
+ url += '?tags=' + escape(this.getName());
+ if (this._url_params !== null){
+ url += escape('&' + this._url_params);
+ }
+ this._inner_element.attr('href', url);
+ }
+ this._inner_element.addClass('tag tag-right');
+ this._inner_element.attr('rel', 'tag');
+ if (this._title === null){
+ this.setTitle(
+ $.i18n._(
+ "see questions tagged '{tag}'"
+ ).replace(
+ '{tag}',
+ this.getName()
+ )
+ );
+ }
+ this._inner_element.attr('title', this._title);
+ this._inner_element.html(this.getDisplayTagName());
+
+ this._element.append(this._inner_element);
+
+ if (!this.isLinkable() && this._handler !== null){
+ this.setHandlerInternal();
+ }
+
+ if (this._deletable){
+ this._delete_icon = new DeleteIcon();
+ this._delete_icon.setHandler(this.getDeleteHandler());
+ if (this._delete_icon_title !== null){
+ this._delete_icon.setTitle(this._delete_icon_title);
+ }
+ this._element.append(this._delete_icon.getElement());
+ }
+};
+
//Search Engine Keyword Highlight with Javascript
//http://scott.yang.id.au/code/se-hilite/
Hilite={elementid:"content",exact:true,max_nodes:1000,onload:true,style_name:"hilite",style_name_suffix:true,debug_referrer:""};Hilite.search_engines=[["local","q"],["cnprog\\.","q"],["google\\.","q"],["search\\.yahoo\\.","p"],["search\\.msn\\.","q"],["search\\.live\\.","query"],["search\\.aol\\.","userQuery"],["ask\\.com","q"],["altavista\\.","q"],["feedster\\.","q"],["search\\.lycos\\.","q"],["alltheweb\\.","q"],["technorati\\.com/search/([^\\?/]+)",1],["dogpile\\.com/info\\.dogpl/search/web/([^\\?/]+)",1,true]];Hilite.decodeReferrer=function(d){var g=null;var e=new RegExp("");for(var c=0;c<Hilite.search_engines.length;c++){var f=Hilite.search_engines[c];e.compile("^http://(www\\.)?"+f[0],"i");var b=d.match(e);if(b){var a;if(isNaN(f[1])){a=Hilite.decodeReferrerQS(d,f[1])}else{a=b[f[1]+1]}if(a){a=decodeURIComponent(a);if(f.length>2&&f[2]){a=decodeURIComponent(a)}a=a.replace(/\'|"/g,"");a=a.split(/[\s,\+\.]+/);return a}break}}return null};Hilite.decodeReferrerQS=function(f,d){var b=f.indexOf("?");var c;if(b>=0){var a=new String(f.substring(b+1));b=0;c=0;while((b>=0)&&((c=a.indexOf("=",b))>=0)){var e,g;e=a.substring(b,c);b=a.indexOf("&",c)+1;if(e==d){if(b<=0){return a.substring(c+1)}else{return a.substring(c+1,b-1)}}else{if(b<=0){return null}}}}return null};Hilite.hiliteElement=function(f,e){if(!e||f.childNodes.length==0){return}var c=new Array();for(var b=0;b<e.length;b++){e[b]=e[b].toLowerCase();if(Hilite.exact){c.push("\\b"+e[b]+"\\b")}else{c.push(e[b])}}c=new RegExp(c.join("|"),"i");var a={};for(var b=0;b<e.length;b++){if(Hilite.style_name_suffix){a[e[b]]=Hilite.style_name+(b+1)}else{a[e[b]]=Hilite.style_name}}var d=function(m){var j=c.exec(m.data);if(j){var n=j[0];var i="";var h=m.splitText(j.index);var g=h.splitText(n.length);var l=m.ownerDocument.createElement("SPAN");m.parentNode.replaceChild(l,h);l.className=a[n.toLowerCase()];l.appendChild(h);return l}else{return m}};Hilite.walkElements(f.childNodes[0],1,d)};Hilite.hilite=function(){var a=Hilite.debug_referrer?Hilite.debug_referrer:document.referrer;var b=null;a=Hilite.decodeReferrer(a);if(a&&((Hilite.elementid&&(b=document.getElementById(Hilite.elementid)))||(b=document.body))){Hilite.hiliteElement(b,a)}};Hilite.walkElements=function(d,f,e){var a=/^(script|style|textarea)/i;var c=0;while(d&&f>0){c++;if(c>=Hilite.max_nodes){var b=function(){Hilite.walkElements(d,f,e)};setTimeout(b,50);return}if(d.nodeType==1){if(!a.test(d.tagName)&&d.childNodes.length>0){d=d.childNodes[0];f++;continue}}else{if(d.nodeType==3){d=e(d)}}if(d.nextSibling){d=d.nextSibling}else{while(f>0){d=d.parentNode;f--;if(d.nextSibling){d=d.nextSibling;break}}}}};if(Hilite.onload){if(window.attachEvent){window.attachEvent("onload",Hilite.hilite)}else{if(window.addEventListener){window.addEventListener("load",Hilite.hilite,false)}else{var __onload=window.onload;window.onload=function(){Hilite.hilite();__onload()}}}};
/* json2.js by D. Crockford */
if(!this.JSON){this.JSON={}}(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof JSON.stringify!=="function"){JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}}());
+//jquery fieldselection
+(function(){var a={getSelection:function(){var b=this.jquery?this[0]:this;return(("selectionStart" in b&&function(){var c=b.selectionEnd-b.selectionStart;return{start:b.selectionStart,end:b.selectionEnd,length:c,text:b.value.substr(b.selectionStart,c)}})||(document.selection&&function(){b.focus();var d=document.selection.createRange();if(d==null){return{start:0,end:b.value.length,length:0}}var c=b.createTextRange();var e=c.duplicate();c.moveToBookmark(d.getBookmark());e.setEndPoint("EndToStart",c);return{start:e.text.length,end:e.text.length+d.text.length,length:d.text.length,text:d.text}})||function(){return{start:0,end:b.value.length,length:0}})()},replaceSelection:function(){var b=this.jquery?this[0]:this;var c=arguments[0]||"";return(("selectionStart" in b&&function(){b.value=b.value.substr(0,b.selectionStart)+c+b.value.substr(b.selectionEnd,b.value.length);return this})||(document.selection&&function(){b.focus();document.selection.createRange().text=c;return this})||function(){b.value+=c;return this})()}};jQuery.each(a,function(b){jQuery.fn[b]=this})})();
+//our custom autocompleter
+var AutoCompleter=function(a){var b={autocompleteMultiple:true,multipleSeparator:" ",inputClass:"acInput",loadingClass:"acLoading",resultsClass:"acResults",selectClass:"acSelect",queryParamName:"q",limitParamName:"limit",extraParams:{},lineSeparator:"\n",cellSeparator:"|",minChars:2,maxItemsToShow:10,delay:400,useCache:true,maxCacheLength:10,matchSubset:true,matchCase:false,matchInside:true,mustMatch:false,preloadData:false,selectFirst:false,stopCharRegex:/\s+/,selectOnly:false,formatItem:null,onItemSelect:false,autoFill:false,filterResults:true,sortResults:true,sortFunction:false,onNoMatch:false};this.options=$.extend({},b,a);this.cacheData_={};this.cacheLength_=0;this.selectClass_="jquery-autocomplete-selected-item";this.keyTimeout_=null;this.lastKeyPressed_=null;this.lastProcessedValue_=null;this.lastSelectedValue_=null;this.active_=false;this.finishOnBlur_=true;this.options.minChars=parseInt(this.options.minChars,10);if(isNaN(this.options.minChars)||this.options.minChars<1){this.options.minChars=2}this.options.maxItemsToShow=parseInt(this.options.maxItemsToShow,10);if(isNaN(this.options.maxItemsToShow)||this.options.maxItemsToShow<1){this.options.maxItemsToShow=10}this.options.maxCacheLength=parseInt(this.options.maxCacheLength,10);if(isNaN(this.options.maxCacheLength)||this.options.maxCacheLength<1){this.options.maxCacheLength=10}if(this.options.preloadData===true){this.fetchRemoteData("",function(){})}};inherits(AutoCompleter,WrappedElement);AutoCompleter.prototype.decorate=function(a){this._element=a;this._element.attr("autocomplete","off");this._results=$("<div></div>").hide();if(this.options.resultsClass){this._results.addClass(this.options.resultsClass)}this._results.css({position:"absolute"});$("body").append(this._results);this.setEventHandlers()};AutoCompleter.prototype.setEventHandlers=function(){var a=this;a._element.keydown(function(b){a.lastKeyPressed_=b.keyCode;switch(a.lastKeyPressed_){case 38:b.preventDefault();if(a.active_){a.focusPrev()}else{a.activate()}return false;break;case 40:b.preventDefault();if(a.active_){a.focusNext()}else{a.activate()}return false;break;case 9:case 13:if(a.active_){b.preventDefault();a.selectCurrent();return false}break;case 27:if(a.active_){b.preventDefault();a.finish();return false}break;default:a.activate()}});a._element.blur(function(){if(a.finishOnBlur_){setTimeout(function(){a.finish()},200)}})};AutoCompleter.prototype.position=function(){var a=this._element.offset();this._results.css({top:a.top+this._element.outerHeight(),left:a.left})};AutoCompleter.prototype.cacheRead=function(d){var f,c,b,a,e;if(this.options.useCache){d=String(d);f=d.length;if(this.options.matchSubset){c=1}else{c=f}while(c<=f){if(this.options.matchInside){a=f-c}else{a=0}e=0;while(e<=a){b=d.substr(0,c);if(this.cacheData_[b]!==undefined){return this.cacheData_[b]}e++}c++}}return false};AutoCompleter.prototype.cacheWrite=function(a,b){if(this.options.useCache){if(this.cacheLength_>=this.options.maxCacheLength){this.cacheFlush()}a=String(a);if(this.cacheData_[a]!==undefined){this.cacheLength_++}return this.cacheData_[a]=b}return false};AutoCompleter.prototype.cacheFlush=function(){this.cacheData_={};this.cacheLength_=0};AutoCompleter.prototype.callHook=function(c,b){var a=this.options[c];if(a&&$.isFunction(a)){return a(b,this)}return false};AutoCompleter.prototype.activate=function(){var b=this;var a=function(){b.activateNow()};var c=parseInt(this.options.delay,10);if(isNaN(c)||c<=0){c=250}if(this.keyTimeout_){clearTimeout(this.keyTimeout_)}this.keyTimeout_=setTimeout(a,c)};AutoCompleter.prototype.activateNow=function(){var a=this.getValue();if(a!==this.lastProcessedValue_&&a!==this.lastSelectedValue_){if(a.length>=this.options.minChars){this.active_=true;this.lastProcessedValue_=a;this.fetchData(a)}}};AutoCompleter.prototype.fetchData=function(b){if(this.options.data){this.filterAndShowResults(this.options.data,b)}else{var a=this;this.fetchRemoteData(b,function(c){a.filterAndShowResults(c,b)})}};AutoCompleter.prototype.fetchRemoteData=function(c,e){var d=this.cacheRead(c);if(d){e(d)}else{var a=this;if(this._element){this._element.addClass(this.options.loadingClass)}var b=function(g){var f=false;if(g!==false){f=a.parseRemoteData(g);a.options.data=f;a.cacheWrite(c,f)}if(a._element){a._element.removeClass(a.options.loadingClass)}e(f)};$.ajax({url:this.makeUrl(c),success:b,error:function(){b(false)}})}};AutoCompleter.prototype.setOption=function(a,b){this.options[a]=b};AutoCompleter.prototype.setExtraParam=function(b,c){var a=$.trim(String(b));if(a){if(!this.options.extraParams){this.options.extraParams={}}if(this.options.extraParams[a]!==c){this.options.extraParams[a]=c;this.cacheFlush()}}};AutoCompleter.prototype.makeUrl=function(e){var a=this;var b=this.options.url;var d=$.extend({},this.options.extraParams);if(this.options.queryParamName===false){b+=encodeURIComponent(e)}else{d[this.options.queryParamName]=e}if(this.options.limitParamName&&this.options.maxItemsToShow){d[this.options.limitParamName]=this.options.maxItemsToShow}var c=[];$.each(d,function(f,g){c.push(a.makeUrlParam(f,g))});if(c.length){b+=b.indexOf("?")==-1?"?":"&";b+=c.join("&")}return b};AutoCompleter.prototype.makeUrlParam=function(a,b){return String(a)+"="+encodeURIComponent(b)};AutoCompleter.prototype.splitText=function(a){return String(a).replace(/(\r\n|\r|\n)/g,"\n").split(this.options.lineSeparator)};AutoCompleter.prototype.parseRemoteData=function(c){var h,b,f,d,g;var e=[];var b=this.splitText(c);for(f=0;f<b.length;f++){var a=b[f].split(this.options.cellSeparator);g=[];for(d=0;d<a.length;d++){g.push(unescape(a[d]))}h=g.shift();e.push({value:unescape(h),data:g})}return e};AutoCompleter.prototype.filterAndShowResults=function(a,b){this.showResults(this.filterResults(a,b),b)};AutoCompleter.prototype.filterResults=function(d,b){var f=[];var l,c,e,m,j,a;var k,h,g;for(e=0;e<d.length;e++){m=d[e];j=typeof m;if(j==="string"){l=m;c={}}else{if($.isArray(m)){l=m[0];c=m.slice(1)}else{if(j==="object"){l=m.value;c=m.data}}}l=String(l);if(l>""){if(typeof c!=="object"){c={}}if(this.options.filterResults){h=String(b);g=String(l);if(!this.options.matchCase){h=h.toLowerCase();g=g.toLowerCase()}a=g.indexOf(h);if(this.options.matchInside){a=a>-1}else{a=a===0}}else{a=true}if(a){f.push({value:l,data:c})}}}if(this.options.sortResults){f=this.sortResults(f,b)}if(this.options.maxItemsToShow>0&&this.options.maxItemsToShow<f.length){f.length=this.options.maxItemsToShow}return f};AutoCompleter.prototype.sortResults=function(c,d){var b=this;var a=this.options.sortFunction;if(!$.isFunction(a)){a=function(g,e,h){return b.sortValueAlpha(g,e,h)}}c.sort(function(f,e){return a(f,e,d)});return c};AutoCompleter.prototype.sortValueAlpha=function(d,c,e){d=String(d.value);c=String(c.value);if(!this.options.matchCase){d=d.toLowerCase();c=c.toLowerCase()}if(d>c){return 1}if(d<c){return -1}return 0};AutoCompleter.prototype.showResults=function(e,b){var k=this;var g=$("<ul></ul>");var f,l,j,a,h=false,d=false;var c=e.length;for(f=0;f<c;f++){l=e[f];j=$("<li>"+this.showResult(l.value,l.data)+"</li>");j.data("value",l.value);j.data("data",l.data);j.click(function(){var i=$(this);k.selectItem(i)}).mousedown(function(){k.finishOnBlur_=false}).mouseup(function(){k.finishOnBlur_=true});g.append(j);if(h===false){h=String(l.value);d=j;j.addClass(this.options.firstItemClass)}if(f==c-1){j.addClass(this.options.lastItemClass)}}this.position();this._results.html(g).show();a=this._results.outerWidth()-this._results.width();this._results.width(this._element.outerWidth()-a);$("li",this._results).hover(function(){k.focusItem(this)},function(){});if(this.autoFill(h,b)){this.focusItem(d)}};AutoCompleter.prototype.showResult=function(b,a){if($.isFunction(this.options.showResult)){return this.options.showResult(b,a)}else{return b}};AutoCompleter.prototype.autoFill=function(e,c){var b,a,d,f;if(this.options.autoFill&&this.lastKeyPressed_!=8){b=String(e).toLowerCase();a=String(c).toLowerCase();d=e.length;f=c.length;if(b.substr(0,f)===a){this._element.val(e);this.selectRange(f,d);return true}}return false};AutoCompleter.prototype.focusNext=function(){this.focusMove(+1)};AutoCompleter.prototype.focusPrev=function(){this.focusMove(-1)};AutoCompleter.prototype.focusMove=function(a){var b,c=$("li",this._results);a=parseInt(a,10);for(var b=0;b<c.length;b++){if($(c[b]).hasClass(this.selectClass_)){this.focusItem(b+a);return}}this.focusItem(0)};AutoCompleter.prototype.focusItem=function(b){var a,c=$("li",this._results);if(c.length){c.removeClass(this.selectClass_).removeClass(this.options.selectClass);if(typeof b==="number"){b=parseInt(b,10);if(b<0){b=0}else{if(b>=c.length){b=c.length-1}}a=$(c[b])}else{a=$(b)}if(a){a.addClass(this.selectClass_).addClass(this.options.selectClass)}}};AutoCompleter.prototype.selectCurrent=function(){var a=$("li."+this.selectClass_,this._results);if(a.length==1){this.selectItem(a)}else{this.finish()}};AutoCompleter.prototype.selectItem=function(d){var c=d.data("value");var b=d.data("data");var a=this.displayValue(c,b);this.lastProcessedValue_=a;this.lastSelectedValue_=a;this.setValue(a);this.setCaret(a.length);this.callHook("onItemSelect",{value:c,data:b});this.finish()};AutoCompleter.prototype.isContentChar=function(a){if(a.match(this.options.stopCharRegex)){return false}else{if(a===this.options.multipleSeparator){return false}else{return true}}};AutoCompleter.prototype.getValue=function(){var c=this._element.getSelection();var d=this._element.val();var f=c.start;var e=f;for(cpos=f;cpos>=0;cpos=cpos-1){if(cpos===d.length){continue}var b=d.charAt(cpos);if(!this.isContentChar(b)){break}e=cpos}var a=f;for(cpos=f;cpos<d.length;cpos=cpos+1){if(cpos===0){continue}var b=d.charAt(cpos);if(!this.isContentChar(b)){break}a=cpos}this._selection_start=e;this._selection_end=a;return d.substring(e,a)};AutoCompleter.prototype.setValue=function(b){var a=this._element.val().substring(0,this._selection_start);var c=this._element.val().substring(this._selection_end+1);this._element.val(a+b+c)};AutoCompleter.prototype.displayValue=function(b,a){if($.isFunction(this.options.displayValue)){return this.options.displayValue(b,a)}else{return b}};AutoCompleter.prototype.finish=function(){if(this.keyTimeout_){clearTimeout(this.keyTimeout_)}if(this._element.val()!==this.lastSelectedValue_){if(this.options.mustMatch){this._element.val("")}this.callHook("onNoMatch")}this._results.hide();this.lastKeyPressed_=null;this.lastProcessedValue_=null;if(this.active_){this.callHook("onFinish")}this.active_=false};AutoCompleter.prototype.selectRange=function(d,a){var c=this._element.get(0);if(c.setSelectionRange){c.focus();c.setSelectionRange(d,a)}else{if(this.createTextRange){var b=this.createTextRange();b.collapse(true);b.moveEnd("character",a);b.moveStart("character",d);b.select()}}};AutoCompleter.prototype.setCaret=function(a){this.selectRange(a,a)};
diff --git a/askbot/skins/default/media/style/jquery.autocomplete.css b/askbot/skins/default/media/style/jquery.autocomplete.css
index 3bf2c2d9..1ad98ddf 100755..100644
--- a/askbot/skins/default/media/style/jquery.autocomplete.css
+++ b/askbot/skins/default/media/style/jquery.autocomplete.css
@@ -1,13 +1,14 @@
-.ac_results {
+.acInput {
+ width: 200px;
+}
+.acResults {
padding: 0px;
- border: 1px solid black;
- background-color: white;
+ border: 1px solid WindowFrame;
+ background-color: Window;
overflow: hidden;
- z-index: 99999;
- text-align:left;
}
-.ac_results ul {
+.acResults ul {
width: 100%;
list-style-position: outside;
list-style: none;
@@ -15,35 +16,22 @@
margin: 0;
}
-.ac_results li {
+.acResults li {
margin: 0px;
padding: 2px 5px;
- cursor: default;
+ cursor: pointer;
display: block;
- /*
- if width will be 100% horizontal scrollbar will apear
- when scroll mode will be used
- */
- /*width: 100%;*/
+ width: 100%;
font: menu;
font-size: 12px;
- /*
- it is very important, if line-height not setted or setted
- in relative units scroll will be broken in firefox
- */
- line-height: 16px;
overflow: hidden;
}
-.ac_loading {
- background: white url(../../images/indicator.gif) right center no-repeat;
-}
-
-.ac_odd {
- background-color: #E7F1F8;
+.acLoading {
+ background : url('indicator.gif') right center no-repeat;
}
-.ac_over {
- background-color: #0A246A;
- color: white;
+.acSelect {
+ background-color: Highlight;
+ color: HighlightText;
}
diff --git a/askbot/skins/default/media/style/style.css b/askbot/skins/default/media/style/style.css
index 54309781..34be550f 100755
--- a/askbot/skins/default/media/style/style.css
+++ b/askbot/skins/default/media/style/style.css
@@ -2,7 +2,7 @@
body {
background: #FFF;
- font-size: 12px;
+ font-size: 14px;
line-height: 150%;
margin: 0;
padding: 0;
@@ -36,9 +36,10 @@ input, select {
}
p {
- margin-bottom: 13px;
- font-size: 13px;
+ font-size: 14px;
line-height: 140%;
+ margin-bottom: 6px;
+ padding-left: 5px;
}
a {
@@ -56,106 +57,27 @@ a:hover {
text-decoration: underline;
}
-.block {
- width: 960px;
- height: auto;
+h1 {
+ font-size: 160%;
+ padding: 10px 0 5px 5px;
}
-.fleft {
+.users-page h1, .tags-page h1 {
float: left;
}
-.fright {
- float: right;
-}
-
-.tleft {
- text-align: left;
-}
-
-.tcenter {
- text-align: center;
-}
-
-.tright {
- text-align: right;
-}
-
-.dis {
- display: block;
-}
-
-.inline {
- display: inline;
-}
-
-.none {
- display: none;
-}
-
-.red {
- color: #CC0000;
-}
-
-.b {
- font-weight: bold;
-}
-
-.f10 {
- font-size: 10px;
-}
-
-.f11 {
- font-size: 11px;
-}
-
-.f12 {
- font-size: 12px;
-}
-
-.f13 {
- font-size: 13px;
-}
-
-.f14 {
- font-size: 14px;
-}
-
-.white {
- color: #FFFFFF;
-}
-
-.u {
- text-decoration: underline;
-}
-
-.spacer1 {
- height: 6px;
- line-height: 6px;
- clear: both;
- visibility: hidden;
-}
-
-.spacer3 {
- height: 30px;
- line-height: 30px;
- clear: both;
- visibility: hidden;
-}
-
-h1 {
- font-size: 160%;
- padding: 5px 0 5px 0;
+.main-page h1 {
+ margin-right: 5px;
}
h2 {
font-size: 140%;
- padding: 3px 0 3px 0;
+ padding: 3px 0 3px 5px;
}
h3 {
font-size: 120%;
- padding: 3px 0 3px 0;
+ padding: 3px 0 3px 5px;
}
ul {
@@ -185,10 +107,10 @@ pre {
font-size: 100%;
margin-bottom: 10px;
overflow: auto;
- width: 580px;
background-color: #F5F5F5;
padding-left: 5px;
padding-top: 5px;
+ width: 671px;
padding-bottom: 20px ! ie7;
}
@@ -205,121 +127,109 @@ blockquote {
background-color: #F5F5F5;
}
-#wrapper {
+.content-wrapper {/* wrapper positioning class */
width: 960px;
margin: auto;
- padding: 0;
+ position:relative;
}
-#roof {
- position: relative;
+#ab-header {
margin-top: 0px;
background: #FFF;
}
-#room {
- padding: 0 0 10px 0;
- background-color: #FFF;
+#ab-header .content-wrapper {
+ height: 90px;/* same as logo height */
}
#CALeft {
width: 710px;
float: left;
position: relative;
- padding-left: 0 5px;
-
+ padding: 0 5px 10px 5px;
}
#CARight {
- width: 235px;
+ width: 230px;
float: right;
- padding-right: 5px;
+ padding: 0 5px 10px 5px;
}
#CAFull {
float: left;
- padding: 0 5px;
+ padding: 0 5px 10px 5px;
width: 950px;
}
#ground {
width: 100%;
+ clear: both;
border-top: 1px solid #000;
- padding-top: 6px;
- padding-bottom: 0px;
+ padding: 6px 0 0 0;
text-align: center;
background: #777;
}
-/*#licenseLogo {position:absolute;top:10px;right:10px;}*/
+#ab-logo {
+ padding: 0px 0px 0px 10px;
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ height: 90px;
+ width: 70px;
+}
-/* why is this called top? - this contains links like login, faq, etc */
-#top {
+#ab-meta-nav,
+#ab-main-nav {
position: absolute;
+ left: 100px;
+}
+
+#ab-meta-nav {
top: 0px;
- right: 250px;
height: 20px;
- text-align: right;
padding: 3px;
- background-color: #ffffff;
+ margin: 0;
}
-/*#header {width:960px;}*/
-#top a {
+#ab-meta-nav a {
height: 35px;
- text-align: right; /*letter-spacing:1px; */
+ text-align: right;
margin-left: 20px;
text-decoration: underline;
- font-size: 12px;
color: #555555;
}
-#top a.ab-responses-envelope {
+#ab-meta-nav a:first-child {
+ margin-left: 0;
+}
+
+#ab-meta-nav a#ab-responses {
margin-left: 3px;
}
-#top a img {
+#ab-meta-nav a img {
vertical-align:middle;
margin-bottom:2px;
}
-#logo {
- padding: 0px 0px 0px 10px;
- height: 90px;
- width: 70px;
-}
-
-#logoContainer {
-}
-#navTabContainer {
- width: 610px;
- padding-left: 10px;
- text-align: left;
-}
-
-/* navBar includes logo, main tabs and links like logout, about, faq */
-#navBar {
- float: clear;
- position: relative;
- display: block;
- width: 960px;
+#ab-meta-nav .user-info a {
+ margin: 0;
+ text-decoration: none;
}
-#navBar .nav {
- margin: 20px 0px 0px 0px; /*letter-spacing:1px; */
+#ab-main-nav {
+ bottom: 0;
}
-#navBar .nav a {
+#ab-main-nav a {
color: #333333;
background-color: #fff0e0;
- /*border-left: 1px solid #eeeeec;
- border-right: 1px solid #babdb6;
- border-top: 1px solid #eeeeec;*/
border: 1px solid #888888;
border-bottom: none;
padding: 0px 12px 3px 12px;
height: 25px;
line-height: 30px;
- margin-left: 10px;
+ margin-right: 10px;
font-size: 18px;
font-weight: 100;
text-decoration: none;
@@ -327,11 +237,11 @@ blockquote {
float: left;
}
-#navBar .nav a:hover {
- text-decoration: underline
+#ab-main-nav a:hover {
+ text-decoration: underline;
}
-#navBar .nav a.on {
+#ab-main-nav a.on {
height: 24px;
line-height: 28px;
border-bottom: 1px solid #a40000;
@@ -344,71 +254,60 @@ blockquote {
text-decoration: none
}
-#navBar .nav a.special {
+#ab-main-nav a.special {
font-size: 18px;
color: #B02B2C;
font-weight: bold;
text-decoration: none;
}
-#navBar .nav a.special:hover {
+#ab-main-nav a.special:hover {
text-decoration: underline;
}
-/* todo: this is probably not used any more */
-#navBar .nav div.focus {
- float: right;
- padding-right: 0px;
-}
-
#searchBar {
display:inline-block;
background-color: #cccccc;/*888a85; /*#e9b96e;*/
width:700px;
border: 1px solid #aaaaaa;
- padding: 4px 7px 5px 5px;
+ padding: 4px 5px 4px 4px;
}
-#searchBar .searchInput {
+#searchBar .searchInput, #searchBar .searchInputCancelable {
font-size: 24px;
line-height: 24px;
- height: 36px;
- width: 605px;
- margin: 0px 3px 0px 0px;
+ height: 31px;
+ margin: 0px 4px 0px 0px;
padding: 5px 0 0 5px;
}
+#searchBar .searchInput, #searchBar .searchInputCancelable {
+ width: 607px;
+}
+
#searchBar .searchInputCancelable {
- font-size: 24px;
- line-height: 24px;
- height: 36px;
- width: 561px;
- padding: 5px 0 0 5px;
- margin: 0px 3px 0px 0px;
+ width: 564px;
}
-#searchBar .searchBtn {
+#searchBar .searchBtn, #searchBar .cancelSearchBtn {
font-size: 20px;
- color: #666666;
+ color: #666;
+ background-color: #eee;
height: 40px;
- width: 80px;
- width: 80px;
- width: 80px;
+ border: 1px solid #aaa;
line-height: 22px;
- margin: 0px;
text-align: center;
padding-bottom: 4px;
}
+#searchBar .searchBtn {
+ margin: 0px;
+ width: 78px;
+}
+
#searchBar .cancelSearchBtn {
- font-size: 20px;
- color: #666666;
- height: 40px;
width: 40px;
- line-height: 22px;
margin: 0px 3px 0px 0px;
- padding-bottom: 4px;
- text-align: center;
}
#askFormBar {
@@ -430,145 +329,155 @@ blockquote {
padding: 5px 0 0 5px;
}
-
-#searchBar .options {
- padding: 3px 0 3px 0;
- font-size: 100%;
- color: #EEE; /*letter-spacing:1px;*/
-}
-
-#searchBar .options INPUT {
- margin: 0 3px 0 15px;
-}
-
-#searchBar .options INPUT:hover {
- cursor: pointer
-}
-
-/*问题列表*/
-#listA {
+#question-list {
float: left;
background-color: #FFF;
padding: 0;
width: 100%;
}
-#listA .qstA {
- position: relative;
- padding: 3px 5px 5px 10px;
- border-top: 1px dashed #ccccce;
- /*border-left:1px solid #ebebbe;
- border-right:1px solid #b4b48e;
- border-bottom:1px solid #b4b48e;*/
- background: white; /* #f9f7ed;*/
-/*margin:10px 0 10px 0;*/
-/*background:url(../images/quest-bg.gif) repeat-x top;*/
-}
-
-#listA .qstA thumb {
- float: left;
+.ask-page div#question-list {
+ float: none;
+ width: 706px;
}
-
-#listA .qstA H2 {
+.ask-page div#question-list h2 {
font-size: 14px;
- font-weight: 800;
- margin: 8px auto;
- padding: 0px;
+ padding-bottom: 0;
}
-
-#listA .qstA H2 a {
- color: 333333 /*#2e3436*/;
- font-size: 15px;
+.ask-page div#question-list span {
+ padding: 3px 7px;
+ margin-right: 5px;
+ background: #ccc;
}
-#listA .qstA .stat {
- position: absolute;
- right: 0px;
- bottom: 5px;
- font-size: 12px; /*letter-spacing:1px;*/
- float: right;
+/* tag formatting is also copy-pasted in template
+ because it must be the same in the emails
+ askbot/models/__init__.py:format_instant_notification_email()
+*/
+ul.tags,
+.boxC ul.tags,
+ul.tags.marked-tags,
+ul#related-tags {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ line-height: 170%;
+ display: block;
}
-#listA .qstA .stat span {
- margin-right: 5px;
+ul.tags li {
+ float:left;
+ display: block;
+ margin: 0 5px 0 0;
+ padding: 0;
}
-#listA .qstA .stat td {
- min-width: 40px;
- text-align: center;
+.wildcard-tags {
+ clear: both;
}
-#listA .qstA .stat .num {
- font-family: sans-serif;
- color: #a40000;
- /*background:#eeeeec;
- border: 1px solid #babdb6;*/
- margin: 0px;
- font-size: 17px;
- font-weight: 800;
+ul.tags.marked-tags li,
+.wildcard-tags ul.tags li {
+ margin-bottom: 5px;
}
-#listA .qstA table {
- border-spacing: 0px;
+#tagSelector div.inputs {
+ clear: both;
+ float: none;
}
-#listA .qstA table td {
- padding: 0px;
- width: 60px;
- text-align: center;
+.tags-page ul.tags li,
+ul#ab-user-tags li {
+ width: 160px;
}
-#listA .qstA .stat .unit {
- color: #777777;
- margin: 0px
+ul#related-tags li {
+ margin: 0 5px 3px 0;
+ float: left;
+ clear: left;
}
-#listA .qstA .from {
- margin-top: 5px;
- font-size: 13px;
- color: #777777;
+/* .tag-left and .tag-right are for the sliding doors decoration of tags */
+.tag-left {
+ background: url(../images/tag-right.png) no-repeat right center;
+ border: none;
+ cursor: pointer;
+ display: block;
+ float: left;
+ height: 18px;
+ margin: 0 5px 0 0;
+ overflow-x: hidden;
+ padding: 0;
}
-#listA .qstA .from .score {
- font-family: sans-serif;
- color: #555555;
+.tag-right {
+ background: url(../images/tag-left.png) no-repeat left center;
+ border: none;
+ display: block;
+ float: left;
+ height: 18px;
+ line-height: 20px;
+ font-weight: normal;
+ font-size: 11px;
+ padding: 0px 7px 0px 15px;
+ text-decoration: none;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: middle;
}
-#listA .qstA .date {
- margin-left: 10px;
- color: #777777;
+.deletable-tag {
+ margin-right: 3px;
+ white-space: nowrap;
}
-#listA .qstA .wiki {
- color: #763333;
- font-size: 12px;
+.deletable-tag .tag-right {
+ padding-right: 0px;
+ float: left;
+}
+.deletable-tag.tag-left {
+ padding-right: 3px;
}
-#listA .qstA .from a {
+.tags a.tag-right,
+.tags span.tag-right {
+ color: #333;
+ text-decoration: none;
}
-#listA .qstA .from IMG {
- vertical-align: middle;
+span.delete-icon {
+ padding-left: 13px;
+ vertical-align: bottom;
+ background: url(../images/close-small-dark.png) no-repeat;
+}
+span.delete-icon:hover {
+ background: url(../images/close-small-hover.png) no-repeat;
}
-#listA .qstA .author {
- font-weight: 400;
+.tags span.delete-icon {
+ float: left;
+ height: 15px;
+ margin: 2px 0 0 1px;
+ display: block;
}
-#listA .qstA .author a {
- color: #444444;
+.tag-number {
+ font-weight: 700;
+ display: block;
+ float: left;
+ font-family: sans-serif;
}
-#listA .qstA .summary {
- margin-right: 5px;
+ul#search-tags {
+ padding-top: 3px;
}
.short-summary {
position: relative;
- padding: 3px 5px 5px 10px;
+ padding: 5px 2px 5px 2px;
border-top: 1px dashed #ccccce;
overflow: hidden;
- width: 700px;
+ width: 702px;
float: left;
}
@@ -577,16 +486,24 @@ blockquote {
font-family: "Trebuchet MS", "segoe ui", arial, sans-serif;
}
+.short-summary .userinfo .relativetime,
+.short-summary .userinfo a,
+.short-summary span.anonymous {
+ font-size: 11px;
+ clear:both;
+ font-weight: normal;
+ color: #555;
+}
+
+
.short-summary .userinfo {
- float: right;
- margin-top: 8px;
+ text-align:center;
+ line-height:16px;
}
.short-summary .counts {
float: right;
- margin-top: 4px;
- margin-right: 10px;
- margin-left: 5px;
+ margin: 2px 0 0 5px;
}
.short-summary .counts .item-count {
@@ -598,155 +515,97 @@ blockquote {
font-weight: 800;
}
-.short-summary .counts .votes div {
- padding-top:1px;
+.short-summary .counts .votes div,
+.short-summary .counts .views div,
+.short-summary .counts .answers div
+{
+ font-size: 12px;
+ line-height:14px;
+ color: #555;
+}
+
+.short-summary .tags {
+ margin-top: 0;
}
-.no-votes {
+.no-votes .item-count {
background: white;
color: gray;
}
-.some-votes {
+.some-votes .item-count {
background: #a3d0ff;
color: #4a4a4a;
}
-.no-answers {
+.no-answers .item-count {
background: #b63333;
color: yellow;
}
-.some-answers {
+.some-answers .item-count {
background: #ffed9c;
color: #a4a4a4;
}
-.accepted {
+.accepted .item-count {
background:#338333;
color:#d0f5a9;
}
-.no-views {
+.no-views .item-count {
background: gray;
color: white;
}
-.some-views {
+.some-views .item-count {
background: #ff8c8c;
color: #4a4a4a;
}
.short-summary .votes,
-.short-summary .status,
+.short-summary .answers,
.short-summary .views {
- font-size: 12px;
text-align: center;
- margin: 0 0 0 7px;
+ margin: 0 3px;
padding: 4px 2px 0px 2px;
width: 46px;
- height: 48px;
float: left;
-moz-border-radius: 5px;
-khtml-border-radius: 5px;
-webkit-border-radius: 5px;
}
-#question-table {
- margin-bottom: 10px; /*border-bottom:1px solid #888a85;*/
-}
-
-.evenMore {
- font-size: 14px;
- font-weight: 800;
-}
-
-.evenMore a {
- text-decoration: underline;
-}
-
-.questions-count {
- font-size: 32px;
- font-family: sans-serif;
- font-weight: 600;
- padding: 0 0 5px 0px;
- color: #a40000;
- margin-top: 3px;
-}
-
-/*内容块*/
-.boxA {
- background: #888a85;
- padding: 6px;
- margin-bottom: 8px;
- border 1px solid #babdb6;
-}
-
-.boxA H3 {
- font-size: 13px;
- font-weight: 800;
- color: #FFF;
- margin: 0;
- padding: 0;
- margin-bottom: 4px;
+.short-summary .views {
+ width: 36px;
+ padding-right: 0;
}
-.boxA .body {
- border: 1px solid #999;
- padding: 8px;
- background: #FFF;
- font-size: 13px;
+.short-summary h2 {
+ padding-left: 0;
}
-.boxA .more {
- padding: 2px;
- text-align: right;
- font-weight: 800;
+#question-table,
+.answer-table {
+ margin: 2px 0 10px 0;
+ border-spacing: 0px;
}
-.boxB {
- background: #F9F7ED;
- padding: 6px;
- margin-bottom: 8px;
- border: solid 1px #aaaaaa;
+.answer-table {
+ border-bottom: 1px solid #bbb;
}
-.boxB H3 {
- font-size: 13px;
+.evenMore {
+ font-size: 14px;
font-weight: 800;
- color: #000;
- margin: 0;
- padding: 0 0 0 15px;
- margin-bottom: 4px;
- background: url(../images/dot-g.gif) no-repeat left center;
-}
-
-.boxB .body {
- border: 1px solid #aaaaaa;
- padding: 8px;
- background: #FFF;
- font-size: 13px;
- line-height: 160%;
}
-.boxB .more {
- padding: 1px;
- text-align: right;
- font-weight: 800;
+.evenMore a {
+ text-decoration: underline;
}
.boxC {
background: white /*#cacdc6; /*f9f7ed;*/
padding: 10px 10px 10px 15px;
- margin-bottom: 8px;
- /*
- border-top: 1px solid #eeeeec;
- border-left: 1px solid #eeeeec;
- border-right: 1px solid #a9aca5;
- border-bottom: 1px solid #babdb6;
- */
+ margin-bottom: 12px;
}
.boxC p {
- margin-bottom: 8px;
-}
-
-.boxC p.nomargin {
- margin: 0px;
+ margin-bottom: 4px;
}
.boxC p.info-box-follow-up-links {
@@ -754,6 +613,15 @@ blockquote {
margin: 0;
}
+.boxC h2,
+.boxC h3 {
+ padding-left: 0;
+}
+
+.boxC label {
+ color: #333;
+}
+
.pager {
clear:both;
border-top: 1px solid #777;
@@ -773,20 +641,6 @@ blockquote {
font: normal 12px sans-serif;
}
-.paginator .prev-na,
-.paginator .next-na {
- padding: .3em;
- font: bold .875em sans-serif;
-}
-
-.paginator .prev-na,
-.paginator .next-na {
- border: 1px solid #ccc;
- background-color: #f9f9f9;
- color: #aaa;
- font-weight: normal;
-}
-
.paginator .prev a, .paginator .prev a:visited,
.paginator .next a, .paginator .next a:visited {
border: 1px solid #fff;
@@ -796,11 +650,11 @@ blockquote {
font: bold 100% sans-serif;
}
-.paginator .prev, .paginator .prev-na {
+.paginator .prev {
margin-right: .5em;
}
-.paginator .next, .paginator .next-na {
+.paginator .next {
margin-left: .5em;
}
@@ -836,97 +690,23 @@ blockquote {
font: bold 100% sans-serif;
}
-.paginator-container {
- float: right;
- padding: 10px 0 10px 0;
-}
-
.paginator-container-left {
padding: 5px 0 10px 0;
}
-/*标签*/
-/* todo: probably needs to be removed
-conflicts with WMD!
-.tag {
- font-size: 13px;
- font-weight: normal;
- color: #333;
- text-decoration: none;
- background-color: #EEE;
- border-left: 3px solid #777;
- border-top: 1px solid #EEE;
- border-bottom: 1px solid #CCC;
- border-right: 1px solid #CCC;
- padding: 1px 8px 1px 8px;
-}
-*/
-
-.tags {
- font-family: sans-serif;
- line-height: 200%;
- display: block;
- margin-top: 5px;
-}
-
-.tags a {
- white-space: nowrap;
- font-size: 11px;
- font-weight: normal;
- color: #333;
- text-decoration: none;
- background-color: #EEE;
- border-left: 3px solid #777;
- border-top: 1px solid #EEE;
- border-bottom: 1px solid #CCC;
- border-right: 1px solid #CCC;
- padding: 1px 8px 1px 8px;
- margin-right:3px;
-}
-
-.tags a:hover {
- background-color: #fFF;
- color: #333;
-}
-
-.tagsbox {
- line-height: 200%;
-}
-
-.tagsbox a {
- font-size: 13px;
- font-weight: normal;
- color: #333;
- text-decoration: none;
- background-color: #EEE;
- border-left: 3px solid #777;
- border-top: 1px solid #EEE;
- border-bottom: 1px solid #CCC;
- border-right: 1px solid #CCC;
- padding: 1px 8px 1px 8px;
-}
-
-.tagsbox a:hover {
- background-color: #fFF;
- color: #333;
-}
-
-.tag-number {
- font-weight: 700;
- font-family: sans-serif;
-}
-
-.marked-tags {
- margin-top: 0px;
- margin-bottom: 5px;
+p.rss {
+ float: right;
+ font-size: 12px;
+ color: #666;
+ margin: 0 2px 0 0;
}
-.deletable-tag {
- margin-right: 3px;
- white-space: nowrap;
+p.rss a {
+ padding-left: 16px;
+ background: url(../images/feed-icon-small.png) no-repeat;
}
-/*奖牌*/
+/* badges */
a.medal {
font-size: 14px;
line-height: 250%;
@@ -962,6 +742,10 @@ a:hover.medal {
margin-top: 3px;
}
+.tabBar h2 {
+ float: left;
+}
+
.tabsA, .tabsC {
background-color: #FFF;
float: right;
@@ -1003,7 +787,7 @@ a:hover.medal {
float: left;
height: 20px;
line-height: 22px;
- margin: 5px 4px 0 0;
+ margin: 5px 0 0 4px;
padding: 0 11px 0 11px;
text-decoration: none;
}
@@ -1012,7 +796,7 @@ a:hover.medal {
float: left;
font-weight: bold;
color: #777;
- margin: 8px 4px 0 4px;
+ margin: 8px 0 0 0px;
}
.tabsB a {
@@ -1028,142 +812,6 @@ a:hover.medal {
text-decoration: none;
}
-.headlineA {
- font-size: 13px;
- border-bottom: 1px solid #777;
- padding-bottom: 2px;
- font-weight: 800;
- margin-bottom: 12px;
- text-align: right;
- height: 30px;
-}
-
-.headQuestions {
- height: 23px;
- line-height: 23px;
- margin: 5px 0 0 5px;
- padding: 0px 6px 0px 15px;
- font-size: 15px;
- font-weight: 700;
- border-bottom: 0px solid #777;
- border-left: 0px solid #darkred;
- background-color: #FFF;
- background: url(../images/dot-list.gif) no-repeat left center;
-}
-
-.headAnswers {
- float: left;
- padding: 3px;
- font-size: 18px;
- font-weight: 800;
- background: url(../images/ico_answers.gif) left 2px no-repeat;
- padding-left: 24px;
-}
-
-.headTags {
- float: left;
- padding: 3px;
- font-size: 18px;
- font-weight: 800;
- background: url(../images/ico_tags.gif) no-repeat;
- padding-left: 24px;
-}
-
-/* todo: make this class applicable to all headers it is actually uses in tags.html too */
-.headUsers {
- float: left;
- height: 23px;
- line-height: 23px;
- margin: 5px 0 0 5px;
- padding: 0px 6px 0px 15px;
- font-size: 15px;
- font-weight: 700;
- border-bottom: 0px solid #777;
- border-left: 0px solid #darkred;
- background-color: #FFF;
- background: url(../images/dot-list.gif) no-repeat left center;
-}
-
-.headMedals {
- float: left;
- height: 23px;
- line-height: 23px;
- margin: 5px 0 0 5px;
- padding: 0px 6px 0px 15px;
- font-size: 15px;
- font-weight: 700;
- border-bottom: 0px solid #777;
- border-left: 0px solid #darkred;
- background-color: #FFF;
- background: url(../images/dot-list.gif) no-repeat left center;
-}
-
-.headLogin {
- float: left;
- padding: 3px;
- font-size: 15px;
- font-weight: 800;
- background: url(../images/ico_login.gif) no-repeat;
- padding-left: 24px;
-}
-
-.headNormal {
- text-align: left;
- padding: 3px;
- font-size: 15px;
- margin-bottom: 12px;
- font-weight: bold;
- border-bottom: 1px solid #777;
-}
-
-.headUser {
- text-align: left;
- padding: 5px;
- font-size: 20px; /*letter-spacing:1px;*/
- margin-bottom: 12px;
- font-weight: 800;
- border-bottom: 1px solid #777;
-}
-
-/*RSS订阅*/
-#feeds {
- margin: 10px 0;
-}
-
-#feeds a {
- background: url(../images/feed-icon-small.png) no-repeat 0;
- padding-left: 18px;
- font-weight: 700;
- font-size: 13px;
-}
-
-/*问题*/
-#question {
- margin-bottom: 30px;
-}
-
-#question h1 {
- font-size: 15px;
- background: #CCC;
- padding: 6px 8px;;
-}
-
-#question .body {
- background: #F7F7F7;
- padding: 20px 10px;
-}
-
-.starter {
- padding: 10px;
- background: #E0EAF1;
-}
-
-.vote {
- font-size: 20px;
- color: #666;
- font-weight: 800;
-}
-
.questions-related {
font-weight: 700;
word-wrap: break-word;
@@ -1186,35 +834,19 @@ a:hover.medal {
font-size: 125%;
}
-.question-body {
- min-height: 100px;
- font-size: 13px;
+.question-body, .answer-body {
+ min-height: 39px;
line-height: 20px;
}
-.question-body IMG {
+.question-body IMG, .answer-body IMG {
max-width: 600px;
}
-.question-mark {
- /*background-color:#fff5e0;
- border-top: 1px solid #eeeeec;
- border-right: 1px solid #babdb6;
- border-bottom: 1px solid #babdb6;
- border-left: 1px solid #eeeeec;*/
- text-align: left;
- padding: 5px;
- overflow: hidden;
-}
-
-.question-edit {
- text-align: left;
- overflow: hidden;
-}
-
.vote-buttons {
float: left;
text-align: center;
+ padding-top: 2px;
}
.vote-buttons IMG {
@@ -1291,14 +923,8 @@ a:hover.medal {
color: #ccc;
}
-.wiki-category {
- margin-left: 5px;
- color: #999;
- font-size: 90%;
-}
-
.comments {
- font-size: 11px;
+ font-size: 12px;
line-height: 15px;
clear: both;
}
@@ -1308,7 +934,7 @@ a:hover.medal {
background: url(../images/gray-up-arrow-h18px.png) no-repeat;
width: 100%;
padding-left: 12px;
- margin: 3px 0 20px 0;
+ margin: 3px 0 20px 5px;
}
.comments textarea {
@@ -1317,7 +943,7 @@ a:hover.medal {
width: 664px;
margin: 0 0 4px 0;
font-family: sans-serif;
- font-size: 11px;
+ font-size: 12px;
line-height: 15px;
padding: 2px 0 0 2px;
}
@@ -1388,26 +1014,6 @@ div.comments {
text-decoration: underline;
}
-/*回答*/
-#answers {
-}
-
-.answer {
- padding-top: 10px;
- width: 100%;
- border-bottom: 1px solid #ccccce;
-}
-
-.answer-body {
- min-height: 80px;
- font-size: 13px;
- line-height: 20px;
-}
-
-.answer-body IMG {
- max-width: 600px;
-}
-
.accepted-answer {
background-color: #EBFFE6;
border-bottom-color: #9BD59B;
@@ -1431,11 +1037,6 @@ div.comments {
color: #763333;
}
-.unanswered {
- background: #777;
- color: white;
-}
-
.answered-by-owner {
background: #E9E9FF;
}
@@ -1460,33 +1061,12 @@ div.comments {
background: #F4E7E7 none repeat scroll 0 0;
}
-/*标签列表*/
-/*
-.tagsbox {}
-.tagsbox a {color:#000;line-height:30px;margin-right:10px;font-size:100%;background-color:#F9F7ED;padding:3px;border:1px solid #aaaaaa;}
-.tagsbox a:hover {text-decoration:none;background-color:#F9F7ED;color:#B02B2C;} */
-.tagsList {
- margin: 0;
- list-style-type: none;
- padding: 0px;
-}
-
-.tagsList li {
- width: 235px;
- float: left;
-}
-
-.badge-list {
- margin: 0;
- list-style-type: none;
-}
-/*登录*/
-.list-item {
+.boxC ul {
margin-left: 15px;
}
-.list-item LI {
+.boxC li {
list-style-type: disc;
font-size: 13px;
line-height: 20px;
@@ -1528,9 +1108,6 @@ table.ab-tag-filter-form {
width: 45em;
}
-/*.form-row li label {
- display: inline
-}*/
.submit-row {
line-height: 30px;
padding-top: 10px;
@@ -1555,12 +1132,7 @@ label.retag-error {
font-size: 10px;
}
-.error-list li {
- padding: 5px;
-}
-
.fieldset {
-/* border:solid 1px #777;*/
border: none;
margin-top: 10px;
padding: 10px;
@@ -1593,18 +1165,6 @@ label.retag-error {
font-size: 120%;
}
-.openid-samples {
-
-}
-
-.openid-samples .list, .list li {
- font-family: Trebuchet MS, "segoe ui", Helvetica, "Microsoft YaHei", 宋 体, Tahoma, Verdana, MingLiu, PMingLiu, Arial, sans-serif;
- list-style: none !important;
- margin-left: -30px !important;
- line-height: 20px !important;
-}
-
-/*表单相关*/
span.form-error {
color: #990000;
font-size: 90%;
@@ -1622,7 +1182,7 @@ span.form-error {
font-size: 100%;
min-height: 200px;
line-height: 18px;
- width: 697px;
+ width: 702px;
margin:0;
}
@@ -1631,7 +1191,7 @@ span.form-error {
}
.wmd-preview {
- margin: 0;
+ margin: 3px 0 5px 0;
padding: 6px;
width: 691px;
background-color: #F5F5F5;
@@ -1665,14 +1225,33 @@ span.form-error {
margin-top: 10px;
}
+.checkbox {
+ margin-left:5px;
+ font-weight:normal;
+ cursor:help
+}
+
+.question-options {
+ margin-top: 1px;
+ float: left;
+ color: #666;
+ line-height: 13px;
+}
+.question-options label {
+ vertical-align: text-bottom;
+}
+
+.ask-page input.submit,
+.edit-question-page input.submit {
+ float: left;
+}
+
.edit-content-html {
border-top: 1px dotted #D8D2A9;
border-bottom: 1px dotted #D8D2A9;
margin: 5px 0 5px 0;
}
-/*修订记录*/
-
.revision {
margin: 10px 0 10px 0;
width: 100%;
@@ -1720,11 +1299,6 @@ span.form-error {
font-family: sans-serif;
}
-.revision .body {
- padding-left: 10px;
- margin-bottom: 50px;
-}
-
.revision .answerbody {
padding: 10px 0 5px 10px;
}
@@ -1760,6 +1334,7 @@ ins .post-tag {
font-weight: 800;
color: #777;
line-height: 40px; /*letter-spacing:0px*/
+ margin-top: 3px;
}
.user-details {
@@ -1775,11 +1350,6 @@ ins .post-tag {
width: 90%;
}
-.user-edit-link {
- background: url(../images/edit.png) no-repeat;
- padding-left: 20px;
-}
-
.favorites-count-off {
color: #919191;
float: left;
@@ -1796,36 +1366,16 @@ ins .post-tag {
text-align: center;
}
+/* todo: get rid of this in html */
.favorites-empty {
width: 32px;
height: 45px;
float: left;
}
-.question-summary {
- border-bottom: 1px dotted #999999;
- float: left;
- overflow: hidden;
- padding: 11px 0;
- width: 670px;
-}
-
.user-info-table {
- width: 950;
margin-bottom: 10px;
-}
-
-.user-stats-table .question-summary {
- width: 800px;
-}
-
-.narrow .stats {
- float: left;
- height: 48px;
- margin: 0 0 0 7px;
- padding: 0;
- width: auto;
- font-family: Arial;
+ border-spacing: 0;
}
/* todo: remove this hack? */
@@ -1833,122 +1383,17 @@ ins .post-tag {
width: 660px;
}
-.stats div {
- font-size: 11px;
- text-align: center;
-}
-
-/*
-.narrow .votes {
- background: #EEEEEE none repeat scroll 0 0;
- float: left;
- height: 42px;
- margin: 0 3px 0 0;
- padding: 5px;
- width: 46px;
- text-align: center;
- -moz-border-radius: 5px;
- -khtml-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-*/
-
-/*
-.narrow .summary {
- width: 600px;
- display: inline-block;
-}
-*/
-
.narrow .summary h3 {
padding: 0px;
margin: 0px;
}
-/* todo: delete commented out stuff */
-/*
-.narrow .views {
- height: 42px;
- float: left;
- margin: 0 7px 0 0; *//*padding:5px 0 5px 4px;*//*
- padding: 5px;
- width: 46px;
- text-align: center;
- -moz-border-radius: 5px;
- -khtml-border-radius: 5px;
- -webkit-border-radius: 5px;
- color: #777;
-}
-*/
-
-.narrow .status {
- float: left;
- height: 42px;
- margin: 0 3px 0 0;
- padding: 5px;
- width: 46px;
- text-align: center;
- -moz-border-radius: 5px;
- -khtml-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.narrow .vote-count-post {
- font-weight: 800;
- display: block;
- margin: 0;
- font-size: 190%;
- color: #555;
- line-height: 20px;
-}
-
-.narrow .answer-count-post {
- font-weight: 800;
- display: block;
- margin: 0;
- font-size: 190%;
-}
-
-.narrow .views-count-post {
- font-weight: 800;
- display: block;
- margin: 0;
- font-size: 190%;
-}
-
-div.started {
- color: #999999;
- float: right;
- line-height: 18px;
-
-}
-
-.narrow div.started {
- line-height: inherit;
- padding-top: 4px;
- white-space: nowrap;
- width: auto;
-}
-
.relativetime {
font-weight: bold;
text-decoration: none;
}
-div.started a {
- font-weight: bold;
-}
-
-div.started .reputation-score {
- margin-left: 1px;
-}
-
-#top a.user-micro-info {
- margin-left:0px;
- text-decoration:none;
-}
-
-.narrow .tags {
+.narrow .tags {
float: left;
}
@@ -1980,10 +1425,7 @@ div.started .reputation-score {
color: #777;
}
-.user-action {
-
-}
-
+/* todo: make these more semantic */
.user-action-1 {
font-weight: bold;
color: #333;
@@ -2035,6 +1477,7 @@ div.started .reputation-score {
color: #333;
}
+/* todo: make these more semantic */
.post-type-1 a {
font-weight: bold;
@@ -2065,66 +1508,6 @@ div.started .reputation-score {
color: #333;
}
-/*读书频道*/
-.bookInfo {
- float: left;
- width: 940px;
- padding: 5px;
-}
-
-.bookCover {
- float: left;
- width: 200px;
-}
-
-.bookCover img {
- border: 1px solid #ccc;
- max-width: 200px;
-}
-
-.bookSummary {
- float: left;
- font-size: 13px;
-}
-
-.blogRss {
- float: right;
- margin: 0 10px 0 0;
- width: 460px;
- height: 240px;
- background-color: #EEE;
- padding: 5px;
-}
-
-.bookQuestions {
- margin-bottom: 10px;
-}
-
-.bookFeed {
- float: right;
-}
-
-.bookAsk {
-/*letter-spacing:1px; */
- float: right;
- margin: -30px 10px 0 0;
- padding: 3px 5px 3px 5px;
-}
-
-.bookAsk a {
- font-size: 15px;
- color: #FFF;
- font-weight: bold;
- text-decoration: none;
- background-color: #EC7000;
- padding: 3px 6px 3px 6px;
-}
-
-.bookAsk a:hover {
- text-decoration: underline;
-}
-
-/*其他全局样式*/
.hilite {
background-color: #ff0;
}
@@ -2141,16 +1524,6 @@ div.started .reputation-score {
background-color: #0ff;
}
-.userStatus {
- margin-left: 12px;
- color: #FFF;
- float: right;
-}
-
-.userStatus a {
- color: #FFF;
-}
-
.gold, .badge1 {
color: #FFCC00;
}
@@ -2178,31 +1551,16 @@ div.started .reputation-score {
font-size: 13px;
}
-.subSearch {
- margin-bottom: 12px;
- padding: 4px;
-}
-
a.comment {
background: #EEE;
color: #993300;
padding: 5px;
}
-a.permLink {
- padding: 2px;
-}
-
a.offensive {
color: #999;
}
-ul.bulleta li {
- background: url(../images/bullet_green.gif) no-repeat 0px 2px;
- padding-left: 16px;
- margin-bottom: 4px;
-}
-
.user {
padding: 5px;
line-height: 140%;
@@ -2221,10 +1579,6 @@ ul.bulleta li {
display: inline;
}
-.yellowbg {
- background: yellow;
-}
-
.message {
padding: 5px;
margin: 10px 0 10px 0;
@@ -2286,10 +1640,6 @@ button::-moz-focus-inner {
padding-right: 10px;
}
-.thousand {
- color: orange;
-}
-
.notify {
position: fixed;
top: 0px;
@@ -2331,15 +1681,11 @@ button::-moz-focus-inner {
font-size: 15px;
}
-.bigger {
- font-size: 14px;
-}
-
.strong {
font-weight: bold;
}
-.orange {
+.orange {/* used in django.po */
color: #d64000;
font-weight: bold;
}
@@ -2353,27 +1699,6 @@ button::-moz-focus-inner {
border-top: 1px dashed #aaaaaa;
}
-.about div.first {
- padding-top: 0;
- border-top: none;
-}
-
-.about p {
- margin-bottom: 10px;
-}
-
-.about a {
- color: #d64000;
- text-decoration: underline;
-}
-
-.about h3 {
- line-height: 30px;
- font-size: 15px;
- font-weight: 700;
- padding-top: 0px;
-}
-
.highlight {
background-color: #FFF8C6;
}
@@ -2412,11 +1737,6 @@ button::-moz-focus-inner {
-webkit-border-radius: 5px;
}
-.tight {
- margin: 0;
- padding: 0;
-}
-
.list-table td {
vertical-align: top;
}
@@ -2428,12 +1748,6 @@ button::-moz-focus-inner {
padding: 2px 3px 5px 3px;
}
-.delete-icon {
- vertical-align: middle;
- padding-left: 1px;
- margin-bottom:3px;
-}
-
/* these need to go */
table.form-as-table .errorlist {
display: block;
@@ -2515,51 +1829,39 @@ ul.form-horizontal-rows li input {
margin: 0px;
}
-#emailpw-form li input {
- left: 170px;
-}
-
-#emailpw-form ul.errorlist {
- left: 170px;
-}
-
-#changepw-form li input {
- left: 150px;
-}
-
-#changepw-form ul.errorlist {
- left: 150px;
-}
-
.narrow .summary {
float: left;
}
-.narrow .summary .question-title {
- font-weight: bold;
- font-size: 120%;
-}
-
.user-profile-tool-links {
- padding-bottom: 10px;
font-weight: bold;
+ vertical-align: top;
}
.post-controls, .post-tags {
- clear: left;
- float: left;
font-size: 11px;
line-height: 12px;
min-width: 200px;
+ padding-left: 5px;
margin-bottom: 5px;
}
-.post-tags {
- margin-bottom:8px;
+.post-controls {
+ clear: left;
+ float: left;
+}
+
+ul.post-tags {
+ margin-left: 7px;
+}
+ul.post-tags li {
+ margin-top: 4px;
+ margin-bottom: 3px;
}
-.post-retag {
+ul.post-retag {
margin-bottom:0px;
+ margin-left:5px;
}
#question-controls .tags {
@@ -2568,26 +1870,28 @@ ul.form-horizontal-rows li input {
.post-update-info-container {
float: right;
- min-width: 190px;
+ min-width: 85px;
}
.post-update-info {
display: inline-block;
float: right;
+ font-size: 11px;
width: 190px;
margin-bottom: 5px;
+ line-height: 14px
}
.post-update-info p {
+ line-height: 13px;
font-size: 11px;
- line-height: 15px;
- margin: 0 0 4px 0;
+ margin: 0 0 2px 1px;
padding: 0;
}
-.post-update-info img {
+.post-update-info .gravatar {
float: left;
- margin: 4px 8px 0 0;
+ margin-right: 4px;
}
@@ -2595,29 +1899,24 @@ ul.form-horizontal-rows li input {
color: #444;
}
-.admin {
- background-color: #fff380; /* nice yellow */
- border: 1px solid darkred;
- padding: 0 5px 0 5px;
-}
-
-.admin p {
- margin-bottom: 3px;
-}
-
-.admin #action_status {
- text-align: center;
- font-weight: bold;
-}
-
#tagSelector {
padding-bottom: 2px;
+ margin-bottom: 0;
+}
+
+#related-tags {
+ padding-left: 3px;
}
#hideIgnoredTagsControl {
margin: 5px 0 0 0;
}
+#hideIgnoredTagsControl label {
+ font-size: 12px;
+ color: #666;
+}
+
#hideIgnoredTagsCb {
margin: 0 2px 0 1px;
}
@@ -2670,7 +1969,7 @@ p.signup_p {
}
.karma-diagram {
- width:390px;
+ width:377px;
height:300px;
float:left;
margin-right:10px;
@@ -2703,18 +2002,22 @@ p.signup_p {
.search-result-summary {
font-weight: bold;
font-size:18px;
- line-height:30px;
- margin:0px 0px 0px 5px;
- padding:0px;
+ line-height:22px;
+ margin:0px 0px 0px 0px;
+ padding:2px 0 0 0;
+ float: left;
}
.search-tips {
font-size:12px;
line-height:12px;
- margin:0 0 5px 5px;
+ color: #555;
+ margin:0 0 5px 0;
padding:0px;
+ clear:both;
}
.search-tips a {
text-decoration: underline;
+ color: #555;
}
.faq-rep-item {
@@ -2722,14 +2025,12 @@ p.signup_p {
padding-right:5px;
}
-#top a.ab-nav-karma, #top a.ab-nav-badges {
- margin: 0;
- text-decoration: none;
-}
-
img.gravatar {
margin:2px;
}
+.user-info-table .gravatar {
+ margin:0;
+}
.vote-notification {
z-index: 1;
@@ -2779,6 +2080,38 @@ img.gravatar {
font-weight:bold;
}
+.avatar-page ul {
+ list-style: none;
+}
+.avatar-page li {
+ display: inline;
+}
+.user-profile-page .avatar p {
+ margin-bottom: 0px;
+}
+.user-profile-page .tabBar a#stats {
+ margin-left: 0;
+}
+.user-profile-page img.gravatar {
+ margin: 2px 0 3px 0;
+}
+.user-profile-page h3 {
+ padding: 0;
+ margin-top: -3px;
+}
+.userList {
+ font-size: 13px;
+}
+
+img.flag {
+ border: 1px solid #eee;
+ vertical-align: text-top;
+}
+
+.main-page img.flag {
+ vertical-align: text-bottom;
+}
+
.fb-share, .twitter-share {
background: url(../images/sprite.png) no-repeat;
text-indent:-100em;
@@ -2807,7 +2140,7 @@ a.edit {
.lit { color: #066; }
.pun { color: #660; }
.pln { color: #000; }
-.tag { color: #008; }
+.tag { color: #008; }/* name conflict here */
.atn { color: #606; }
.atv { color: #080; }
.dec { color: #606; }
diff --git a/askbot/skins/default/templates/404.html b/askbot/skins/default/templates/404.html
index 2a3933d8..158bfb94 100644
--- a/askbot/skins/default/templates/404.html
+++ b/askbot/skins/default/templates/404.html
@@ -1,5 +1,5 @@
{% load extra_tags %}
-{% include_jinja "404.jinja.html" %}
+{% include_jinja "404.jinja.html" request %}
{% comment %}
this one has to be a django template because of use of default hander404
{% endcomment %}
diff --git a/askbot/skins/default/templates/404.jinja.html b/askbot/skins/default/templates/404.jinja.html
index db5a3cba..2da99646 100644
--- a/askbot/skins/default/templates/404.jinja.html
+++ b/askbot/skins/default/templates/404.jinja.html
@@ -7,12 +7,10 @@
</style>
{% endblock %}
{% block content %}
-<div id="main-bar" class="headNormal">
- {% trans %}Page not found{% endtrans %}
-</div>
-<div id="main-body" class="">
+<h1>{% trans %}Page not found{% endtrans %}</h1>
+<div id="main-body">
<div style="padding:5px 0px 10px 0;line-height:25px;">
- <h3>{% trans %}Sorry, could not find the page you requested.{% endtrans %}</h3>
+ <h2>{% trans %}Sorry, could not find the page you requested.{% endtrans %}</h2>
<div style="margin-top:5px">
{% trans %}This might have happened for the following reasons:{% endtrans %}<br/>
<ul>
diff --git a/askbot/skins/default/templates/500.html b/askbot/skins/default/templates/500.html
index 04d706ec..8ec1bce4 100644
--- a/askbot/skins/default/templates/500.html
+++ b/askbot/skins/default/templates/500.html
@@ -1,5 +1,5 @@
{% load extra_tags %}
-{% include_jinja "500.jinja.html" %}
+{% include_jinja "500.jinja.html" request %}
{% comment %}this template must be django
because of the use of default handler500
{% endcomment %}
diff --git a/askbot/skins/default/templates/500.jinja.html b/askbot/skins/default/templates/500.jinja.html
index 516dda34..297ae736 100644
--- a/askbot/skins/default/templates/500.jinja.html
+++ b/askbot/skins/default/templates/500.jinja.html
@@ -2,10 +2,8 @@
<!-- template 500.html -->
{% block title %}{% spaceless %}{% trans %}Internal server error{% endtrans %}{% endspaceless %}{% endblock %}
{% block content %}
-<div id="main-bar" class="">
- <h3>{% trans %}Internal server error{% endtrans %}</h3>
-</div>
-<div id="main-body" class="headNormal">
+<h1>{% trans %}Internal server error{% endtrans %}</h1>
+<div id="main-body">
<div style="padding:5px 0px 10px 0;line-height:25px">
{% trans %}system error log is recorded, error will be fixed as soon as possible{% endtrans %}<br/>
{% trans %}please report the error to the site administrators if you wish{% endtrans %}
diff --git a/askbot/skins/default/templates/about.html b/askbot/skins/default/templates/about.html
index 40f6ce12..fce4223e 100644
--- a/askbot/skins/default/templates/about.html
+++ b/askbot/skins/default/templates/about.html
@@ -1,11 +1,8 @@
{% extends "two_column_body.html" %}
<!-- template about.html -->
-{% block title %}{% spaceless %}{% trans %}About{% endtrans %}{% endspaceless %}{% endblock %}
+{% block title %}{% spaceless %}{% trans site_name=settings.APP_SHORT_NAME %}About {{site_name}}{% endtrans %}{% endspaceless %}{% endblock %}
{% block content %}
-<div class="headNormal">
-{% trans %}About{% endtrans %}
-</div>
-
+<h1>{% trans site_name=settings.APP_SHORT_NAME %}About {{site_name}}{% endtrans %}</h1>
<div class="content">
{{settings.FORUM_ABOUT}}
</div>
diff --git a/askbot/skins/default/templates/answer_edit.html b/askbot/skins/default/templates/answer_edit.html
index ab2f2aac..0dc137ae 100644
--- a/askbot/skins/default/templates/answer_edit.html
+++ b/askbot/skins/default/templates/answer_edit.html
@@ -6,9 +6,9 @@
<link rel="stylesheet" type="text/css" href="{{"/js/wmd/wmd.css"|media}}" />
{% endblock %}
{% block content %}
-<div id="main-bar" class="headNormal">
+<h1>
{% trans %}Edit answer{% endtrans %} [<a href="{{ answer.question.get_absolute_url() }}#{{ answer.id }}">{% trans %}back{% endtrans %}</a>]
-</div>
+</h1>
<div id="main-body" class="ask-body">
<div id="askform">
<form id="fmedit" action="{% url edit_answer answer.id %}" method="post" >
@@ -17,22 +17,25 @@
<div style="vertical-align:middle">
{{ revision_form.revision }} <input type="submit" style="display:none" id="select_revision" name="select_revision" value="{% trans %}select revision{% endtrans %}">
</div>
- {{macros.edit_post(form, settings.WIKI_ON and answer.wiki == False)}}
+ {{ macros.edit_post(form) }}
<div class="after-editor">
<input type="submit" value="{% trans %}Save edit{% endtrans %}" class="submit" />&nbsp;
<input type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" onclick="history.back(-1);" />
</div>
+ {% if settings.WIKI_ON and answer.wiki == False %}
+ {{ macros.checkbox_in_div(form.wiki) }}
+ {% endif %}
</form>
</div>
</div>
{% endblock %}
{% block sidebar %}
- {% include "answer_edit_tips.html" %}
+ {% include "blocks/answer_edit_tips.html" %}
{% endblock %}
{% block endjs %}
- {% include "editor_data.html" %}
+ {% include "blocks/editor_data.html" %}
<script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
<script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
<script type='text/javascript' src='{{"/js/post.js"|media}}'></script>
diff --git a/askbot/skins/default/templates/ask.html b/askbot/skins/default/templates/ask.html
index 0bdb5ed1..508cc16e 100644
--- a/askbot/skins/default/templates/ask.html
+++ b/askbot/skins/default/templates/ask.html
@@ -1,4 +1,5 @@
{% extends "two_column_body.html" %}
+{% import "macros.html" as macros %}
<!-- template ask.html -->
{% block title %}{% spaceless %}{% trans %}Ask a question{% endtrans %}{% endspaceless %}{% endblock %}
{% block forestyle %}
@@ -6,7 +7,7 @@
{% endblock %}
{# main contents of ask form is in the template input_bar #}
{% block sidebar %}
-{% include "question_edit_tips.html" %}
+{% include "blocks/question_edit_tips.html" %}
{% endblock %}
{% block endjs %}
<script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
@@ -14,15 +15,21 @@
<script type='text/javascript' src='{{"/js/post.js"|media}}'></script>
<script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script>
<script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script>
- {% include "editor_data.html" %}
<script type='text/javascript'>
+ var sortMethod = undefined;//need for live_search
+ var minSearchWordLength = {{settings.MIN_SEARCH_WORD_LENGTH}};
+ </script>
+ <script type='text/javascript' src='{{"/js/live_search.js"|media}}'></script>
+ {% include "blocks/editor_data.html" %}
+ <script type='text/javascript'>
+ askbot['urls']['api_get_questions'] = '{% url api_get_questions %}';
{% if settings.ENABLE_MATHJAX or settings.MARKUP_CODE_FRIENDLY %}
var codeFriendlyMarkdown = true;
{% else %}
var codeFriendlyMarkdown = false;
{% endif %}
- var tags = {{ tags|safe }};
$().ready(function(){
+ liveSearch().init('ask_page');
//set current module button style
$('#editor').TextAreaResizer();
@@ -41,21 +48,9 @@
$('#previewer').toggle();
$('#pre-collapse').text(txt);
});
- //Tags autocomplete action
- $("#id_tags").autocomplete(tags, {
- minChars: 1,
- matchContains: true,
- max: 20,
- multiple: true,
- multipleSeparator: " ",
- formatItem: function(row, i, max) {
- return row.n + " ("+ row.c +")";
- },
- formatResult: function(row, i, max){
- return row.n;
- }
+ //Tags autocomplete
- });
+ {{ macros.tag_autocomplete_js(id = '#id_tags') }}
setupFormValidation($("#fmask"), CPValidator.getQuestionFormRules(), CPValidator.getQuestionFormMessages());
lanai.highlightSyntax();
diff --git a/askbot/skins/default/templates/authopenid/changeemail.html b/askbot/skins/default/templates/authopenid/changeemail.html
index d2a34a10..52dc6a0c 100644
--- a/askbot/skins/default/templates/authopenid/changeemail.html
+++ b/askbot/skins/default/templates/authopenid/changeemail.html
@@ -3,13 +3,13 @@
{% block content %}
<!-- changeemail.html action_type={{action_type}}-->
{% if action_type=="change" %}
- <div id="main-bar" class="headNormal">
+ <h1>
{% if user.email %}
{% trans %}Change email{% endtrans %}
{% else %}
{% trans %}Save your email address{% endtrans %}
{% endif %}
- </div>
+ </h1>
<p class="message">
{% if user.email %}
{% trans %}change {{email}} info{% endtrans %}
diff --git a/askbot/skins/default/templates/authopenid/complete.html b/askbot/skins/default/templates/authopenid/complete.html
index 468f293b..ccaf753a 100644
--- a/askbot/skins/default/templates/authopenid/complete.html
+++ b/askbot/skins/default/templates/authopenid/complete.html
@@ -20,9 +20,7 @@ parameters:
{% block head %}{% endblock %}
{% block title %}{% spaceless %}{% trans %}Registration{% endtrans %}{% endspaceless %}{% endblock %}
{% block content %}
- <div id="main-bar" class="headNormal">
- {% trans %}Registration{% endtrans %}
- </div>
+ <h1>{% trans %}Registration{% endtrans %}</h1>
<div id="completetxt" >
<div class="message">
{% if login_type=='openid' %}
diff --git a/askbot/skins/default/templates/authopenid/macros.html b/askbot/skins/default/templates/authopenid/macros.html
new file mode 100644
index 00000000..534fb42f
--- /dev/null
+++ b/askbot/skins/default/templates/authopenid/macros.html
@@ -0,0 +1,55 @@
+{% macro login_provider_input(login_provider) %}
+ <input
+ name="{{login_provider.name}}"
+ type="image"
+ class="{{login_provider.type}}"
+ src="{{login_provider.icon_media_path|media}}"
+ alt="{{login_provider.tooltip_text}}"
+ title="{{login_provider.tooltip_text}}"
+ />
+{% endmacro %}
+
+{% macro provider_buttons(
+ login_form = None,
+ major_login_providers = None,
+ minor_login_providers = None,
+ hide_local_login = False,
+ settings = None
+ )
+%}
+ {{login_form.login_provider_name}}
+ {{ login_form.next }}
+ <div id="login-icons">
+ <ul class="login-icons large">
+ {% for login_provider in major_login_providers %}
+ {% if login_provider.name == 'local' and hide_local_login == True %}
+ {# do nothing here, left if statement this way for simplicity #}
+ {% elif settings['SIGNIN_' + login_provider.name.upper() + '_ENABLED'] == True %}
+ <li>
+ {{ login_provider_input(login_provider) }}
+ </li>
+ {% endif %}
+ {% endfor %}
+ </ul>
+ <ul class="login-icons small">
+ {% for login_provider in minor_login_providers %}
+ {% if settings['SIGNIN_' + login_provider.name.upper() + '_ENABLED'] == True %}
+ <li>
+ {{ login_provider_input(login_provider) }}
+ </li>
+ {% endif %}
+ {% endfor %}
+ </ul>
+ </div>
+ <fieldset
+ id="openid-fs"
+ {% if not login_form.openid_login_token.errors %}
+ style="display:none;"
+ {% endif %}
+ >
+ <h2 id="openid-heading">{% trans %}Please enter your <span>user name</span>, then sign in{% endtrans %}</h2>
+ <p class="hint">{% trans %}(or select another login method above){% endtrans %}</p>
+ <input type="text" name="openid_login_token" />
+ <input class="submit-b" type="submit" name="openid_login_with_extra_token" value="{% trans %}Sign in{% endtrans %}"/>
+ </fieldset>
+{% endmacro %}
diff --git a/askbot/skins/default/templates/authopenid/providers_javascript.html b/askbot/skins/default/templates/authopenid/providers_javascript.html
new file mode 100644
index 00000000..6ef86b29
--- /dev/null
+++ b/askbot/skins/default/templates/authopenid/providers_javascript.html
@@ -0,0 +1,63 @@
+<script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
+<script type="text/javascript" src="{{"/jquery-openid/jquery.openid.js"|media}}"></script>
+<script type="text/javascript">
+ var extra_token_name = {};
+ var create_pw_text = {};
+ var change_pw_text = {};
+ var authUrl = '/{% trans %}account/{% endtrans %}';
+ var siteName = '{{settings.APP_SHORT_NAME}}';
+ var provider_count = {{existing_login_methods|length}};
+ {% for login_provider in major_login_providers %}
+ {%if settings['SIGNIN_' + login_provider.name.upper() + '_ENABLED'] == True %}
+ {% if login_provider.extra_token_name %}
+ extra_token_name['{{login_provider.name}}'] = '{{login_provider.extra_token_name}}';
+ {% endif %}
+ {% if login_provider.type == 'password' %}
+ create_pw_text['{{login_provider.name}}'] = '{{login_provider.create_password_prompt}}';
+ change_pw_text['{{login_provider.name}}'] = '{{login_provider.change_password_prompt}}';
+ {% endif %}
+ {% endif %}
+ {% endfor %}
+ {% for login_provider in minor_login_providers %}
+ {% if settings['SIGNIN_' + login_provider.name.upper() + '_ENABLED'] == True %}
+ {% if login_provider.extra_token_name %}
+ extra_token_name['{{login_provider.name}}'] = '{{login_provider.extra_token_name}}';
+ {% endif %}
+ {% if login_provider.type == 'password' %}
+ create_pw_text['{{login_provider.name}}'] = '{{login_provider.create_password_prompt}}';
+ change_pw_text['{{login_provider.name}}'] = '{{login_provider.change_password_prompt}}';
+ {% endif %}
+ {% endif %}
+ {% endfor %}
+ {% if user.is_authenticated() %}
+ var userIsAuthenticated = true;
+ {% else %}
+ var userIsAuthenticated = false;
+ {% endif %}
+ $("body").authenticator();
+ {% if settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN %}
+ {% if settings.SIGNIN_LOCAL_ENABLED %}
+ $('input.password').remove();
+ {% endif %}
+ {%endif%}
+ askbot['settings']['signin_always_show_local_login'] = {% if settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN %}true{% else %}false{% endif %};
+</script>
+{% if settings.FACEBOOK_KEY and settings.FACEBOOK_SECRET %}
+<div id="fb-root"></div>
+<script src="http://connect.facebook.net/en_US/all.js"></script>
+<script>
+ $(document).ready(function(){
+ if (typeof FB != 'undefined'){
+ var ret = FB.init({appId: '{{settings.FACEBOOK_KEY}}', status: true, cookie: true, xfbml: true});
+ FB.Event.subscribe('auth.sessionChange', function(response){
+ if (response.session) {
+ // A user has logged in, and a new cookie has been saved
+ $('#signin-form').submit();
+ } else {
+ // The user has logged out, and the cookie has been cleared
+ }
+ });
+ };
+ });
+</script>
+{% endif %}
diff --git a/askbot/skins/default/templates/authopenid/signin.html b/askbot/skins/default/templates/authopenid/signin.html
index 686068b0..aa67c95f 100644
--- a/askbot/skins/default/templates/authopenid/signin.html
+++ b/askbot/skins/default/templates/authopenid/signin.html
@@ -1,4 +1,5 @@
{% extends "two_column_body.html" %}
+{% import "authopenid/macros.html" as login_macros %}
<!-- signin.html -->
{% block title %}{% spaceless %}{% trans %}User login{% endtrans %}{% endspaceless %}{% endblock %}
{% block forestyle %}
@@ -43,61 +44,35 @@
<p class="warning">{{ openid_error_message }}</p>
{% endif %}
{% if view_subtype != 'email_sent' and view_subtype != 'bad_key' %}
- {# in this branch we display the login icons #}
- <form id="signin-form" method="post" action="{% url user_signin %}">
- {{login_form.login_provider_name}}
- <div id="login-icons">
- <ul class="login-icons large">
- {% for login_provider in major_login_providers %}
- <li>
- <input
- name="{{login_provider.name}}"
- type="image"
- class="{{login_provider.type}}"
- src="{{login_provider.icon_media_path|media}}"
- alt="{{login_provider.tooltip_text}}"
- title="{{login_provider.tooltip_text}}"
- />
- </li>
- {% endfor %}
- </ul>
- <ul class="login-icons small">
- {% for login_provider in minor_login_providers %}
- <li>
- <input
- name="{{login_provider.name}}"
- type="image"
- class="{{login_provider.type}}"
- src="{{login_provider.icon_media_path|media}}"
- alt="{{login_provider.tooltip_text}}"
- title="{{login_provider.tooltip_text}}"
- />
- </li>
- {% endfor %}
- </ul>
- </div>
- {{ login_form.next }}
- <fieldset
- id="openid-fs"
- {% if not login_form.openid_login_token.errors %}
- style="display:none;"
- {% endif %}
- >
- <h2 id="openid-heading">{% trans %}Please enter your <span>user name</span>, then sign in{% endtrans %}</h2>
- <p class="hint">{% trans %}(or select another login method above){% endtrans %}</p>
- <input type="text" name="openid_login_token" />
- <input class="submit-b" type="submit" name="openid_login_with_extra_token" value="{% trans %}Sign in{% endtrans %}"/>
- </fieldset>
+ <form id="signin-form" method="post" action="{% url user_signin %}">
+ {# in this branch - the real signin view we display the login icons
+ here we hide the local login button only if admin
+ wants to always show the password login form - then
+ the button is useless.
+ #}
+ {{
+ login_macros.provider_buttons(
+ login_form = login_form,
+ major_login_providers = major_login_providers,
+ minor_login_providers = minor_login_providers,
+ hide_local_login = settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN,
+ settings = settings
+ )
+ }}
{% if use_password_login==True %}
<fieldset
id="password-fs"
{% if user.is_anonymous() %}
{% if not login_form.username.errors and not login_form.password_login_failed %}
- style="display:none;"
- {% endif %}
+ {% if not settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN %}
+ style="display:none;"
+ {%endif%}
+ {% endif %}
{% else %}
{% if not login_form.new_password.errors and not login_form.new_password_retyped.errors %}
- style="display:none;"
+ {% if not settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN %}
+ style="display:none;"
+ {% endif%}
{% endif %}
{% endif %}
>
@@ -121,7 +96,7 @@
<p id="local_login_buttons">
<input class="submit-b" name="login_with_password" type="submit" value="{% trans %}Login{% endtrans %}" />
{% if settings.USE_LDAP_FOR_PASSWORD_LOGIN == False %}
- <a class="create-password-account" style="vertical-align:middle" href="{% url user_signup_with_password %}">{% trans %}Create a password-protected account{% endtrans %}</a>
+ <a class="create-password-account" style="vertical-align:middle" href="{% url user_signup_with_password %}?login_provider=local">{% trans %}Create a password-protected account{% endtrans %}</a>
{% endif %}
</p>
{% elif settings.USE_LDAP_FOR_PASSWORD_LOGIN == False %}
@@ -144,7 +119,6 @@
{% endif %}
</fieldset>
{% endif %}
- </form>
{% if user.is_authenticated() and existing_login_methods %}
<div
id='existing-login-methods'
@@ -179,6 +153,7 @@
</table>
</div>
{% endif %}
+ </form>
{% endif %}
{% if view_subtype != 'email_sent' or view_subtype == 'bad_key' %}
{% if user.is_anonymous() %}
@@ -218,8 +193,8 @@
{% block sidebar %}
<div class="boxC">
- <h3 class="subtitle">{% trans %}Why use OpenID?{% endtrans %}</h3>
- <ul class="list-item">
+ <h2>{% trans %}Why use OpenID?{% endtrans %}</h2>
+ <ul>
<li>
{% trans %}with openid it is easier{% endtrans %}
</li>
@@ -239,59 +214,7 @@
</p>
</div>
{% endblock%}
-{% block endjs %}
- <script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
- <script type="text/javascript" src="{{"/jquery-openid/jquery.openid.js"|media}}"></script>
- <script type="text/javascript">
- var extra_token_name = {};
- var create_pw_text = {};
- var change_pw_text = {};
- var authUrl = '/{% trans %}account/{% endtrans %}';
- var siteName = '{{settings.APP_SHORT_NAME}}';
- var provider_count = {{existing_login_methods|length}};
- {% for login_provider in major_login_providers %}
- {% if login_provider.extra_token_name %}
- extra_token_name['{{login_provider.name}}'] = '{{login_provider.extra_token_name}}';
- {% endif %}
- {% if login_provider.type == 'password' %}
- create_pw_text['{{login_provider.name}}'] = '{{login_provider.create_password_prompt}}';
- change_pw_text['{{login_provider.name}}'] = '{{login_provider.change_password_prompt}}';
- {% endif %}
- {% endfor %}
- {% for login_provider in minor_login_providers %}
- {% if login_provider.extra_token_name %}
- extra_token_name['{{login_provider.name}}'] = '{{login_provider.extra_token_name}}';
- {% endif %}
- {% if login_provider.type == 'password' %}
- create_pw_text['{{login_provider.name}}'] = '{{login_provider.create_password_prompt}}';
- change_pw_text['{{login_provider.name}}'] = '{{login_provider.change_password_prompt}}';
- {% endif %}
- {% endfor %}
- {% if user.is_authenticated() %}
- var userIsAuthenticated = true;
- {% else %}
- var userIsAuthenticated = false;
- {% endif %}
- $("body").authenticator();
- </script>
- {% if settings.FACEBOOK_KEY and settings.FACEBOOK_SECRET %}
- <div id="fb-root"></div>
- <script src="http://connect.facebook.net/en_US/all.js"></script>
- <script>
- $(document).ready(function(){
- if (typeof FB != 'undefined'){
- var ret = FB.init({appId: '{{settings.FACEBOOK_KEY}}', status: true, cookie: true, xfbml: true});
- FB.Event.subscribe('auth.sessionChange', function(response){
- if (response.session) {
- // A user has logged in, and a new cookie has been saved
- $('#signin-form').submit();
- } else {
- // The user has logged out, and the cookie has been cleared
- }
- });
- };
- });
- </script>
- {% endif %}
-{% endblock %}
+{%block endjs%}
+{%include "authopenid/providers_javascript.html" %}
+{%endblock%}
<!-- end signin.html -->
diff --git a/askbot/skins/default/templates/authopenid/signup_with_password.html b/askbot/skins/default/templates/authopenid/signup_with_password.html
index 84b9a792..d85f8671 100644
--- a/askbot/skins/default/templates/authopenid/signup_with_password.html
+++ b/askbot/skins/default/templates/authopenid/signup_with_password.html
@@ -1,11 +1,30 @@
{% extends "one_column_body.html" %}
+{% import "authopenid/macros.html" as login_macros %}
<!--signup.html-->
{% block title %}{% spaceless %}{% trans %}Signup{% endtrans %}{% endspaceless %}{% endblock %}
+{% block forestyle %}
+ <link rel="stylesheet" type="text/css" media="screen" href="{{"/jquery-openid/openid.css"|media}}"/>
+{% endblock %}
{% block content %}
-<div class="headNormal">
- {% trans %}Create login name and password{% endtrans %}
-</div>
-<p class="message">{% trans %}Traditional signup info{% endtrans %}</p>
+{% if settings.PASSWORD_REGISTER_SHOW_PROVIDER_BUTTONS == True %}
+ <h1>{% trans %}Please register by clicking on any of the icons below{% endtrans %}</h1>
+ <form id="signin-form" method="post" action="{% url user_signin %}">
+ {# hide_local_login == True because it is password reg form #}
+ {{
+ login_macros.provider_buttons(
+ login_form = login_form,
+ major_login_providers = major_login_providers,
+ minor_login_providers = minor_login_providers,
+ hide_local_login = True,
+ settings = settings
+ )
+ }}
+ </form>
+ <h2>{% trans %}or create a new user name and password here{% endtrans %}</h2>
+{% else %}
+ <h1>{% trans %}Create login name and password{% endtrans %}</h1>
+ <p class="message">{% trans %}Traditional signup info{% endtrans %}</p>
+{%endif%}
<form action="{% url user_signup_with_password %}" method="post" accept-charset="utf-8">
{{form.login_provider}}
<ul class="form-horizontal-rows">
@@ -14,18 +33,26 @@
<li><label for="password1_id">{{form.password1.label}}</label>{{form.password1}}{{form.password1.errors}}</li>
<li><label for="password2_id">{{form.password2.label}}</label>{{form.password2}}{{form.password2.errors}}</li>
</ul>
- <p class="margin-top">{% trans %}receive updates motivational blurb{% endtrans %}</p>
+ <p style="margin-top: 10px">{% trans %}receive updates motivational blurb{% endtrans %}</p>
<div class='simple-subscribe-options'>
{{email_feeds_form.subscribe}}
{% if email_feeds_form.errors %}
<p class="error">{% trans %}please select one of the options above{% endtrans %}</p>
{% endif %}
</div>
- <p class="signup_p">{% trans %}Please read and type in the two words below to help us prevent automated account creation.{% endtrans %}</p>
- {{form.recaptcha}}
+ {% if settings.USE_RECAPTCHA %}
+ <p class="signup_p">{% trans %}Please read and type in the two words below to help us prevent automated account creation.{% endtrans %}</p>
+ {{form.recaptcha}}
+ {% endif %}
<div class="submit-row"><input type="submit" class="submit" value="{% trans %}Create Account{% endtrans %}" />
- <strong>{% trans %}or{% endtrans %}
- <a href="{% url user_signin %}">{% trans %}return to OpenID login{% endtrans %}</a></strong></div>
+ {% if settings.PASSWORD_REGISTER_SHOW_PROVIDER_BUTTONS == False %}
+ <strong>{% trans %}or{% endtrans %}
+ <a href="{% url user_signin %}">{% trans %}return to OpenID login{% endtrans %}</a></strong>
+ {% endif %}
+ </div>
</form>
{% endblock %}
+{%block endjs%}
+{%include "authopenid/providers_javascript.html" %}
+{%endblock%}
<!--end signup.html-->
diff --git a/askbot/skins/default/templates/avatar/add.html b/askbot/skins/default/templates/avatar/add.html
new file mode 100644
index 00000000..df700d0c
--- /dev/null
+++ b/askbot/skins/default/templates/avatar/add.html
@@ -0,0 +1,15 @@
+{% extends "user_profile/user.html" %}
+{% import "macros.html" as macros %}
+{% block profilesection %}{% trans %}add avatar{% endtrans %}{% endblock %}
+{% block usercontent %}
+ <h2>{% trans %}Change avatar{% endtrans %}
+ <p>{% trans %}Your current avatar: {% endtrans %}</p>
+ {{ macros.gravatar(user, 128) }}
+ {% if not avatars %}
+ <p>{% trans %}You haven't uploaded an avatar yet. Please upload one now.{% endtrans %}</p>
+ {% endif %}
+ <form enctype="multipart/form-data" method="POST" action="{% url avatar_add %}">
+ {{ upload_avatar_form.as_p() }}
+ <p><input type="submit" value="{% trans %}Upload New Image{% endtrans %}" /></p>
+ </form>
+{% endblock %}
diff --git a/askbot/skins/default/templates/avatar/change.html b/askbot/skins/default/templates/avatar/change.html
new file mode 100644
index 00000000..7a88ddef
--- /dev/null
+++ b/askbot/skins/default/templates/avatar/change.html
@@ -0,0 +1,24 @@
+{% extends "user_profile/user.html" %}
+{% import "macros.html" as macros %}
+{% block profilesection %}
+ {% trans %}change avatar{% endtrans %}
+{% endblock %}
+{% block usercontent %}
+ <p>{% trans %}Your current avatar: {% endtrans %}<br/>
+ {{ macros.gravatar(user, 128) }}
+ </p>
+ {% if not avatars %}
+ <p>{% trans %}You haven't uploaded an avatar yet. Please upload one now.{% endtrans %}</p>
+ {% else %}
+ <form method="POST" action="{% url avatar_change %}">
+ <ul>
+ {{ primary_avatar_form.as_ul() }}
+ </ul>
+ <p><input type="submit" value="{% trans %}Choose new Default{% endtrans %}" /></p>
+ </form>
+ {% endif %}
+ <form enctype="multipart/form-data" method="POST" action="{% url avatar_add %}">
+ {{ upload_avatar_form.as_p() }}
+ <p><input type="submit" value="{% trans %}Upload{% endtrans %}" /></p>
+ </form>
+{% endblock %}
diff --git a/askbot/skins/default/templates/avatar/confirm_delete.html b/askbot/skins/default/templates/avatar/confirm_delete.html
new file mode 100644
index 00000000..042d7c0d
--- /dev/null
+++ b/askbot/skins/default/templates/avatar/confirm_delete.html
@@ -0,0 +1,16 @@
+{% extends "user_profile/user.html" %}
+{% import "macros.html" as macros %}
+{% block profilesection %}{% trans %}delete avatar{% endtrans %}{% endblock %}
+{% block usercontent %}
+ <p>{% trans %}Please select the avatars that you would like to delete.{% endtrans %}</p>
+ {% if not avatars %}
+ <p>{% trans avatar_change_url="avatar_change"|url %}You have no avatars to delete. Please <a href="{{ avatar_change_url }}">upload one</a> now.{% endtrans %}</p>
+ {% else %}
+ <form method="POST" action="{% url avatar_delete %}">
+ <ul>
+ {{ delete_avatar_form.as_ul() }}
+ </ul>
+ <p><input type="submit" value="{% trans %}Delete These{% endtrans %}" /></p>
+ </form>
+ {% endif %}
+{% endblock %}
diff --git a/askbot/skins/default/templates/badge.html b/askbot/skins/default/templates/badge.html
index ef5d3a89..ee7f5360 100644
--- a/askbot/skins/default/templates/badge.html
+++ b/askbot/skins/default/templates/badge.html
@@ -3,10 +3,7 @@
<!-- template badge.html -->
{% block title %}{% spaceless %}{% trans name=badge.name %}{{name}}{% endtrans %} - {% trans %}Badge{% endtrans %}{% endspaceless %}{% endblock %}
{% block content %}
-<div id="main-bar" class="headNormal">
-{% trans %}Badge{% endtrans %}
-</div>
-<div id="main-body" style="width:100%;margin-bottom:20px">
+<h1>{% trans name=badge.name %}Badge "{{name}}"{% endtrans %}</h1>
<p>
<a href="{{badge.get_absolute_url()}}" title="{{ badge.get_type_display() }} : {% trans description=badge.description %}{{description}}{% endtrans %}" class="medal"><span class="{{ badge.css_class }}">&#9679;</span>&nbsp;{% trans name=badge.name%}{{name}}{% endtrans %}</a> {% trans description=badge.description %}{{description}}{% endtrans %}
</p>
@@ -23,7 +20,5 @@
</p>
{% endfor %}
</div>
-
-</div>
{% endblock %}
<!-- end template badge.html -->
diff --git a/askbot/skins/default/templates/badges.html b/askbot/skins/default/templates/badges.html
index a56f62d0..bbd09951 100644
--- a/askbot/skins/default/templates/badges.html
+++ b/askbot/skins/default/templates/badges.html
@@ -2,42 +2,37 @@
<!-- template badges.html -->
{% block title %}{% spaceless %}{% trans %}Badges summary{% endtrans %}{% endspaceless %}{% endblock %}
{% block content %}
-<div class="headlineA">
- <span class="headMedals">{% trans %}Badges{% endtrans %}</span>
-</div>
-<div class="badges" id="main-body">
- <p>
- {% trans %}Community gives you awards for your questions, answers and votes.{% endtrans %}<br/>
+<h1>{% trans %}Badges{% endtrans %}</h1>
+<p>
+{% trans %}Community gives you awards for your questions, answers and votes.{% endtrans %}<br/>
{% trans %}Below is the list of available badges and number
- of times each type of badge has been awarded. Give us feedback at {{feedback_faq_url}}.
- {% endtrans %}
- </p>
- <div id="medalList">
- {% for badge in badges %}
- <div style="clear:both;line-height:30px">
- <div style="float:left;min-width:30px;text-align:right;height:30px">
- {% for a in mybadges %}
- {% if a.badge_id == badge.id %}
- <span style="font-size:175%; padding-right:5px; color:#5B9058;">&#10004;</span>
- {% endif %}
- {% endfor %}
- </div>
- <div style="float:left;width:230px;">
- <a href="{{badge.get_absolute_url()}}"
- title="{{badge.get_type_display()}} : {{badge.description}}"
- class="medal"><span class="{{ badge.css_class }}">&#9679;</span>&nbsp;{{badge.name}}</a><strong>
- &#215; {{ badge.awarded_count|intcomma }}</strong>
- </div>
- <p style="float:left;margin-top:8px;">{{badge.description}}</p>
- </div>
+of times each type of badge has been awarded. Give us feedback at {{feedback_faq_url}}.
+{% endtrans %}
+</p>
+<div id="medalList">
+ {% for badge in badges %}
+ <div style="clear:both;line-height:30px">
+ <div style="float:left;min-width:30px;text-align:right;height:30px">
+ {% for a in mybadges %}
+ {% if a.badge_id == badge.id %}
+ <span style="font-size:175%; padding-right:5px; color:#5B9058;">&#10004;</span>
+ {% endif %}
{% endfor %}
+ </div>
+ <div style="float:left;width:230px;">
+ <a href="{{badge.get_absolute_url()}}"
+ title="{{badge.get_type_display()}} : {{badge.description}}"
+ class="medal"><span class="{{ badge.css_class }}">&#9679;</span>&nbsp;{{badge.name}}</a><strong>
+ &#215; {{ badge.awarded_count|intcomma }}</strong>
+ </div>
+ <p style="float:left;margin-top:8px;">{{badge.description}}</p>
</div>
+ {% endfor %}
</div>
{% endblock %}
{% block sidebar %}
<div class="boxC">
- <h3>{% trans %}Community badges{% endtrans %}</h3>
- <div class="body">
+ <h2>{% trans %}Community badges{% endtrans %}</h2>
<p>
<a style="cursor:default;" title="{% trans %}gold badge: the highest honor and is very rare{% endtrans %}" class="medal"><span class="badge1">&#9679;</span>&nbsp;{% trans %}gold{% endtrans %}</a>
</p>
@@ -60,7 +55,6 @@
<p>
{% trans %}bronze badge description{% endtrans %}
</p>
- </div>
</div>
{% endblock %}
<!-- end template badges.html -->
diff --git a/askbot/skins/default/templates/base.html b/askbot/skins/default/templates/base.html
index 1af581b3..b4056e4d 100644
--- a/askbot/skins/default/templates/base.html
+++ b/askbot/skins/default/templates/base.html
@@ -4,7 +4,6 @@
{% spaceless %}
<head>
<title>{% block title %}{% endblock %} - {{ settings.APP_TITLE|escape }}</title>
- {#% include "blocks/head.html" %#}
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
{% block meta_description %}
<meta name="description" content="{{settings.APP_DESCRIPTION|escape}}" />
@@ -15,6 +14,7 @@
{% endif %}
<link rel="shortcut icon" href="{{ "/images/favicon.gif"|media }}" />
<link href="{{"/style/style.css"|media }}" rel="stylesheet" type="text/css" />
+ {{ skin.get_extra_css_link() }}
{% if settings.USE_CUSTOM_CSS %}
<link
href="{% url "custom_css" %}?v={{settings.MEDIA_RESOURCE_REVISION}}"
@@ -43,24 +43,20 @@
{# avoid adding javascript here so that pages load faster #}
</head>
{% endspaceless %}
- <body{% if page_class %} class="{{page_class}}"{% endif %}>
- {#% include "blocks/forum_body.html" %#}
- <div class="notify" style="display:none">
- {% if user_messages %}
- {% for message in user_messages %}
- <p class="darkred">{{ message }}</p>
- {% endfor %}
- {% endif %}
- <a id="close-notify" onclick="notify.close(true)">&times;</a>
+ <body class="{% block body_class %}{% endblock %}{% if page_class %} {{page_class}}{% endif %}">
+ {% include "blocks/system_messages.html" %}
+ {% include "custom_header.html" ignore missing %}
+ {% include "blocks/header.html" %}
+ <div class="content-wrapper">
+ {% block body %}
+ {% endblock %}
</div>
- {% include "header.html" %}
- {% block body %}
- {% endblock %}
{% if settings.FOOTER_MODE == 'default' %}
- {% include "footer.html" %}
+ {% include "blocks/footer.html" %}
{% elif settings.FOOTER_MODE == 'customize' %}
{{ settings.CUSTOM_FOOTER }}
{% endif %}
+ {% include "custom_footer.html" ignore missing %}
{% include "blocks/bottom_scripts.html" %}
{% block endjs %}
{% endblock %}
diff --git a/askbot/skins/default/templates/answer_edit_tips.html b/askbot/skins/default/templates/blocks/answer_edit_tips.html
index 5e9f689a..23e4df53 100644
--- a/askbot/skins/default/templates/answer_edit_tips.html
+++ b/askbot/skins/default/templates/blocks/answer_edit_tips.html
@@ -1,8 +1,8 @@
<!-- template answer_edit_tips.html -->
<div class="boxC">
- <h3>{% trans %}answer tips{% endtrans %}</h3>
+ <h2>{% trans %}answer tips{% endtrans %}</h2>
<div>
- <ul class="list-item">
+ <ul>
<li> <b>{% trans %}please make your answer relevant to this community{% endtrans %}</b>
</li>
<li>
@@ -22,8 +22,8 @@
</div>
<div class="boxC">
- <h3>{% trans %}Markdown tips{% endtrans %}</h3>
- <ul class="list-item">
+ <h2>{% trans %}Markdown tips{% endtrans %}</h2>
+ <ul>
{% if settings.MARKUP_CODE_FRIENDLY or settings.ENABLE_MATHJAX %}
<li>
{% trans %}*italic*{% endtrans %}
diff --git a/askbot/skins/default/templates/ask_form.html b/askbot/skins/default/templates/blocks/ask_form.html
index ff7fea0d..8df6c019 100644
--- a/askbot/skins/default/templates/ask_form.html
+++ b/askbot/skins/default/templates/blocks/ask_form.html
@@ -14,7 +14,7 @@
{% endif %}
{% endif %}
{% endif %}
- <input id="id_title" class="questionTitleInput" name="title"
+ <input id="id_title" class="questionTitleInput" name="title" autocomplete="off"
value="{% if form.initial.title %}{{form.initial.title}}{% endif %}"/>
<span class="form-error">{{ form.title.errors }}</span>
</div>
@@ -22,11 +22,20 @@
{{ form.title.help_text }}
</div>
</div>
- {{macros.edit_post(form, settings.WIKI_ON, post_type='question', edit_title=False)}}
+ <div id='question-list'></div>
+ {{macros.edit_post(form, post_type='question', edit_title=False)}}
{% if not request.user.is_authenticated() %}
<input type="submit" name="post_anon" value="{% trans %}Login/signup to post your question{% endtrans %}" class="submit" />
{% else %}
<input type="submit" name="post" value="{% trans %}Ask your question{% endtrans %}" class="submit" />
{% endif %}
+ <div class="question-options">
+ {% if settings.WIKI_ON %}
+ {{ macros.checkbox_in_div(form.wiki) }}
+ {% endif %}
+ {% if settings.ALLOW_ASK_ANONYMOUSLY %}
+ {{ macros.checkbox_in_div(form.ask_anonymously) }}
+ {% endif %}
+ </div>
</form>
</div>
diff --git a/askbot/skins/default/templates/blocks/bottom_scripts.html b/askbot/skins/default/templates/blocks/bottom_scripts.html
index 929bf9c1..3ba2d959 100644
--- a/askbot/skins/default/templates/blocks/bottom_scripts.html
+++ b/askbot/skins/default/templates/blocks/bottom_scripts.html
@@ -18,6 +18,8 @@
askbot['data']['userIsAuthenticated'] = false;
{% endif %}
askbot['urls']['mark_read_message'] = '{% url "read_message" %}';
+ askbot['urls']['get_tags_by_wildcard'] = '{% url "get_tags_by_wildcard" %}';
+ askbot['urls']['get_tag_list'] = '{% url "get_tag_list" %}';
</script>
<script
type="text/javascript"
@@ -29,6 +31,7 @@
></script>
<script type='text/javascript' src="{{"/js/i18n.js"|media }}"></script>
<script type='text/javascript' src="{{"/js/jquery.i18n.js"|media }}"></script>
+<script type='text/javascript' src="{% url "askbot_jsi18n" %}"></script>
<script type='text/javascript' src="{{"/js/utils.js"|media }}"></script>
{% if settings.ENABLE_MATHJAX %}
<script type='text/javascript' src="{{settings.MATHJAX_BASE_URL}}/MathJax.js">
diff --git a/askbot/skins/default/templates/editor_data.html b/askbot/skins/default/templates/blocks/editor_data.html
index 79ed96fb..79ed96fb 100644
--- a/askbot/skins/default/templates/editor_data.html
+++ b/askbot/skins/default/templates/blocks/editor_data.html
diff --git a/askbot/skins/default/templates/footer.html b/askbot/skins/default/templates/blocks/footer.html
index 03f27460..582e6d33 100644
--- a/askbot/skins/default/templates/footer.html
+++ b/askbot/skins/default/templates/blocks/footer.html
@@ -19,7 +19,7 @@
</div>
<p>
<a href="http://askbot.org" target="_blank">
- powered by ASKBOT
+ powered by ASKBOT version {{settings.ASKBOT_VERSION}}
</a><br/>{{settings.APP_COPYRIGHT}}
</p>
</div>
diff --git a/askbot/skins/default/templates/blocks/head.html b/askbot/skins/default/templates/blocks/head.html
deleted file mode 100644
index 1e3060f3..00000000
--- a/askbot/skins/default/templates/blocks/head.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-{% block meta_description %}
-<meta name="description" content="{{settings.APP_DESCRIPTION|escape}}" />
-{% endblock %}
-<meta name="keywords" content="{%block keywords%}{%endblock%},{{settings.APP_KEYWORDS|escape}}" />
-{% if settings.GOOGLE_SITEMAP_CODE %}
-<meta name="google-site-verification" content="{{settings.GOOGLE_SITEMAP_CODE}}" />
-{% endif %}
-<link rel="shortcut icon" href="{{ "/images/favicon.gif"|media }}" />
-<link href="{{"/style/style.css"|media }}" rel="stylesheet" type="text/css" />
-{% block forestyle %}{% endblock %}
-{% if user_messages %}
-<style type="text/css">
- body { margin-top:2.4em; }
-</style>
-{% endif %}
-<script type="text/javascript">
- var askbot = {};
- askbot['data'] = {};
- askbot['urls'] = {};
- askbot['settings'] = {};
- askbot['messages'] = {};
-</script>
-{% block forejs %}
-{% endblock %}
diff --git a/askbot/skins/default/templates/header.html b/askbot/skins/default/templates/blocks/header.html
index 917e3a4f..981168ea 100644
--- a/askbot/skins/default/templates/header.html
+++ b/askbot/skins/default/templates/blocks/header.html
@@ -1,24 +1,15 @@
<!-- template header.html -->
{% import "macros.html" as macros %}
-<div id="roof">
- <div id="navBar">
- <div id="top">
- {% include "blocks/header_meta_links.html" %}
- </div>
- <table border="0" cellspacing="0" cellpadding="0">
- <tr>
- {% if settings.SHOW_LOGO %}
- <td id="logoContainer">
- <div id="logo">
- <a href="{% url questions %}?start_over=true"><img
- src="{{ settings.SITE_LOGO_URL|media }}"
- title="{% trans %}back to home page{% endtrans %}"
- alt="{% trans site=settings.APP_SHORT_NAME %}{{site}} logo{% endtrans %}"/></a>
- </div>
- </td>
- {% endif %}
- <td id="navTabContainer" valign="bottom" align="left">
- <div class="nav">
+<div id="ab-header">
+ <div class="content-wrapper">
+ {% if settings.SHOW_LOGO %}
+ <a id="ab-logo" href="{% url questions %}?start_over=true"><img
+ src="{{ settings.SITE_LOGO_URL|media }}"
+ title="{% trans %}back to home page{% endtrans %}"
+ alt="{% trans site=settings.APP_SHORT_NAME %}{{site}} logo{% endtrans %}"/></a>
+ {% endif %}
+ <div id="ab-meta-nav">{% include "blocks/header_meta_links.html" %}</div>
+ <div id="ab-main-nav">
<a
id="nav_questions"
href="{% url questions %}"
@@ -45,9 +36,6 @@
class="{% if active_tab == 'ask' %}on{% else %}special{% endif %}"
>{% trans %}ask a question{% endtrans %}</a>
</div>
- </td>
- </tr>
- </table>
</div>
</div>
<!-- end template header.html -->
diff --git a/askbot/skins/default/templates/blocks/header_meta_links.html b/askbot/skins/default/templates/blocks/header_meta_links.html
index ecdcde6a..bbc87c0f 100644
--- a/askbot/skins/default/templates/blocks/header_meta_links.html
+++ b/askbot/skins/default/templates/blocks/header_meta_links.html
@@ -1,55 +1,16 @@
{% if request.user.is_authenticated() %}
<a href="{{ request.user.get_absolute_url() }}">{{ request.user.username }}</a>
- {% spaceless %}
- {% if request.user.new_response_count > 0 or request.user.seen_response_count > 0 %}
- <a class='ab-responses-envelope' href="{{request.user.get_absolute_url()}}?sort=inbox&section=forum">
- <img
- alt="{% trans username=request.user.username %}responses for {{username}}{% endtrans %}"
- {% if request.user.new_response_count > 0 %}
- src="{{ "/images/mail-envelope-full.png"|media }}"
- title="{% trans response_count=request.user.new_response_count %}you have a new response{% pluralize %}you nave {{response_count}} new responses{% endtrans %}"
- {% elif request.user.seen_response_count > 0 %}
- src="{{ "/images/mail-envelope-empty.png"|media }}"
- title="{% trans %}no new responses yet{% endtrans %}"
- {% endif %}
- />
- </a>
- {% endif %}
- {% if moderation_items %}
- <a class="ab-responses-envelope"
- href="{{request.user.get_absolute_url()}}?sort=inbox&section=flags"
- >
- {% if moderation_items['new_count'] > 0 %}
- <img src="{{'/images/dialog-warning.png'|media}}"
- {% if moderation_items['seen_count'] > 0 %}
- alt="{% trans new=moderation_items['new_count'], seen=moderation_items['seen_count']%}{{new}} new flagged posts and {{seen}} previous{% endtrans %}"
- title="{% trans new=moderation_items['new_count'], seen=moderation_items['seen_count']%}{{new}} new flagged posts and {{seen}} previous{% endtrans %}"
- {% else %}
- alt="{% trans new=moderation_items['new_count'] %}{{new}} new flagged posts{% endtrans %}"
- title="{% trans new=moderation_items['new_count'] %}{{new}} new flagged posts{% endtrans %}"
- {% endif %}
- />
- {% elif moderation_items['seen_count'] > 0 %}
- <img src={{'/images/dialog-warning-off.png'|media}}
- alt="{% trans seen=moderation_items['seen_count'] %}{{seen}} flagged posts{% endtrans %}"
- title="{% trans seen=moderation_items['seen_count'] %}{{seen}} flagged posts{% endtrans %}"
- />
- {% endif %}
- </a>
- {% endif %}
- {#
- {% endif %}
- {% else if moderation_items['seen_count'] > 0 %}
- {% endif %}
- {% endif %#}
- {% endspaceless %}
+ <span class="user-info">
+ {{ macros.inbox_link(request.user) }}
+ {{ macros.moderation_items_link(request.user, moderation_items) }}
({{ macros.user_long_score_and_badge_summary(user) }})
- <a href="{% url logout %}">{% trans %}logout{% endtrans %}</a>
+ </span>
+ <a href="{% url user_signout %}?next={% url logout %}">{% trans %}logout{% endtrans %}</a>
{% else %}
<a href="{% url user_signin %}">{% trans %}login{% endtrans %}</a>
{% endif %}
-<a href="{% url about %}">{% trans %}about{% endtrans %}</a>
-<a href="{% url faq %}">{% trans %}faq{% endtrans %}</a>
-{% if request.user.is_administrator %}
-<a href="{% url site_settings %}">{% trans %}settings{% endtrans %}</a>
+ <a href="{% url about %}">{% trans %}about{% endtrans %}</a>
+ <a href="{% url faq %}">{% trans %}faq{% endtrans %}</a>
+{% if request.user.is_authenticated() and request.user.is_administrator() %}
+ <a href="{% url site_settings %}">{% trans %}settings{% endtrans %}</a>
{% endif %}
diff --git a/askbot/skins/default/templates/input_bar.html b/askbot/skins/default/templates/blocks/input_bar.html
index c3453955..bed97eb4 100644
--- a/askbot/skins/default/templates/input_bar.html
+++ b/askbot/skins/default/templates/blocks/input_bar.html
@@ -3,8 +3,10 @@
<div id="searchBar">
{# url action depends on which tab is active #}
<form
- {% if active_tab == "tags" or active_tab == "users" %}
- action="{% url search %}"
+ {% if active_tab == "tags" %}
+ action="{% url tags %}"
+ {% elif active_tab == "users" %}
+ action="{% url users %}"
{% else %}
action="{% url questions %}"
{% endif %}
@@ -41,5 +43,5 @@
</div>
{% endspaceless %}
{% else %}
- {% include "ask_form.html" %}
+ {% include "blocks/ask_form.html" %}
{% endif %}
diff --git a/askbot/skins/default/templates/paginator.html b/askbot/skins/default/templates/blocks/paginator.html
index 9782407f..9782407f 100644
--- a/askbot/skins/default/templates/paginator.html
+++ b/askbot/skins/default/templates/blocks/paginator.html
diff --git a/askbot/skins/default/templates/question_edit_tips.html b/askbot/skins/default/templates/blocks/question_edit_tips.html
index 2c239115..83c36840 100644
--- a/askbot/skins/default/templates/question_edit_tips.html
+++ b/askbot/skins/default/templates/blocks/question_edit_tips.html
@@ -1,26 +1,24 @@
<!-- question_edit_tips.html -->
<div class="boxC">
- <h3>{% trans %}question tips{% endtrans %}</h3>
- <div>
- <ul class="list-item">
- <li> <b>{% trans %}please ask a relevant question{% endtrans %}</b>
- </li>
- <li>
- {% trans %}please try provide enough details{% endtrans %}
- </li>
- <li>
- {% trans %}be clear and concise{% endtrans %}
- </li>
- </ul>
- <p class='info-box-follow-up-links'>
- <a href="{% url faq %}" target="_blank" title="{% trans %}see frequently asked questions{% endtrans %}">{% trans %}faq{% endtrans %} »</a>
- </p>
- </div>
+ <h2>{% trans %}question tips{% endtrans %}</h2>
+ <ul>
+ <li> <b>{% trans %}please ask a relevant question{% endtrans %}</b>
+ </li>
+ <li>
+ {% trans %}please try provide enough details{% endtrans %}
+ </li>
+ <li>
+ {% trans %}be clear and concise{% endtrans %}
+ </li>
+ </ul>
+ <p class='info-box-follow-up-links'>
+ <a href="{% url faq %}" target="_blank" title="{% trans %}see frequently asked questions{% endtrans %}">{% trans %}faq{% endtrans %} »</a>
+ </p>
</div>
<div class="boxC">
- <h3>{% trans %}Markdown tips{% endtrans %}</h3>
- <ul class="list-item">
+ <h2>{% trans %}Markdown tips{% endtrans %}</h2>
+ <ul>
{% if settings.MARKDUP_CODE_FRIENDLY or settings.ENABLE_MATHJAX %}
<li>
{% trans %}*italic*{% endtrans %}
diff --git a/askbot/skins/default/templates/blocks/system_messages.html b/askbot/skins/default/templates/blocks/system_messages.html
new file mode 100644
index 00000000..18ba03d7
--- /dev/null
+++ b/askbot/skins/default/templates/blocks/system_messages.html
@@ -0,0 +1,8 @@
+<div class="notify" style="display:none">
+ {% if user_messages %}
+ {% for message in user_messages %}
+ <p class="darkred">{{ message }}</p>
+ {% endfor %}
+ {% endif %}
+ <a id="close-notify" onclick="notify.close(true)">&times;</a>
+</div>
diff --git a/askbot/skins/default/templates/blocks/tag_selector.html b/askbot/skins/default/templates/blocks/tag_selector.html
new file mode 100644
index 00000000..c3626be9
--- /dev/null
+++ b/askbot/skins/default/templates/blocks/tag_selector.html
@@ -0,0 +1,46 @@
+{# todo - maybe disable navigation from ignored tags here when "hide" is on - with js? #}
+{% import "macros.html" as macros %}
+<div id="tagSelector" class="boxC">
+ <h2>{% trans %}Interesting tags{% endtrans %}</h2>
+ {{
+ macros.tag_list_widget(
+ interesting_tag_names,
+ deletable = True,
+ css_class = 'interesting marked-tags'
+ )
+ }}
+ {# todo - add this via js
+ "remove '%(tag_name)s' from the list of interesting tags"|
+ format(tag_name = tag_name)
+ #}
+ <div class="inputs">
+ <input id="interestingTagInput" autocomplete="off" type="text"/>&nbsp;
+ <input id="interestingTagAdd" type="submit" value="{% trans %}Add{% endtrans %}"/>
+ </div>
+ <h2>{% trans %}Ignored tags{% endtrans %}</h2>
+ {{
+ macros.tag_list_widget(
+ ignored_tag_names,
+ deletable = True,
+ css_class = 'ignored marked-tags'
+ )
+ }}
+ {# todo: add this via javascript
+ "remove '%(tag_name)s' from the list of ignored tags"|
+ format(tag_name = tag_name)
+ #}
+ <div class="inputs">
+ <input id="ignoredTagInput" autocomplete="off" type="text"/>&nbsp;
+ <input id="ignoredTagAdd" type="submit" value="{% trans %}Add{% endtrans%}"/>
+ </div>
+ <h3>{% trans %}Display tag filter{% endtrans%}</h3>
+ <div id="displayTagFilterControl">
+ {{
+ macros.radio_select(
+ name = "display_tag_filter_strategy",
+ value = request.user.display_tag_filter_strategy,
+ choices = tag_filter_strategy_choices
+ )
+ }}
+ </div>
+</div>
diff --git a/askbot/skins/default/templates/close.html b/askbot/skins/default/templates/close.html
index 0cfd5b06..57ff5780 100644
--- a/askbot/skins/default/templates/close.html
+++ b/askbot/skins/default/templates/close.html
@@ -2,10 +2,7 @@
<!-- template close.html -->
{% block title %}{% spaceless %}{% trans %}Close question{% endtrans %}{% endspaceless %}{% endblock %}
{% block content %}
-<div id="main-bar" class="headNormal">
- {% trans %}Close question{% endtrans %}
-</div>
-<div id="main-body" style="width:100%;margin-bottom:10px">
+<h1>{% trans %}Close question{% endtrans %}</h1>
<p>{% trans %}Close the question{% endtrans %}: <a href="{{ question.get_absolute_url() }}">
<strong>{{ question.get_question_title() }}</strong></a>
</p>
@@ -14,12 +11,11 @@
<strong>{% trans %}Reasons{% endtrans %}:</strong>
{{ form.reason }}
</p>
- <div id="" style="padding-top:20px">
- <input type="submit" value="{% trans %}OK to close{% endtrans %}" class="submit" />&nbsp;
- <input id="btBack" type="button" class="submit" value="{% trans %}Cancel{% endtrans %}" />
- </div>
+ <p>
+ <input type="submit" value="{% trans %}OK to close{% endtrans %}" class="submit" />&nbsp;
+ <input id="btBack" type="button" class="submit" value="{% trans %}Cancel{% endtrans %}" />
+ </p>
</form>
-</div>
{% endblock %}
{% block endjs %}
<script type="text/javascript">
diff --git a/askbot/skins/default/templates/faq.html b/askbot/skins/default/templates/faq.html
index b23df74c..74d5b0ef 100644
--- a/askbot/skins/default/templates/faq.html
+++ b/askbot/skins/default/templates/faq.html
@@ -2,117 +2,84 @@
<!-- template faq.html -->
{% block title %}{% spaceless %}{% trans %}FAQ{% endtrans %}{% endspaceless %}{% endblock %}
{% block content %}
-<div class="headNormal">
- {% trans %}Frequently Asked Questions {% endtrans %}({% trans %}FAQ{% endtrans %})
-</div>
-<div id="main-body" class="about" style="width:100%">
-
- <div class="first">
- <h3 class="subtitle">{% trans %}What kinds of questions can I ask here?{% endtrans %}</h3>
- <p>{% trans %}Most importanly - questions should be <strong>relevant</strong> to this community.{% endtrans %}
- {% trans %}Before asking the question - please make sure to use search to see whether your question has alredy been answered.{% endtrans %}
- </p>
- <h3 class="subtitle">{% trans %}What questions should I avoid asking?{% endtrans %}</h3>
- <p>{% trans %}Please avoid asking questions that are not relevant to this community, too subjective and argumentative.{% endtrans %}
- </p>
- </div>
- <div>
- <h3 class="subtitle">{% trans %}What should I avoid in my answers?{% endtrans %}</h3>
- <p>{{ settings.APP_TITLE }} {% trans %}is a Q&A site, not a discussion group. Therefore - please avoid having discussions in your answers, comment facility allows some space for brief discussions.{% endtrans %}</p>
- </div>
- <div>
- <h3 class="subtitle">{% trans %}Who moderates this community?{% endtrans %}</h3>
- <p>{% trans %}The short answer is: <strong>you</strong>.{% endtrans %}
- {% trans %}This website is moderated by the users.{% endtrans %}
- {% trans %}The reputation system allows users earn the authorization to perform a variety of moderation tasks.{% endtrans %}
- </p>
- </div>
-
- <div>
- <h3 class="subtitle">{% trans %}How does reputation system work?{% endtrans %}</h3>
- <p>{% trans %}Rep system summary{% endtrans %}</p>
- <p>{% trans MAX_REP_GAIN_PER_USER_PER_DAY=settings.MAX_REP_GAIN_PER_USER_PER_DAY, REP_GAIN_FOR_RECEIVING_UPVOTE=settings.REP_GAIN_FOR_RECEIVING_UPVOTE, REP_LOSS_FOR_RECEIVING_DOWNVOTE=settings.REP_LOSS_FOR_RECEIVING_DOWNVOTE|absolute_value %}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.{% endtrans %}
- </p>
+<h1>{% trans %}Frequently Asked Questions {% endtrans %}({% trans %}FAQ{% endtrans %})</h1>
+<h2 class="first">{% trans %}What kinds of questions can I ask here?{% endtrans %}</h2>
+<p>{% trans %}Most importanly - questions should be <strong>relevant</strong> to this community.{% endtrans %}
+{% trans %}Before asking the question - please make sure to use search to see whether your question has alredy been answered.{% endtrans %}
+</p>
+<h2>{% trans %}What questions should I avoid asking?{% endtrans %}</h2>
+<p>{% trans %}Please avoid asking questions that are not relevant to this community, too subjective and argumentative.{% endtrans %}
+</p>
+<h2>{% trans %}What should I avoid in my answers?{% endtrans %}</h2>
+<p>{{ settings.APP_TITLE }} {% trans %}is a Q&A site, not a discussion group. Therefore - please avoid having discussions in your answers, comment facility allows some space for brief discussions.{% endtrans %}</p>
+<h2>{% trans %}Who moderates this community?{% endtrans %}</h2>
+<p>{% trans %}The short answer is: <strong>you</strong>.{% endtrans %}
+{% trans %}This website is moderated by the users.{% endtrans %}
+{% trans %}The reputation system allows users earn the authorization to perform a variety of moderation tasks.{% endtrans %}
+</p>
+<h2>{% trans %}How does reputation system work?{% endtrans %}</h2>
+<p>{% trans %}Rep system summary{% endtrans %}</p>
+<p>{% trans MAX_REP_GAIN_PER_USER_PER_DAY=settings.MAX_REP_GAIN_PER_USER_PER_DAY, REP_GAIN_FOR_RECEIVING_UPVOTE=settings.REP_GAIN_FOR_RECEIVING_UPVOTE, REP_LOSS_FOR_RECEIVING_DOWNVOTE=settings.REP_LOSS_FOR_RECEIVING_DOWNVOTE|absolute_value %}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.{% endtrans %}
+</p>
- <table style="font-family:arial;" cellspacing="3" cellpadding="3">
- <tr>
- <th width="40px" style="text-align:right"></th>
- <th width="300px"></th>
- </tr>
- <tr>
- <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_VOTE_UP}}</strong></td>
- <td>{% trans %}upvote{% endtrans %}</td>
- </tr>
- <!--
- <tr>
- <td class="faq-rep-item"><strong>15</strong></td>
- <td>{% trans %}use tags{% endtrans %}</td>
- </tr>
- -->
- <tr>
- <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_LEAVE_COMMENTS}}</strong></td>
- <td>{% trans %}add comments{% endtrans %}</td>
- </tr>
- <tr>
- <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_VOTE_DOWN}}</strong></td>
- <td>{% trans %}downvote{% endtrans %}</td>
- </tr><tr>
- <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_CLOSE_OWN_QUESTIONS}}</strong></td>
- <td>{% trans %}open and close own questions{% endtrans %}</td>
- </tr>
- <tr>
- <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_RETAG_OTHERS_QUESTIONS}}</strong></td>
- <td>{% trans %}retag other's questions{% endtrans %}</td>
- </tr>
- {% if settings.WIKI_ON %}
- <tr>
- <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_EDIT_WIKI}}</strong></td>
- <td>{% trans %}edit community wiki questions{% endtrans %}</td>
- </tr>
- {% endif %}
- <tr>
- <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_EDIT_OTHERS_POSTS}}</strong></td>
- <td>{% trans %}"edit any answer{% endtrans %}</td>
- </tr>
- <tr>
- <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_DELETE_OTHERS_COMMENTS}}</strong></td>
- <td>{% trans %}"delete any comment{% endtrans %}</td>
- </tr>
- </table>
- </div>
- {#
- {% if settings.EMAIL_VALIDATION %}
- <div>
- <a id='validate'></a><h3 class="subtitle">{% trans %}how to validate email title{% endtrans %}</h3>
- <!--special case here message must contain paragraphs-->
- {% trans %}how to validate email info with {{send_email_key_url}} {{gravatar_faq_url}}{% endtrans %}
- </div>
- {% endif %}
- #}
- <div>
- <a id='gravatar'></a><h3 class="subtitle">{% trans %}what is gravatar{% endtrans %}</h3>
- {% trans %}gravatar faq info{% endtrans %}
- </div>
- <div>
- <h3 class="subtitle">{% trans %}To register, do I need to create new password?{% endtrans %}</h3>
- <p>{% trans %}No, you don't have to. You can login through any service that supports OpenID, e.g. Google, Yahoo, AOL, etc."{% endtrans %}
- <strong><a href="{% url user_signin %}">{% trans %}"Login now!"{% endtrans %}</a> »</strong>
- </p>
- </div>
- <div>
- <h3 class="subtitle">{% trans %}Why other people can edit my questions/answers?{% endtrans %}</h3>
- <p> {% trans %}Goal of this site is...{% endtrans %} {% trans %}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.{% endtrans %}
- {% trans %}If this approach is not for you, we respect your choice.{% endtrans %}
- </p>
- </div>
- <div>
- <h3 class="subtitle">{% trans %}Still have questions?{% endtrans %}</h3>
- <p>{% trans %}Please ask your question at {{ask_question_url}}, help make our community better!{% endtrans %}
- <!--
- <a href="{% url tags %}faq" class="big">{{ settings.APP_TITLE }} {% trans %}questions{% endtrans %}</a>{% trans %}.{% endtrans %}
- -->
- </p>
- </div>
+<table cellspacing="3" cellpadding="3">
+ <tr>
+ <th width="40px" style="text-align:right"></th>
+ <th width="300px"></th>
+ </tr>
+ <tr>
+ <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_VOTE_UP}}</strong></td>
+ <td>{% trans %}upvote{% endtrans %}</td>
+ </tr>
+ <!--
+ <tr>
+ <td class="faq-rep-item"><strong>15</strong></td>
+ <td>{% trans %}use tags{% endtrans %}</td>
+ </tr>
+ -->
+ <tr>
+ <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_LEAVE_COMMENTS}}</strong></td>
+ <td>{% trans %}add comments{% endtrans %}</td>
+ </tr>
+ <tr>
+ <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_VOTE_DOWN}}</strong></td>
+ <td>{% trans %}downvote{% endtrans %}</td>
+ </tr><tr>
+ <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_CLOSE_OWN_QUESTIONS}}</strong></td>
+ <td>{% trans %}open and close own questions{% endtrans %}</td>
+ </tr>
+ <tr>
+ <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_RETAG_OTHERS_QUESTIONS}}</strong></td>
+ <td>{% trans %}retag other's questions{% endtrans %}</td>
+ </tr>
+ {% if settings.WIKI_ON %}
+ <tr>
+ <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_EDIT_WIKI}}</strong></td>
+ <td>{% trans %}edit community wiki questions{% endtrans %}</td>
+ </tr>
+ {% endif %}
+ <tr>
+ <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_EDIT_OTHERS_POSTS}}</strong></td>
+ <td>{% trans %}"edit any answer{% endtrans %}</td>
+ </tr>
+ <tr>
+ <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_DELETE_OTHERS_COMMENTS}}</strong></td>
+ <td>{% trans %}"delete any comment{% endtrans %}</td>
+ </tr>
+</table>
+<a id='gravatar'></a><h2>{% trans %}what is gravatar{% endtrans %}</h2>
+{% trans %}gravatar faq info{% endtrans %}
+<h2>{% trans %}To register, do I need to create new password?{% endtrans %}</h2>
+<p>{% trans %}No, you don't have to. You can login through any service that supports OpenID, e.g. Google, Yahoo, AOL, etc."{% endtrans %}
+<strong><a href="{% url user_signin %}">{% trans %}"Login now!"{% endtrans %}</a> »</strong>
+</p>
+<h2>{% trans %}Why other people can edit my questions/answers?{% endtrans %}</h2>
+<p> {% trans %}Goal of this site is...{% endtrans %} {% trans %}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.{% endtrans %}
+{% trans %}If this approach is not for you, we respect your choice.{% endtrans %}
+</p>
+<h2>{% trans %}Still have questions?{% endtrans %}</h2>
+<p>{% trans %}Please ask your question at {{ask_question_url}}, help make our community better!{% endtrans %}
+</p>
</div>
<script type="text/javascript">
//highlihts section if url has matching #anchor_name
diff --git a/askbot/skins/default/templates/feedback.html b/askbot/skins/default/templates/feedback.html
index 7d76ef8d..258a85dc 100644
--- a/askbot/skins/default/templates/feedback.html
+++ b/askbot/skins/default/templates/feedback.html
@@ -2,49 +2,45 @@
<!-- template feedback.html -->
{% block title %}{% spaceless %}{% trans %}Feedback{% endtrans %}{% endspaceless %}{% endblock %}
{% block content %}
-<div class="headNormal">
-{% trans %}Give us your feedback!{% endtrans %}
-</div>
-<div class="content">
- <form method="post" action="{% url feedback %}" accept-charset="utf-8">
- {% if user.is_authenticated() %}
- <p class="message">
- {% trans user_name=user.username %}
- <span class='big strong'>Dear {{user_name}}</span>, we look forward to hearing your feedback.
- Please type and send us your message below.
- {% endtrans %}
- <p>
- {% else %}
- <p class="message">
- {% trans %}
- <span class='big strong'>Dear visitor</span>, we look forward to hearing your feedback.
- Please type and send us your message below.
- {% endtrans %}
- </p>
- <div class="form-row"><label>{{form.name.label}}</label><br/>{{form.name}}</div>
- <div class="form-row">
- <label>{{form.email.label}}
- {% if form.errors.email %}
- <span class='red'>{% trans %}(please enter a valid email){% endtrans %}</span>
- {% endif %}
- </label><br/>{{form.email}}
- </div>
- {% endif %}
+<h1>{% trans %}Give us your feedback!{% endtrans %}</h1>
+<form method="post" action="{% url feedback %}" accept-charset="utf-8">
+ {% if user.is_authenticated() %}
+ <p class="message">
+ {% trans user_name=user.username %}
+ <span class='big strong'>Dear {{user_name}}</span>, we look forward to hearing your feedback.
+ Please type and send us your message below.
+ {% endtrans %}
+ <p>
+ {% else %}
+ <p class="message">
+ {% trans %}
+ <span class='big strong'>Dear visitor</span>, we look forward to hearing your feedback.
+ Please type and send us your message below.
+ {% endtrans %}
+ </p>
+ <div class="form-row"><label>{{form.name.label}}</label><br/>{{form.name}}</div>
<div class="form-row">
- <label>{{form.message.label}}
- {% if form.errors.message %}
- <span class="red">{% trans %}(this field is required){% endtrans %}</span>
- </label>
- {% endif %}
- <br/>
- {{form.message}}
- </div>
- {{form.next}}
- <div class="submit-row">
- <input type="submit" class="submit" value="{% trans %}Send Feedback{% endtrans %}"/>&nbsp;
- <input type="submit" class="submit" name="cancel" value="{% trans %}Cancel{% endtrans %}"/>
+ <label>{{form.email.label}}
+ {% if form.errors.email %}
+ <span class='error'>{% trans %}(please enter a valid email){% endtrans %}</span>
+ {% endif %}
+ </label><br/>{{form.email}}
</div>
- </form>
-</div>
+ {% endif %}
+ <div class="form-row">
+ <label>{{form.message.label}}
+ {% if form.errors.message %}
+ <span class="error">{% trans %}(this field is required){% endtrans %}</span>
+ </label>
+ {% endif %}
+ <br/>
+ {{form.message}}
+ </div>
+ {{form.next}}
+ <div class="submit-row">
+ <input type="submit" class="submit" value="{% trans %}Send Feedback{% endtrans %}"/>&nbsp;
+ <input type="submit" class="submit" name="cancel" value="{% trans %}Cancel{% endtrans %}"/>
+ </div>
+</form>
{% endblock %}
<!-- end template feedback.html -->
diff --git a/askbot/skins/default/templates/html.list b/askbot/skins/default/templates/html.list
deleted file mode 100644
index 1f2c46c8..00000000
--- a/askbot/skins/default/templates/html.list
+++ /dev/null
@@ -1,56 +0,0 @@
-==TODO==
-yadis.xrdf - inline into .py file
-signup_with_password.html - create password protected account - a variation of complete.html
-
-==not used yet, but are linked to in code==
-confirm_email.txt - new user greeting - not used yet
-email_validation.txt - not used now
-changeemail.html - used only is EMAIL_VALIDATION == True, but the setting is disabled now
-
-==done==
-authopenid/signin.html - main signin template
-authopenid/complete.html - main registration template
-404.html
-500.html
-question_retag.html
-paginator.html
-user_responses.html
-users_questions.html
-users.html
-user_favorites.html
-user_recent.html
-user_info.html
-user_reputation.html
-user_moderate.html
-user_votes.html
-user_stats.html
-user_email_subscriptions.html
-user_edit.html
-tags.html
-revisions.html
-reopen.html
-question_edit.html
-privacy.html
-tag_selector..html
-questions..html
-ask_form..html
-base..html
-footer..html
-header..html
-input_bar..html
-answer_edit_tips.html
-answer_edit.html
-ask.html
-badges.html
-base_content.html
-close.html
-edit_user_email_feeds_form.html
-user.html
-user_tabs.html
-faq.html
-feedback.html
-instant_notification.html
-macros.html
-question_edit_tips.html
-question.html
-
diff --git a/askbot/skins/default/templates/import_data.html b/askbot/skins/default/templates/import_data.html
new file mode 100644
index 00000000..7bc370ab
--- /dev/null
+++ b/askbot/skins/default/templates/import_data.html
@@ -0,0 +1,31 @@
+{% extends "two_column_body.html" %}
+{% block title %}{% trans %}Import StackExchange data{% endtrans %}{% endblock %}
+{% block content %}
+ <h1>{% trans %}Import StackExchange data{% endtrans %}</h1>
+ {% if need_configuration %}
+ <p><em>Note:</em> to import stackexchange data, first add
+ <code>'askbot.importers.stackexchange',</code>
+ to the <code>INSTALLED_APPS</code> setting in your <code>settings.py</code>
+ file, then run <code>python manage.py syncdb</code>, and restart the application.
+ After that, pleale return to here and try again.
+ </p>
+ {% else %}
+ <p class="message">{% trans %}<em>Warning:</em> if your database is not empty, please back it up
+ before attempting this operation.{% endtrans %}
+ </p>
+ <p>{% trans %}Upload your stackexchange dump .zip file, then wait until
+ the data import completes. This process may take several minutes.
+ Please note that feedback will be printed in plain text.
+ {% endtrans %}
+ </p>
+ <form id="load-dump-form" method="post" enctype="multipart/form-data">
+ <table>
+ {{dump_upload_form.as_table()}}
+ </table>
+ <input type="submit" value="{% trans %}Import data{% endtrans %}" />
+ </form>
+ <p>{% trans %}In the case you experience any difficulties in using this import tool,
+ please try importing your data via command line: <code>python manage.py load_stackexchange path/to/your-data.zip</code>{% endtrans %}
+ </p>
+ {% endif %}
+{% endblock %}
diff --git a/askbot/skins/default/templates/logout.html b/askbot/skins/default/templates/logout.html
index 2b16c407..d9ab69f0 100644
--- a/askbot/skins/default/templates/logout.html
+++ b/askbot/skins/default/templates/logout.html
@@ -2,13 +2,8 @@
<!-- template logout.html -->
{% block title %}{% spaceless %}{% trans %}Logout{% endtrans %}{% endspaceless %}{% endblock %}
{% block content %}
-<div class="headNormal">
- {% trans %}Logout{% endtrans %}
-</div>
-<div id="main-body" style="width:100%">
- <p>{% trans %}As a registered user you can login with your OpenID, log out of the site or permanently remove your account.{% endtrans %}</p>
- <input id="btLogout" type="button" class="submit" value="{% trans %}Logout now{% endtrans %}"><!-- style="width:150px">-->
-</div>
+<h1>{% trans %}You have successfully logged out{% endtrans %}</h1>
+<p>{% trans %}However, you still may be logged in to your OpenID provider. Please logout of your provider if you wish to do so.{% endtrans %}</p>
{% if settings.FACEBOOK_KEY and settings.FACEBOOK_SECRET %}
<div id="fb-root"></div>
<script src="http://connect.facebook.net/en_US/all.js"></script>
@@ -19,27 +14,15 @@
{% endblock %}
{% block endjs %}
<script type="text/javascript">
- var sign_out = function(){
- window.location.href='{% url user_signout %}?next={{ next }}';
- }
$(document).ready(function(){
- $('#btLogout').bind('click', function(){
- if (typeof FB != 'undefined'){
- FB.getLoginStatus(function(response){
- if (response.session){
- FB.logout(function(response){
- sign_out();
- });
- }
- else {
- sign_out();
- }
- });
- }
- else {
- sign_out();
- }
- });
+ //logout user from facebook
+ if (typeof FB != 'undefined'){
+ FB.getLoginStatus(function(response){
+ if (response.session){
+ FB.logout();
+ }
+ });
+ }
});
</script>
{% endblock %}
diff --git a/askbot/skins/default/templates/macros.html b/askbot/skins/default/templates/macros.html
index a6daeeea..d593fec5 100644
--- a/askbot/skins/default/templates/macros.html
+++ b/askbot/skins/default/templates/macros.html
@@ -44,6 +44,36 @@
{%- endif -%}
{%- endmacro -%}
+{%- macro user_country_flag(user) -%}
+ {% if user.country and user.show_country %}
+ <img class="flag"
+ src="{{ ('/images/flags/' ~ user.country.code|lower ~ '.gif')|media }}"
+ alt="{% trans
+ country=user.country.name
+ %}flag of {{country}}{%
+ endtrans %}"
+ title="{% trans
+ country=user.country.name,
+ person=user.username %}{{person}} is from {{country}}{%
+ endtrans %}"
+ />
+ {% endif %}
+{%- endmacro -%}
+
+{%- macro user_country_name_and_flag(user) -%}
+ {% if user.country and user.show_country %}
+ {{ user.country.name }}
+ {{ user_country_flag(user) }}
+ {% endif %}
+{%- endmacro -%}
+
+{%- macro user_full_location(user) -%}
+ {% if user.location %}
+ {{ user.location }},
+ {% endif %}
+ {{ user_country_name_and_flag(user) }}
+{%- endmacro -%}
+
{%- macro paginator(p, position='left') -%}{# p is paginator context dictionary #}
{% spaceless %}
{% if p.is_paginated %}
@@ -108,26 +138,53 @@
{% endspaceless %}
{%- endmacro -%}
+{#todo: rename this to avatar #}
{%- macro gravatar(user, size) -%}
{% spaceless %}
<a style="text-decoration:none"
- href="{{user.get_absolute_url()}}"
+ href="{{ user.get_absolute_url() }}"
><img class="gravatar"
width="{{size}}" height="{{size}}"
- src="http://www.gravatar.com/avatar/{{user.gravatar}}s?s={{size}}&amp;d=identicon&amp;r=PG"
+ src="{{ user.get_avatar_url(size) }}"
title="{{user.username}}"
alt="{% trans username=user.username %}{{username}} gravatar image{% endtrans %}"
/></a>
{% endspaceless %}
{%- endmacro -%}
+{%- macro user_website_link(user, max_display_length=25) -%}
+ {% if user.website %}
+ <a
+ href="{{user.website}}"
+ title="{% trans username=user.username|escape, url=user.website %}{{username}}'s website is {{url}}{% endtrans %}"
+ {% if user.can_have_strong_url() == False %}
+ rel="nofollow"
+ {% endif %}
+ >
+ {{user.website|truncate(length=max_display_length, killwords=True, end='...')}}
+ </a>
+ {% endif %}
+{%- endmacro -%}
+
+{%- macro post_contributor_avatar_and_credentials(post, user) -%}
+ {% if post.is_anonymous %}
+ <img alt="{% trans %}anonymous user{% endtrans %}" src="{{ '/images/anon.png'|media }} " class="gravatar" width="32" height="32" />
+ <p>{{ user.get_anonymous_name() }}</p>
+ {% else %}
+ {{ gravatar(user, 32) }}
+ {{ user.get_profile_link()}}{{ user_country_flag(user) }}{% if not user.website %}<br/>{% endif %}
+ {{ user_score_and_badge_summary(user) }}<br/>
+ {{ user_website_link(user) }}
+ {% endif %}
+{%- endmacro -%}
+
{%- macro post_contributor_info(post, contributor_type, is_wiki, wiki_min_rep) -%}
-<div class='post-update-info'>
{# there is a whole bunch of trickery here, probably indicative of
poor design of the data or methods on data objects #}
{% if contributor_type=="original_author" %}
+ <div class='post-update-info'>
{% if is_wiki %}
- <p style="line-height:12px">
+ <p>
{%- if post.__class__.__name__ == 'Question' -%}
{%- trans %}asked{% endtrans %}
{% elif post.__class__.__name__ == 'Answer' %}
@@ -160,11 +217,10 @@ poor design of the data or methods on data objects #}
<strong>{{post.added_at|diff_date}}</strong>
{% endif %}
</p>
- {{ gravatar(post.author, 32) }}
- <p>{{post.author.get_profile_link()}}<br/>
- {{ user_score_and_badge_summary(post.author) }}</p>
+ {{ post_contributor_avatar_and_credentials(post, post.author) }}
{% endif %}
-{% else %}
+ </div>
+{% elif contributor_type=="last_updater" %}
{% if post.__class__.__name__ in ('Question', 'Answer') %}
{% set last_edited_at = post.last_edited_at %}
{% set original_author = post.author %}
@@ -175,6 +231,7 @@ poor design of the data or methods on data objects #}
{% set update_author = post.author %}
{% endif %}
{% if last_edited_at %}
+ <div class='post-update-info'>
<p style="line-height:12px;">
<a
{% if post.__class__.__name__ == 'Question' %}
@@ -185,34 +242,117 @@ poor design of the data or methods on data objects #}
>{% trans %}updated{% endtrans %} <strong>{{ last_edited_at|diff_date }}</strong></a>
</p>
{% if original_author != update_author or is_wiki %}
- {{ gravatar(update_author, 32) }}
- <p style="float:left">{{update_author.get_profile_link()}}<br/>
- {{ user_score_and_badge_summary(update_author) }}</p>
+ {{ post_contributor_avatar_and_credentials(post, update_author) }}
{% endif %}
+ </div>
{% endif %}
{% endif %}
-</div>
+{%- endmacro -%}
+
+{%- macro if_else(condition, if_true, if_false) -%}
+ {%- if condition == True -%}
+ {{if_true}}
+ {%- else -%}
+ {{if_false}}
+ {%- endif -%}
+{%- endmacro -%}
+
+{%- macro tag_list_widget(
+ tags,
+ id = None,
+ deletable = False,
+ make_links = True,
+ url_params = None,
+ css_class = None
+ )
+-%}
+<ul {% if id %}id="{{ id }}"{% endif %}
+ class="tags{% if css_class %} {{css_class}}{% endif %}"
+>
+ {% if tags %}
+ {% for tag in tags %}
+ {{ tag_widget(
+ tag,
+ deletable = deletable,
+ is_link = make_links,
+ url_params = url_params,
+ html_tag = 'li'
+ )}}
+ {% endfor %}
+ {% endif %}
+</ul>
+{%- endmacro -%}
+
+{# todo: remove the extra content argument to make its usage more explicit #}
+{%- macro tag_widget(
+ tag,
+ deletable = False,
+ is_link = True,
+ delete_link_title = None,
+ css_class = None,
+ url_params = None,
+ html_tag = 'div',
+ extra_content = ''
+ )
+-%}
+ {% spaceless %}
+ <{{ html_tag }} class="tag-left{% if deletable %} deletable-tag{% endif %}">
+ <{% if not is_link or tag[-1] == '*' %}span{% else %}a{% endif %}
+ class="tag tag-right{% if css_class %} {{ css_class }}{% endif %}"
+ href="{% url questions %}?tags={{tag|urlencode}}{{
+ if_else(
+ url_params != None,
+ '&' ~ url_params,
+ ''
+ )|escape
+ }}"
+ title="{% trans %}see questions tagged '{{ tag }}'{% endtrans %}" rel="tag"
+ >{{ tag|replace('*', '&#10045;') }}</{% if not is_link or tag[-1] == '*' %}span{% else %}a{% endif %}>
+ {% if deletable %}
+ <span class="delete-icon"
+ {% if delete_link_title %}
+ title="{{ delete_link_title }}"
+ {% endif %}
+ ></span>
+ {% endif %}
+ </{{ html_tag }}>
+ {{ extra_content }}
+ {% endspaceless %}
+{%- endmacro -%}
+
+{%- macro radio_select(name = None, value = None, choices = None) -%}
+ {% for choice in choices %}
+ <p class="choice">
+ {% set id = "id_" ~ name ~ "_" ~ choice[0] %}
+ <input
+ id="{{ id }}"
+ name="{{ name }}"
+ value="{{ choice[0] }}"
+ type="radio"
+ {% if value == choice[0] %}
+ checked="checked"
+ {% endif %}
+ />
+ <label for="{{ id }}">{{ choice[1] }}</label>
+ </p>
+ {% endfor %}
{%- endmacro -%}
{%- macro question_summary(question, extra_class=None) -%}
<div class="short-summary{% if extra_class %} {{extra_class}}{% endif %}">
<div class="counts">
- <div class="votes">
- <span
- class="item-count
+ <div class="votes
{% if question.score == 0 -%}
no-votes
{% else -%}
some-votes
- {%- endif -%}"
- >{{question.score|humanize_counter}}</span>
+ {%- endif -%}">
+ <span class="item-count">{{question.score|humanize_counter}}</span>
<div>
{% trans cnt=question.score %}vote{% pluralize %}votes{% endtrans %}
</div>
</div>
- <div class="votes">
- <span
- class="item-count
+ <div class="answers
{% if question.answer_count == 0 -%}
no-answers
{% else -%}
@@ -221,36 +361,38 @@ poor design of the data or methods on data objects #}
{%- else -%}
some-answers
{%- endif -%}
- {%- endif -%}"
+ {%- endif -%}">
+ <span
+ class="item-count"
>{{question.answer_count|humanize_counter}}{% if question.answer_accepted%}&#10003;{% endif %}</span>
<div>
{% trans cnt=question.answer_count %}answer{% pluralize %}answers{% endtrans %}
</div>
</div>
- <div class="votes">
- <span class="item-count
+ <div class="views
{% if question.view_count == 0 -%}
no-views
{% else -%}
some-views
- {%- endif -%}"
- >{{question.view_count|humanize_counter}}</span>
+ {%- endif -%}">
+ <span class="item-count">{{question.view_count|humanize_counter}}</span>
<div>
{% trans cnt=question.view_count %}view{% pluralize %}views{% endtrans %}
</div>
</div>
+ <div style="clear:both"></div>
+ <div class="userinfo">
+ <span class="relativetime" title="{{question.last_activity_at}}">{{ question.last_activity_at|diff_date }}</span>
+ {% if question.is_anonymous %}
+ <span class="anonymous">{{ question.last_activity_by.get_anonymous_name() }}</span>
+ {% else %}
+ <a href="{% url user_profile question.last_activity_by.id, question.last_activity_by.username|slugify %}">{{question.last_activity_by.username}}</a>{{ user_country_flag(question.last_activity_by) }}
+ {#{user_score_and_badge_summary(question.last_activity_by)}#}
+ {% endif %}
+ </div>
</div>
<h2><a title="{{question.summary|escape}}" href="{{ question.get_absolute_url() }}">{{question.get_question_title()|escape}}</a></h2>
- <div class="userinfo">
- <span class="relativetime" title="{{question.last_activity_at}}">{{ question.last_activity_at|diff_date }}</span>
- <a href="{% url user_profile question.last_activity_by.id, question.last_activity_by.username|slugify %}">{{question.last_activity_by.username}}</a>
- {#{user_score_and_badge_summary(question.last_activity_by)}#}
- </div>
- <div class="tags">
- {% for tag in question.get_tag_names() %}
- <a href="{% url questions %}?tags={{tag|urlencode}}" title="{% trans %}see questions tagged '{{ tag }}'{% endtrans %}" rel="tag">{{ tag }}</a>
- {% endfor %}
- </div>
+ {{ tag_list_widget(question.get_tag_names()) }}
</div>
{%- endmacro -%}
@@ -267,10 +409,9 @@ poor design of the data or methods on data objects #}
<a class="edit">{% trans %}edit{% endtrans %}</a>
{% endif %}
{% if user|can_delete_comment(comment) %}
- <img class="delete-icon"
- src="{{"/images/close-small.png"|media}}"
+ <span class="delete-icon"
title="{% trans %}delete this comment{% endtrans %}"
- />
+ ></span>
{% endif %}
</div>
{% endfor %}
@@ -370,17 +511,17 @@ poor design of the data or methods on data objects #}
<a id="by_{{key_name}}"
href="?sort={{key_name}}-desc"
class="on"
- title="{{desc_tooltip}}">{{label}} &#9650;</a>
+ title="{{desc_tooltip}}"><span>{{label}} &#9650;</span></a>
{% elif sort == key_name + "-desc" %}{# "best first" #}
<a id="by_{{key_name}}"
href="?sort={{key_name}}-asc"
class="on"
- title="{{asc_tooltip}}">{{label}} &#9660;</a>
+ title="{{asc_tooltip}}"><span>{{label}} &#9660;</span></a>
{% else %}{# default, when other button is active #}
<a id="by_{{key_name}}"
href="?sort={{key_name}}-desc"
class="off"
- title="{{desc_tooltip}}">{{label}}</a>
+ title="{{desc_tooltip}}"><span>{{label}}</span></a>
{% endif %}
<script type="text/javascript">{# need to pass on text translations to js #}
var sortButtonData = sortButtonData || {};
@@ -392,7 +533,21 @@ poor design of the data or methods on data objects #}
</script>
{%- endmacro %}
-{%- macro edit_post(post_form, wiki_on, post_type=None, edit_title=False) -%}
+{%- macro checkbox_in_div(checkbox_field, class = 'checkbox') -%}
+ <div{% if class %} class="{{class}}"{% endif %}
+ title="{{checkbox_field.help_text}}">
+ {{ checkbox_field }}
+ {{ checkbox_field.label_tag() }}
+ {{ checkbox_field.errors }}
+ </div>
+{%- endmacro -%}
+
+{%- macro edit_post(
+ post_form,
+ post_type=None,
+ edit_title=False
+ )
+-%}
{% if edit_title %}
<div class="form-item">
<label for="id_title" ><strong>{{ post_form.title.label_tag() }}:</strong></label> <span class="form-error"></span><br/>
@@ -405,13 +560,6 @@ poor design of the data or methods on data objects #}
<div id="wmd-button-bar" class="wmd-panel"></div>
<div class="form-item">
{{ post_form.text }}{# this element is resizable and will be wrapped by js #}
- {% if wiki_on %}
- <div style="margin-right:5px;float:right;font-weight:normal;cursor:help"
- title="{{post_form.wiki.help_text}}">
- {{ post_form.wiki }}
- {{ post_form.wiki.label_tag() }}
- </div>
- {% endif %}
<label for="editor" class="form-error">{{ post_form.text.errors }}</label>
</div>
{# need label element for resizable input, b/c form validation won't find span #}
@@ -446,3 +594,58 @@ poor design of the data or methods on data objects #}
</div>
<div id="previewer" class="wmd-preview"></div>
{%- endmacro -%}
+
+{%- macro inbox_link(user) -%}
+ {% if user.new_response_count > 0 or user.seen_response_count > 0 %}
+ <a id='ab-responses' href="{{user.get_absolute_url()}}?sort=inbox&section=forum">
+ <img
+ alt="{% trans username=user.username %}responses for {{username}}{% endtrans %}"
+ {% if user.new_response_count > 0 %}
+ src="{{ "/images/mail-envelope-full.png"|media }}"
+ title="{% trans response_count=user.new_response_count %}you have a new response{% pluralize %}you have {{response_count}} new responses{% endtrans %}"
+ {% elif user.seen_response_count > 0 %}
+ src="{{ "/images/mail-envelope-empty.png"|media }}"
+ title="{% trans %}no new responses yet{% endtrans %}"
+ {% endif %}
+ />
+ </a>
+ {% endif %}
+{%- endmacro -%}
+
+{%- macro moderation_items_link(user, moderation_items) -%}
+ {% if moderation_items %}
+ <a id="ab-responses"
+ href="{{user.get_absolute_url()}}?sort=inbox&section=flags"
+ >
+ {% if moderation_items['new_count'] > 0 %}
+ <img src="{{'/images/dialog-warning.png'|media}}"
+ {% if moderation_items['seen_count'] > 0 %}
+ alt="{% trans new=moderation_items['new_count'], seen=moderation_items['seen_count']%}{{new}} new flagged posts and {{seen}} previous{% endtrans %}"
+ title="{% trans new=moderation_items['new_count'], seen=moderation_items['seen_count']%}{{new}} new flagged posts and {{seen}} previous{% endtrans %}"
+ {% else %}
+ alt="{% trans new=moderation_items['new_count'] %}{{new}} new flagged posts{% endtrans %}"
+ title="{% trans new=moderation_items['new_count'] %}{{new}} new flagged posts{% endtrans %}"
+ {% endif %}
+ />
+ {% elif moderation_items['seen_count'] > 0 %}
+ <img src={{'/images/dialog-warning-off.png'|media}}
+ alt="{% trans seen=moderation_items['seen_count'] %}{{seen}} flagged posts{% endtrans %}"
+ title="{% trans seen=moderation_items['seen_count'] %}{{seen}} flagged posts{% endtrans %}"
+ />
+ {% endif %}
+ </a>
+ {% endif %}
+{%- endmacro -%}
+
+{%- macro tag_autocomplete_js(id = '#id_tags') -%}
+ var tagAc = new AutoCompleter({
+ url: '{% url "get_tag_list" %}',
+ preloadData: true,
+ minChars: 1,
+ useCache: true,
+ matchInside: true,
+ maxCacheLength: 100,
+ delay: 10,
+ });
+ tagAc.decorate($("{{ id }}"));
+{%- endmacro -%}
diff --git a/askbot/skins/default/templates/main_page.html b/askbot/skins/default/templates/main_page.html
new file mode 100644
index 00000000..d0cddc68
--- /dev/null
+++ b/askbot/skins/default/templates/main_page.html
@@ -0,0 +1,24 @@
+{% extends "two_column_body.html" %}
+{#
+ this template is split into several
+ blocks that are included here
+ the blocks are within directory templates/main_page
+ relative to the skin directory
+
+ there is no html markup in this file
+#}
+<!-- questions.html -->
+{% block title %}{% spaceless %}{% trans %}Questions{% endtrans %}{% endspaceless %}{% endblock %}
+{% block content %}
+ {% include "main_page/tab_bar.html" %}
+ {% include "main_page/headline.html" %}
+ {% include "main_page/content.html" %}
+ {% include "main_page/paginator.html" %}
+{% endblock %}
+{% block sidebar %}
+ {% include "main_page/sidebar.html" %}
+{% endblock %}
+{% block endjs %}
+ {% include "main_page/javascript.html" %}
+{% endblock %}
+<!-- end questions.html -->
diff --git a/askbot/skins/default/templates/main_page/content.html b/askbot/skins/default/templates/main_page/content.html
new file mode 100644
index 00000000..72128cdc
--- /dev/null
+++ b/askbot/skins/default/templates/main_page/content.html
@@ -0,0 +1,17 @@
+{% import "macros.html" as macros %}
+<div id="question-list">
+{% cache 0 "questions" questions search_tags scope sort query context.page context.page_size language_code %}
+ {% for question in questions.object_list %}
+ {{macros.question_summary(question)}}
+ {% endfor %}
+{% endcache %}
+{# comment todo: fix css here #}
+{% if questions_count == 0 %}
+ {% include "main_page/nothing_found.html" %}
+{% else %}
+ <p class="evenMore" style="padding-left:9px">
+ {% trans %}Did not find what you were looking for?{% endtrans %}
+ <a href="{% url ask %}">{% trans %}Please, post your question!{% endtrans %}</a>
+ </p>
+{% endif %}
+</div>
diff --git a/askbot/skins/default/templates/main_page/headline.html b/askbot/skins/default/templates/main_page/headline.html
new file mode 100644
index 00000000..130a9bd9
--- /dev/null
+++ b/askbot/skins/default/templates/main_page/headline.html
@@ -0,0 +1,48 @@
+{% import "macros.html" as macros %}
+{% if questions_count > 0 %}
+ <div style="clear:both">
+ <p class="rss">
+ (<a
+ href="{{settings.APP_URL}}/feeds/rss/"
+ title="{% trans %}subscribe to the questions feed{% endtrans %}"
+ >{% trans %}rss feed{% endtrans %}</a>)
+ </p>
+ <h1 id="question-count" class="search-result-summary">
+ {% if search_tags %}
+ {% trans cnt=questions_count, q_num=questions_count|intcomma %}{{q_num}} question, tagged{% pluralize %}{{q_num}} questions, tagged{% endtrans %}
+ {% else %}
+ {% trans cnt=questions_count, q_num=questions_count|intcomma %}{{q_num}} question{% pluralize %}{{q_num}} questions{% endtrans %}
+ {% endif %}
+ {% if author_name %}
+ {% trans %}with {{author_name}}'s contributions{% endtrans %}
+ {% endif %}
+ </h1>
+ {{ macros.tag_list_widget(
+ search_tags,
+ id = 'search-tags',
+ deletable = True,
+ make_links = False
+ )
+ }}
+ {% if author_name or search_tags or query %}
+ <p class="search-tips">{% trans %}Search tips:{% endtrans %}
+ {% if reset_method_count > 1 %}
+ {% if author_name %}
+ <a href="{% url questions %}?reset_author=true">{% trans %}reset author{% endtrans %}</a>
+ {% endif %}
+ {% if search_tags %}{% if author_name and query %}, {% elif author_name %}{% trans %} or {% endtrans %}{% endif %}
+ <a href="{% url questions %}?reset_tags=true">{% trans %}reset tags{% endtrans %}</a>
+ {% endif %}
+ {% if query %}{% trans %} or {% endtrans %}
+ <a href="{% url questions %}?start_over=true">{% trans %}start over{% endtrans %}</a>
+ {% endif %}
+ {% else %}
+ <a href="{% url questions %}?start_over=true">{% trans %}start over{% endtrans %}</a>
+ {% endif %}
+ {% trans %} - to expand, or dig in by adding more tags and revising the query.{% endtrans %}
+ </p>
+ {% else %}
+ <p class="search-tips">{% trans %}Search tip:{% endtrans %} {% trans %}add tags and a query to focus your search{% endtrans %}</p>
+ {% endif %}
+ </div>
+{% endif %}
diff --git a/askbot/skins/default/templates/main_page/javascript.html b/askbot/skins/default/templates/main_page/javascript.html
new file mode 100644
index 00000000..09a5d15b
--- /dev/null
+++ b/askbot/skins/default/templates/main_page/javascript.html
@@ -0,0 +1,26 @@
+<script type="text/javascript">
+ var sortMethod = '{{sort}}';
+ var showSortByRelevance = {% if show_sort_by_relevance %}true{% else %}false{% endif %};
+ var minSearchWordLength = {{settings.MIN_SEARCH_WORD_LENGTH}};
+ $(document).ready(function(){
+ /*var on_tab = '#nav_questions';
+ $(on_tab).attr('className','on');*/
+ liveSearch().init('main_page');
+ Hilite.exact = false;
+ Hilite.elementid = "question-list";
+ Hilite.debug_referrer = location.href;
+ });
+ askbot['urls']['mark_interesting_tag'] = scriptUrl + '{% trans %}mark-tag/{% endtrans %}{% trans %}interesting/{% endtrans %}';
+ askbot['urls']['mark_ignored_tag'] = scriptUrl + '{% trans %}mark-tag/{% endtrans %}{% trans %}ignored/{% endtrans %}';
+ askbot['urls']['unmark_tag'] = scriptUrl + '{% trans %}unmark-tag/{% endtrans %}';
+ askbot['urls']['set_tag_filter_strategy'] = '{% url "set_tag_filter_strategy" %}';
+ askbot['urls']['questions'] = '{% url "questions" %}';
+ askbot['urls']['question_url_template'] = scriptUrl + '{% trans %}question/{% endtrans %}{{ "{{QuestionID}}/" }}';
+ askbot['urls']['user_url_template'] = scriptUrl + '{% trans %}users/{% endtrans %}{{ "{{user_id}}" }}/{{ "{{slug}}" }}/';
+ askbot['messages']['name_of_anonymous_user'] = '{{ name_of_anonymous_user }}';
+</script>
+<script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
+{% if request.user.is_authenticated() %}
+<script type='text/javascript' src='{{"/js/tag_selector.js"|media}}'></script>
+{% endif %}
+<script type="text/javascript" src="{{"/js/live_search.js"|media}}"></script>
diff --git a/askbot/skins/default/templates/main_page/nothing_found.html b/askbot/skins/default/templates/main_page/nothing_found.html
new file mode 100644
index 00000000..bc58fc27
--- /dev/null
+++ b/askbot/skins/default/templates/main_page/nothing_found.html
@@ -0,0 +1,31 @@
+{# todo: add tips to widen selection #}
+<p class="evenMore" style="padding-top:30px;text-align:center;">
+{% if scope == "unanswered" %}
+ {% trans %}There are no unanswered questions here{% endtrans %}
+{% endif %}
+{% if scope == "favorite" %}
+ {% trans %}No favorite questions here. {% endtrans %}
+ {% trans %}Please start (bookmark) some questions when you visit them{% endtrans %}
+{% endif %}
+</p>
+{% if query or search_tags or author_name %}
+<p class="evenMore" style="text-align:center">
+ {% trans %}You can expand your search by {% endtrans %}
+ {% if reset_method_count > 1 %}
+ {% if author_name %}
+ <a href="{% url questions %}?reset_author=true">{% trans %}resetting author{% endtrans %}</a>
+ {% endif %}
+ {% if search_tags %}{% if author_name and query %}, {% elif author_name %}{% trans %} or {% endtrans %}{% endif %}
+ <a href="{% url questions %}?reset_tags=true">{% trans %}resetting tags{% endtrans %}</a>
+ {% endif %}
+ {% if query %}{% trans %} or {% endtrans %}
+ <a href="{% url questions %}?start_over=true">{% trans %}starting over{% endtrans %}</a>
+ {% endif %}
+ {% else %}
+ <a href="{% url questions %}?start_over=true">{% trans %}starting over{% endtrans %}</a>
+ {% endif %}
+</p>
+{% endif %}
+<p class="evenMore" style="text-align:center">
+<a href="{% url ask %}">{% trans %}Please always feel free to ask your question!{% endtrans %}</a>
+</p>
diff --git a/askbot/skins/default/templates/main_page/paginator.html b/askbot/skins/default/templates/main_page/paginator.html
new file mode 100644
index 00000000..4a77060f
--- /dev/null
+++ b/askbot/skins/default/templates/main_page/paginator.html
@@ -0,0 +1,7 @@
+{% import "macros.html" as macros %}
+{% if questions_count > 10 %}{# todo: remove magic number #}
+ <div id="pager" class="pager">
+ {{ macros.paginator(context|setup_paginator, position='left') }}
+ {{ macros.pagesize_switch(context, position='right') }}
+ </div>
+{% endif %}
diff --git a/askbot/skins/default/templates/main_page/sidebar.html b/askbot/skins/default/templates/main_page/sidebar.html
new file mode 100644
index 00000000..52d107af
--- /dev/null
+++ b/askbot/skins/default/templates/main_page/sidebar.html
@@ -0,0 +1,37 @@
+{% import "macros.html" as macros %}
+{% if contributors %}
+ {% cache 600 "contributors" contributors search_tags scope sort query context.page context.page_size language_code %}
+ <div id="contrib-users" class="boxC">
+ <h2>{% trans %}Contributors{% endtrans %}</h2>
+ {% spaceless %}
+ {% for person in contributors %}
+ {{ macros.gravatar(person,48) }}
+ {% endfor %}
+ {% endspaceless %}
+ </div>
+ {% endcache %}
+{% endif %}
+
+{% if request.user.is_authenticated() %}
+ {% include "blocks/tag_selector.html" %}
+{% endif %}
+
+{% if tags %}
+ {% cache 0 "tags" tags search_tags scope sort query context.page context.page_size language_code %}
+ <div class="boxC">
+ <h2>{% trans %}Related tags{% endtrans %}</h2>
+ <ul id="related-tags" class="tags">
+ {% for tag in tags %}
+ <li>
+ {{ macros.tag_widget(
+ tag.name,
+ html_tag = 'div',
+ extra_content = '<span class="tag-number">&#215; ' ~
+ tag.local_used_count|intcomma ~ '</span>'
+ )}}
+ </li>
+ {% endfor %}
+ </ul>
+ </div>
+ {% endcache %}
+{% endif %}
diff --git a/askbot/skins/default/templates/main_page/tab_bar.html b/askbot/skins/default/templates/main_page/tab_bar.html
new file mode 100644
index 00000000..9189db13
--- /dev/null
+++ b/askbot/skins/default/templates/main_page/tab_bar.html
@@ -0,0 +1,86 @@
+{% import "macros.html" as macros %}
+{% cache 600 "scope_sort_tabs" search_tags request.user scope sort query context.page context.page_size language_code %}
+<div class="tabBar">
+ <div class="tabsC">
+ <span class="label">{% trans %}In:{% endtrans %}</span>
+ <a id="all"
+ class="{% if scope == 'all' %}on{% else %}off{% endif %}"
+ href="?scope=all"
+ title="{% trans %}see all questions{% endtrans %}"
+ ><span>{% trans %}all{% endtrans %}</span></a>
+ <a id="unanswered"
+ class="{% if scope == 'unanswered' %}on{% else %}off{% endif %}"
+ href="?scope=unanswered&amp;sort=answers-asc"
+ title="{% trans %}see unanswered questions{% endtrans %}"
+ ><span>{% trans %}unanswered{% endtrans %}</span></a>
+ {% if request.user.is_authenticated() %}
+ <a id="favorite"
+ class="{% if scope == 'favorite' %}on{% else %}off{% endif %}"
+ href="?scope=favorite"
+ title="{% trans %}see your favorite questions{% endtrans %}"
+ ><span>{% trans %}favorite{% endtrans %}</span></a>
+ {% endif %}
+ </div>
+ <div id="sort_tabs" class="tabsA">
+ <span class="label">{% trans %}Sort by:{% endtrans %}</span>
+ {% if show_sort_by_relevance %}
+ {% set asc_relevance_tooltip = _('most relevant questions') %}
+ {% set desc_relevance_tooltip = _('click to see most relevant questions') %}
+ {% set relevance_label = _('relevance') %}
+ {% if query %}
+ <a id="by_relevance"
+ {% if sort == "relevance-desc" %}
+ href="?sort=relevance-desc"
+ class="on"
+ title="{{asc_relevance_tooltip}}"><span>{{relevance_label}} &#9660;</span>
+ {% else %}
+ href="?sort=relevance-desc"
+ class="off"
+ title="{{desc_relevance_tooltip}}"><span>{{relevance_label}}</span>
+ {% endif %}
+ </a>
+ {% endif %}
+ <script type="text/javascript">
+ var sortButtonData = sortButtonData || {};
+ sortButtonData['relevance'] = {
+ asc_tooltip: "{{asc_relevance_tooltip}}",
+ desc_tooltip: "{{desc_relevance_tooltip}}",
+ label: "{{relevance_label}}",
+ };
+ </script>
+ {% endif %}
+ {{macros.reversible_sort_button(
+ button_sort_criterium = 'age',
+ label = _('by date'),
+ asc_tooltip = _('click to see the oldest questions'),
+ desc_tooltip = _('click to see the newest questions'),
+ current_sort_method = sort
+ )
+ }}
+ {{macros.reversible_sort_button(
+ button_sort_criterium = 'activity',
+ label = _('by activity'),
+ asc_tooltip = _('click to see the least recently updated questions'),
+ desc_tooltip = _('click to see the most recently updated questions'),
+ current_sort_method = sort
+ )
+ }}
+ {{macros.reversible_sort_button(
+ button_sort_criterium = 'answers',
+ label = _('by answers'),
+ asc_tooltip = _('click to see the least answered questions'),
+ desc_tooltip = _('click to see the most answered questions'),
+ current_sort_method = sort
+ )
+ }}
+ {{macros.reversible_sort_button(
+ button_sort_criterium = 'votes',
+ label = _('by votes'),
+ asc_tooltip = _('click to see least voted questions'),
+ desc_tooltip = _('click to see most voted questions'),
+ current_sort_method = sort
+ )
+ }}
+ </div>
+</div>
+{% endcache %}
diff --git a/askbot/skins/default/templates/one_column_body.html b/askbot/skins/default/templates/one_column_body.html
index f920a1ed..e97de505 100644
--- a/askbot/skins/default/templates/one_column_body.html
+++ b/askbot/skins/default/templates/one_column_body.html
@@ -1,17 +1,9 @@
{% extends "base.html" %}
+{% block body_class %}one-col{% endblock %}
{% block body %}
-<div id="wrapper">
- <div id="room">
- <div id="CAFull">
- {% include "input_bar.html" %}
- {% block content%}
- {% endblock%}
- </div>
- <div id="tail" style="clear:both;">
- {% block tail %}
- {% endblock %}
- </div>
- </div>
- <div class="spacer3"></div>
+<div id="CAFull">
+ {% include "blocks/input_bar.html" %}
+ {% block content%}
+ {% endblock%}
</div>
{% endblock %}
diff --git a/askbot/skins/default/templates/privacy.html b/askbot/skins/default/templates/privacy.html
index deb49053..61f4d945 100644
--- a/askbot/skins/default/templates/privacy.html
+++ b/askbot/skins/default/templates/privacy.html
@@ -2,11 +2,7 @@
<!-- privacy.html -->
{% block title %}{% spaceless %}{% trans %}Privacy policy{% endtrans %}{% endspaceless %}{% endblock %}
{% block content %}
-<div class="headNormal">
- {% trans %}Privacy policy{% endtrans %}
-</div>
-<div id="main-body" style="width:100%">
- {{settings.FORUM_PRIVACY}}
-</div>
+<h1>{% trans %}Privacy policy{% endtrans %}</h1>
+{{settings.FORUM_PRIVACY}}
{% endblock %}
<!-- end privacy.html -->
diff --git a/askbot/skins/default/templates/question.html b/askbot/skins/default/templates/question.html
index e0bd062f..d95fd6c0 100644
--- a/askbot/skins/default/templates/question.html
+++ b/askbot/skins/default/templates/question.html
@@ -11,364 +11,365 @@
<link rel="stylesheet" type="text/css" href="{{"/js/wmd/wmd.css"|media}}" />
{% endblock %}
{% block content %}
-<div class="headNormal">
- <a href="{{ question.get_absolute_url() }}">{{ question.get_question_title() }}</a>
-</div>
-<div id="main-body" class="">
- <div id="askform">
- <table style="width:100%;" id="question-table" {% if question.deleted %}class="deleted"{%endif%}>
- <tr>
- <td style="width:30px;vertical-align:top">
- <div class="vote-buttons">
- {% if question_vote %}
- <img id="question-img-upvote-{{ question.id }}" class="question-img-upvote"
- {% if question_vote.is_upvote() %}
- src="{{"/images/vote-arrow-up-on.png"|media}}"
- {% else %}
- src="{{"/images/vote-arrow-up.png"|media}}"
- {% endif %}
- alt="{% trans %}i like this post (click again to cancel){% endtrans %}"
- title="{% trans %}i like this post (click again to cancel){% endtrans %}" />
- <div id="question-vote-number-{{ question.id }}" class="vote-number"
- title="{% trans %}current number of votes{% endtrans %}">
- {{ question.score }}
- </div>
- <img id="question-img-downvote-{{ question.id }}" class="question-img-downvote"
- {% if question_vote.is_downvote() %}
- src="{{"/images/vote-arrow-down-on.png"|media}}"
- {% else %}
- src="{{"/images/vote-arrow-down.png"|media}}"
- {% endif %}
- alt="{% trans %}i dont like this post (click again to cancel){% endtrans %}"
- title="{% trans %}i dont like this post (click again to cancel){% endtrans %}" />
+<h1><a href="{{ question.get_absolute_url() }}">{{ question.get_question_title() }}</a></h1>
+<div id="askform">
+ <table style="width:100%;" id="question-table" {% if question.deleted %}class="deleted"{%endif%}>
+ <tr>
+ <td style="width:30px;vertical-align:top">
+ <div class="vote-buttons">
+ {% if question_vote %}
+ <img id="question-img-upvote-{{ question.id }}" class="question-img-upvote"
+ {% if question_vote.is_upvote() %}
+ src="{{"/images/vote-arrow-up-on.png"|media}}"
{% else %}
- <img id="question-img-upvote-{{ question.id }}" class="question-img-upvote"
- alt="{% trans %}i like this post (click again to cancel){% endtrans %}"
src="{{"/images/vote-arrow-up.png"|media}}"
- title="{% trans %}i like this post (click again to cancel){% endtrans %}" />
- <div id="question-vote-number-{{ question.id }}" class="vote-number"
- title="{% trans %}current number of votes{% endtrans %}">
- {{ question.score }}
- </div>
- <img id="question-img-downvote-{{ question.id }}" class="question-img-downvote"
- src="{{"/images/vote-arrow-down.png"|media}}"
- alt="{% trans %}i dont like this post (click again to cancel){% endtrans %}"
- title="{% trans %}i dont like this post (click again to cancel){% endtrans %}" />
{% endif %}
- {% if favorited %}
- <img class="question-img-favorite" src="{{"/images/vote-favorite-on.png"|media}}"
- alt="{% trans %}mark this question as favorite (click again to cancel){% endtrans %}"
- title="{% trans %}mark this question as favorite (click again to cancel){% endtrans %}" />
- <div id="favorite-number" class="favorite-number my-favorite-number">
- {{ question.favourite_count }}
- </div>
+ alt="{% trans %}i like this post (click again to cancel){% endtrans %}"
+ title="{% trans %}i like this post (click again to cancel){% endtrans %}" />
+ <div id="question-vote-number-{{ question.id }}" class="vote-number"
+ title="{% trans %}current number of votes{% endtrans %}">
+ {{ question.score }}
+ </div>
+ <img id="question-img-downvote-{{ question.id }}" class="question-img-downvote"
+ {% if question_vote.is_downvote() %}
+ src="{{"/images/vote-arrow-down-on.png"|media}}"
{% else %}
- <img class="question-img-favorite" src="{{"/images/vote-favorite-off.png"|media}}"
- alt="{% trans %}remove favorite mark from this question (click again to restore mark){% endtrans %}"
- title="{% trans %}remove favorite mark from this question (click again to restore mark){% endtrans %}" />
- <div id="favorite-number" class="favorite-number">
- {% if question.favourite_count != 0 %}{{ question.favourite_count }}{% endif %}
- </div>
- {% endif %}
- {% if settings.ENABLE_SOCIAL_SHARING %}
- <a class="twitter-share" alt="{% trans %}Share this question on twitter{% endtrans %}"></a>
- <a class="fb-share" alt="{% trans %}Share this question on facebook{% endtrans %}"></a>
+ src="{{"/images/vote-arrow-down.png"|media}}"
{% endif %}
+ alt="{% trans %}i dont like this post (click again to cancel){% endtrans %}"
+ title="{% trans %}i dont like this post (click again to cancel){% endtrans %}" />
+ {% else %}
+ <img id="question-img-upvote-{{ question.id }}" class="question-img-upvote"
+ alt="{% trans %}i like this post (click again to cancel){% endtrans %}"
+ src="{{"/images/vote-arrow-up.png"|media}}"
+ title="{% trans %}i like this post (click again to cancel){% endtrans %}" />
+ <div id="question-vote-number-{{ question.id }}" class="vote-number"
+ title="{% trans %}current number of votes{% endtrans %}">
+ {{ question.score }}
</div>
- </td>
- <td>
- <div id="item-right">
- <div class="question-body">
- {{question.html}}
- </div>
- <div id="question-tags" class="post-tags tags">
- {% for tag in question.get_tag_names() %}
- <a href="{% url questions %}?tags={{tag|urlencode}}&amp;start_over=true"
- class="post-tag"
- title="{% trans %}see questions tagged '{{tag}}'{% endtrans %}" rel="tag">{{ tag }}</a>
- {% endfor %}
- </div>
- <div id="question-controls" class="post-controls">
- {% set pipe=joiner('<span class="sep">|</span>') %}
- {% if request.user|can_edit_post(question) %}{{ pipe() }}
- <a href="{% url edit_question question.id %}">{% trans %}edit{% endtrans %}</a>
- {% endif %}
- {% if request.user|can_retag_question(question) %}{{ pipe() }}
- <a id="retag" href="{% url retag_question question.id %}">{% trans %}retag{% endtrans %}</a>
- <script type="text/javascript">
- var retagUrl = "{% url retag_question question.id %}";
- </script>
- {% endif %}
- {% if question.closed %}
- {% if request.user|can_reopen_question(question) %}{{ pipe() }}
- <a href="{% url reopen question.id %}">{% trans %}reopen{% endtrans %}</a>
- {% endif %}
- {% else %}
- {% if request.user|can_close_question(question) %}{{ pipe() }}
- <a href="{% url close question.id %}">{% trans %}close{% endtrans %}</a>
- {% endif %}
- {% endif %}
- {% if request.user|can_flag_offensive(question) %}{{ pipe() }}
- <span id="question-offensive-flag-{{ question.id }}" class="offensive-flag"
- title="{% trans %}report as offensive (i.e containing spam, advertising, malicious text, etc.){% endtrans %}">
- <a>{% trans %}flag offensive{% endtrans %}</a>
- {% if request.user|can_see_offensive_flags(question) %}
- <span class="darkred">{% if question.offensive_flag_count > 0 %}({{ question.offensive_flag_count }}){% endif %}</span>
- {% endif %}
- </span>
- {% endif %}
- {% if request.user|can_delete_post(question) %}{{ pipe() }}
- <a id="question-delete-link-{{question.id}}">{% if question.deleted %}{% trans %}undelete{% endtrans %}{% else %}{% trans %}delete{% endtrans %}{% endif %}</a>
- {% endif %}
- </div>
- </div>
- <div class="post-update-info-container">
- {{
- macros.post_contributor_info(
- question,
- "original_author",
- question.wiki,
- settings.MIN_REP_TO_EDIT_WIKI
- )
- }}
- {{
- macros.post_contributor_info(
- question,
- "last_updater",
- question.wiki,
- settings.MIN_REP_TO_EDIT_WIKI,
- )
- }}
- </div>
- {{
- macros.post_comments_widget(
- post = question,
- show_post = show_post,
- show_comment = show_comment,
- comment_order_number = comment_order_number,
- user = request.user,
- max_comments = settings.MAX_COMMENTS_TO_SHOW
- )
- }}
+ <img id="question-img-downvote-{{ question.id }}" class="question-img-downvote"
+ src="{{"/images/vote-arrow-down.png"|media}}"
+ alt="{% trans %}i dont like this post (click again to cancel){% endtrans %}"
+ title="{% trans %}i dont like this post (click again to cancel){% endtrans %}" />
+ {% endif %}
+ {% if favorited %}
+ <img class="question-img-favorite" src="{{"/images/vote-favorite-on.png"|media}}"
+ alt="{% trans %}mark this question as favorite (click again to cancel){% endtrans %}"
+ title="{% trans %}mark this question as favorite (click again to cancel){% endtrans %}" />
+ <div id="favorite-number" class="favorite-number my-favorite-number">
+ {{ question.favourite_count }}
</div>
- </td>
- </tr>
- </table>
- {% if question.closed %}
- <div class="question-status" style="margin-bottom:15px">
- <h3>{% trans close_reason=question.get_close_reason_display() %}The question has been closed for the following reason "{{ close_reason }}" by{% endtrans %}
- <a href="{{ question.closed_by.get_profile_url() }}">{{ question.closed_by.username }}</a>
- {% trans closed_at=question.closed_at %}close date {{closed_at}}{% endtrans %}</h3>
- </div>
- {% endif %}
- {% if answers %}
- <hr/>
- <div class="tabBar">
- <a name="sort-top"></a>
- <div class="headUsers">
- {% trans counter=answers|length %}
- {{counter}} Answer:
- {% pluralize %}
- {{counter}} Answers:
- {% endtrans %}
+ {% else %}
+ <img class="question-img-favorite" src="{{"/images/vote-favorite-off.png"|media}}"
+ alt="{% trans %}remove favorite mark from this question (click again to restore mark){% endtrans %}"
+ title="{% trans %}remove favorite mark from this question (click again to restore mark){% endtrans %}" />
+ <div id="favorite-number" class="favorite-number">
+ {% if question.favourite_count != 0 %}{{ question.favourite_count }}{% endif %}
+ </div>
+ {% endif %}
+ {% if settings.ENABLE_SOCIAL_SHARING %}
+ <a class="twitter-share" alt="{% trans %}Share this question on twitter{% endtrans %}"></a>
+ <a class="fb-share" alt="{% trans %}Share this question on facebook{% endtrans %}"></a>
+ {% endif %}
+ </div>
+ </td>
+ <td>
+ <div class="question-body">
+ {{question.html}}
+ </div>
+ <ul id="question-tags" class="post-tags tags">
+ {% for tag in question.get_tag_names() %}
+ {{ macros.tag_widget(
+ tag,
+ css_class = 'post-tag',
+ html_tag = 'li'
+ )
+ }}
+ {% endfor %}
+ </ul>
+ <div id="question-controls" class="post-controls">
+ {% set pipe=joiner('<span class="sep">|</span>') %}
+ {% if request.user|can_edit_post(question) %}{{ pipe() }}
+ <a href="{% url edit_question question.id %}">{% trans %}edit{% endtrans %}</a>
+ {% endif %}
+ {% if request.user|can_retag_question(question) %}{{ pipe() }}
+ <a id="retag" href="{% url retag_question question.id %}">{% trans %}retag{% endtrans %}</a>
+ <script type="text/javascript">
+ var retagUrl = "{% url retag_question question.id %}";
+ </script>
+ {% endif %}
+ {% if question.closed %}
+ {% if request.user|can_reopen_question(question) %}{{ pipe() }}
+ <a href="{% url reopen question.id %}">{% trans %}reopen{% endtrans %}</a>
+ {% endif %}
+ {% else %}
+ {% if request.user|can_close_question(question) %}{{ pipe() }}
+ <a href="{% url close question.id %}">{% trans %}close{% endtrans %}</a>
+ {% endif %}
+ {% endif %}
+ {% if request.user|can_flag_offensive(question) %}{{ pipe() }}
+ <span id="question-offensive-flag-{{ question.id }}" class="offensive-flag"
+ title="{% trans %}report as offensive (i.e containing spam, advertising, malicious text, etc.){% endtrans %}">
+ <a>{% trans %}flag offensive{% endtrans %}</a>
+ {% if request.user|can_see_offensive_flags(question) %}
+ <span class="darkred">{% if question.offensive_flag_count > 0 %}({{ question.offensive_flag_count }}){% endif %}</span>
+ {% endif %}
+ </span>
+ {% endif %}
+ {% if request.user|can_delete_post(question) %}{{ pipe() }}
+ <a id="question-delete-link-{{question.id}}">{% if question.deleted %}{% trans %}undelete{% endtrans %}{% else %}{% trans %}delete{% endtrans %}{% endif %}</a>
+ {% endif %}
</div>
- <div class="tabsA">
- <a id="oldest" href="{{ question.get_absolute_url() }}?sort=oldest#sort-top"
- title="{% trans %}oldest answers will be shown first{% endtrans %}">{% trans %}oldest answers{% endtrans %}</a>
- <a id="latest" href="{{ question.get_absolute_url() }}?sort=latest#sort-top"
- title="{% trans %}newest answers will be shown first{% endtrans %}">{% trans %}newest answers{% endtrans %}</a>
- <a id="votes" href="{{ question.get_absolute_url() }}?sort=votes#sort-top"
- title="{% trans %}most voted answers will be shown first{% endtrans %}">{% trans %}popular answers{% endtrans %}</a>
+ <div class="post-update-info-container">
+ {{
+ macros.post_contributor_info(
+ question,
+ "original_author",
+ question.wiki,
+ settings.MIN_REP_TO_EDIT_WIKI
+ )
+ }}
+ {{
+ macros.post_contributor_info(
+ question,
+ "last_updater",
+ question.wiki,
+ settings.MIN_REP_TO_EDIT_WIKI,
+ )
+ }}
</div>
+ {{
+ macros.post_comments_widget(
+ post = question,
+ show_post = show_post,
+ show_comment = show_comment,
+ comment_order_number = comment_order_number,
+ user = request.user,
+ max_comments = settings.MAX_COMMENTS_TO_SHOW
+ )
+ }}
+ <!--/div-->
+ </td>
+ </tr>
+ </table>
+ {% if question.closed %}
+ <div class="question-status" style="margin-bottom:15px">
+ <h3>{% trans close_reason=question.get_close_reason_display() %}The question has been closed for the following reason "{{ close_reason }}" by{% endtrans %}
+ <a href="{{ question.closed_by.get_profile_url() }}">{{ question.closed_by.username }}</a>
+ {% trans closed_at=question.closed_at %}close date {{closed_at}}{% endtrans %}</h3>
+ </div>
+ {% endif %}
+ {% if answers %}
+ <div class="tabBar">
+ <h2 id="sort-top">
+ {% trans counter=answers|length %}
+ {{counter}} Answer:
+ {% pluralize %}
+ {{counter}} Answers:
+ {% endtrans %}
+ </h2>
+ <div class="tabsA">
+ <a id="oldest" href="{{ question.get_absolute_url() }}?sort=oldest#sort-top"
+ title="{% trans %}oldest answers will be shown first{% endtrans %}"
+ ><span>{% trans %}oldest answers{% endtrans %}</span></a>
+ <a id="latest" href="{{ question.get_absolute_url() }}?sort=latest#sort-top"
+ title="{% trans %}newest answers will be shown first{% endtrans %}"
+ ><span>{% trans %}newest answers{% endtrans %}</span></a>
+ <a id="votes" href="{{ question.get_absolute_url() }}?sort=votes#sort-top"
+ title="{% trans %}most voted answers will be shown first{% endtrans %}"
+ ><span>{% trans %}popular answers{% endtrans %}</span></a>
</div>
- {{ macros.paginator(paginator_context) }}
+ </div>
+ {{ macros.paginator(paginator_context) }}
- {% for answer in answers %}
- <a name="{{ answer.id }}"></a>
- <div id="answer-container-{{ answer.id }}" class="answer {% if answer.accepted %}accepted-answer{% endif %} {% if answer.author_id==question.author_id %} answered-by-owner{% endif %} {% if answer.deleted %}deleted{% endif %}">
- <table style="width:100%;">
- <tr>
- <td style="width:30px;vertical-align:top">
- <div class="vote-buttons">
- <img id="answer-img-upvote-{{ answer.id }}" class="answer-img-upvote"
- {% if user_answer_votes[answer.id] == 1 %}
- src="{{"/images/vote-arrow-up-on.png"|media}}"
- {% else %}
- src="{{"/images/vote-arrow-up.png"|media}}"
- {% endif %}
- alt="{% trans %}i like this answer (click again to cancel){% endtrans %}"
- title="{% trans %}i like this answer (click again to cancel){% endtrans %}"/>
- <div id="answer-vote-number-{{ answer.id }}" class="vote-number" title="{% trans %}current number of votes{% endtrans %}">
- {{ answer.score }}
- </div>
- <img id="answer-img-downvote-{{ answer.id }}" class="answer-img-downvote"
- {% if user_answer_votes[answer.id] == -1 %}
- src="{{"/images/vote-arrow-down-on.png"|media}}"
- {% else %}
- src="{{"/images/vote-arrow-down.png"|media}}"
- {% endif %}
- alt="{% trans %}i dont like this answer (click again to cancel){% endtrans %}"
- title="{% trans %}i dont like this answer (click again to cancel){% endtrans %}" />
- {% if request.user == question.author %}
+ {% for answer in answers %}
+ <a name="{{ answer.id }}"></a>
+ <div id="answer-container-{{ answer.id }}" class="answer {% if answer.accepted %}accepted-answer{% endif %} {% if answer.author_id==question.author_id %} answered-by-owner{% endif %} {% if answer.deleted %}deleted{% endif %}">
+ <table style="width:100%;" class="answer-table">
+ <tr>
+ <td style="width:30px;vertical-align:top">
+ <div class="vote-buttons">
+ <img id="answer-img-upvote-{{ answer.id }}" class="answer-img-upvote"
+ {% if user_answer_votes[answer.id] == 1 %}
+ src="{{"/images/vote-arrow-up-on.png"|media}}"
+ {% else %}
+ src="{{"/images/vote-arrow-up.png"|media}}"
+ {% endif %}
+ alt="{% trans %}i like this answer (click again to cancel){% endtrans %}"
+ title="{% trans %}i like this answer (click again to cancel){% endtrans %}"/>
+ <div id="answer-vote-number-{{ answer.id }}" class="vote-number" title="{% trans %}current number of votes{% endtrans %}">
+ {{ answer.score }}
+ </div>
+ <img id="answer-img-downvote-{{ answer.id }}" class="answer-img-downvote"
+ {% if user_answer_votes[answer.id] == -1 %}
+ src="{{"/images/vote-arrow-down-on.png"|media}}"
+ {% else %}
+ src="{{"/images/vote-arrow-down.png"|media}}"
+ {% endif %}
+ alt="{% trans %}i dont like this answer (click again to cancel){% endtrans %}"
+ title="{% trans %}i dont like this answer (click again to cancel){% endtrans %}" />
+ {% if request.user == question.author %}
+ <img id="answer-img-accept-{{ answer.id }}" class="answer-img-accept"
+ {% if answer.accepted %}
+ src="{{"/images/vote-accepted-on.png"|media}}"
+ {% else %}
+ src="{{"/images/vote-accepted.png"|media}}"
+ {% endif %}
+ alt="{% trans %}mark this answer as favorite (click again to undo){% endtrans %}"
+ title="{% trans %}mark this answer as favorite (click again to undo){% endtrans %}" />
+ {% else %}
+ {% if answer.accepted %}
<img id="answer-img-accept-{{ answer.id }}" class="answer-img-accept"
{% if answer.accepted %}
src="{{"/images/vote-accepted-on.png"|media}}"
{% else %}
- src="{{"/images/vote-accepted.png"|media}}"
- {% endif %}
- alt="{% trans %}mark this answer as favorite (click again to undo){% endtrans %}"
- title="{% trans %}mark this answer as favorite (click again to undo){% endtrans %}" />
- {% else %}
- {% if answer.accepted %}
- <img id="answer-img-accept-{{ answer.id }}" class="answer-img-accept"
- {% if answer.accepted %}
- src="{{"/images/vote-accepted-on.png"|media}}"
- {% else %}
- src="{{"/images/vote-accepted.png"|media}}"
- {% endif %}
- alt="{% trans question_author=question.author.username %}{{question_author}} has selected this answer as correct{% endtrans %}"
- title="{% trans questsion_author=question.author.username%}{{question_author}} has selected this answer as correct{% endtrans %}"
+ src="{{"/images/vote-accepted.png"|media}}"
{% endif %}
+ alt="{% trans question_author=question.author.username %}{{question_author}} has selected this answer as correct{% endtrans %}"
+ title="{% trans questsion_author=question.author.username%}{{question_author}} has selected this answer as correct{% endtrans %}"
{% endif %}
+ {% endif %}
+ </div>
+ </td>
+ <td>
+ <div class="item-right">
+ <div class="answer-body">
+ {{ answer.html }}
</div>
- </td>
- <td>
- <div class="item-right">
- <div class="answer-body">
- {{ answer.html }}
- </div>
- <div class="answer-controls post-controls">
- {% set pipe=joiner('<span class="sep">|</span>') %}
- <span class="linksopt">{{ pipe() }}
- <a
- href="{{ answer.get_absolute_url() }}"
- title="{% trans %}answer permanent link{% endtrans %}">
- {% trans %}permanent link{% endtrans %}
- </a>
- </span>
- {% if request.user|can_edit_post(answer) %}{{ pipe() }}
- <span class="action-link"><a href="{% url edit_answer answer.id %}">{% trans %}edit{% endtrans %}</a></span>
+ <div class="answer-controls post-controls">
+ {% set pipe=joiner('<span class="sep">|</span>') %}
+ <span class="linksopt">{{ pipe() }}
+ <a
+ href="{{ answer.get_absolute_url() }}"
+ title="{% trans %}answer permanent link{% endtrans %}">
+ {% trans %}permanent link{% endtrans %}
+ </a>
+ </span>
+ {% if request.user|can_edit_post(answer) %}{{ pipe() }}
+ <span class="action-link"><a href="{% url edit_answer answer.id %}">{% trans %}edit{% endtrans %}</a></span>
+ {% endif %}
+ {% if request.user|can_flag_offensive(answer) %}{{ pipe() }}
+ <span id="answer-offensive-flag-{{ answer.id }}" class="offensive-flag"
+ title="{% trans %}report as offensive (i.e containing spam, advertising, malicious text, etc.){% endtrans %}">
+ <a>{% trans %}flag offensive{% endtrans %}</a>
+ {% if request.user|can_see_offensive_flags(answer) %}
+ <span class="darkred">{% if answer.offensive_flag_count > 0 %}({{ answer.offensive_flag_count }}){% endif %}</span>
{% endif %}
- {% if request.user|can_flag_offensive(answer) %}{{ pipe() }}
- <span id="answer-offensive-flag-{{ answer.id }}" class="offensive-flag"
- title="{% trans %}report as offensive (i.e containing spam, advertising, malicious text, etc.){% endtrans %}">
- <a>{% trans %}flag offensive{% endtrans %}</a>
- {% if request.user|can_see_offensive_flags(answer) %}
- <span class="darkred">{% if answer.offensive_flag_count > 0 %}({{ answer.offensive_flag_count }}){% endif %}</span>
- {% endif %}
+ </span>
+ {% endif %}
+ {% if request.user|can_delete_post(answer) %}{{ pipe() }}
+ {% spaceless %}
+ <span class="action-link">
+ <a id="answer-delete-link-{{answer.id}}">
+ {% if answer.deleted %}{% trans %}undelete{% endtrans %}{% else %}{% trans %}delete{% endtrans %}{% endif %}</a>
</span>
- {% endif %}
- {% if request.user|can_delete_post(answer) %}{{ pipe() }}
- {% spaceless %}
- <span class="action-link">
- <a id="answer-delete-link-{{answer.id}}">
- {% if answer.deleted %}{% trans %}undelete{% endtrans %}{% else %}{% trans %}delete{% endtrans %}{% endif %}</a>
- </span>
- {% endspaceless %}
- {% endif %}
- </div>
- <div class="post-update-info-container">
- {{
- macros.post_contributor_info(
- answer,
- "original_author",
- answer.wiki,
- settings.MIN_REP_TO_EDIT_WIKI
- )
- }}
- {{
- macros.post_contributor_info(
- answer,
- "last_updater",
- answer.wiki,
- settings.MIN_REP_TO_EDIT_WIKI
- )
- }}
- </div>
- {{
- macros.post_comments_widget(
- post = answer,
- show_post = show_post,
- show_comment = show_comment,
- comment_order_number = comment_order_number,
- user = request.user,
- max_comments = settings.MAX_COMMENTS_TO_SHOW
+ {% endspaceless %}
+ {% endif %}
+ </div>
+ <div class="post-update-info-container">
+ {{
+ macros.post_contributor_info(
+ answer,
+ "original_author",
+ answer.wiki,
+ settings.MIN_REP_TO_EDIT_WIKI
+ )
+ }}
+ {{
+ macros.post_contributor_info(
+ answer,
+ "last_updater",
+ answer.wiki,
+ settings.MIN_REP_TO_EDIT_WIKI
)
- }}
+ }}
</div>
- </td>
- </tr>
- </table>
- </div>
- {% endfor %}
- <div class="paginator-container-left">
- {{ macros.paginator(paginator_context) }}
+ {{
+ macros.post_comments_widget(
+ post = answer,
+ show_post = show_post,
+ show_comment = show_comment,
+ comment_order_number = comment_order_number,
+ user = request.user,
+ max_comments = settings.MAX_COMMENTS_TO_SHOW
+ )
+ }}
+ </div>
+ </td>
+ </tr>
+ </table>
</div>
+ {% endfor %}
+ <div class="paginator-container-left">
+ {{ macros.paginator(paginator_context) }}
+ </div><br/>
+ {% endif %}
+<form id="fmanswer" action="{% url answer question.id %}" method="post">
+ {% if request.user.is_authenticated() %}
+ <p style="padding-left:3px">
+ {{ answer.email_notify }}
+ <label for="question-subscribe-updates">
+ {% set email_feed_frequency = request.user.get_q_sel_email_feed_frequency() %}
+ {% if email_feed_frequency =='n' %}
+ {% trans %}Notify me once a day when there are any new answers{% endtrans %}
+ {% elif email_feed_frequency =='d' %}
+ {% trans %}Notify me once a day when there are any new answers{% endtrans %}
+ {% elif email_feed_frequency =='w' %}
+ {% trans %}Notify me weekly when there are any new answers{% endtrans %}
+ {% elif email_feed_frequency =='i' %}
+ {% trans %}Notify me immediately when there are any new answers{% endtrans %}
{% endif %}
- <form id="fmanswer" action="{% url answer question.id %}" method="post">
- {% if request.user.is_authenticated() %}
- <p style="padding-left:3px">
- {{ answer.email_notify }}
- <label for="question-subscribe-updates">
- {% set email_feed_frequency = request.user.get_q_sel_email_feed_frequency() %}
- {% if email_feed_frequency =='n' %}
- {% trans %}Notify me once a day when there are any new answers{% endtrans %}
- {% elif email_feed_frequency =='d' %}
- {% trans %}Notify me once a day when there are any new answers{% endtrans %}
- {% elif email_feed_frequency =='w' %}
- {% trans %}Notify me weekly when there are any new answers{% endtrans %}
- {% elif email_feed_frequency =='i' %}
- {% trans %}Notify me immediately when there are any new answers{% endtrans %}
- {% endif %}
- </label>
- {% trans profile_url=request.user.get_profile_url() %}You can always adjust frequency of email updates from your {{profile_url}}{% endtrans %}
- </p>
+ </label>
+ {% trans profile_url=request.user.get_profile_url() %}You can always adjust frequency of email updates from your {{profile_url}}{% endtrans %}
+ </p>
+ {% else %}
+ <p style="padding-left:3px">
+ <input class="nomargin" type="checkbox" disabled="disabled" />
+ <label>{% trans %}once you sign in you will be able to subscribe for any updates here{% endtrans %}</label>
+ </p>
+ {% endif %}
+ <div style="clear:both">
+ </div>
+ {% if not question.closed %}
+ <div style="padding:10px 0 0 0;">
+ {% spaceless %}
+ <h2>
+ {% if answers %}
+ {% trans %}Your answer{% endtrans %}
+ {% else %}
+ {% trans %}Be the first one to answer this question!{% endtrans %}
+ {% endif %}
+ </h2>
+ {% endspaceless %}
+ </div>
+ {% if not request.user.is_authenticated() %}
+ <div class="message">{% trans %}you can answer anonymously and then login{% endtrans %}</div>
{% else %}
- <p style="padding-left:3px">
- <input class="nomargin" type="checkbox" disabled="disabled" />
- <label>{% trans %}once you sign in you will be able to subscribe for any updates here{% endtrans %}</label>
+ <p class="message">
+ {% if request.user==question.author %}
+ {% trans %}answer your own question only to give an answer{% endtrans %}
+ {% else %}
+ {% trans %}please only give an answer, no discussions{% endtrans %}
+ {% endif %}
</p>
{% endif %}
- <div style="clear:both">
- </div>
- {% if not question.closed %}
- <div style="padding:10px 0 0 0;">
- {% spaceless %}
- <div class="headNormal">
- {% if answers %}
- {% trans %}Your answer{% endtrans %}
- {% else %}
- {% trans %}Be the first one to answer this question!{% endtrans %}
- {% endif %}
- </div>
- {% endspaceless %}
- </div>
- {% if not request.user.is_authenticated() %}
- <div class="message">{% trans %}you can answer anonymously and then login{% endtrans %}</div>
+ {{ macros.edit_post(answer) }}
+ <input type="submit"
+ {% if user.is_anonymous() %}
+ value="{% trans %}Login/Signup to Post Your Answer{% endtrans %}"
{% else %}
- <p class="message">
- {% if request.user==question.author %}
- {% trans %}answer your own question only to give an answer{% endtrans %}
- {% else %}
- {% trans %}please only give an answer, no discussions{% endtrans %}
- {% endif %}
- </p>
- {% endif %}
- {{macros.edit_post(answer, settings.WIKI_ON)}}
- <input type="submit"
- {% if user.is_anonymous() %}
- value="{% trans %}Login/Signup to Post Your Answer{% endtrans %}"
+ {% if user == question.author %}
+ value="{% trans %}Answer Your Own Question{% endtrans %}"
{% else %}
- {% if user == question.author %}
- value="{% trans %}Answer Your Own Question{% endtrans %}"
- {% else %}
- value="{% trans %}Answer the question{% endtrans %}"
- {% endif %}
+ value="{% trans %}Answer the question{% endtrans %}"
{% endif %}
- class="submit after-editor" style="float:left"/>
{% endif %}
- </form>
- </div>
+ class="submit after-editor" style="float:left"/>
+ {% if settings.WIKI_ON %}
+ {{ macros.checkbox_in_div(answer.wiki) }}
+ {% endif %}
+ {% endif %}
+ </form>
</div>
{% endblock %}
@@ -378,15 +379,21 @@
<p>
{% trans %}Question tags{% endtrans %}:
</p>
- <p class="tags" >
+ <ul id="related-tags" class="tags">
{% for tag in tags %}
- <a href="{% url questions %}?tags={{tag.name|urlencode}}&amp;start_over=true"
- title="{% trans tag_name=tag.name %}see questions tagged '{{tag_name}}'{% endtrans %}"
- rel="tag">{{ tag.name }}</a>
- <span class="tag-number">&#215;{{ tag.used_count|intcomma }}</span><br/>
+ <li>
+ {{ macros.tag_widget(
+ tag,
+ html_tag = 'div',
+ url_params = 'start_over=true',
+ extra_content = '<span class="tag-number">&#215; ' ~
+ tag.used_count|intcomma ~ '</span>'
+ )
+ }}
+ </li>
{% endfor %}
- </p>
- <p>
+ </ul>
+ <p style="clear:left">
{% trans %}question asked{% endtrans %}: <strong title="{{ question.added_at }}">{{question.added_at|diff_date}}</strong>
</p>
<p>
@@ -400,7 +407,7 @@
{% if similar_questions.data %}
{% cache 1800 "related_questions" related_questions question.id language_code %}
<div class="boxC">
- <h3 class="subtitle">{% trans %}Related questions{% endtrans %}</h3>
+ <h2>{% trans %}Related questions{% endtrans %}</h2>
<div class="questions-related">
{% for question in similar_questions.data() %}
<p>
@@ -430,6 +437,11 @@
askbot['urls']['user_signin'] = '{% url user_signin %}';
askbot['urls']['vote_url_template'] = scriptUrl + '{% trans %}questions/{% endtrans %}{{ "{{QuestionID}}/" }}{% trans %}vote/{% endtrans %}';
askbot['messages']['addComment'] = '{% trans %}add comment{% endtrans %}';
+ {% if settings.SAVE_COMMENT_ON_ENTER %}
+ askbot['settings']['saveCommentOnEnter'] = true;
+ {% else %}
+ askbot['settings']['saveCommentOnEnter'] = false;
+ {% endif %}
</script>
<script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script>
<script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script>
@@ -437,9 +449,6 @@
<script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
<script type='text/javascript' src='{{"/js/post.js"|media}}'></script>
<script type="text/javascript">
- {% if request.user.is_authenticated() %}
- var tags_autocomplete = {{tags_autocomplete|safe}};
- {% endif %}
// define reputation needs for comments
var repNeededForComments = 50;
$().ready(function(){
@@ -473,5 +482,5 @@
setupFormValidation($("#fmanswer"), CPValidator.getQuestionFormRules(), CPValidator.getQuestionFormMessages());
}
</script>
- {% include "editor_data.html" %}
+ {% include "blocks/editor_data.html" %}
{% endblock %}
diff --git a/askbot/skins/default/templates/question_edit.html b/askbot/skins/default/templates/question_edit.html
index ef2ecb82..c1a84426 100644
--- a/askbot/skins/default/templates/question_edit.html
+++ b/askbot/skins/default/templates/question_edit.html
@@ -6,38 +6,37 @@
<link rel="stylesheet" type="text/css" href="{{"/js/wmd/wmd.css"|media}}" />
{% endblock %}
{% block content %}
-<div id="main-bar" class="headNormal">
- {% trans %}Edit question{% endtrans %} [<a href="{{ question.get_absolute_url() }}">{% trans %}back{% endtrans %}</a>]
-</div>
-<div id="main-body" class="ask-body">
- <form id="fmedit" action="{% url edit_question question.id %}" method="post" >
- <label for="id_revision" ><strong>{% trans %}revision{% endtrans %}:</strong></label> <br/>
- {% if revision_form.revision.errors %}{{ revision_form.revision.errors.as_ul() }}{% endif %}
- <div style="vertical-align:middle">
- {{ revision_form.revision }} <input type="submit" style="display:none"
- id="select_revision" name="select_revision"
- value="{% trans %}select revision{% endtrans %}">
- </div>
- {{macros.edit_post(
- form,
- settings.WIKI_ON and question.wiki == False,
- post_type='question',
- edit_title=True,
- )}}
- <div class="after-editor">
- <input type="submit" value="{% trans %}Save edit{% endtrans %}" class="submit" />&nbsp;
- <input type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" onclick="history.back(-1);" />
+<h1>{% trans %}Edit question{% endtrans %} [<a href="{{ question.get_absolute_url() }}">{% trans %}back{% endtrans %}</a>]</h1>
+<form id="fmedit" action="{% url edit_question question.id %}" method="post" >
+ <label for="id_revision" ><strong>{% trans %}revision{% endtrans %}:</strong></label> <br/>
+ {% if revision_form.revision.errors %}{{ revision_form.revision.errors.as_ul() }}{% endif %}
+ <div style="vertical-align:middle">
+ {{ revision_form.revision }} <input type="submit" style="display:none"
+ id="select_revision" name="select_revision"
+ value="{% trans %}select revision{% endtrans %}">
+ </div>
+ {{ macros.edit_post(form, post_type='question', edit_title=True,) }}
+ <div class="after-editor">
+ <input type="submit" value="{% trans %}Save edit{% endtrans %}" class="submit" />&nbsp;
+ <input type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" onclick="history.back(-1);" />
+ <div class="question-options">
+ {% if settings.WIKI_ON and question.wiki == False %}
+ {{ macros.checkbox_in_div(form.wiki) }}
+ {% endif %}
+ {% if form.can_stay_anonymous() %}
+ {{ macros.checkbox_in_div(form.reveal_identity) }}
+ {% endif %}
</div>
- </form>
-</div>
+ </div>
+</form>
{% endblock %}
{% block sidebar %}
-{% include "question_edit_tips.html" %}
+{% include "blocks/question_edit_tips.html" %}
{% endblock %}
{% block endjs %}
- {% include "editor_data.html" %}
+ {% include "blocks/editor_data.html" %}
<script type='text/javascript' src='{{"/js/editor.js"|media }}'></script>
<script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
<script type='text/javascript' src='{{"/js/post.js"|media}}'></script>
@@ -69,24 +68,7 @@
$('#pre-collapse').text(txt);
});
- //Tags autocomplete action
- var tags = {{ tags }};
- $("#id_tags").autocomplete(tags, {
- matchContains: true,
- max: 20,
- multiple: true,
- multipleSeparator: " ",
- highlightItem: true,
- scroll: true,
- scrollHeight: 300,
- formatItem: function(row, i, max) {
- return row.n + " ("+ row.c +")";
- },
- formatResult: function(row, i, max){
- return row.n;
- }
-
- });
+ {{ macros.tag_autocomplete_js(id = '#id_tags') }}
setupFormValidation(
$("#fmedit"),
diff --git a/askbot/skins/default/templates/question_retag.html b/askbot/skins/default/templates/question_retag.html
index 49b68745..f521ccb3 100644
--- a/askbot/skins/default/templates/question_retag.html
+++ b/askbot/skins/default/templates/question_retag.html
@@ -2,37 +2,33 @@
<!-- question_retag.html -->
{% block title %}{% spaceless %}{% trans %}Change tags{% endtrans %}{% endspaceless %}{% endblock %}
{% block content %}
-<div id="main-bar" class="headNormal">
- {% trans %}Change tags{% endtrans %} [<a href="{{ question.get_absolute_url() }}">{% trans %}back{% endtrans %}</a>]
-</div>
-<div id="main-body" class="ask-body">
- <div id="askform">
- <form id="fmretag" action="{% url retag_question question.id %}" method="post" >
- <h3>
- {{ question.get_question_title() }}
- </h3>
- <div id="description" class="edit-content-html">
- {{ question.html }}
- </div>
- <div class="form-item">
- <strong>{{ form.tags.label_tag() }}:</strong> <span class="form-error"></span><br/>
- {{ form.tags }} {{ form.tags.errors }}
- <div class="title-desc">
- {{ form.tags.help_text }}
- </div>
+<h1>{% trans %}Change tags{% endtrans %} [<a href="{{ question.get_absolute_url() }}">{% trans %}back{% endtrans %}</a>]</h1>
+<div id="askform">
+ <form id="fmretag" action="{% url retag_question question.id %}" method="post" >
+ <h2>
+ {{ question.get_question_title() }}
+ </h2>
+ <div id="description" class="edit-content-html">
+ {{ question.html }}
+ </div>
+ <div class="form-item">
+ <strong>{{ form.tags.label_tag() }}:</strong> <span class="form-error"></span><br/>
+ {{ form.tags }} {{ form.tags.errors }}
+ <div class="title-desc">
+ {{ form.tags.help_text }}
</div>
- <div class="error" ></div>
- <input type="submit" value="{% trans %}Retag{% endtrans %}" class="submit" />&nbsp;
- <input type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" onclick="history.back(-1);" />
- </form>
- </div>
+ </div>
+ <div class="error" ></div>
+ <input type="submit" value="{% trans %}Retag{% endtrans %}" class="submit" />&nbsp;
+ <input type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" onclick="history.back(-1);" />
+ </form>
</div>
{% endblock %}
{% block sidebar %}
<div class="boxC">
- <h3>{% trans %}Why use and modify tags?{% endtrans %}</h3>
- <ul class="list-item">
+ <h2>{% trans %}Why use and modify tags?{% endtrans %}</h2>
+ <ul>
<li>{% trans %}Tags help to keep the content better organized and searchable{% endtrans %}</li>
<li>
{% trans %}tag editors receive special awards from the community{% endtrans %}
@@ -50,39 +46,25 @@
<script type="text/javascript">
$().ready(function(){
$("#nav_questions").attr('className',"on");
- //Tags autocomplete action
- var tags = {{ tags }};
- $("#id_tags").autocomplete(tags, {
- minChars: 1,
- matchContains: true,
- max: 20,
- multiple: true,
- multipleSeparator: " ",
- formatItem: function(row, i, max) {
- return row.n + " ("+ row.c +")";
- },
- formatResult: function(row, i, max){
- return row.n;
- }
-
- });
- $("#fmretag").validate({
- rules: {
- tags: {
- required: true,
- maxength: 105
- }
- },
- messages: {
- tags: {
- required: "{% trans %}tags are required{% endtrans %}",
- maxlength: "{% trans %}up to 5 tags, less than 20 characters each{% endtrans %}"
- }
- }
-
- });
- lanai.highlightSyntax();
- });
+ {% import "macros.html" as macros %}
+ {{ macros.tag_autocomplete_js(id = '#id_tags') }}
+ $("#fmretag").validate({
+ rules: {
+ tags: {
+ required: true,
+ maxength: 105
+ }
+ },
+ messages: {
+ tags: {
+ required: "{% trans %}tags are required{% endtrans %}",
+ maxlength: "{% trans %}up to 5 tags, less than 20 characters each{% endtrans %}"
+ }
+ }
+
+ });
+ lanai.highlightSyntax();
+ });
</script>
{% endblock %}
<!-- end question_retag.html -->
diff --git a/askbot/skins/default/templates/questions.html b/askbot/skins/default/templates/questions.html
deleted file mode 100644
index a0439819..00000000
--- a/askbot/skins/default/templates/questions.html
+++ /dev/null
@@ -1,260 +0,0 @@
-{% extends "two_column_body.html" %}
-<!-- questions.html -->
-{% import "macros.html" as macros %}
-{% block title %}{% spaceless %}{% trans %}Questions{% endtrans %}{% endspaceless %}{% endblock %}
-{% block content %}
-{% cache 600 "scope_sort_tabs" search_tags request.user scope sort query context.page context.page_size language_code %}
-<div class="tabBar">
- <div class="tabsC">
- <span class="label">{% trans %}In:{% endtrans %}</span>
- <a id="all"
- class="{% if scope == 'all' %}on{% else %}off{% endif %}"
- href="?scope=all"
- title="{% trans %}see all questions{% endtrans %}"
- >{% trans %}all{% endtrans %}</a>
- <a id="unanswered"
- class="{% if scope == 'unanswered' %}on{% else %}off{% endif %}"
- href="?scope=unanswered&amp;sort=answers-asc"
- title="{% trans %}see unanswered questions{% endtrans %}"
- >{% trans %}unanswered{% endtrans %}</a>
- {% if request.user.is_authenticated() %}
- <a id="favorite"
- class="{% if scope == 'favorite' %}on{% else %}off{% endif %}"
- href="?scope=favorite"
- title="{% trans %}see your favorite questions{% endtrans %}"
- >{% trans %}favorite{% endtrans %}</a>
- {% endif %}
- </div>
- <div id="sort_tabs" class="tabsA">
- <span class="label">{% trans %}Sort by:{% endtrans %}</span>
- {% if show_sort_by_relevance %}
- {% set asc_relevance_tooltip = _('most relevant questions') %}
- {% set desc_relevance_tooltip = _('click to see most relevant questions') %}
- {% set relevance_label = _('relevance') %}
- {% if query %}
- <a id="by_relevance"
- {% if sort == "relevance-desc" %}
- href="?sort=relevance-desc"
- class="on"
- title="{{asc_relevance_tooltip}}">{{relevance_label}} &#9660;
- {% else %}
- href="?sort=relevance-desc"
- class="off"
- title="{{desc_relevance_tooltip}}">{{relevance_label}}
- {% endif %}
- </a>
- {% endif %}
- <script type="text/javascript">
- var sortButtonData = sortButtonData || {};
- sortButtonData['relevance'] = {
- asc_tooltip: "{{asc_relevance_tooltip}}",
- desc_tooltip: "{{desc_relevance_tooltip}}",
- label: "{{relevance_label}}",
- };
- </script>
- {% endif %}
- {{macros.reversible_sort_button(
- button_sort_criterium = 'age',
- label = _('by date'),
- asc_tooltip = _('click to see the oldest questions'),
- desc_tooltip = _('click to see the newest questions'),
- current_sort_method = sort
- )
- }}
- {{macros.reversible_sort_button(
- button_sort_criterium = 'activity',
- label = _('by activity'),
- asc_tooltip = _('click to see the least recently updated questions'),
- desc_tooltip = _('click to see the most recently updated questions'),
- current_sort_method = sort
- )
- }}
- {{macros.reversible_sort_button(
- button_sort_criterium = 'answers',
- label = _('by answers'),
- asc_tooltip = _('click to see the least answered questions'),
- desc_tooltip = _('click to see the most answered questions'),
- current_sort_method = sort
- )
- }}
- {{macros.reversible_sort_button(
- button_sort_criterium = 'votes',
- label = _('by votes'),
- asc_tooltip = _('click to see least voted questions'),
- desc_tooltip = _('click to see most voted questions'),
- current_sort_method = sort
- )
- }}
- </div>
-</div>
-{% endcache %}
-{% if questions_count > 0 %}
- <div style="clear:both">
- <p style="float:right;margin:3px 3px 0 0;">
- (<a style="text-decoration:none;"
- href="{{settings.APP_URL}}/feeds/rss/"
- title="{% trans %}subscribe to the questions feed{% endtrans %}"
- ><img
- style="vertical-align:middle;"
- alt="{% trans %}subscribe to the questions feed{% endtrans %}"
- src="{{"/images/feed-icon-small.png"|media}}"/> {% trans %}rss feed{% endtrans %}</a>)
- </p>
- <p id="question-count" class="search-result-summary">
- {% if author_name or search_tags or query %}
- {% trans cnt=questions_count, q_num=questions_count|intcomma %}
- {{q_num}} question
- {% pluralize %}
- {{q_num}} questions
- {% endtrans %}
- {% else %}
- {% trans cnt=questions_count, q_num=questions_count|intcomma %}{{q_num}} question{% pluralize %}{{q_num}} questions{% endtrans %}
- {% endif %}
- {% if author_name %}
- {% trans %}with {{author_name}}'s contributions{% endtrans %}
- {% endif %}
- {% if search_tags %}{% if author_name %}, {% endif %}
- {% trans %}tagged{% endtrans %}
- "{{ search_tags|join('", "') }}"
- {% endif %}
- </p>
- {% if author_name or search_tags or query %}
- <p class="search-tips">{% trans %}Search tips:{% endtrans %}
- {% if reset_method_count > 1 %}
- {% if author_name %}
- <a href="{% url questions %}?reset_author=true">{% trans %}reset author{% endtrans %}</a>
- {% endif %}
- {% if search_tags %}{% if author_name and query %}, {% elif author_name %}{% trans %} or {% endtrans %}{% endif %}
- <a href="{% url questions %}?reset_tags=true">{% trans %}reset tags{% endtrans %}</a>
- {% endif %}
- {% if query %}{% trans %} or {% endtrans %}
- <a href="{% url questions %}?start_over=true">{% trans %}start over{% endtrans %}</a>
- {% endif %}
- {% else %}
- <a href="{% url questions %}?start_over=true">{% trans %}start over{% endtrans %}</a>
- {% endif %}
- {% trans %} - to expand, or dig in by adding more tags and revising the query.{% endtrans %}
- </p>
- {% else %}
- <p class="search-tips">{% trans %}Search tip:{% endtrans %} {% trans %}add tags and a query to focus your search{% endtrans %}</p>
- {% endif %}
- </div>
-{% endif %}
-<div id="listA">
-{% cache 0 "questions" questions search_tags scope sort query context.page context.page_size language_code %}
- {% for question in questions.object_list %}
- {{macros.question_summary(question)}}
- {% endfor %}
-{% endcache %}
- {# comment todo: fix css here #}
- {% if questions_count == 0 %}
- {# todo: add tips to widen selection #}
- <p class="evenMore" style="padding-top:30px;text-align:center;">
- {% if scope == "unanswered" %}
- {% trans %}There are no unanswered questions here{% endtrans %}
- {% endif %}
- {% if scope == "favorite" %}
- {% trans %}No favorite questions here. {% endtrans %}
- {% trans %}Please start (bookmark) some questions when you visit them{% endtrans %}
- {% endif %}
- </p>
- {% if query or search_tags or author_name %}
- <p class="evenMore" style="text-align:center">
- {% trans %}You can expand your search by {% endtrans %}
- {% if reset_method_count > 1 %}
- {% if author_name %}
- <a href="{% url questions %}?reset_author=true">{% trans %}resetting author{% endtrans %}</a>
- {% endif %}
- {% if search_tags %}{% if author_name and query %}, {% elif author_name %}{% trans %} or {% endtrans %}{% endif %}
- <a href="{% url questions %}?reset_tags=true">{% trans %}resetting tags{% endtrans %}</a>
- {% endif %}
- {% if query %}{% trans %} or {% endtrans %}
- <a href="{% url questions %}?start_over=true">{% trans %}starting over{% endtrans %}</a>
- {% endif %}
- {% else %}
- <a href="{% url questions %}?start_over=true">{% trans %}starting over{% endtrans %}</a>
- {% endif %}
- </p>
- {% endif %}
- <p class="evenMore" style="text-align:center">
- <a href="{% url ask %}">{% trans %}Please always feel free to ask your question!{% endtrans %}</a>
- </p>
- {% else %}
- <p class="evenMore" style="padding-left:9px">
- {% trans %}Did not find what you were looking for?{% endtrans %}
- <a href="{% url ask %}">{% trans %}Please, post your question!{% endtrans %}</a>
- </p>
- {% endif %}
-</div>
-{% if questions_count > 10 %}{# todo: remove magic number #}
- <div id="pager" class="pager">
- {{ macros.paginator(context|setup_paginator, position='left') }}
- {{ macros.pagesize_switch(context, position='right') }}
- </div>
-{% endif %}
-{% endblock %}
-{% block sidebar %}
- {% if contributors %}
- {% cache 600 "contributors" contributors search_tags scope sort query context.page context.page_size language_code %}
- <div id="contrib-users" class="boxC">
- <h3 class="subtitle">{% trans %}Contributors{% endtrans %}</h3>
- {% spaceless %}
- {% for person in contributors %}
- {{ macros.gravatar(person,48) }}
- {% endfor %}
- {% endspaceless %}
- </div>
- {% endcache %}
- {% endif %}
-
- {% if request.user.is_authenticated() %}
- {% include "tag_selector.html" %}
- {% endif %}
-
- {% if tags %}
- {% cache 0 "tags" tags search_tags scope sort query context.page context.page_size language_code %}
- <div class="boxC">
- <h3 class="subtitle">{% trans %}Related tags{% endtrans %}</h3>
- <div id="related-tags" class="tags">
- {% for tag in tags %}
- <a
- rel="tag"
- title="{% trans tag_name=tag.name %}see questions tagged '{{ tag_name }}'{% endtrans %}"
- href="{% url questions %}?tags={{tag.name|urlencode}}">{{ tag.name }}</a>
- <span class="tag-number">&#215; {{ tag.local_used_count|intcomma }}</span>
- <br />
- {% endfor %}
- </div>
- </div>
- {% endcache %}
- {% endif %}
-{% endblock %}
-{% block endjs %}
- <script type="text/javascript">
- {% if request.user.is_authenticated() %}
- var tags = {{ tags_autocomplete|safe }};
- {% endif %}
- var sortMethod = '{{sort}}';
- var showSortByRelevance = {% if show_sort_by_relevance %}true{% else %}false{% endif %};
- var minSearchWordLength = {{settings.MIN_SEARCH_WORD_LENGTH}};
- $(document).ready(function(){
- /*var on_tab = '#nav_questions';
- $(on_tab).attr('className','on');*/
- Hilite.exact = false;
- Hilite.elementid = "listA";
- Hilite.debug_referrer = location.href;
- });
- askbot['urls']['mark_interesting_tag'] = scriptUrl + '{% trans %}mark-tag/{% endtrans %}{% trans %}interesting/{% endtrans %}';
- askbot['urls']['mark_ignored_tag'] = scriptUrl + '{% trans %}mark-tag/{% endtrans %}{% trans %}ignored/{% endtrans %}';
- askbot['urls']['unmark_tag'] = scriptUrl + '{% trans %}unmark-tag/{% endtrans %}';
- askbot['urls']['command'] = '{% url "call_ajax" %}';
- askbot['urls']['questions'] = '{% url "questions" %}';
- askbot['urls']['question_url_template'] = scriptUrl + '{% trans %}question/{% endtrans %}{{ "{{QuestionID}}/" }}';
- askbot['urls']['user_url_template'] = scriptUrl + '{% trans %}users/{% endtrans %}{{ "{{user_id}}" }}/{{ "{{slug}}" }}/';
- </script>
- <script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
- {% if request.user.is_authenticated() %}
- <script type='text/javascript' src='{{"/js/tag_selector.js"|media}}'></script>
- {% endif %}
- <script type="text/javascript" src="{{"/js/live_search.js"|media}}"></script>
-{% endblock %}
-<!-- end questions.html -->
diff --git a/askbot/skins/default/templates/reopen.html b/askbot/skins/default/templates/reopen.html
index d1012d1b..58d798a3 100644
--- a/askbot/skins/default/templates/reopen.html
+++ b/askbot/skins/default/templates/reopen.html
@@ -2,35 +2,31 @@
<!-- reopen.html -->
{% block title %}{% spaceless %}{% trans %}Reopen question{% endtrans %}{% endspaceless %}{% endblock %}
{% block content %}
-<div id="main-bar" class="headNormal">
- {% trans %}Reopen question{% endtrans %}
-</div>
-<div id="main-body" style="width:100%">
- <p>{% trans %}Title{% endtrans %}:
- <a href="{{ question.get_absolute_url() }}">
- <span class="big">{{ question.get_question_title() }}</span>
- </a>
- </p>
- <p>{% trans %}This question has been closed by
- <a href="{{closed_by_profile_url}}">{{closed_by_username}}</a>
- {% endtrans %}
- </p>
- <p>
- {% trans %}Close reason:{% endtrans %} "<strong>{{question.get_close_reason_display()}}</strong>".
- </p>
- <p>
- {% trans %}When:{% endtrans %} {{question.closed_at|diff_date}}
- </p>
- <p>
- {% trans %}Reopen this question?{% endtrans %}
- </p>
- <form id="fmclose" action="{% url reopen question.id %}" method="post" >
- <div id="" style="padding:20px 0 20px 0">
- <input type="submit" value="{% trans %}Reopen this question{% endtrans %}" class="submit" />&nbsp;
- <input id="btBack" type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" />
- </div>
- </form>
-</div>
+<h1>{% trans %}Reopen question{% endtrans %}</h1>
+<p>{% trans %}Title{% endtrans %}:
+ <a href="{{ question.get_absolute_url() }}">
+ <span class="big">{{ question.get_question_title() }}</span>
+ </a>
+</p>
+<p>{% trans %}This question has been closed by
+ <a href="{{closed_by_profile_url}}">{{closed_by_username}}</a>
+{% endtrans %}
+</p>
+<p>
+ {% trans %}Close reason:{% endtrans %} "<strong>{{question.get_close_reason_display()}}</strong>".
+</p>
+<p>
+ {% trans %}When:{% endtrans %} {{question.closed_at|diff_date}}
+</p>
+<p>
+ {% trans %}Reopen this question?{% endtrans %}
+</p>
+<form id="fmclose" action="{% url reopen question.id %}" method="post" >
+ <div id="" style="padding:20px 0 20px 0">
+ <input type="submit" value="{% trans %}Reopen this question{% endtrans %}" class="submit" />&nbsp;
+ <input id="btBack" type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" />
+ </div>
+</form>
{% endblock %}
{% block endjs %}
<script type="text/javascript">
diff --git a/askbot/skins/default/templates/revisions.html b/askbot/skins/default/templates/revisions.html
index cb1af2f0..0c10e6d4 100644
--- a/askbot/skins/default/templates/revisions.html
+++ b/askbot/skins/default/templates/revisions.html
@@ -3,9 +3,9 @@
<!-- revisions.html -->
{% block title %}{% spaceless %}{% trans %}Revision history{% endtrans %}{% endspaceless %}{% endblock %}
{% block content %}
-<div id="main-bar" class="headNormal">
+<h1>
{% trans %}Revision history{% endtrans %} [<a href="{{ post.get_absolute_url() }}">{% trans %}back{% endtrans %}</a>]
-</div>
+</h1>
<div id="revisions">
{% for revision in revisions %}
<div class="revision">
diff --git a/askbot/skins/default/templates/subscribe_for_tags.html b/askbot/skins/default/templates/subscribe_for_tags.html
new file mode 100644
index 00000000..9a58ccbf
--- /dev/null
+++ b/askbot/skins/default/templates/subscribe_for_tags.html
@@ -0,0 +1,19 @@
+{% extends "two_column_body.html" %}
+{% import "macros.html" as macros %}
+{% block title %}{% trans %}Subscribe for tags{% endtrans %}{% endblock %}
+{% block content %}
+<h1>{% trans %}Subscribe for tags{% endtrans %}</h1>
+<p>{% trans %}Please, subscribe for the following tags:{% endtrans %}</p>
+<ul class="tags" style="margin-left: 4px">
+ {% for tag in tags %}
+ {{ macros.tag_widget(tag, html_tag = 'li', is_link = False) }}
+ {% endfor %}
+</ul>
+<div style="clear:both;padding-top: 5px">
+ <form method="post" action="{% url subscribe_for_tags %}">
+ <input type="hidden" name="tags" value="{{tags|join(' ')|escape}}" />
+ <input type="submit" name="ok" value="{% trans %}Subscribe{% endtrans %}" />
+ <input type="submit" name="nope" value="{% trans %}Cancel{% endtrans %}" />
+ </form>
+</div>
+{% endblock %}
diff --git a/askbot/skins/default/templates/tag_selector.html b/askbot/skins/default/templates/tag_selector.html
deleted file mode 100644
index 6f6b8dc6..00000000
--- a/askbot/skins/default/templates/tag_selector.html
+++ /dev/null
@@ -1,41 +0,0 @@
-{# todo - maybe disable navigation from ignored tags here when "hide" is on - with js? #}
-<div id="tagSelector" class="boxC">
- <h3 class="subtitle">{% trans %}Interesting tags{% endtrans %}</h3>
- <div class="tags interesting marked-tags">
- {% for tag_name in interesting_tag_names %}
- {% spaceless %}
- <span class="deletable-tag" id="interesting-tag-{{tag_name}}">
- <a rel="tag"
- title="{% trans %}see questions tagged '{{ tag_name }}'{% endtrans %}"
- href="{% url questions %}?tags={{tag_name|urlencode}}">{{tag_name}}</a>
- <img class="delete-icon"
- src="{{'/images/close-small-dark.png'|media}}"
- title="{% trans %}remove '{{tag_name}}' from the list of interesting tags{% endtrans %}"/>
- </span>
- {% endspaceless %}
- {% endfor %}
- </div>
- <input id="interestingTagInput" autocomplete="off" type="text"/>&nbsp;
- <input id="interestingTagAdd" type="submit" value="{% trans %}Add{% endtrans %}"/>
- <h3 class="subtitle">{% trans %}Ignored tags{% endtrans %}</h3>
- <div class="tags ignored marked-tags">
- {% for tag_name in ignored_tag_names %}
- {% spaceless %}
- <span class="deletable-tag" id="ignored-tag-{{tag_name}}">
- <a rel="tag"
- title="{% trans %}see questions tagged '{{ tag_name }}'{% endtrans %}"
- href="{% url questions %}?tags={{tag_name|urlencode}}">{{tag_name}}</a>
- <img class="delete-icon"
- src="{{'/images/close-small-dark.png'|media}}"
- title="{% trans %}remove '{{tag_name}}' from the list of ignored tags{% endtrans %}"/>
- </span>
- {% endspaceless %}
- {% endfor %}
- </div>
- <input id="ignoredTagInput" autocomplete="off" type="text"/>&nbsp;
- <input id="ignoredTagAdd" type="submit" value="{% trans %}Add{% endtrans%}"/>
- <p id="hideIgnoredTagsControl">
- <input id="hideIgnoredTagsCb" type="checkbox" {% if request.user.hide_ignored_questions %}checked="checked"{% endif %} />&nbsp;
- <label id="hideIgnoredTagsLabel" for="hideIgnoredTagsCb">{% trans %}keep ignored questions hidden{% endtrans %}</label>
- <p>
-</div>
diff --git a/askbot/skins/default/templates/tags.html b/askbot/skins/default/templates/tags.html
index c23b57f9..619c35bf 100644
--- a/askbot/skins/default/templates/tags.html
+++ b/askbot/skins/default/templates/tags.html
@@ -5,49 +5,49 @@
{% block content %}
<!-- Tabs -->
<div class="tabBar">
- <div class="headUsers">{% trans %}Tag list{% endtrans %}</div>
+ <h1>{% trans %}Tag list{% endtrans %}</h1>
<div class="tabsA">
<a
id="sort_name"
href="{% url tags %}?sort=name"
{% if tab_id == 'name' %}class="on"{% endif %}
title="{% trans %}sorted alphabetically{% endtrans %}"
- >{% trans %}by name{% endtrans %}</a>
+ ><span>{% trans %}by name{% endtrans %}</span></a>
<a
id="sort_used"
href="{% url tags %}?sort=used"
{% if tab_id == 'used' %}class="on"{% endif %}
title="{% trans %}sorted by frequency of tag use{% endtrans %}"
- >{% trans %}by popularity{% endtrans %}</a>
+ ><span>{% trans %}by popularity{% endtrans %}</span></a>
</div>
</div>
-<div id="searchtags">
- <p>
- {% if stag %}
- {% trans %}All tags matching '<span class="darkred"><strong>{{ stag }}</strong></span>'{% endtrans %}:
- {% endif %}
- {% if not tags.object_list %}
- <span>{% trans %}Nothing found{% endtrans %}</span>
- {% endif %}
- </p>
- {% if tags.object_list %}
- <ul class="tagsList tags">
- {% for tag in tags.object_list %}
- <li>
- <a href="{% url questions %}?tags={{tag|urlencode}}&start_over=true"
- title="{% trans %}see questions tagged '{{ tag }}'{% endtrans %}" rel="tag">
- {{ tag }}
- </a>&nbsp;
- <span class="tag-number">&#215; {{ tag.used_count|intcomma }}</span>
- <br/>
+<p>
+ {% if stag %}
+ {% trans %}All tags matching '<span class="darkred"><strong>{{ stag }}</strong></span>'{% endtrans %}:
+ {% endif %}
+ {% if not tags.object_list %}
+ <span>{% trans %}Nothing found{% endtrans %}</span>
+ {% endif %}
+</p>
+{% if tags.object_list %}
+ <ul class='tags'>
+ {% for tag in tags.object_list %}
+ <li>
+ {{ macros.tag_widget(
+ tag = tag.name,
+ url_params = 'start_over=true',
+ html_tag = 'div',
+ extra_content = '<span class="tag-number">&#215; ' ~
+ tag.used_count|intcomma ~ '</span>'
+ )
+ }}
</li>
- {% endfor %}
+ {% endfor %}
</ul>
- {% endif %}
-</div>
+{% endif %}
<div class="pager">
{{macros.paginator(paginator_context)}}
-</div>
+</div>
{% endblock %}
{% block endjs %}
<script type="text/javascript">
diff --git a/askbot/skins/default/templates/two_column_body.html b/askbot/skins/default/templates/two_column_body.html
index f13d0f5d..a284744e 100644
--- a/askbot/skins/default/templates/two_column_body.html
+++ b/askbot/skins/default/templates/two_column_body.html
@@ -1,21 +1,13 @@
{% extends "base.html" %}
+{% block body_class %}two-col{% endblock %}
{% block body %}
-<div id="wrapper">
- <div id="room">
- <div id="CALeft">
- {% include "input_bar.html" %}
- {% block content%}
- {% endblock%}
- </div>
- <div id="CARight">
- {% block sidebar%}
- {% endblock%}
- </div>
- <div id="tail" style="clear:both;">
- {% block tail %}
- {% endblock %}
- </div>
- </div>
- <div class="spacer3"></div>
+<div id="CALeft">
+ {% include "blocks/input_bar.html" %}
+ {% block content%}
+ {% endblock%}
+</div>
+<div id="CARight">
+ {% block sidebar%}
+ {% endblock%}
</div>
{% endblock %}
diff --git a/askbot/skins/default/templates/unused/email_base.html b/askbot/skins/default/templates/unused/email_base.html
deleted file mode 100644
index 406041e4..00000000
--- a/askbot/skins/default/templates/unused/email_base.html
+++ /dev/null
@@ -1,23 +0,0 @@
-{# this template is not used yet #}
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <link href="{{"/style/style.css"|fullmedia}}" rel="stylesheet" type="text/css" />
- </head>
- <body>
- <a href="{{settings.APP_URL}}{% url index %}">
- <img src="{{"/images/logo.png"|fullmedia}}" title="{% trans %}home{% endtrans %}" alt="{{settings.APP_TITLE}} logo"/>
- </a>
- <br />
- <p>{{ settings.APP_TITLE }}</p>
- <br /><br />
- <div id="wrapper">
- <div id="room">
- <div id="CALeft">
- {% block content%}
- {% endblock%}
- </div>
- </div>
- <div class="spacer3"></div>
- </div>
- </body>
-</html>
diff --git a/askbot/skins/default/templates/unused/notarobot.html b/askbot/skins/default/templates/unused/notarobot.html
deleted file mode 100644
index e84756b7..00000000
--- a/askbot/skins/default/templates/unused/notarobot.html
+++ /dev/null
@@ -1,15 +0,0 @@
-{% extends "one_column_body.html" %}
-{% load i18n %}
-{% block title %}{% spaceless %}{% trans "Please prove that you are a Human Being" %}{% endspaceless %}{% endblock %}
-{% block content %}
-{% comment %} this form is set up to be used in wizards {% endcomment %}
-<form name="notarobot" action="." method="POST">
- <div>
- {{form}}
- </div>
- <input type="submit" value="{% trans "I am a Human Being" %}" class="submit" style="float:left"/>&nbsp;
- <input type="hidden" name="{{ step_field }}" value="{{ step0 }}" />
- {{ previous_fields|safe }}
- </form>
-</form>
-{% endblock %}
diff --git a/askbot/skins/default/templates/unused/question_counter_widget.html b/askbot/skins/default/templates/unused/question_counter_widget.html
deleted file mode 100644
index ce9d38cf..00000000
--- a/askbot/skins/default/templates/unused/question_counter_widget.html
+++ /dev/null
@@ -1,119 +0,0 @@
-{% comment %}
-this template was at one point used with the following template tag
-for the django templates
-the tag was removed from use because it was slowing down the template
-rendering partly because of parsing the template many times over
-and partly because of too many calls into askbot_settings
-which added up to the total time
-
-
-@register.inclusion_tag('question_counter_widget.html') #too slow
-def question_counter_widget(question):
- """todo: maybe worth trying again. it could have been too slow
- because of all the calls to the askbot_settings
-
- returns colorized counter widget for a question
-
- .. versionchanged:: 0.6.6
- switched from inclusion tag style to in-code template string
- for the better speed of the front page rendering
- """
- view_count = functions.get_from_dict_or_object(question, 'view_count')
- answer_count = functions.get_from_dict_or_object(question, 'answer_count')
- vote_count = functions.get_from_dict_or_object(question, 'score')
- answer_accepted = functions.get_from_dict_or_object(question, 'answer_accepted')
-
- #background and foreground colors for each item
- (views_fg, views_bg) = colors.get_counter_colors(
- 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,
- )
- #views_fg = askbot_settings.COLORS_VIEW_COUNTER_EMPTY_FG
- #views_bg = askbot_settings.COLORS_VIEW_COUNTER_EMPTY_BG
-
- (answers_fg, answers_bg) = colors.get_counter_colors(
- 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,
- )
- #answers_fg = askbot_settings.COLORS_ANSWER_COUNTER_EMPTY_FG
- #answers_bg = askbot_settings.COLORS_ANSWER_COUNTER_EMPTY_BG
- if answer_accepted:
- #todo: maybe recalculate the foreground color too
- 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,
- 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,
- )
- votes_fg = askbot_settings.COLORS_VOTE_COUNTER_EMPTY_FG
- votes_fg = askbot_settings.COLORS_VOTE_COUNTER_EMPTY_BG
-
- return locals()
-{% endcomment %}
-
-{% load extra_filters %}
-{% load i18n %}
-<div class="counts">
- <div class="votes"
- style="background:{{votes_bg}};color:{{votes_fg}}"
- title="{% trans "Please decide if you like this question or not by voting" %}">
- {% spaceless %}
- <div class="item-count">
- {{question.score|humanize_counter}}
- </div>
- <div>
- {% blocktrans count question.score as cnt %}
- vote
- {% plural %}
- votes
- {% endblocktrans %}
- </div>
- {% endspaceless %}
- </div >
- {% comment %}
- <div {% if question.answer_accepted %}title="{% trans "this answer has been accepted to be correct" %}"{% endif %} class="status {% if question.answer_accepted %}answered-accepted{% endif %} {% ifequal question.answer_count 0 %}unanswered{% endifequal %}{% ifnotequal question.answer_count 0 %}answered{% endifnotequal %}">
- {% endcomment %}
- <div class="votes" style="background:{{answers_bg}};color:{{answers_fg}}">
- <div class="item-count">{{question.answer_count|humanize_counter}}</div>
- {% spaceless %}
- <div>
- {% blocktrans count question.answer_count as cnt %}
- answer
- {% plural %}
- answers
- {% endblocktrans %}
- </div>
- {% endspaceless %}
- </div>
- <div class="views" style="background:{{views_bg}};color:{{views_fg}}">
- {% spaceless %}
- <div class="item-count">{{question.view_count|humanize_counter}}</div>
- <div>
- {% blocktrans count question.view_count as cnt %}
- view
- {% plural %}
- views
- {% endblocktrans %}
- </div>
- {% endspaceless %}
- </div>
-</div>
diff --git a/askbot/skins/default/templates/unused/question_list.html b/askbot/skins/default/templates/unused/question_list.html
deleted file mode 100644
index 95e4834a..00000000
--- a/askbot/skins/default/templates/unused/question_list.html
+++ /dev/null
@@ -1,68 +0,0 @@
-{% load cache %}
-{% load i18n %}
-{% load humanize %}
-{% load extra_filters %}
-{% load extra_tags %}
-{% for question in questions.object_list %}
-<div class="short-summary">
- <div class="counts">
- <div class="votes">
- <span
- class="item-count"
- style="background:{{settings.COLORS_VOTE_COUNTER_MIN_BG}};color:{{settings.COLORS_VOTE_COUNTER_MIN_FG}}"
- >{{question.score|humanize_counter}}</span>
- <div>
- {% blocktrans count question.score as cnt %}
- vote
- {% plural %}
- votes
- {% endblocktrans %}
- </div>
- </div >
- {% comment %}
- <div {% if question.answer_accepted %}title="{% trans "this answer has been accepted to be correct" %}"{% endif %} class="status {% if question.answer_accepted %}answered-accepted{% endif %} {% ifequal question.answer_count 0 %}unanswered{% endifequal %}{% ifnotequal question.answer_count 0 %}answered{% endifnotequal %}">
- {% endcomment %}
- <div class="votes">
- <span
- class="item-count"
- {% if question.answer_accepted %}
- style="background:{{settings.COLORS_ANSWER_COUNTER_ACCEPTED_BG}};color:{{settings.COLORS_ANSWER_COUNTER_ACCEPTED_FG}}"
- {% else %}
- style="background:{{settings.COLORS_ANSWER_COUNTER_MIN_BG}};color:{{settings.COLORS_ANSWER_COUNTER_MIN_FG}}"
- {% endif %}
- >{{question.answer_count|humanize_counter}}</span>
- <div>
- {% blocktrans count question.answer_count as cnt %}
- answer
- {% plural %}
- answers
- {% endblocktrans %}
- </div>
- </div>
- <div class="votes">
- <span class="item-count"
- style="background:{{settings.COLORS_VIEW_COUNTER_MIN_BG}};color:{{settings.COLORS_VIEW_COUNTER_MIN_FG}}"
- >{{question.view_count|humanize_counter}}</span>
- <div>
- {% blocktrans count question.view_count as cnt %}
- view
- {% plural %}
- views
- {% endblocktrans %}
- </div>
- </div>
- </div>
- <h2><a title="{{question.summary}}" href="{% url question id=question.id %}{{question.title|slugify}}">{{question.title}}</a></h2>
- <div class="userinfo">
- <span class="relativetime" title="{{question.last_activity_at}}">{% diff_date question.last_activity_at %}</span>
- {% if 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">
- {% for tag in question.get_tag_names %}
- <a href="{% url questions %}?tags={{tag|urlencode}}" title="{% blocktrans %}see questions tagged '{{ tag }}'{%endblocktrans %}" rel="tag">{{ tag }}</a>
- {% endfor %}
- </div>
-</div>
-{% endfor %}
diff --git a/askbot/skins/default/templates/unused/question_summary_list_roll.html b/askbot/skins/default/templates/unused/question_summary_list_roll.html
deleted file mode 100644
index 04297c68..00000000
--- a/askbot/skins/default/templates/unused/question_summary_list_roll.html
+++ /dev/null
@@ -1,55 +0,0 @@
- <div class="qstA">
- <h2>
- <a href="{{ question.get_absolute_url }}">{{ question.get_question_title }}</a>
- </h2>
- <div class="stat">
- <table>
- <tr>
- <td><span class="num">{{ question.answer_count|intcomma }}</span> </td>
- <td><span class="num">{{ question.score|intcomma }}</span> </td>
- <td><span class="num">{{ question.view_count|cnprog_intword|safe }}</span> </td>
- </tr>
- <tr>
- <td><span class="unit">{% trans "answers" %}</span></td>
- <td><span class="unit">{% trans "votes" %}</span></td>
- <td><span class="unit">{% trans "views" %}</span></td>
- </tr>
- </table>
- </div>
-
- <div class="summary">
- {{ question.summary }}...
- </div>
-
- {% ifequal tab_id 'active'%}
- {% if question.wiki and settings.WIKI_ON %}
- <span class="from wiki">{% trans "community wiki" %}</span>
- <span class="date" title="{{ question.added_at }}">{% diff_date question.added_at %}</span>
- {% else %}
- <div class="from">
- {% comment %}{% gravatar question.last_activity_by 24 %}{% endcomment %}
- <span class="author"><a href="{{ question.last_activity_by.get_profile_url }}">{{ question.last_activity_by }}</a></span>
- <span class="score">{% get_score_badge question.last_activity_by %} </span>
- <span class="date" title="{{ question.last_activity_at }}">{% diff_date question.last_activity_at %}</span>
- </div>
- {% endif %}
- {% else %}
- {% if question.wiki and settings.WIKI_ON %}
- <span class="from wiki">{% trans "community wiki" %}</span>
- <span class="date" title="{{ question.added_at }}">{% diff_date question.added_at %}</span>
- {% else %}
- <div class="from">
- {% comment %}{% gravatar question.author 24 %}{% endcomment %}
- <span class="author"><a href="{{ question.author.get_profile_url }}">{{ question.author }}</a></span>
- <span class="score">{% get_score_badge question.author %} </span>
- <span class="date" title="{{ question.added_at }}">{% diff_date question.added_at %}</span>
- </div>
- {% endif %}
- {% endifequal %}
-
- <div class="tags">
- {% for tag in question.get_tag_names %}
- <a href="{% url questions %}?tags={{tag|urlencode}}" title="{% blocktrans %}see questions tagged '{{ tag }}'{% endblocktrans %}" rel="tag">{{ tag }}</a>
- {% endfor %}
- </div>
- </div>
diff --git a/askbot/skins/default/templates/unused/questions_ajax.html b/askbot/skins/default/templates/unused/questions_ajax.html
deleted file mode 100644
index d2df8015..00000000
--- a/askbot/skins/default/templates/unused/questions_ajax.html
+++ /dev/null
@@ -1,118 +0,0 @@
-<!-- questions_ajax.html -->
-{% load extra_tags %}
-{% load i18n %}
-{% load humanize %}
-{% load extra_filters %}
-{% load smart_if %}
-{% load cache %}
-{% get_current_language as LANGUAGE_CODE %}
-{% cache 60 questions search_tags scope sort query context.page context.page_size LANGUAGE_CODE %}
- {% for question in questions.object_list %}
- <div class="short-summary">
- <div class="counts">
- <div class="votes">
- <span
- class="item-count"
- {% if question.score == 0 %}
- style="background:{{settings.COLORS_VOTE_COUNTER_EMPTY_BG}};color:{{settings.COLORS_VOTE_COUNTER_EMPTY_FG}}"
- {% else %}
- style="background:{{settings.COLORS_VOTE_COUNTER_MIN_BG}};color:{{settings.COLORS_VOTE_COUNTER_MIN_FG}}"
- {% endif %}
- >{{question.score|humanize_counter}}</span>
- <div>
- {% blocktrans count question.score as cnt %}vote{% plural %}votes{% endblocktrans %}
- </div>
- </div >
- {% comment %}
- <div {% if question.answer_accepted %}title="{% trans "this answer has been accepted to be correct" %}"{% endif %} class="status {% if question.answer_accepted %}answered-accepted{% endif %} {% ifequal question.answer_count 0 %}unanswered{% endifequal %}{% ifnotequal question.answer_count 0 %}answered{% endifnotequal %}">
- {% endcomment %}
- <div class="votes">
- <span
- class="item-count"
- {% if question.answer_count == 0 %}
- style="background:{{settings.COLORS_ANSWER_COUNTER_EMPTY_BG}};color:{{settings.COLORS_ANSWER_COUNTER_EMPTY_FG}}"
- {% else %}
- {% if question.answer_accepted %}
- style="background:{{settings.COLORS_ANSWER_COUNTER_ACCEPTED_BG}};color:{{settings.COLORS_ANSWER_COUNTER_ACCEPTED_FG}}"
- {% else %}
- style="background:{{settings.COLORS_ANSWER_COUNTER_MIN_BG}};color:{{settings.COLORS_ANSWER_COUNTER_MIN_FG}}"
- {% endif %}
- {% endif %}
- >{{question.answer_count|humanize_counter}}</span>
- <div>
- {% blocktrans count question.answer_count as cnt %}answer{% plural %}answers{% endblocktrans %}
- </div>
- </div>
- <div class="votes">
- <span class="item-count"
- {% if question.view_count == 0 %}
- style="background:{{settings.COLORS_VIEW_COUNTER_EMPTY_BG}};color:{{settings.COLORS_VIEW_COUNTER_EMPTY_FG}}"
- {% else %}
- style="background:{{settings.COLORS_VIEW_COUNTER_MIN_BG}};color:{{settings.COLORS_VIEW_COUNTER_MIN_FG}}"
- {% endif %}
- >{{question.view_count|humanize_counter}}</span>
- <div>
- {% blocktrans count question.view_count as cnt %}view{% plural %}views{% endblocktrans %}
- </div>
- </div>
- </div>
- <h2><a title="{{question.summary}}" href="{% url question id=question.id %}{{question.title|slugify}}">{{question.title}}</a></h2>
- <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 %}
- {% endif %}
- </div>
- <div class="tags">
- {% for tag in question.get_tag_names %}
- <a href="{% url questions %}?tags={{tag|urlencode}}" title="{% blocktrans %}see questions tagged '{{ tag }}'{%endblocktrans %}" rel="tag">{{ tag }}</a>
- {% endfor %}
- </div>
- </div>
- {% endfor %}
-{% endcache %}
- {% comment %}todo: fix css here{% endcomment %}
- {% if questions_count == 0 %}
- {% comment %}todo: add tips to widen selection{% endcomment%}
- <p class="evenMore" style="padding-top:30px;text-align:center;">
- {% if scope == "unanswered" %}
- {% trans "There are no unanswered questions here" %}
- {% endif %}
- {% if scope == "favorite" %}
- {% trans "No favorite questions here. " %}
- {% trans "Please start (bookmark) some questions when you visit them" %}
- {% endif %}
- </p>
- {% if query or search_tags or author_name %}
- <p class="evenMore" style="text-align:center">
- {% trans "You can expand your search by " %}
- {% ifmany query search_tags author_name %}
- {% joinitems using ', ' ' or ' %}
- {% if author_name %}
- <a href="{% url questions %}?reset_author=true">{% trans "resetting author" %}</a>
- {% endif %}
- {% separator %}
- {% if search_tags %}
- <a href="{% url questions %}?reset_tags=true">{% trans "resetting tags" %}</a>
- {% endif %}
- {% separator %}
- {% ifmany query search_tags author_name %}
- <a href="{% url questions %}?start_over=true">{% trans "starting over" %}</a>
- {% endifmany %}
- {% endjoinitems %}
- {% else %}
- <a href="{% url questions %}?start_over=true">{% trans "starting over" %}</a>
- {% endifmany %}
- </p>
- {% endif %}
- <p class="evenMore" style="text-align:center">
- <a href="{% url ask %}">{% trans "Please always feel free to ask your question!" %}</a>
- </p>
- {% else %}
- <p class="evenMore" style="padding-left:9px">
- {% trans "Did not find what you were looking for?" %}
- <a href="{% url ask %}">{% trans "Please, post your question!" %}</a>
- </p>
- {% endif %}
-</div>
-<!-- end questions_ajax.html -->
diff --git a/askbot/skins/default/templates/unused/user_footer.html b/askbot/skins/default/templates/unused/user_footer.html
deleted file mode 100644
index ee347742..00000000
--- a/askbot/skins/default/templates/unused/user_footer.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<!-- user_footer.html -->
-<div id="mainbar-footer">
-
-</div><!-- end user_footer.html -->
diff --git a/askbot/skins/default/templates/user_favorites.html b/askbot/skins/default/templates/user_favorites.html
deleted file mode 100644
index c346bbb6..00000000
--- a/askbot/skins/default/templates/user_favorites.html
+++ /dev/null
@@ -1,6 +0,0 @@
-{% extends "user.html" %}
-<!-- user_favorites.html -->
-{% block usercontent %}
-{% include "users_questions.html" %}
-{% endblock %}
-<!-- end user_favorites.html -->
diff --git a/askbot/skins/default/templates/user.html b/askbot/skins/default/templates/user_profile/user.html
index 1d0881a2..e8abdf4b 100644
--- a/askbot/skins/default/templates/user.html
+++ b/askbot/skins/default/templates/user_profile/user.html
@@ -7,15 +7,15 @@
</style>
{% endblock %}
{% block content %}
- <div id="mainbar-full">
- <div id="subheader" class="headUser">
- {% spaceless %}
- <a href="{% url user_profile view_user.id, view_user.username|slugify %}">
- {% trans username=view_user.username %}{{username}}'s profile{% endtrans %}
- </a>
- {% endspaceless %}
- </div>
- {% include "user_tabs.html" %}
+ <h1>
+ {% spaceless %}
+ <a href="{% url user_profile view_user.id, view_user.username|slugify %}">
+ {% trans username=view_user.username %}{{username}}'s profile{% endtrans %} - {% block profilesection %}{% endblock %}
+ </a>
+ {% endspaceless %}
+ </h1>
+ <div style="margin-left: 5px;">
+ {% include "user_profile/user_tabs.html" %}
{% block usercontent %}
{% endblock %}
</div>
diff --git a/askbot/skins/default/templates/user_edit.html b/askbot/skins/default/templates/user_profile/user_edit.html
index ecdc8809..9308bf90 100644
--- a/askbot/skins/default/templates/user_edit.html
+++ b/askbot/skins/default/templates/user_profile/user_edit.html
@@ -3,9 +3,9 @@
<!-- user_edit.html -->
{% block title %}{% spaceless %}{% trans %}Edit user profile{% endtrans %}{% endspaceless %}{% endblock %}
{% block content %}
-<div id="main-bar" class="headNormal">
+<h1>
{{ request.user.username }} - {% trans %}edit profile{% endtrans %}
-</div>
+</h1>
<div id="main-body" style="width:100%;padding-top:10px">
<form name="" action="{% url edit_user request.user.id %}" method="post">
<div id="left" style="float:left;width:180px">
@@ -23,7 +23,7 @@
<th width="100px"></th>
<th></th>
</tr>
- <tr style="height:35px">
+ <tr>
<td>{% trans %}Screen Name{% endtrans %}:</td>
<td>
{% if settings.EDITABLE_SCREEN_NAME %}
@@ -34,31 +34,39 @@
{% endif %}
</td>
</tr>
- <tr style="height:35px">
+ <tr>
<td>{{ form.email.label_tag() }}:</td>
<td>{{ form.email }} <span class="form-error"></span> {{ form.email.errors }} </td>
</tr>
- <tr style="height:35px">
+ <tr>
<td></td>
<td class="title-desc">{{ form.email.help_text }}</td>
</tr>
- <tr style="height:35px">
+ <tr>
<td>{{ form.realname.label_tag() }}:</td>
<td>{{ form.realname }} <span class="form-error"></span> {{ form.realname.errors }} </td>
</tr>
- <tr style="height:35px">
+ <tr>
<td>{{ form.website.label_tag() }}:</td>
<td>{{ form.website }} <span class="form-error"></span> {{ form.website.errors }} </td>
</tr>
- <tr style="height:35px">
+ <tr>
<td>{{ form.city.label_tag() }}:</td>
<td>{{ form.city }} <span class="form-error"></span> {{ form.city.errors }} </td>
</tr>
- <tr style="height:35px">
+ <tr>
+ <td>{{ form.country.label_tag() }}:</td>
+ <td>{{ form.country }} <span class="form-error"></span> {{ form.country.errors }} </td>
+ </tr>
+ <tr>
+ <td>{{ form.show_country.label_tag() }}:</td>
+ <td>{{ form.show_country }} <span class="form-error"></span> {{ form.show_country.errors }} </td>
+ </tr>
+ <tr>
<td>{{ form.birthday.label_tag() }}:</td>
<td>{{ form.birthday }} <span class="form-error"></span> {{ form.birthday.errors }} </td>
</tr>
- <tr style="height:35px">
+ <tr>
<td></td>
<td class="title-desc">{{ form.birthday.help_text }}</td>
</tr>
diff --git a/askbot/skins/default/templates/user_email_subscriptions.html b/askbot/skins/default/templates/user_profile/user_email_subscriptions.html
index c14834a3..896a77f0 100644
--- a/askbot/skins/default/templates/user_email_subscriptions.html
+++ b/askbot/skins/default/templates/user_profile/user_email_subscriptions.html
@@ -1,5 +1,8 @@
-{% extends "user.html" %}
+{% extends "user_profile/user.html" %}
<!-- user_email_subscriptions.html -->
+{% block profilesection %}
+ {% trans %}subscriptions{% endtrans %}
+{% endblock %}
{% block usercontent %}
<h2>{% trans %}Email subscription settings{% endtrans %}</h2>
<p class="message">{% trans %}email subscription settings info{% endtrans %}</p>
diff --git a/askbot/skins/default/templates/user_profile/user_favorites.html b/askbot/skins/default/templates/user_profile/user_favorites.html
new file mode 100644
index 00000000..befcd471
--- /dev/null
+++ b/askbot/skins/default/templates/user_profile/user_favorites.html
@@ -0,0 +1,9 @@
+{% extends "user_profile/user.html" %}
+<!-- user_favorites.html -->
+{% block profilesection %}
+ {% trans %}favorites{% endtrans %}
+{% endblock %}
+{% block usercontent %}
+{% include "user_profile/users_questions.html" %}
+{% endblock %}
+<!-- end user_favorites.html -->
diff --git a/askbot/skins/default/templates/user_inbox.html b/askbot/skins/default/templates/user_profile/user_inbox.html
index 0904a302..f3622bd4 100644
--- a/askbot/skins/default/templates/user_inbox.html
+++ b/askbot/skins/default/templates/user_profile/user_inbox.html
@@ -1,4 +1,4 @@
-{% extends "user.html" %}
+{% extends "user_profile/user.html" %}
{% import "macros.html" as macros %}
<!-- user_responses.html -->
{#
@@ -14,6 +14,9 @@ response_title - title of the question
response_snippet - abbreviated content of the response
inbox_section - forum|flags
#}
+{% block profilesection %}
+ {% trans %}inbox{% endtrans %}
+{% endblock %}
{% block usercontent %}
<div style="padding-top:5px;font-size:13px;">
{% set re_count = request.user.new_response_count +
diff --git a/askbot/skins/default/templates/user_info.html b/askbot/skins/default/templates/user_profile/user_info.html
index 7c8d4eac..6c6868c7 100644
--- a/askbot/skins/default/templates/user_info.html
+++ b/askbot/skins/default/templates/user_profile/user_info.html
@@ -2,37 +2,41 @@
{% import "macros.html" as macros %}
<table class="user-info-table">
<tr>
- <td width="180" style="vertical-align:middle;text-align:center;">
- <table width="100%">
- <tr>
- <td>
- {{ macros.gravatar(view_user, 128) }}
- {% if request.user == view_user %}
- <h1><a href="{% url faq %}#gravatar">{% trans %}change picture{% endtrans %}</a></h1>
+ <td style="vertical-align:top;text-align:center;">
+ <div class='avatar'>
+ {{ macros.gravatar(view_user, 128) }}
+ {% if request.user == view_user %}
+ <p><a
+ {% if support_custom_avatars %}
+ href="{% url avatar_change %}"
+ {% else %}
+ href="{% url faq %}#gravatar"
{% endif %}
- </td>
- </tr>
- <tr>
- <td align="center">
- <div class="scoreNumber">{{view_user.reputation|intcomma}}</div>
- <p><b style="color:#777;">{% trans %}reputation{% endtrans %}</b></p>
- </td>
- </tr>
- </table>
+ >{% trans %}change picture{% endtrans %}</a></p>
+ {% if support_custom_avatars %}
+ <p><a
+ href="{% url avatar_delete %}"
+ >{% trans %}remove{% endtrans %}</a>
+ </p>
+ {% endif %}
+ {% endif %}
+ </div>
+ <div class="scoreNumber">{{view_user.reputation|intcomma}}</div>
+ <p><b style="color:#777;">{% trans %}reputation{% endtrans %}</b></p>
</td>
- <td width="360" style="vertical-align: top;">
+ <td width="360" style="padding-left:5px;vertical-align: top;">
<table class="user-details">
- {% if request.user|can_view_user_edit(view_user) %}
+ {% if request.user == view_user %}
<tr>
<td class="user-profile-tool-links" align="left" colspan="2">
- {% if request.user == view_user %}
- <a href="{% url user_signin %}?next={% url user_signin %}">
- {% trans %}manage login methods{% endtrans %}
- </a> |
- {% endif %}
<a href="{% url edit_user view_user.id %}">
{% trans %}update profile{% endtrans %}
</a>
+ {% if request.user == view_user %}
+ | <a href="{% url user_signin %}?next={% url user_signin %}">
+ {% trans %}manage login methods{% endtrans %}
+ </a>
+ {% endif %}
</td>
</tr>
{% endif %}
@@ -60,13 +64,13 @@
{% if view_user.website %}
<tr>
<td>{% trans %}user website{% endtrans %}</td>
- <td><a rel="nofollow" target="_blank" href="{{view_user.website}}">{{view_user.website}}</a></td>
+ <td>{{ macros.user_website_link(view_user, max_display_length = 30) }}</td>
</tr>
{% endif %}
- {% if view_user.location %}
+ {% if view_user.location or view_user.country %}
<tr>
<td>{% trans %}location{% endtrans %}</td>
- <td>{{view_user.location}}</td>
+ <td>{{ macros.user_full_location(view_user) }}</td>
</tr>
{% endif %}
{% if view_user.date_of_birth%}
diff --git a/askbot/skins/default/templates/user_moderate.html b/askbot/skins/default/templates/user_profile/user_moderate.html
index 75ea970e..b8070e50 100644
--- a/askbot/skins/default/templates/user_moderate.html
+++ b/askbot/skins/default/templates/user_profile/user_moderate.html
@@ -1,5 +1,8 @@
-{% extends "user.html" %}
+{% extends "user_profile/user.html" %}
<!-- user_moderate.html -->
+{% block profilesection %}
+ {% trans %}moderation{% endtrans %}
+{% endblock %}
{% block usercontent %}
{% if request.user != view_user %}
<h3>{% trans username=view_user.username, status=view_user.get_status_display() %}{{username}}'s current status is "{{status}}"{% endtrans %}
diff --git a/askbot/skins/default/templates/user_recent.html b/askbot/skins/default/templates/user_profile/user_recent.html
index 39dc4bea..f641a077 100644
--- a/askbot/skins/default/templates/user_recent.html
+++ b/askbot/skins/default/templates/user_profile/user_recent.html
@@ -1,5 +1,8 @@
-{% extends "user.html" %}
+{% extends "user_profile/user.html" %}
<!-- user_recent.html -->
+{% block profilesection %}
+ {% trans %}activity{% endtrans %}
+{% endblock %}
{% block usercontent %}
<div style="padding-top:5px;font-size:13px;">
{% for act in activities %}
diff --git a/askbot/skins/default/templates/user_reputation.html b/askbot/skins/default/templates/user_profile/user_reputation.html
index dd9d341d..99b304d2 100644
--- a/askbot/skins/default/templates/user_reputation.html
+++ b/askbot/skins/default/templates/user_profile/user_reputation.html
@@ -1,14 +1,17 @@
-{% extends "user.html" %}
+{% extends "user_profile/user.html" %}
<!-- user_reputation.html -->
+{% block profilesection %}
+ {% trans %}karma{% endtrans %}
+{% endblock %}
{% block usercontent %}
<div class="karma-summary">
<div id="diagram" class="karma-diagram"></div>
- {% if view_user.id == user.id %}
- <h3>{% trans %}Your karma change log.{% endtrans %}</h3>
- {% else %}
- <h3>{% trans user_name=view_user.username %}{{user_name}}'s karma change log{% endtrans %}</h3>
- {% endif %}
<div class="karma-details">
+ {% if view_user.id == user.id %}
+ <h3>{% trans %}Your karma change log.{% endtrans %}</h3>
+ {% else %}
+ <h3>{% trans user_name=view_user.username %}{{user_name}}'s karma change log{% endtrans %}</h3>
+ {% endif %}
{% for rep in reputation %}
<p>
<span class="karma-gained">{{ rep.positive }}</span>
diff --git a/askbot/skins/default/templates/user_stats.html b/askbot/skins/default/templates/user_profile/user_stats.html
index 6c96d94d..02849df1 100644
--- a/askbot/skins/default/templates/user_stats.html
+++ b/askbot/skins/default/templates/user_profile/user_stats.html
@@ -1,12 +1,16 @@
-{% extends "user.html" %}
+{% extends "user_profile/user.html" %}
+{% import "macros.html" as macros %}
<!-- user_stats.html -->
+{% block profilesection %}
+ {% trans %}overview{% endtrans %}
+{% endblock %}
{% block usercontent %}
- {% include "user_info.html" %}
+ {% include "user_profile/user_info.html" %}
<a name="questions"></a>
{% spaceless %}
<h2>{% trans counter=questions|length %}<span class="count">{{counter}}</span> Question{% pluralize %}<span class="count">{{counter}}</span> Questions{% endtrans %}</h2>
{% endspaceless %}
- {% include "users_questions.html" %}
+ {% include "user_profile/users_questions.html" %}
<a name="answers"></a>
{% spaceless %}
<h2 style="clear:both;">{% trans counter=answered_questions|length %}<span class="count">{{counter}}</span> Answer{% pluralize %}<span class="count">{{counter}}</span> Answers{% endtrans %}</h2>
@@ -61,17 +65,31 @@
<div class="user-stats-table">
<table class="tags">
<tr>
- <td width="180" valign="top">
+ <td valign="top">
+ <ul id="ab-user-tags" class="tags">
{% for tag in user_tags %}
- <a rel="tag"
- title="{% trans tag_name=tag.name %}see other questions with {{view_user}}'s contributions tagged '{{ tag_name }}' {% endtrans %}"
- href="{% url questions %}?tags={{tag|urlencode}}&amp;author={{view_user.id}}&amp;start_over=true">{{tag.name}}</a>
- <span class="tag-number">&#215; {{ tag.user_tag_usage_count|intcomma }}</span><br/>
+ <li>
+ {{ macros.tag_widget(
+ tag.name,
+ html_tag = 'div',
+ url_params =
+ "author=" ~ view_user.id ~
+ "&start_over=true",
+ extra_content =
+ '<span class="tag-number">&#215; ' ~
+ tag.user_tag_usage_count|intcomma ~
+ '</span>'
+ )
+ }}
+ </li>
+ {#
{% if loop.index is divisibleby 10 %}
</td>
<td width="180" valign="top">
{% endif %}
+ #}
{% endfor %}
+ </ul>
</td>
</tr>
</table>
diff --git a/askbot/skins/default/templates/user_tabs.html b/askbot/skins/default/templates/user_profile/user_tabs.html
index bf63ae77..276590c9 100644
--- a/askbot/skins/default/templates/user_tabs.html
+++ b/askbot/skins/default/templates/user_profile/user_tabs.html
@@ -3,35 +3,43 @@
<div class="tabsC">
<a id="stats" {% if tab_name=="stats" %}class="on"{% endif %}
title="{% trans %}User profile{% endtrans %}"
- href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=stats">{% trans %}overview{% endtrans %}</a>
+ href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=stats"
+ ><span>{% trans %}overview{% endtrans %}</span></a>
{% if request.user == view_user or request.user|can_moderate_user(view_user) %}
<a id="inbox" {% if tab_name=="inbox" %}class="on"{% endif %}
title="{% trans %}comments and answers to others questions{% endtrans %}"
- href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=inbox">{% trans %}inbox{% endtrans %}</a>
+ href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=inbox"
+ ><span>{% trans %}inbox{% endtrans %}</span></a>
{% endif %}
<a id="reputation" {% if tab_name=="reputation" %}class="on"{% endif %}
title="{% trans %}graph of user reputation{% endtrans %}"
- href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=reputation">{% trans %}reputation history{% endtrans %}</a>
+ href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=reputation"
+ ><span>{% trans %}reputation history{% endtrans %}</span></a>
<a id="favorites" {% if tab_name=="favorites" %}class="on"{% endif %}
title="{% trans %}questions that user selected as his/her favorite{% endtrans %}"
- href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=favorites">{% trans %}favorites{% endtrans %}</a>
+ href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=favorites"
+ ><span>{% trans %}favorites{% endtrans %}</span></a>
<a id="recent" {% if tab_name=="recent" %}class="on"{% endif %}
title="{% trans %}recent activity{% endtrans %}"
- href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=recent">{% trans %}activity{% endtrans %}</a>
+ href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=recent"
+ ><span>{% trans %}activity{% endtrans %}</span></a>
{% if request.user == view_user or request.user|can_moderate_user(view_user) %}
<a id="votes" {% if tab_name=="votes" %}class="on"{% endif %}
title="{% trans %}user vote record{% endtrans %}"
- href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=votes">{% trans %}casted votes{% endtrans %}</a>
+ href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=votes"
+ ><span>{% trans %}casted votes{% endtrans %}</span></a>
{% endif %}
{% if request.user == view_user or request.user|can_moderate_user(view_user) %}
<a id="email_subscriptions" {% if tab_name=="email_subscriptions" %}class="on"{% endif %}
title="{% trans %}email subscription settings{% endtrans %}"
- href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=email_subscriptions">{% trans %}subscriptions{% endtrans %}</a>
+ href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=email_subscriptions"
+ ><span>{% trans %}subscriptions{% endtrans %}</span></a>
{% endif %}
{% if request.user|can_moderate_user(view_user) %}
<a id="moderation" {% if tab_name=="moderation" %}class="on"{% endif %}
title="{% trans %}moderate this user{% endtrans %}"
- href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=moderation">{% trans %}moderation{% endtrans %}</a>
+ href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=moderation"
+ ><span>{% trans %}moderation{% endtrans %}</span></a>
{% endif %}
</div>
</div>
diff --git a/askbot/skins/default/templates/user_votes.html b/askbot/skins/default/templates/user_profile/user_votes.html
index 33f6f1fe..b6fe784b 100644
--- a/askbot/skins/default/templates/user_votes.html
+++ b/askbot/skins/default/templates/user_profile/user_votes.html
@@ -1,5 +1,8 @@
-{% extends "user.html" %}
+{% extends "user_profile/user.html" %}
<!-- user_votes.html -->
+{% block profilesection %}
+ {% trans %}votes{% endtrans %}
+{% endblock %}
{% block usercontent %}
<div style="padding-top:5px;font-size:13px;">
{% for vote in votes %}
diff --git a/askbot/skins/default/templates/users_questions.html b/askbot/skins/default/templates/user_profile/users_questions.html
index aaec21b7..aaec21b7 100644
--- a/askbot/skins/default/templates/users_questions.html
+++ b/askbot/skins/default/templates/user_profile/users_questions.html
diff --git a/askbot/skins/default/templates/users.html b/askbot/skins/default/templates/users.html
index e98ce039..74c171c8 100644
--- a/askbot/skins/default/templates/users.html
+++ b/askbot/skins/default/templates/users.html
@@ -4,65 +4,63 @@
{% block title %}{% spaceless %}{% trans %}Users{% endtrans %}{% endspaceless %}{% endblock %}
{% block content %}
<div class="tabBar">
- <div class="headUsers">{% trans %}Users{% endtrans %}</div>
+ <h1>{% trans %}Users{% endtrans %}</h1>
<div class="tabsA">
<a
id="sort_reputation"
href="{% url users %}?sort=reputation"
{% if tab_id == 'reputation' %}class="on"{% endif %}
title="{% trans %}reputation{% endtrans %}"
- >{% trans %}reputation{% endtrans %}</a>
+ ><span>{% trans %}reputation{% endtrans %}</span></a>
<a
id="sort_newest"
href="{% url users %}?sort=newest"
{% if tab_id == 'newest' %}class="on"{% endif %}
class="off" title="{% trans %}recent{% endtrans %}"
- >{% trans %}recent{% endtrans %}</a>
+ ><span>{% trans %}recent{% endtrans %}</span></a>
<a
id="sort_last"
href="{% url users %}?sort=last"
{% if tab_id == 'last' %}class="on"{% endif %}
class="off" title="{% trans %}oldest{% endtrans %}"
- >{% trans %}oldest{% endtrans %}</a>
+ ><span>{% trans %}oldest{% endtrans %}<span></a>
<a
id="sort_user"
href="{% url users %}?sort=user"
{% if tab_id == 'user' %}class="on"{% endif %}
title="{% trans %}by username{% endtrans %}"
- >{% trans %}by username{% endtrans %}</a>
+ ><span>{% trans %}by username{% endtrans %}</span></a>
</div>
</div>
-<div id="main-body" style="width:100%">
- <p>
- {% if suser %}
- {% trans %}users matching query {{suser}}:{% endtrans %}
+<p>
+ {% if suser %}
+ {% trans %}users matching query {{suser}}:{% endtrans %}
+ {% endif %}
+ {% if not users.object_list %}
+ <span>{% trans %}Nothing found.{% endtrans %}</span>
+ {% endif %}
+</p>
+<div class="userList">
+ <table class="list-table">
+ <tr>
+ <td class="list-td">
+ {% for user in users.object_list %}
+ <div class="user">
+ <ul>
+ <li class="thumb">{{ macros.gravatar(user, 32) }}</li>
+ <li><a href="{% url user_profile user.id, user.username|slugify %}">{{user.username}}</a>{{ macros.user_country_flag(user) }}</li>
+ <li>{{ macros.user_score_and_badge_summary(user) }}</li>
+ </ul>
+ </div>
+
+ {% if loop.index is divisibleby 7 %}
+ </td>
+ <td>
{% endif %}
- {% if not users.object_list %}
- <span>{% trans %}Nothing found.{% endtrans %}</span>
- {% endif %}
- </p>
- <div class="userList">
- <table class="list-table">
- <tr>
- <td class="list-td">
- {% for user in users.object_list %}
- <div class="user">
- <ul>
- <li class="thumb">{{ macros.gravatar(user, 32) }}</li>
- <li><a href="{% url user_profile user.id, user.username|slugify %}">{{user.username}}</a></li>
- <li>{{ macros.user_score_and_badge_summary(user) }}</li>
- </ul>
- </div>
-
- {% if loop.index is divisibleby 7 %}
- </td>
- <td>
- {% endif %}
- {% endfor %}
- </td>
- </tr>
- </table>
- </div>
+ {% endfor %}
+ </td>
+ </tr>
+ </table>
</div>
<div class="pager">
{{ macros.paginator(paginator_context) }}
diff --git a/askbot/skins/loaders.py b/askbot/skins/loaders.py
index f264c546..04c398bc 100644
--- a/askbot/skins/loaders.py
+++ b/askbot/skins/loaders.py
@@ -1,12 +1,19 @@
import os.path
from django.template.loaders import filesystem
+from django.template import RequestContext
+from django.http import HttpResponse
from django.utils import translation
-from askbot.conf import settings as askbot_settings
from django.conf import settings as django_settings
from coffin.common import CoffinEnvironment
from jinja2 import loaders as jinja_loaders
+from jinja2.exceptions import TemplateNotFound
+from jinja2.utils import open_if_exists
+from askbot.conf import settings as askbot_settings
from askbot.skins import utils
+from coffin import template
+template.add_to_builtins('askbot.templatetags.extra_filters_jinja')
+
#module for skinning askbot
#via ASKBOT_DEFAULT_SKIN configureation variable (not django setting)
@@ -32,20 +39,52 @@ def load_template_source(name, dirs=None):
return filesystem.load_template_source(tname,dirs)
load_template_source.is_usable = True
+class SkinLoader(jinja_loaders.BaseLoader):
+ """loads template from the skin directory
+ code largely copy-pasted from the jinja2 internals
+ """
+ def get_source(self, environment, template):
+ pieces = jinja_loaders.split_template_path(template)
+ skin = askbot_settings.ASKBOT_DEFAULT_SKIN
+ skin_path = utils.get_path_to_skin(skin)
+ filename = os.path.join(skin_path, 'templates', *pieces)
+ print 'want file %s' % filename
+ f = open_if_exists(filename)
+ if f is None:
+ raise TemplateNotFound(template)
+ try:
+ contents = f.read().decode('utf-8')
+ finally:
+ f.close()
+
+ mtime = os.path.getmtime(filename)
+ def uptodate():
+ try:
+ return os.path.getmtime(filename) == mtime
+ except OSError:
+ return False
+ return contents, filename, uptodate
+
class SkinEnvironment(CoffinEnvironment):
"""Jinja template environment
that loads templates from askbot skins
"""
+ def __init__(self, *args, **kwargs):
+ """save the skin path and initialize the
+ Coffin Environment
+ """
+ self.skin = kwargs.pop('skin')
+ super(SkinEnvironment, self).__init__(*args, **kwargs)
+
def _get_loaders(self):
- """over-ridden function _get_loaders that creates
+ """this method is not used
+ over-ridden function _get_loaders that creates
the loader for the skin templates
"""
loaders = list()
- skin_name = askbot_settings.ASKBOT_DEFAULT_SKIN
- skin_dirs = utils.get_available_skins(selected = skin_name).values()
+ skin_dirs = utils.get_available_skins(selected = self.skin).values()
template_dirs = [os.path.join(skin_dir, 'templates') for skin_dir in skin_dirs]
-
loaders.append(jinja_loaders.FileSystemLoader(template_dirs))
return loaders
@@ -57,6 +96,50 @@ class SkinEnvironment(CoffinEnvironment):
trans = translation.trans_real.translation(language_code)
self.install_gettext_translations(trans)
+ def get_extra_css_link(self):
+ """returns either the link tag (to be inserted in the html head element)
+ or empty string - depending on the existence of file
+ SKIN_PATH/media/style/extra.css
+ """
+ url = utils.get_media_url('style/extra.css')
+ if url is not None:
+ return '<link href="%s" rel="stylesheet" type="text/css" />' % url
+ return ''
+
+def load_skins():
+ skins = dict()
+ for skin_name in utils.get_available_skins():
+ skins[skin_name] = SkinEnvironment(
+ skin = skin_name,
+ extensions=['jinja2.ext.i18n',]
+ )
+ skins[skin_name].set_language(django_settings.LANGUAGE_CODE)
+ #from askbot.templatetags import extra_filters_jinja as filters
+ #skins[skin_name].filters['media'] = filters.media
+ return skins
+
+SKINS = load_skins()
+
+def get_skin(request = None):
+ """retreives the skin environment
+ for a given request (request var is not used at this time)"""
+ return SKINS[askbot_settings.ASKBOT_DEFAULT_SKIN]
-ENV = SkinEnvironment(autoescape=False, extensions=['jinja2.ext.i18n'])
-ENV.set_language(django_settings.LANGUAGE_CODE)
+def get_template(template, request = None):
+ """retreives template for the skin
+ request variable will be used in the future to set
+ template according to the user preference or admins preference
+
+ at this point request variable is not used though
+ """
+ skin = get_skin(request)
+ return skin.get_template(template)
+
+def render_into_skin(template, data, request, mimetype = 'text/html'):
+ """in the future this function will be able to
+ switch skin depending on the site administrator/user selection
+ right now only admins can switch
+ """
+ context = RequestContext(request, data)
+ template = get_template(template, request)
+ return HttpResponse(template.render(context), mimetype = mimetype)
diff --git a/askbot/skins/utils.py b/askbot/skins/utils.py
index b244da00..5c9a7a7c 100644
--- a/askbot/skins/utils.py
+++ b/askbot/skins/utils.py
@@ -3,7 +3,6 @@
the lookup resolution process for templates and media works as follows:
* look up item in selected skin
* if not found look in 'default'
-* the look in 'common'
* raise an exception
"""
import os
@@ -29,11 +28,10 @@ def get_skins_from_dir(directory):
def get_available_skins(selected=None):
"""selected is a name of preferred skin
if it's None, then information about all skins will be returned
- otherwise, only data about selected, default and common skins
+ otherwise, only data about selected and default skins
will be returned
selected skin is guaranteed to be the first item in the dictionary
-
"""
skins = SortedDict()
if hasattr(django_settings, 'ASKBOT_EXTRA_SKINS_DIR'):
@@ -42,7 +40,6 @@ def get_available_skins(selected=None):
stock_dir = os.path.normpath(os.path.dirname(__file__))
stock_skins = get_skins_from_dir(stock_dir)
default_dir = stock_skins.pop('default')
- common_dir = stock_skins.pop('common')
skins.update(stock_skins)
@@ -55,9 +52,8 @@ def get_available_skins(selected=None):
assert(selected == 'default')
skins = SortedDict()
- #re-insert default and common as last two items
+ #re-insert default as a last item
skins['default'] = default_dir
- skins['common'] = common_dir
return skins
@@ -75,11 +71,10 @@ def get_skin_choices():
"""returns a tuple for use as a set of
choices in the form"""
skin_names = list(reversed(get_available_skins().keys()))
- skin_names.remove('common')
return zip(skin_names, skin_names)
def resolve_skin_for_media(media=None, preferred_skin = None):
- #see if file exists, if not, try skins 'default', then 'common'
+ #see if file exists, if not, try skin 'default'
available_skins = get_available_skins(selected = preferred_skin).items()
for skin_name, skin_dir in available_skins:
if os.path.isfile(os.path.join(skin_dir, 'media', media)):
@@ -93,6 +88,8 @@ def get_media_url(url):
askbot_settings.ASKBOT_DEFAULT_SKIN, then 'default', then 'commmon'
if file is not found - returns None
and logs an error message
+
+ todo: move this to the skin environment class
"""
#import datetime
#before = datetime.datetime.now()
diff --git a/askbot/sql_scripts/091111_upgrade_evgeny.sql b/askbot/sql_scripts/091111_upgrade_evgeny.sql
deleted file mode 100644
index cb76ec3c..00000000
--- a/askbot/sql_scripts/091111_upgrade_evgeny.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE `auth_user` add column is_approved tinyint(1) not NULL;
diff --git a/askbot/sql_scripts/091208_upgrade_evgeny.sql b/askbot/sql_scripts/091208_upgrade_evgeny.sql
deleted file mode 100644
index d9c4289a..00000000
--- a/askbot/sql_scripts/091208_upgrade_evgeny.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE `auth_user` add column hide_ignored_questions tinyint(1) not NULL;
diff --git a/askbot/sql_scripts/091208_upgrade_evgeny_1.sql b/askbot/sql_scripts/091208_upgrade_evgeny_1.sql
deleted file mode 100644
index b1b4107f..00000000
--- a/askbot/sql_scripts/091208_upgrade_evgeny_1.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE `auth_user` add column `tag_filter_setting` varchar(16) not NULL default 'ignored';
diff --git a/askbot/sql_scripts/100108_upgrade_ef.sql b/askbot/sql_scripts/100108_upgrade_ef.sql
deleted file mode 100644
index 1c9a5c1c..00000000
--- a/askbot/sql_scripts/100108_upgrade_ef.sql
+++ /dev/null
@@ -1,4 +0,0 @@
-alter table auth_user add column hide_ignored_questions tinyint(1) not NULL;
-update auth_user set hide_ignored_questions=0;
-alter table auth_user add column tag_filter_setting varchar(16) not NULL;
-update auth_user set tag_filter_setting='ignored';
diff --git a/askbot/sql_scripts/badges.sql b/askbot/sql_scripts/badges.sql
deleted file mode 100644
index 5fd03d18..00000000
--- a/askbot/sql_scripts/badges.sql
+++ /dev/null
@@ -1,37 +0,0 @@
-INSERT INTO badge ( id, name, type, slug, description, multiple, awarded_count) VALUES
-(1, 'Disciplined', 3, 'disciplined', 'Deleted own post with score of 3 or higher', TRUE, 0),
-(2, 'Peer Pressure', 3, 'peer-pressure', 'Deleted own post with score of -3 or lower', TRUE, 0),
-(3, 'Nice answer', 3, 'nice-answer', 'Answer voted up 10 times', TRUE, 0),
-(4, 'Nice Question', 3, 'nice-question', 'Question voted up 10 times', TRUE, 0),
-(5, 'Pundit', 3, 'pundit', 'Left 10 comments with score of 10 or more', FALSE, 0),
-(6, 'Popular Question', 3, 'popular-question', 'Asked a question with 1,000 views', TRUE, 0),
-(7, 'Citizen patrol', 3, 'citizen-patrol', 'First flagged post', FALSE, 0),
-(8, 'Cleanup', 3, 'cleanup', 'First rollback', FALSE, 0),
-(9, 'Critic', 3, 'critic', 'First down vote', FALSE, 0),
-(10, 'Editor', 3, 'editor', 'First edit', FALSE, 0),
-(11, 'Organizer', 3, 'organizer', 'First retag', FALSE, 0),
-(12, 'Scholar', 3, 'scholar', 'First accepted answer on your own question', FALSE, 0),
-(13, 'Student', 3, 'student', 'Asked first question with at least one up vote', FALSE, 0),
-(14, 'Supporter', 3, 'supporter', 'First up vote', FALSE, 0),
-(15, 'Teacher', 3, 'teacher', 'Answered first question with at least one up vote', FALSE, 0),
-(16, 'Autobiographer', 3, 'autobiographer', 'Completed all user profile fields', FALSE, 0),
-(17, 'Self-Learner', 3, 'self-learner', 'Answered your own question with at least 3 up votes', TRUE, 0),
-(18, 'Great Answer', 1, 'great-answer', 'Answer voted up 100 times', TRUE, 0),
-(19, 'Great Question', 1, 'great-question', 'Question voted up 100 times', TRUE, 0),
-(20, 'Stellar Question', 1, 'stellar-question', 'Question favorited by 100 users', TRUE, 0),
-(21, 'Famous question', 1, 'famous-question', 'Asked a question with 10,000 views', TRUE, 0),
-(22, 'Alpha', 2, 'alpha', 'Actively participated in the private alpha', FALSE, 0),
-(23, 'Good Answer', 2, 'good-answer', 'Answer voted up 25 times', TRUE, 0),
-(24, 'Good Question', 2, 'good-question', 'Question voted up 25 times', TRUE, 0),
-(25, 'Favorite Question', 2, 'favorite-question', 'Question favorited by 25 users', TRUE, 0),
-(26, 'Civic duty', 2, 'civic-duty', 'Voted 300 times', FALSE, 0),
-(27, 'Strunk & White', 2, 'strunk-and-white', 'Edited 100 entries', FALSE, 0),
-(28, 'Generalist', 2, 'generalist', 'Active in many different tags', FALSE, 0),
-(29, 'Expert', 2, 'export', 'Very active in one tag', FALSE, 0),
-(30, 'Yearling', 2, 'yearling', 'Active member for a year', FALSE, 0),
-(31, 'Notable Question', 2, 'notable-question', 'Asked a question with 2,500 views', TRUE, 0),
-(32, 'Enlightened', 2, 'enlightened', 'First answer was accepted with at least 10 up votes', FALSE, 0),
-(33, 'Beta', 2, 'beta', 'Actively participated in the private beta', FALSE, 0),
-(34, 'Guru', 2, 'guru', 'Accepted answer and voted up 40 times', TRUE, 0),
-(35, 'Necromancer', 2, 'necromancer', 'Answered a question more than 60 days later with at least 5 votes', TRUE, 0),
-(36, 'Taxonomist', 2, 'taxonomist', 'Created a tag used by 50 questions', TRUE, 0);
diff --git a/askbot/sql_scripts/cnprog.xml b/askbot/sql_scripts/cnprog.xml
deleted file mode 100644
index 95f9b362..00000000
--- a/askbot/sql_scripts/cnprog.xml
+++ /dev/null
@@ -1,1498 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Db flnm="cnprog" nm="cnprog" ver="1.3.4">
-<VerLbl></VerLbl>
-<VerNotes></VerNotes>
-<DefTblOpts></DefTblOpts>
-<DocFolder>/Users/sailing/Development/cnprog_beta2/sql_scripts</DocFolder>
-<Sch Cm="" nm="schemaA">
-<Tbl UsSo="1" nm="activity">
-<TblOpts>ENGINE=MyISAM AUTO_INCREMENT=103 DEFAULT CHARSET=latin1</TblOpts>
-<Pk ClNs="id" nm="pkactivity"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="activity_type" nu="0">
-<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="active_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="content_type_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="object_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="0" nm="is_auditted" nu="1">
-<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_activity_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="activity" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="activity_content_type_id" unq="0">
-<ClNs>content_type_id</ClNs>
-</Idx>
-<Idx clu="0" nm="activity_user_id" unq="0">
-<ClNs>user_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="answer">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkanswer"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="question_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="author_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="added_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="wiki" nu="0">
-<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="wikified_at" nu="1">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="accepted" nu="0">
-<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="deleted" nu="0">
-<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="deleted_by_id" nu="1">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="locked" nu="0">
-<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="locked_by_id" nu="1">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="locked_at" nu="1">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="score" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="comment_count" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="" nm="offensive_flag_count" nu="0">
-<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="last_edited_at" nu="1">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="last_edited_by_id" nu="1">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="html" nu="0">
-<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="vote_up_count" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="vote_down_count" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="accepted_at" nu="1">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="deleted_by_id_refs_id_192b0170" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="1"/>
-<CdTb mn="1" nm="answer" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="deleted_by_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_answer_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="answer" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="author_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_answer_question" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="question" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="answer" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="question_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="last_edited_by_id_refs_id_192b0170" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="1"/>
-<CdTb mn="1" nm="answer" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="last_edited_by_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="locked_by_id_refs_id_192b0170" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="1"/>
-<CdTb mn="1" nm="answer" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="locked_by_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="answer_author_id" unq="0">
-<ClNs>author_id</ClNs>
-</Idx>
-<Idx clu="0" nm="answer_deleted_by_id" unq="0">
-<ClNs>deleted_by_id</ClNs>
-</Idx>
-<Idx clu="0" nm="answer_last_edited_by_id" unq="0">
-<ClNs>last_edited_by_id</ClNs>
-</Idx>
-<Idx clu="0" nm="answer_locked_by_id" unq="0">
-<ClNs>locked_by_id</ClNs>
-</Idx>
-<Idx clu="0" nm="answer_question_id" unq="0">
-<ClNs>question_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="answer_revision">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci</TblOpts>
-<Pk ClNs="id" nm="pkanswer_revision"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="answer_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="revision" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="" nm="author_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="revised_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="summary" nu="0">
-<DT ds="VarChar" en="" id="12" ln="300" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="text" nu="0">
-<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_answer_revision_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="answer_revision" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="author_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="answer_revision_answer_id" unq="0">
-<ClNs>answer_id</ClNs>
-</Idx>
-<Idx clu="0" nm="answer_revision_author_id" unq="0">
-<ClNs>author_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="auth_group">
-<TblOpts>ENGINE=InnoDB DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkauth_group"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="name" nu="0">
-<DT ds="VarChar" en="" id="12" ln="80" sc="null" sg="1"/>
-</Cl>
-<Idx clu="0" nm="name" unq="1">
-<ClNs>name</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="auth_group_permissions">
-<TblOpts>ENGINE=InnoDB DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkauth_group_permissions"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="group_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="permission_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_auth_group_permissions_auth_group" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_group" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="auth_group_permissions" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="group_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_auth_group_permissions_auth_permission" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_permission" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="auth_group_permissions" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="permission_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="group_id" unq="1">
-<ClNs>group_id, permission_id</ClNs>
-</Idx>
-<Idx clu="0" nm="permission_id_refs_id_5886d21f" unq="0">
-<ClNs>permission_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="auth_message">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkauth_message"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="message" nu="0">
-<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_auth_message_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="auth_message" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="auth_message_user_id" unq="0">
-<ClNs>user_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="auth_permission">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=88 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkauth_permission"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="name" nu="0">
-<DT ds="VarChar" en="" id="12" ln="50" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="content_type_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="codename" nu="0">
-<DT ds="VarChar" en="" id="12" ln="100" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_auth_permission_django_content_type" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="django_content_type" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="auth_permission" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="content_type_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="auth_permission_content_type_id" unq="0">
-<ClNs>content_type_id</ClNs>
-</Idx>
-<Idx clu="0" nm="content_type_id" unq="1">
-<ClNs>content_type_id, codename</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="auth_user">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=104 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkauth_user"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="username" nu="0">
-<DT ds="VarChar" en="" id="12" ln="30" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="first_name" nu="0">
-<DT ds="VarChar" en="" id="12" ln="30" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="last_name" nu="0">
-<DT ds="VarChar" en="" id="12" ln="30" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="email" nu="0">
-<DT ds="VarChar" en="" id="12" ln="75" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="password" nu="0">
-<DT ds="VarChar" en="" id="12" ln="128" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="is_staff" nu="0">
-<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="is_active" nu="0">
-<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="is_superuser" nu="0">
-<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="last_login" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="date_joined" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="0" nm="gold" nu="0">
-<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="0" nm="silver" nu="0">
-<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="0" nm="bronze" nu="0">
-<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="1" nm="reputation" nu="1">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="" nm="gravatar" nu="1">
-<DT ds="VarChar" en="" id="12" ln="128" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="10" nm="questions_per_page" nu="1">
-<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="" nm="last_seen" nu="1">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="real_name" nu="1">
-<DT ds="VarChar" en="" id="12" ln="100" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="website" nu="1">
-<DT ds="VarChar" en="" id="12" ln="200" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="location" nu="1">
-<DT ds="VarChar" en="" id="12" ln="100" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="date_of_birth" nu="1">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="about" nu="1">
-<DT ds="Text" en="" id="703" ln="null" sc="null" sg="1"/>
-</Cl>
-<Idx clu="0" nm="username" unq="1">
-<ClNs>username</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="auth_user_groups">
-<TblOpts>ENGINE=InnoDB DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkauth_user_groups"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="group_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_auth_user_groups_auth_group" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_group" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="auth_user_groups" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="group_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_auth_user_groups_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="auth_user_groups" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="group_id_refs_id_f116770" unq="0">
-<ClNs>group_id</ClNs>
-</Idx>
-<Idx clu="0" nm="user_id" unq="1">
-<ClNs>user_id, group_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="auth_user_user_permissions">
-<TblOpts>ENGINE=InnoDB DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkauth_user_user_permissions"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="permission_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_auth_user_user_permissions_auth_permission" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_permission" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="auth_user_user_permissions" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="permission_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_auth_user_user_permissions_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="auth_user_user_permissions" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="permission_id_refs_id_67e79cb" unq="0">
-<ClNs>permission_id</ClNs>
-</Idx>
-<Idx clu="0" nm="user_id" unq="1">
-<ClNs>user_id, permission_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="award">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkaward"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="badge_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="awarded_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="notified" nu="0">
-<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="content_type_id" nu="1">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="object_id" nu="1">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_award_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="award" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_award_badge" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="badge" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="award" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="badge_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="award_badge_id" unq="0">
-<ClNs>badge_id</ClNs>
-</Idx>
-<Idx clu="0" nm="award_user_id" unq="0">
-<ClNs>user_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="badge">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkbadge"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="name" nu="0">
-<DT ds="VarChar" en="" id="12" ln="50" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="type" nu="0">
-<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="slug" nu="0">
-<DT ds="VarChar" en="" id="12" ln="50" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="description" nu="0">
-<DT ds="VarChar" en="" id="12" ln="300" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="multiple" nu="0">
-<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="awarded_count" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
-</Cl>
-<Idx clu="0" nm="badge_slug" unq="0">
-<ClNs>slug</ClNs>
-</Idx>
-<Idx clu="0" nm="name" unq="1">
-<ClNs>name, type</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="book">
-<TblOpts></TblOpts>
-<Pk ClNs="id" nm="pkbook"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="title" nu="0">
-<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="short_name" nu="0">
-<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="author" nu="0">
-<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="1">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="price" nu="1">
-<DT ds="Decimal" en="" id="3" ln="10" sc="2" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="pages" nu="1">
-<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="published_at" nu="0">
-<DT ds="Date" en="" id="91" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="publication" nu="0">
-<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="cover_img" nu="1">
-<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="tagnames" nu="1">
-<DT ds="VarChar" en="" id="12" ln="125" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="added_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="last_edited_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_books_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="book" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="book_short_name_Idx" unq="1">
-<ClNs>short_name</ClNs>
-</Idx>
-<Idx clu="0" nm="fk_books_auth_user" unq="0">
-<ClNs>user_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="book_author_info">
-<TblOpts></TblOpts>
-<Pk ClNs="id" nm="pkbook_author_info"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="blog_url" nu="1">
-<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="added_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="last_edited_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="book_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_book_author_info_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="book_author_info" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_book_author_info_book" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="book" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="book_author_info" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="book_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="fk_book_author_info_auth_user" unq="0">
-<ClNs>user_id</ClNs>
-</Idx>
-<Idx clu="0" nm="fk_book_author_info_book" unq="0">
-<ClNs>book_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="book_author_rss">
-<TblOpts></TblOpts>
-<Pk ClNs="id" nm="pkbook_author_rss"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="title" nu="0">
-<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="url" nu="0">
-<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="rss_created_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="added_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="book_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_book_author_rss_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="book_author_rss" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_book_author_rss_book" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="book" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="book_author_rss" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="book_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="fk_book_author_rss_auth_user" unq="0">
-<ClNs>user_id</ClNs>
-</Idx>
-<Idx clu="0" nm="fk_book_author_rss_book" unq="0">
-<ClNs>book_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="book_question">
-<TblOpts></TblOpts>
-<Pk ClNs="id" nm="pkbook_question"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="book_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="question_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_book_question_book" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="book" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="book_question" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="book_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_book_question_question" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="question" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="book_question" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="question_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="fk_book_question_book" unq="0">
-<ClNs>book_id</ClNs>
-</Idx>
-<Idx clu="0" nm="fk_book_question_question" unq="0">
-<ClNs>question_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="comment">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkcomment"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="content_type_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="object_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="comment" nu="0">
-<DT ds="VarChar" en="" id="12" ln="300" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="added_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_comment_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="comment" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_comment_django_content_type" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="django_content_type" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="comment" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="content_type_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="comment_content_type_id" unq="0">
-<ClNs>content_type_id</ClNs>
-</Idx>
-<Idx clu="0" nm="comment_user_id" unq="0">
-<ClNs>user_id</ClNs>
-</Idx>
-<Idx clu="0" nm="content_type_id" unq="0">
-<ClNs>content_type_id, object_id, user_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="django_admin_log">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkdjango_admin_log"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="action_time" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="content_type_id" nu="1">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="object_id" nu="1">
-<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="object_repr" nu="0">
-<DT ds="VarChar" en="" id="12" ln="200" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="action_flag" nu="0">
-<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="" nm="change_message" nu="0">
-<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_django_admin_log_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="django_admin_log" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_django_admin_log_django_content_type" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="django_content_type" oe="1" sch="schemaA" zr="1"/>
-<CdTb mn="1" nm="django_admin_log" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="content_type_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="django_admin_log_content_type_id" unq="0">
-<ClNs>content_type_id</ClNs>
-</Idx>
-<Idx clu="0" nm="django_admin_log_user_id" unq="0">
-<ClNs>user_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="django_authopenid_association">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkdjango_authopenid_association"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="server_url" nu="0">
-<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="handle" nu="0">
-<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="secret" nu="0">
-<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="issued" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="lifetime" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="assoc_type" nu="0">
-<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
-</Cl>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="django_authopenid_nonce">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkdjango_authopenid_nonce"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="server_url" nu="0">
-<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="timestamp" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="salt" nu="0">
-<DT ds="VarChar" en="" id="12" ln="40" sc="null" sg="1"/>
-</Cl>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="django_authopenid_userassociation">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkdjango_authopenid_userassociation"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="openid_url" nu="0">
-<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_django_authopenid_userassociation_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="django_authopenid_userassociation" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="user_id" unq="1">
-<ClNs>user_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="django_authopenid_userpasswordqueue">
-<TblOpts>ENGINE=InnoDB DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkdjango_authopenid_userpasswordqueue"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="new_password" nu="0">
-<DT ds="VarChar" en="" id="12" ln="30" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="confirm_key" nu="0">
-<DT ds="VarChar" en="" id="12" ln="40" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_django_authopenid_userpasswordqueue_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="django_authopenid_userpasswordqueue" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="user_id" unq="1">
-<ClNs>user_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="django_content_type">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkdjango_content_type"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="name" nu="0">
-<DT ds="VarChar" en="" id="12" ln="100" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="app_label" nu="0">
-<DT ds="VarChar" en="" id="12" ln="100" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="model" nu="0">
-<DT ds="VarChar" en="" id="12" ln="100" sc="null" sg="1"/>
-</Cl>
-<Idx clu="0" nm="app_label" unq="1">
-<ClNs>app_label, model</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="django_session">
-<TblOpts>ENGINE=InnoDB DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="session_key" nm="pkdjango_session"/>
-<Cl au="0" df="" nm="session_key" nu="0">
-<DT ds="VarChar" en="" id="12" ln="40" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="session_data" nu="0">
-<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="expire_date" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="django_site">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkdjango_site"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="domain" nu="0">
-<DT ds="VarChar" en="" id="12" ln="100" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="name" nu="0">
-<DT ds="VarChar" en="" id="12" ln="50" sc="null" sg="1"/>
-</Cl>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="favorite_question">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkfavorite_question"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="question_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="added_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_favorite_question_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="favorite_question" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_favorite_question_question" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="question" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="favorite_question" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="question_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="favorite_question_question_id" unq="0">
-<ClNs>question_id</ClNs>
-</Idx>
-<Idx clu="0" nm="favorite_question_user_id" unq="0">
-<ClNs>user_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="flagged_item">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkflagged_item"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="content_type_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="object_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="flagged_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_flagged_item_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="flagged_item" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_flagged_item_django_content_type" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="django_content_type" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="flagged_item" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="content_type_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="content_type_id" unq="1">
-<ClNs>content_type_id, object_id, user_id</ClNs>
-</Idx>
-<Idx clu="0" nm="flagged_item_content_type_id" unq="0">
-<ClNs>content_type_id</ClNs>
-</Idx>
-<Idx clu="0" nm="flagged_item_user_id" unq="0">
-<ClNs>user_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="question">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkquestion"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="title" nu="0">
-<DT ds="VarChar" en="" id="12" ln="300" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="author_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="added_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="wiki" nu="0">
-<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="wikified_at" nu="1">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="answer_accepted" nu="0">
-<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="closed" nu="0">
-<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="closed_by_id" nu="1">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="closed_at" nu="1">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="close_reason" nu="1">
-<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="deleted" nu="0">
-<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="deleted_at" nu="1">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="deleted_by_id" nu="1">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="locked" nu="0">
-<DT ds="TinyInt" en="" id="-6" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="locked_by_id" nu="1">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="locked_at" nu="1">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="score" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="answer_count" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="" nm="comment_count" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="" nm="view_count" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="" nm="offensive_flag_count" nu="0">
-<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="favourite_count" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="" nm="last_edited_at" nu="1">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="last_edited_by_id" nu="1">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="last_activity_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="last_activity_by_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="tagnames" nu="0">
-<DT ds="VarChar" en="" id="12" ln="125" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="summary" nu="0">
-<DT ds="VarChar" en="" id="12" ln="180" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="html" nu="0">
-<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="vote_up_count" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="vote_down_count" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="closed_by_id_refs_id_56e9d00c" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="1"/>
-<CdTb mn="1" nm="question" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="closed_by_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="deleted_by_id_refs_id_56e9d00c" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="1"/>
-<CdTb mn="1" nm="question" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="deleted_by_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_question_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="question" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="author_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="last_activity_by_id_refs_id_56e9d00c" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="question" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="last_activity_by_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="last_edited_by_id_refs_id_56e9d00c" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="1"/>
-<CdTb mn="1" nm="question" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="last_edited_by_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="locked_by_id_refs_id_56e9d00c" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="1"/>
-<CdTb mn="1" nm="question" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="locked_by_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="question_author_id" unq="0">
-<ClNs>author_id</ClNs>
-</Idx>
-<Idx clu="0" nm="question_closed_by_id" unq="0">
-<ClNs>closed_by_id</ClNs>
-</Idx>
-<Idx clu="0" nm="question_deleted_by_id" unq="0">
-<ClNs>deleted_by_id</ClNs>
-</Idx>
-<Idx clu="0" nm="question_last_activity_by_id" unq="0">
-<ClNs>last_activity_by_id</ClNs>
-</Idx>
-<Idx clu="0" nm="question_last_edited_by_id" unq="0">
-<ClNs>last_edited_by_id</ClNs>
-</Idx>
-<Idx clu="0" nm="question_locked_by_id" unq="0">
-<ClNs>locked_by_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="question_revision">
-<TblOpts>ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1</TblOpts>
-<Pk ClNs="id" nm="pkquestion_revision"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="question_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="revision" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="" nm="title" nu="0">
-<DT ds="VarChar" en="" id="12" ln="300" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="author_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="revised_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="tagnames" nu="0">
-<DT ds="VarChar" en="" id="12" ln="125" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="summary" nu="0">
-<DT ds="VarChar" en="" id="12" ln="300" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="text" nu="0">
-<DT ds="LongText" en="" id="712" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_question_revision_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="question_revision" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="author_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_question_revision_question" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="question" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="question_revision" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="question_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="question_revision_author_id" unq="0">
-<ClNs>author_id</ClNs>
-</Idx>
-<Idx clu="0" nm="question_revision_question_id" unq="0">
-<ClNs>question_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="question_tags">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkquestion_tags"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="question_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="tag_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_question_tags_question" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="question" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="question_tags" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="question_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_question_tags_tag" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="tag" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="question_tags" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="tag_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="question_id" unq="1">
-<ClNs>question_id, tag_id</ClNs>
-</Idx>
-<Idx clu="0" nm="tag_id_refs_id_43fcb953" unq="0">
-<ClNs>tag_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="repute">
-<TblOpts>ENGINE=MyISAM AUTO_INCREMENT=17 DEFAULT CHARSET=latin1</TblOpts>
-<Pk ClNs="id" nm="pkrepute"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="positive" nu="0">
-<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="negative" nu="0">
-<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="question_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="reputed_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="reputation_type" nu="0">
-<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="reputation" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_repute_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="repute" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_repute_question" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="question" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="repute" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="question_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="repute_question_id" unq="0">
-<ClNs>question_id</ClNs>
-</Idx>
-<Idx clu="0" nm="repute_user_id" unq="0">
-<ClNs>user_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="tag">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pktag"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="name" nu="0">
-<DT ds="VarChar" en="" id="12" ln="255" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="created_by_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="used_count" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
-</Cl>
-<Fk deAc="3" nm="fk_tag_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="tag" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="created_by_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="name" unq="1">
-<ClNs>name</ClNs>
-</Idx>
-<Idx clu="0" nm="tag_created_by_id" unq="0">
-<ClNs>created_by_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="user_badge">
-<TblOpts>ENGINE=InnoDB DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkuser_badge"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="badge_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_user_badge_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="user_badge" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_user_badge_badge" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="badge" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="user_badge" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="badge_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="fk_user_badge_auth_user" unq="0">
-<ClNs>user_id</ClNs>
-</Idx>
-<Idx clu="0" nm="fk_user_badge_badge" unq="0">
-<ClNs>badge_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="user_favorite_questions">
-<TblOpts>ENGINE=InnoDB DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkuser_favorite_questions"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="question_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_user_favorite_questions_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="user_favorite_questions" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_user_favorite_questions_question" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="question" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="user_favorite_questions" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="question_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="fk_user_favorite_questions_auth_user" unq="0">
-<ClNs>user_id</ClNs>
-</Idx>
-<Idx clu="0" nm="fk_user_favorite_questions_question" unq="0">
-<ClNs>question_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-<Tbl UsSo="1" nm="vote">
-<TblOpts>ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8</TblOpts>
-<Pk ClNs="id" nm="pkvote"/>
-<Cl au="1" df="" nm="id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="content_type_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="object_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="0"/>
-</Cl>
-<Cl au="0" df="" nm="user_id" nu="0">
-<DT ds="Integer" en="" id="4" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="vote" nu="0">
-<DT ds="SmallInt" en="" id="5" ln="null" sc="null" sg="1"/>
-</Cl>
-<Cl au="0" df="" nm="voted_at" nu="0">
-<DT ds="DateTime" en="" id="700" ln="null" sc="null" sg="1"/>
-</Cl>
-<Fk deAc="3" nm="fk_vote_auth_user" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="auth_user" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="vote" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="user_id" prCl="id"/>
-</Fk>
-<Fk deAc="3" nm="fk_vote_django_content_type" prLkCl="id" upAc="3">
-<PrTb mn="0" nm="django_content_type" oe="1" sch="schemaA" zr="0"/>
-<CdTb mn="1" nm="vote" oe="1" sch="schemaA" zr="1"/>
-<ClPr cdCl="content_type_id" prCl="id"/>
-</Fk>
-<Idx clu="0" nm="content_type_id" unq="1">
-<ClNs>content_type_id, object_id, user_id</ClNs>
-</Idx>
-<Idx clu="0" nm="vote_content_type_id" unq="0">
-<ClNs>content_type_id</ClNs>
-</Idx>
-<Idx clu="0" nm="vote_user_id" unq="0">
-<ClNs>user_id</ClNs>
-</Idx>
-<SchTrHis/>
-</Tbl>
-</Sch>
-<Dgm nm="diagramA">
-<RnCf FtSz="12" lkStgy="OffsetDirect" zm="1.0">
-<VbCfg>
-<Fg ky="Auto Number" vl="0"/>
-<Fg ky="Check" vl="0"/>
-<Fg ky="Comment" vl="0"/>
-<Fg ky="Data Type" vl="1"/>
-<Fg ky="Default" vl="0"/>
-<Fg ky="ENUM Values" vl="0"/>
-<Fg ky="Length" vl="1"/>
-<Fg ky="Name" vl="1"/>
-<Fg ky="Nullable" vl="0"/>
-<Fg ky="Schema Name" vl="0"/>
-<Fg ky="Signed" vl="0"/>
-</VbCfg>
-</RnCf>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="activity" x="811" y="284"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="answer" x="413" y="472"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="answer_revision" x="1067" y="41"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="auth_group" x="593" y="703"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="auth_group_permissions" x="765" y="703"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="auth_message" x="323" y="1441"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="auth_permission" x="636" y="794"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="auth_user" x="50" y="50"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="auth_user_groups" x="403" y="703"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="auth_user_user_permissions" x="393" y="794"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="award" x="373" y="971"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="badge" x="606" y="971"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="comment" x="383" y="880"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="django_admin_log" x="363" y="1087"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="django_authopenid_association" x="1543" y="50"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="django_authopenid_nonce" x="1781" y="50"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="django_authopenid_userassociation" x="313" y="1502"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="django_authopenid_userpasswordqueue" x="303" y="1563"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="django_content_type" x="636" y="880"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="django_session" x="1088" y="222"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="django_site" x="1312" y="152"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="favorite_question" x="433" y="50"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="flagged_item" x="353" y="1198"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="question" x="423" y="121"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="question_revision" x="1380" y="241"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="question_tags" x="736" y="121"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="repute" x="1661" y="180"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="tag" x="343" y="1279"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="user_badge" x="916" y="200"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="user_favorite_questions" x="1070" y="366"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="vote" x="93" y="1341"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="book" x="962" y="1063"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="book_question" x="702" y="1160"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="book_author_info" x="931" y="1436"/>
-<TbGl bkCl="ffffffe6" sch="schemaA" tbl="book_author_rss" x="619" y="1321"/>
-<FkGl bkCl="ff000000" nm="schemaA.activity.fk_activity_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.answer.deleted_by_id_refs_id_192b0170"/>
-<FkGl bkCl="ff000000" nm="schemaA.answer.fk_answer_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.answer.fk_answer_question"/>
-<FkGl bkCl="ff000000" nm="schemaA.answer.last_edited_by_id_refs_id_192b0170"/>
-<FkGl bkCl="ff000000" nm="schemaA.answer.locked_by_id_refs_id_192b0170"/>
-<FkGl bkCl="ff000000" nm="schemaA.answer_revision.fk_answer_revision_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.auth_group_permissions.fk_auth_group_permissions_auth_group"/>
-<FkGl bkCl="ff000000" nm="schemaA.auth_group_permissions.fk_auth_group_permissions_auth_permission"/>
-<FkGl bkCl="ff000000" nm="schemaA.auth_message.fk_auth_message_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.auth_permission.fk_auth_permission_django_content_type"/>
-<FkGl bkCl="ff000000" nm="schemaA.auth_user_groups.fk_auth_user_groups_auth_group"/>
-<FkGl bkCl="ff000000" nm="schemaA.auth_user_groups.fk_auth_user_groups_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.auth_user_user_permissions.fk_auth_user_user_permissions_auth_permission"/>
-<FkGl bkCl="ff000000" nm="schemaA.auth_user_user_permissions.fk_auth_user_user_permissions_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.award.fk_award_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.award.fk_award_badge"/>
-<FkGl bkCl="ff000000" nm="schemaA.book.fk_books_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.book_author_info.fk_book_author_info_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.book_author_info.fk_book_author_info_book"/>
-<FkGl bkCl="ff000000" nm="schemaA.book_author_rss.fk_book_author_rss_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.book_author_rss.fk_book_author_rss_book"/>
-<FkGl bkCl="ff000000" nm="schemaA.book_question.fk_book_question_book"/>
-<FkGl bkCl="ff000000" nm="schemaA.book_question.fk_book_question_question"/>
-<FkGl bkCl="ff000000" nm="schemaA.comment.fk_comment_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.comment.fk_comment_django_content_type"/>
-<FkGl bkCl="ff000000" nm="schemaA.django_admin_log.fk_django_admin_log_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.django_admin_log.fk_django_admin_log_django_content_type"/>
-<FkGl bkCl="ff000000" nm="schemaA.django_authopenid_userassociation.fk_django_authopenid_userassociation_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.django_authopenid_userpasswordqueue.fk_django_authopenid_userpasswordqueue_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.favorite_question.fk_favorite_question_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.favorite_question.fk_favorite_question_question"/>
-<FkGl bkCl="ff000000" nm="schemaA.flagged_item.fk_flagged_item_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.flagged_item.fk_flagged_item_django_content_type"/>
-<FkGl bkCl="ff000000" nm="schemaA.question.closed_by_id_refs_id_56e9d00c"/>
-<FkGl bkCl="ff000000" nm="schemaA.question.deleted_by_id_refs_id_56e9d00c"/>
-<FkGl bkCl="ff000000" nm="schemaA.question.fk_question_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.question.last_activity_by_id_refs_id_56e9d00c"/>
-<FkGl bkCl="ff000000" nm="schemaA.question.last_edited_by_id_refs_id_56e9d00c"/>
-<FkGl bkCl="ff000000" nm="schemaA.question.locked_by_id_refs_id_56e9d00c"/>
-<FkGl bkCl="ff000000" nm="schemaA.question_revision.fk_question_revision_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.question_revision.fk_question_revision_question"/>
-<FkGl bkCl="ff000000" nm="schemaA.question_tags.fk_question_tags_question"/>
-<FkGl bkCl="ff000000" nm="schemaA.question_tags.fk_question_tags_tag"/>
-<FkGl bkCl="ff000000" nm="schemaA.repute.fk_repute_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.repute.fk_repute_question"/>
-<FkGl bkCl="ff000000" nm="schemaA.tag.fk_tag_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.user_badge.fk_user_badge_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.user_badge.fk_user_badge_badge"/>
-<FkGl bkCl="ff000000" nm="schemaA.user_favorite_questions.fk_user_favorite_questions_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.user_favorite_questions.fk_user_favorite_questions_question"/>
-<FkGl bkCl="ff000000" nm="schemaA.vote.fk_vote_auth_user"/>
-<FkGl bkCl="ff000000" nm="schemaA.vote.fk_vote_django_content_type"/>
-</Dgm>
-<RnmMgr NxRnmId="6">
-<RnmCh ObjCls="Table" ParCls="Schema" ParNme="schemaA" SupCls="" SupNme="">
-<Rnm id="1" nNm="book" oNm="books"/>
-</RnmCh>
-<RnmCh ObjCls="Table" ParCls="Schema" ParNme="schemaA" SupCls="" SupNme="">
-<Rnm id="2" nNm="book_question" oNm="books_questions"/>
-</RnmCh>
-<RnmCh ObjCls="Column" ParCls="Table" ParNme="book_question" SupCls="Schema" SupNme="schemaA">
-<Rnm id="3" nNm="id" oNm="books_questions_id"/>
-</RnmCh>
-<RnmCh ObjCls="Column" ParCls="Table" ParNme="book_author_rss" SupCls="Schema" SupNme="schemaA">
-<Rnm id="4" nNm="user_id" oNm="book_author_id"/>
-</RnmCh>
-<RnmCh ObjCls="Column" ParCls="Table" ParNme="book" SupCls="Schema" SupNme="schemaA">
-<Rnm id="5" nNm="short_name" oNm="shot_name"/>
-</RnmCh>
-</RnmMgr>
-<DbDocOptionMgr>
-<BasicOptionMgr>
-<Name>db.doc.option.mgr</Name>
-<BoolOpt lbl="Diagrams" nm="doc.diagrams" on="1" spl="0"/>
-<BoolOpt lbl="Foreign Keys" nm="doc.fks" on="1" spl="0"/>
-<BoolOpt lbl="Indexes" nm="doc.indexes" on="1" spl="0"/>
-<BoolOpt lbl="Overwrite CSS File" nm="doc.overwrite.css" on="1" spl="0"/>
-<BoolOpt lbl="Procedures" nm="doc.procs" on="1" spl="0"/>
-<BoolOpt lbl="Schemas" nm="doc.schemas" on="1" spl="0"/>
-<BoolOpt lbl="Sequences" nm="doc.sequences" on="1" spl="0"/>
-<BoolOpt lbl="Tables" nm="doc.tables" on="1" spl="0"/>
-<BoolOpt lbl="Triggers" nm="doc.triggers" on="1" spl="0"/>
-<BoolOpt lbl="Views" nm="doc.views" on="1" spl="0"/>
-</BasicOptionMgr>
-</DbDocOptionMgr>
-</Db>
diff --git a/askbot/sql_scripts/cnprog_new_install.sql b/askbot/sql_scripts/cnprog_new_install.sql
deleted file mode 100644
index ac33a6ba..00000000
--- a/askbot/sql_scripts/cnprog_new_install.sql
+++ /dev/null
@@ -1,811 +0,0 @@
--- MySQL Administrator dump 1.4
---
--- ------------------------------------------------------
--- Server version 5.0.67
-
-
-/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
-/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!40101 SET NAMES utf8 */;
-
-/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
-/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
-/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-
-
---
--- Create schema cnprog
---
-
-CREATE DATABASE IF NOT EXISTS cnprog;
-USE cnprog;
-
---
--- Definition of table `cnprog`.`answer`
---
-
-DROP TABLE IF EXISTS `cnprog`.`answer`;
-CREATE TABLE `cnprog`.`answer` (
- `id` int(11) NOT NULL auto_increment,
- `question_id` int(11) NOT NULL,
- `author_id` int(11) NOT NULL,
- `added_at` datetime NOT NULL,
- `wiki` tinyint(1) NOT NULL,
- `wikified_at` datetime default NULL,
- `accepted` tinyint(1) NOT NULL,
- `deleted` tinyint(1) NOT NULL,
- `deleted_by_id` int(11) default NULL,
- `locked` tinyint(1) NOT NULL,
- `locked_by_id` int(11) default NULL,
- `locked_at` datetime default NULL,
- `score` int(11) NOT NULL,
- `vote_up_count` int(11) NOT NULL,
- `vote_down_count` int(11) NOT NULL,
- `comment_count` int(10) unsigned NOT NULL,
- `offensive_flag_count` smallint(6) NOT NULL,
- `last_edited_at` datetime default NULL,
- `last_edited_by_id` int(11) default NULL,
- `html` longtext NOT NULL,
- PRIMARY KEY (`id`),
- KEY `answer_question_id` (`question_id`),
- KEY `answer_author_id` (`author_id`),
- KEY `answer_deleted_by_id` (`deleted_by_id`),
- KEY `answer_locked_by_id` (`locked_by_id`),
- KEY `answer_last_edited_by_id` (`last_edited_by_id`),
- CONSTRAINT `author_id_refs_id_192b0170` FOREIGN KEY (`author_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `deleted_by_id_refs_id_192b0170` FOREIGN KEY (`deleted_by_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `last_edited_by_id_refs_id_192b0170` FOREIGN KEY (`last_edited_by_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `locked_by_id_refs_id_192b0170` FOREIGN KEY (`locked_by_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `question_id_refs_id_7d6550c9` FOREIGN KEY (`question_id`) REFERENCES `question` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;
-
---
--- Definition of table `cnprog`.`auth_group`
---
-
-DROP TABLE IF EXISTS `cnprog`.`auth_group`;
-CREATE TABLE `cnprog`.`auth_group` (
- `id` int(11) NOT NULL auto_increment,
- `name` varchar(80) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `name` (`name`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`auth_group`
---
-
---
--- Definition of table `cnprog`.`auth_group_permissions`
---
-
-DROP TABLE IF EXISTS `cnprog`.`auth_group_permissions`;
-CREATE TABLE `cnprog`.`auth_group_permissions` (
- `id` int(11) NOT NULL auto_increment,
- `group_id` int(11) NOT NULL,
- `permission_id` int(11) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `group_id` (`group_id`,`permission_id`),
- KEY `permission_id_refs_id_5886d21f` (`permission_id`),
- CONSTRAINT `group_id_refs_id_3cea63fe` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`),
- CONSTRAINT `permission_id_refs_id_5886d21f` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`auth_group_permissions`
---
-
---
--- Definition of table `cnprog`.`auth_message`
---
-
-DROP TABLE IF EXISTS `cnprog`.`auth_message`;
-CREATE TABLE `cnprog`.`auth_message` (
- `id` int(11) NOT NULL auto_increment,
- `user_id` int(11) NOT NULL,
- `message` longtext NOT NULL,
- PRIMARY KEY (`id`),
- KEY `auth_message_user_id` (`user_id`),
- CONSTRAINT `user_id_refs_id_650f49a6` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`auth_message`
---
-
---
--- Definition of table `cnprog`.`auth_permission`
---
-
-DROP TABLE IF EXISTS `cnprog`.`auth_permission`;
-CREATE TABLE `cnprog`.`auth_permission` (
- `id` int(11) NOT NULL auto_increment,
- `name` varchar(50) NOT NULL,
- `content_type_id` int(11) NOT NULL,
- `codename` varchar(100) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `content_type_id` (`content_type_id`,`codename`),
- KEY `auth_permission_content_type_id` (`content_type_id`),
- CONSTRAINT `content_type_id_refs_id_728de91f` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=76 DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`auth_permission`
---
-INSERT INTO `cnprog`.`auth_permission` VALUES (1,'Can add permission',1,'add_permission'),
- (2,'Can change permission',1,'change_permission'),
- (3,'Can delete permission',1,'delete_permission'),
- (4,'Can add group',2,'add_group'),
- (5,'Can change group',2,'change_group'),
- (6,'Can delete group',2,'delete_group'),
- (7,'Can add user',3,'add_user'),
- (8,'Can change user',3,'change_user'),
- (9,'Can delete user',3,'delete_user'),
- (10,'Can add message',4,'add_message'),
- (11,'Can change message',4,'change_message'),
- (12,'Can delete message',4,'delete_message'),
- (13,'Can add content type',5,'add_contenttype'),
- (14,'Can change content type',5,'change_contenttype'),
- (15,'Can delete content type',5,'delete_contenttype'),
- (16,'Can add session',6,'add_session'),
- (17,'Can change session',6,'change_session'),
- (18,'Can delete session',6,'delete_session'),
- (19,'Can add site',7,'add_site'),
- (20,'Can change site',7,'change_site'),
- (21,'Can delete site',7,'delete_site'),
- (25,'Can add answer',9,'add_answer'),
- (26,'Can change answer',9,'change_answer'),
- (27,'Can delete answer',9,'delete_answer'),
- (28,'Can add comment',10,'add_comment'),
- (29,'Can change comment',10,'change_comment'),
- (30,'Can delete comment',10,'delete_comment'),
- (31,'Can add tag',11,'add_tag'),
- (32,'Can change tag',11,'change_tag'),
- (33,'Can delete tag',11,'delete_tag'),
- (37,'Can add nonce',13,'add_nonce'),
- (38,'Can change nonce',13,'change_nonce'),
- (39,'Can delete nonce',13,'delete_nonce'),
- (40,'Can add association',14,'add_association'),
- (41,'Can change association',14,'change_association'),
- (42,'Can delete association',14,'delete_association'),
- (43,'Can add nonce',15,'add_nonce'),
- (44,'Can change nonce',15,'change_nonce'),
- (45,'Can delete nonce',15,'delete_nonce'),
- (46,'Can add association',16,'add_association'),
- (47,'Can change association',16,'change_association'),
- (48,'Can delete association',16,'delete_association'),
- (49,'Can add user association',17,'add_userassociation'),
- (50,'Can change user association',17,'change_userassociation'),
- (51,'Can delete user association',17,'delete_userassociation'),
- (52,'Can add user password queue',18,'add_userpasswordqueue'),
- (53,'Can change user password queue',18,'change_userpasswordqueue'),
- (54,'Can delete user password queue',18,'delete_userpasswordqueue'),
- (55,'Can add log entry',19,'add_logentry'),
- (56,'Can change log entry',19,'change_logentry'),
- (57,'Can delete log entry',19,'delete_logentry'),
- (58,'Can add question',20,'add_question'),
- (59,'Can change question',20,'change_question'),
- (60,'Can delete question',20,'delete_question'),
- (61,'Can add vote',21,'add_vote'),
- (62,'Can change vote',21,'change_vote'),
- (63,'Can delete vote',21,'delete_vote'),
- (64,'Can add flagged item',22,'add_flaggeditem'),
- (65,'Can change flagged item',22,'change_flaggeditem'),
- (66,'Can delete flagged item',22,'delete_flaggeditem'),
- (67,'Can add favorite question',23,'add_favoritequestion'),
- (68,'Can change favorite question',23,'change_favoritequestion'),
- (69,'Can delete favorite question',23,'delete_favoritequestion'),
- (70,'Can add badge',24,'add_badge'),
- (71,'Can change badge',24,'change_badge'),
- (72,'Can delete badge',24,'delete_badge'),
- (73,'Can add award',25,'add_award'),
- (74,'Can change award',25,'change_award'),
- (75,'Can delete award',25,'delete_award');
-
---
--- Definition of table `cnprog`.`auth_user`
---
-
-DROP TABLE IF EXISTS `cnprog`.`auth_user`;
-CREATE TABLE `cnprog`.`auth_user` (
- `id` int(11) NOT NULL auto_increment,
- `username` varchar(30) NOT NULL,
- `first_name` varchar(30) NOT NULL,
- `last_name` varchar(30) NOT NULL,
- `email` varchar(75) NOT NULL,
- `password` varchar(128) NOT NULL,
- `is_staff` tinyint(1) NOT NULL,
- `is_active` tinyint(1) NOT NULL,
- `is_superuser` tinyint(1) NOT NULL,
- `last_login` datetime NOT NULL,
- `date_joined` datetime NOT NULL,
- `gold` smallint(6) NOT NULL default '0',
- `silver` smallint(5) unsigned NOT NULL default '0',
- `bronze` smallint(5) unsigned NOT NULL default '0',
- `reputation` int(10) unsigned default '1',
- `gravatar` varchar(128) default NULL,
- `questions_per_page` smallint(5) unsigned default '10',
- `last_seen` datetime default NULL,
- `real_name` varchar(100) default NULL,
- `website` varchar(200) default NULL,
- `location` varchar(100) default NULL,
- `date_of_birth` datetime default NULL,
- `about` text,
- PRIMARY KEY (`id`),
- UNIQUE KEY `username` (`username`)
-) ENGINE=InnoDB AUTO_INCREMENT=104 DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`auth_user`
---
-INSERT INTO `cnprog`.`auth_user` VALUES (2,'chagel','','','chagel@gmail.com','sha1$6a2fb$0d2ffe90bcba542fc962f57967a88e507799cc74',1,1,1,'2008-12-16 15:35:17','2008-12-11 20:12:53',0,0,0,1,'8c1efc4f4618aa68b18c88f2bcaa5564',10,NULL,NULL,NULL,NULL,NULL,NULL),
- (3,'mike','','','ichagel@yahoo.com','sha1$f7ef5$1015ae6b2c8a2774a028419d3c57e13145b83284',0,1,0,'2008-12-15 12:56:23','2008-12-15 12:56:23',0,0,0,1,NULL,10,NULL,NULL,NULL,NULL,NULL,NULL),
- (4,'sailingcai','','','sailingcai@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-23 06:14:45','2008-12-20 15:19:21',1,2,3,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','',NULL,''),
- (5,'sailingcai1','','','1@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21',NULL,NULL,NULL,NULL,NULL),
- (6,'sailing2','','','2@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (7,'sailing3','','','3@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (8,'sailing4','','','4@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (9,'sailing5','','','5@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (10,'sailing6','','','6@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (11,'sailing7','','','7@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (12,'sailing8','','','8@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (13,'sailing9','','','9@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (14,'sailing10','','','10@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (15,'sailing11','','','11@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (16,'sailing12','','','12@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (17,'sailing13','','','13@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (18,'sailing14','','','14@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (19,'sailing15','','','15@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (20,'sailing16','','','16@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (21,'sailing17','','','17@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (22,'sailing18','','','18@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (23,'sailing19','','','19@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (24,'sailing20','','','20@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (25,'sailing21','','','21@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (26,'sailing22','','','22@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (27,'sailing23','','','23@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (28,'sailing24','','','24@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (29,'sailing25','','','25@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (30,'sailing26','','','26@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (31,'sailing27','','','27@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (32,'sailing28','','','28@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (33,'sailing29','','','29@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (34,'sailing30','','','30@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (35,'sailing31','','','31@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (36,'sailing32','','','32@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (37,'sailing33','','','33@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (38,'sailing34','','','34@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (39,'sailing35','','','35@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (40,'sailing36','','','36@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (41,'sailing37','','','37@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (42,'sailing38','','','38@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (43,'sailing39','','','39@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (44,'sailing40','','','40@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (45,'sailing41','','','41@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (46,'sailing42','','','42@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (47,'sailing43','','','43@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (48,'sailing44','','','44@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (49,'sailing45','','','45@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (50,'sailing46','','','46@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (51,'sailing47','','','47@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (52,'sailing48','','','48@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (53,'sailing49','','','49@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (54,'sailing50','','','50@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (55,'sailing51','','','51@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (56,'sailing52','','','52@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (57,'sailing53','','','53@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (58,'sailing54','','','54@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (59,'sailing55','','','55@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (60,'sailing56','','','56@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (61,'sailing57','','','57@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (62,'sailing58','','','58@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (63,'sailing59','','','59@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (64,'sailing60','','','60@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (65,'sailing61','','','61@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (66,'sailing62','','','62@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (67,'sailing63','','','63@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (68,'sailing64','','','64@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (69,'sailing65','','','65@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (70,'sailing66','','','66@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (71,'sailing67','','','67@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (72,'sailing68','','','68@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (73,'sailing69','','','69@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (74,'sailing70','','','70@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (75,'sailing71','','','71@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (76,'sailing72','','','72@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (77,'sailing73','','','73@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (78,'sailing74','','','74@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (79,'sailing75','','','75@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (80,'sailing76','','','76@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (81,'sailing77','','','77@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (82,'sailing78','','','78@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (83,'sailing79','','','79@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (84,'sailing80','','','80@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (85,'sailing81','','','81@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (86,'sailing82','','','82@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (87,'sailing83','','','83@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (88,'sailing84','','','84@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (89,'sailing85','','','85@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (90,'sailing86','','','86@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (91,'sailing87','','','87@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (92,'sailing88','','','88@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (93,'sailing89','','','89@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (94,'sailing90','','','90@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (95,'sailing91','','','91@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (96,'sailing92','','','92@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (97,'sailing93','','','93@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (98,'sailing94','','','94@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (99,'sailing95','','','95@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (100,'sailing96','','','96@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (101,'sailing97','','','97@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (102,'sailing98','','','98@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00',''),
- (103,'sailing99','','','99@gmail.com','sha1$a417c$ca7d9f2ad55666bf98068cc392b6f62450b216e0',0,1,0,'2008-12-20 15:19:21','2008-12-20 15:19:21',0,0,0,1,'a1cb9864605a32760518b90a4f9a0e73',10,'2008-12-20 15:19:21','','','','0000-00-00 00:00:00','');
-
---
--- Definition of table `cnprog`.`auth_user_groups`
---
-
-DROP TABLE IF EXISTS `cnprog`.`auth_user_groups`;
-CREATE TABLE `cnprog`.`auth_user_groups` (
- `id` int(11) NOT NULL auto_increment,
- `user_id` int(11) NOT NULL,
- `group_id` int(11) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `user_id` (`user_id`,`group_id`),
- KEY `group_id_refs_id_f116770` (`group_id`),
- CONSTRAINT `group_id_refs_id_f116770` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`),
- CONSTRAINT `user_id_refs_id_7ceef80f` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`auth_user_groups`
---
-
---
--- Definition of table `cnprog`.`auth_user_user_permissions`
---
-
-DROP TABLE IF EXISTS `cnprog`.`auth_user_user_permissions`;
-CREATE TABLE `cnprog`.`auth_user_user_permissions` (
- `id` int(11) NOT NULL auto_increment,
- `user_id` int(11) NOT NULL,
- `permission_id` int(11) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `user_id` (`user_id`,`permission_id`),
- KEY `permission_id_refs_id_67e79cb` (`permission_id`),
- CONSTRAINT `permission_id_refs_id_67e79cb` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`),
- CONSTRAINT `user_id_refs_id_dfbab7d` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`auth_user_user_permissions`
---
-
---
--- Definition of table `cnprog`.`award`
---
-
-DROP TABLE IF EXISTS `cnprog`.`award`;
-CREATE TABLE `cnprog`.`award` (
- `id` int(11) NOT NULL auto_increment,
- `user_id` int(11) NOT NULL,
- `badge_id` int(11) NOT NULL,
- `awarded_at` datetime NOT NULL,
- `notified` tinyint(1) NOT NULL,
- PRIMARY KEY (`id`),
- KEY `award_user_id` (`user_id`),
- KEY `award_badge_id` (`badge_id`),
- CONSTRAINT `badge_id_refs_id_651af0e1` FOREIGN KEY (`badge_id`) REFERENCES `badge` (`id`),
- CONSTRAINT `user_id_refs_id_2d83e9b6` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`award`
---
-
---
--- Definition of table `cnprog`.`badge`
---
-
-DROP TABLE IF EXISTS `cnprog`.`badge`;
-CREATE TABLE `cnprog`.`badge` (
- `id` int(11) NOT NULL auto_increment,
- `name` varchar(50) NOT NULL,
- `type` smallint(6) NOT NULL,
- `slug` varchar(50) NOT NULL,
- `description` varchar(300) NOT NULL,
- `multiple` tinyint(1) NOT NULL,
- `awarded_count` int(10) unsigned NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `name` (`name`,`type`),
- KEY `badge_slug` (`slug`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`badge`
---
-
---
--- Definition of table `cnprog`.`comment`
---
-
-DROP TABLE IF EXISTS `cnprog`.`comment`;
-CREATE TABLE `cnprog`.`comment` (
- `id` int(11) NOT NULL auto_increment,
- `content_type_id` int(11) NOT NULL,
- `object_id` int(10) unsigned NOT NULL,
- `user_id` int(11) NOT NULL,
- `comment` varchar(300) NOT NULL,
- `added_at` datetime NOT NULL,
- PRIMARY KEY (`id`),
- KEY `content_type_id` (`content_type_id`,`object_id`,`user_id`),
- KEY `comment_content_type_id` (`content_type_id`),
- KEY `comment_user_id` (`user_id`),
- CONSTRAINT `content_type_id_refs_id_13a5866c` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
- CONSTRAINT `user_id_refs_id_6be725e8` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`comment`
---
-
---
--- Definition of table `cnprog`.`django_admin_log`
---
-
-DROP TABLE IF EXISTS `cnprog`.`django_admin_log`;
-CREATE TABLE `cnprog`.`django_admin_log` (
- `id` int(11) NOT NULL auto_increment,
- `action_time` datetime NOT NULL,
- `user_id` int(11) NOT NULL,
- `content_type_id` int(11) default NULL,
- `object_id` longtext,
- `object_repr` varchar(200) NOT NULL,
- `action_flag` smallint(5) unsigned NOT NULL,
- `change_message` longtext NOT NULL,
- PRIMARY KEY (`id`),
- KEY `django_admin_log_user_id` (`user_id`),
- KEY `django_admin_log_content_type_id` (`content_type_id`),
- CONSTRAINT `content_type_id_refs_id_288599e6` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
- CONSTRAINT `user_id_refs_id_c8665aa` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`django_admin_log`
---
-INSERT INTO `cnprog`.`django_admin_log` VALUES (1,'2008-12-18 23:41:41',2,7,'1','cnprog.com',2,'已修改 domain 和 name 。');
-
---
--- Definition of table `cnprog`.`django_authopenid_association`
---
-
-DROP TABLE IF EXISTS `cnprog`.`django_authopenid_association`;
-CREATE TABLE `cnprog`.`django_authopenid_association` (
- `id` int(11) NOT NULL auto_increment,
- `server_url` longtext NOT NULL,
- `handle` varchar(255) NOT NULL,
- `secret` longtext NOT NULL,
- `issued` int(11) NOT NULL,
- `lifetime` int(11) NOT NULL,
- `assoc_type` longtext NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`django_authopenid_association`
---
-INSERT INTO `cnprog`.`django_authopenid_association` VALUES (2,'https://www.google.com/accounts/o8/ud','AOQobUfcCH4sgjsBGGscrzxIa5UM4clofAB6nixx8Qq_NWco4ynn_Kc4','u5cva43abzdwF8CJOFZfkzfk7x8=\n',1229022261,1229022261,'HMAC-SHA1'),
- (3,'https://api.screenname.aol.com/auth/openidServer','diAyLjAgayAwIGJhT2VvYkdDZ21RSHJ4QldzQnhTdjIxV3BVbz0%3D-j5HRXRB1VbPyg48jGKE1Q70dfv76lGHEPwd9071%2FJ7f6SSw5YhakrwWpsVXtr34T6iHwPDdo6RU%3D','EmQL3+5oR6mFKIaeBNy6hXyUJ/w=\n',1229282202,1229282202,'HMAC-SHA1'),
- (4,'https://open.login.yahooapis.com/openid/op/auth','JcBeY.uWXu2YjzbuCQiqFzAb0MIc7ATeKiPO4eAp3vluPMqZp_NCxepvMLGrJjxxDKTaNnr06wepMos8ap6SQYZiTi51tZ05lMWnpZAiOA1hsq_WMlEL7G9YE66GEA9A','QXiuN6B7E8nP5QhyHI3IB26t4SA=\n',1229282256,1229282256,'HMAC-SHA1'),
- (5,'http://openid.claimid.com/server','{HMAC-SHA1}{494575fd}{uLEbxQ==}','GvPbkgMHh0QVPH7mStCGuWb2AKY=\n',1229288957,1229288957,'HMAC-SHA1'),
- (6,'http://www.blogger.com/openid-server.g','oida-1229424484019-158830626','8gaU4aKnIFCLKIkHdxZQp7ZGNck=\n',1229424478,1229424478,'HMAC-SHA1');
-
---
--- Definition of table `cnprog`.`django_authopenid_nonce`
---
-
-DROP TABLE IF EXISTS `cnprog`.`django_authopenid_nonce`;
-CREATE TABLE `cnprog`.`django_authopenid_nonce` (
- `id` int(11) NOT NULL auto_increment,
- `server_url` varchar(255) NOT NULL,
- `timestamp` int(11) NOT NULL,
- `salt` varchar(40) NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;
-
---
--- Definition of table `cnprog`.`django_authopenid_userassociation`
---
-
-DROP TABLE IF EXISTS `cnprog`.`django_authopenid_userassociation`;
-CREATE TABLE `cnprog`.`django_authopenid_userassociation` (
- `id` int(11) NOT NULL auto_increment,
- `openid_url` varchar(255) NOT NULL,
- `user_id` int(11) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `user_id` (`user_id`),
- CONSTRAINT `user_id_refs_id_163d208d` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`django_authopenid_userassociation`
---
-INSERT INTO `cnprog`.`django_authopenid_userassociation` VALUES (2,'https://www.google.com/accounts/o8/id?id=AItOawl7CVVHl4DWtteqj4dd_A23zKRwPZgOOjw',2),
- (3,'https://me.yahoo.com/a/f8f2zXF91okYL4iN2Zh4P542a5s-#f4af2',3),
- (4,'https://me.yahoo.com/sailingcai#6fa4e',4);
-
---
--- Definition of table `cnprog`.`django_authopenid_userpasswordqueue`
---
-
-DROP TABLE IF EXISTS `cnprog`.`django_authopenid_userpasswordqueue`;
-CREATE TABLE `cnprog`.`django_authopenid_userpasswordqueue` (
- `id` int(11) NOT NULL auto_increment,
- `user_id` int(11) NOT NULL,
- `new_password` varchar(30) NOT NULL,
- `confirm_key` varchar(40) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `user_id` (`user_id`),
- CONSTRAINT `user_id_refs_id_76bcaaa4` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`django_authopenid_userpasswordqueue`
---
-
---
--- Definition of table `cnprog`.`django_content_type`
---
-
-DROP TABLE IF EXISTS `cnprog`.`django_content_type`;
-CREATE TABLE `cnprog`.`django_content_type` (
- `id` int(11) NOT NULL auto_increment,
- `name` varchar(100) NOT NULL,
- `app_label` varchar(100) NOT NULL,
- `model` varchar(100) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `app_label` (`app_label`,`model`)
-) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`django_content_type`
---
-INSERT INTO `cnprog`.`django_content_type` VALUES (1,'permission','auth','permission'),
- (2,'group','auth','group'),
- (3,'user','auth','user'),
- (4,'message','auth','message'),
- (5,'content type','contenttypes','contenttype'),
- (6,'session','sessions','session'),
- (7,'site','sites','site'),
- (9,'answer','forum','answer'),
- (10,'comment','forum','comment'),
- (11,'tag','forum','tag'),
- (13,'nonce','django_openidconsumer','nonce'),
- (14,'association','django_openidconsumer','association'),
- (15,'nonce','django_authopenid','nonce'),
- (16,'association','django_authopenid','association'),
- (17,'user association','django_authopenid','userassociation'),
- (18,'user password queue','django_authopenid','userpasswordqueue'),
- (19,'log entry','admin','logentry'),
- (20,'question','forum','question'),
- (21,'vote','forum','vote'),
- (22,'flagged item','forum','flaggeditem'),
- (23,'favorite question','forum','favoritequestion'),
- (24,'badge','forum','badge'),
- (25,'award','forum','award');
-
---
--- Definition of table `cnprog`.`django_session`
---
-
-DROP TABLE IF EXISTS `cnprog`.`django_session`;
-CREATE TABLE `cnprog`.`django_session` (
- `session_key` varchar(40) NOT NULL,
- `session_data` longtext NOT NULL,
- `expire_date` datetime NOT NULL,
- PRIMARY KEY (`session_key`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Definition of table `cnprog`.`django_site`
---
-
-DROP TABLE IF EXISTS `cnprog`.`django_site`;
-CREATE TABLE `cnprog`.`django_site` (
- `id` int(11) NOT NULL auto_increment,
- `domain` varchar(100) NOT NULL,
- `name` varchar(50) NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`django_site`
---
-INSERT INTO `cnprog`.`django_site` VALUES (1,'cnprog.com','CNProg.com');
-
---
--- Definition of table `cnprog`.`favorite_question`
---
-
-DROP TABLE IF EXISTS `cnprog`.`favorite_question`;
-CREATE TABLE `cnprog`.`favorite_question` (
- `id` int(11) NOT NULL auto_increment,
- `question_id` int(11) NOT NULL,
- `user_id` int(11) NOT NULL,
- `added_at` datetime NOT NULL,
- PRIMARY KEY (`id`),
- KEY `favorite_question_question_id` (`question_id`),
- KEY `favorite_question_user_id` (`user_id`),
- CONSTRAINT `question_id_refs_id_1ebe1cc3` FOREIGN KEY (`question_id`) REFERENCES `question` (`id`),
- CONSTRAINT `user_id_refs_id_52853822` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`favorite_question`
---
-
---
--- Definition of table `cnprog`.`flagged_item`
---
-
-DROP TABLE IF EXISTS `cnprog`.`flagged_item`;
-CREATE TABLE `cnprog`.`flagged_item` (
- `id` int(11) NOT NULL auto_increment,
- `content_type_id` int(11) NOT NULL,
- `object_id` int(10) unsigned NOT NULL,
- `user_id` int(11) NOT NULL,
- `flagged_at` datetime NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `content_type_id` (`content_type_id`,`object_id`,`user_id`),
- KEY `flagged_item_content_type_id` (`content_type_id`),
- KEY `flagged_item_user_id` (`user_id`),
- CONSTRAINT `content_type_id_refs_id_76e44d74` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
- CONSTRAINT `user_id_refs_id_35e3c608` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`flagged_item`
---
-
---
--- Definition of table `cnprog`.`question`
---
-
-DROP TABLE IF EXISTS `cnprog`.`question`;
-CREATE TABLE `cnprog`.`question` (
- `id` int(11) NOT NULL auto_increment,
- `title` varchar(300) NOT NULL,
- `author_id` int(11) NOT NULL,
- `added_at` datetime NOT NULL,
- `wiki` tinyint(1) NOT NULL,
- `wikified_at` datetime default NULL,
- `answer_accepted` tinyint(1) NOT NULL,
- `closed` tinyint(1) NOT NULL,
- `closed_by_id` int(11) default NULL,
- `closed_at` datetime default NULL,
- `close_reason` smallint(6) default NULL,
- `deleted` tinyint(1) NOT NULL,
- `deleted_at` datetime default NULL,
- `deleted_by_id` int(11) default NULL,
- `locked` tinyint(1) NOT NULL,
- `locked_by_id` int(11) default NULL,
- `locked_at` datetime default NULL,
- `vote_up_count` int(11) NOT NULL,
- `vote_down_count` int(11) NOT NULL,
- `score` int(11) NOT NULL,
- `answer_count` int(10) unsigned NOT NULL,
- `comment_count` int(10) unsigned NOT NULL,
- `view_count` int(10) unsigned NOT NULL,
- `offensive_flag_count` smallint(6) NOT NULL,
- `favourite_count` int(10) unsigned NOT NULL,
- `last_edited_at` datetime default NULL,
- `last_edited_by_id` int(11) default NULL,
- `last_activity_at` datetime NOT NULL,
- `last_activity_by_id` int(11) NOT NULL,
- `tagnames` varchar(125) NOT NULL,
- `summary` varchar(180) NOT NULL,
- `html` longtext NOT NULL,
- PRIMARY KEY (`id`),
- KEY `question_author_id` (`author_id`),
- KEY `question_closed_by_id` (`closed_by_id`),
- KEY `question_deleted_by_id` (`deleted_by_id`),
- KEY `question_locked_by_id` (`locked_by_id`),
- KEY `question_last_edited_by_id` (`last_edited_by_id`),
- KEY `question_last_activity_by_id` (`last_activity_by_id`),
- CONSTRAINT `author_id_refs_id_56e9d00c` FOREIGN KEY (`author_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `closed_by_id_refs_id_56e9d00c` FOREIGN KEY (`closed_by_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `deleted_by_id_refs_id_56e9d00c` FOREIGN KEY (`deleted_by_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `last_activity_by_id_refs_id_56e9d00c` FOREIGN KEY (`last_activity_by_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `last_edited_by_id_refs_id_56e9d00c` FOREIGN KEY (`last_edited_by_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `locked_by_id_refs_id_56e9d00c` FOREIGN KEY (`locked_by_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
-
---
--- Definition of table `cnprog`.`question_tags`
---
-
-DROP TABLE IF EXISTS `cnprog`.`question_tags`;
-CREATE TABLE `cnprog`.`question_tags` (
- `id` int(11) NOT NULL auto_increment,
- `question_id` int(11) NOT NULL,
- `tag_id` int(11) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `question_id` (`question_id`,`tag_id`),
- KEY `tag_id_refs_id_43fcb953` (`tag_id`),
- CONSTRAINT `question_id_refs_id_266147c6` FOREIGN KEY (`question_id`) REFERENCES `question` (`id`),
- CONSTRAINT `tag_id_refs_id_43fcb953` FOREIGN KEY (`tag_id`) REFERENCES `tag` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8;
-
---
--- Definition of table `cnprog`.`tag`
---
-
-DROP TABLE IF EXISTS `cnprog`.`tag`;
-CREATE TABLE `cnprog`.`tag` (
- `id` int(11) NOT NULL auto_increment,
- `name` varchar(255) NOT NULL,
- `created_by_id` int(11) NOT NULL,
- `used_count` int(10) unsigned NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `name` (`name`),
- KEY `tag_created_by_id` (`created_by_id`),
- CONSTRAINT `created_by_id_refs_id_47205d6d` FOREIGN KEY (`created_by_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
-
---
--- Definition of table `cnprog`.`user_badge`
---
-
-DROP TABLE IF EXISTS `cnprog`.`user_badge`;
-CREATE TABLE `cnprog`.`user_badge` (
- `id` int(10) unsigned NOT NULL auto_increment,
- `user_id` int(10) unsigned NOT NULL,
- `badge_id` int(10) unsigned NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Definition of table `cnprog`.`user_favorite_questions`
---
-
-DROP TABLE IF EXISTS `cnprog`.`user_favorite_questions`;
-CREATE TABLE `cnprog`.`user_favorite_questions` (
- `id` int(10) unsigned NOT NULL auto_increment,
- `user_id` int(10) unsigned NOT NULL,
- `question_id` int(10) unsigned NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`user_favorite_questions`
---
-
-DROP TABLE IF EXISTS `cnprog`.`vote`;
-CREATE TABLE `cnprog`.`vote` (
- `id` int(11) NOT NULL auto_increment,
- `content_type_id` int(11) NOT NULL,
- `object_id` int(10) unsigned NOT NULL,
- `user_id` int(11) NOT NULL,
- `vote` smallint(6) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `content_type_id` (`content_type_id`,`object_id`,`user_id`),
- KEY `vote_content_type_id` (`content_type_id`),
- KEY `vote_user_id` (`user_id`),
- CONSTRAINT `content_type_id_refs_id_50124414` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
- CONSTRAINT `user_id_refs_id_760a4df0` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `cnprog`.`vote`
---
-
-
-
-/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
-/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
-/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
-/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
-/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
-/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
-/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
diff --git a/askbot/sql_scripts/cnprog_new_install_2009_02_28.sql b/askbot/sql_scripts/cnprog_new_install_2009_02_28.sql
deleted file mode 100644
index 80b9fced..00000000
--- a/askbot/sql_scripts/cnprog_new_install_2009_02_28.sql
+++ /dev/null
@@ -1,456 +0,0 @@
-SET FOREIGN_KEY_CHECKS = 0;
-
-CREATE TABLE `activity` (
- `id` int(11) NOT NULL auto_increment,
- `user_id` int(11) NOT NULL,
- `activity_type` smallint(6) NOT NULL,
- `active_at` datetime NOT NULL,
- `content_type_id` int(11) NOT NULL,
- `object_id` int(10) unsigned NOT NULL,
- `is_auditted` tinyint(1) default '0',
- PRIMARY KEY (`id`),
- KEY `activity_user_id` (`user_id`),
- KEY `activity_content_type_id` (`content_type_id`)
-) ENGINE=MyISAM AUTO_INCREMENT=103 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `answer` (
- `id` int(11) NOT NULL auto_increment,
- `question_id` int(11) NOT NULL,
- `author_id` int(11) NOT NULL,
- `added_at` datetime NOT NULL,
- `wiki` tinyint(1) NOT NULL,
- `wikified_at` datetime default NULL,
- `accepted` tinyint(1) NOT NULL,
- `deleted` tinyint(1) NOT NULL,
- `deleted_by_id` int(11) default NULL,
- `locked` tinyint(1) NOT NULL,
- `locked_by_id` int(11) default NULL,
- `locked_at` datetime default NULL,
- `score` int(11) NOT NULL,
- `comment_count` int(10) unsigned NOT NULL,
- `offensive_flag_count` smallint(6) NOT NULL,
- `last_edited_at` datetime default NULL,
- `last_edited_by_id` int(11) default NULL,
- `html` longtext NOT NULL,
- `vote_up_count` int(11) NOT NULL,
- `vote_down_count` int(11) NOT NULL,
- PRIMARY KEY (`id`),
- KEY `answer_question_id` (`question_id`),
- KEY `answer_author_id` (`author_id`),
- KEY `answer_deleted_by_id` (`deleted_by_id`),
- KEY `answer_locked_by_id` (`locked_by_id`),
- KEY `answer_last_edited_by_id` (`last_edited_by_id`),
- CONSTRAINT `author_id_refs_id_192b0170` FOREIGN KEY (`author_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `deleted_by_id_refs_id_192b0170` FOREIGN KEY (`deleted_by_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `last_edited_by_id_refs_id_192b0170` FOREIGN KEY (`last_edited_by_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `locked_by_id_refs_id_192b0170` FOREIGN KEY (`locked_by_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `question_id_refs_id_7d6550c9` FOREIGN KEY (`question_id`) REFERENCES `question` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `answer_revision` (
- `id` int(11) NOT NULL auto_increment,
- `answer_id` int(11) NOT NULL,
- `revision` int(10) unsigned NOT NULL,
- `author_id` int(11) NOT NULL,
- `revised_at` datetime NOT NULL,
- `summary` varchar(300) collate utf8_unicode_ci NOT NULL,
- `text` longtext collate utf8_unicode_ci NOT NULL,
- PRIMARY KEY (`id`),
- KEY `answer_revision_answer_id` (`answer_id`),
- KEY `answer_revision_author_id` (`author_id`)
-) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `auth_group` (
- `id` int(11) NOT NULL auto_increment,
- `name` varchar(80) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `name` (`name`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `auth_group_permissions` (
- `id` int(11) NOT NULL auto_increment,
- `group_id` int(11) NOT NULL,
- `permission_id` int(11) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `group_id` (`group_id`,`permission_id`),
- KEY `permission_id_refs_id_5886d21f` (`permission_id`),
- CONSTRAINT `group_id_refs_id_3cea63fe` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`),
- CONSTRAINT `permission_id_refs_id_5886d21f` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `auth_message` (
- `id` int(11) NOT NULL auto_increment,
- `user_id` int(11) NOT NULL,
- `message` longtext NOT NULL,
- PRIMARY KEY (`id`),
- KEY `auth_message_user_id` (`user_id`),
- CONSTRAINT `user_id_refs_id_650f49a6` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `auth_permission` (
- `id` int(11) NOT NULL auto_increment,
- `name` varchar(50) NOT NULL,
- `content_type_id` int(11) NOT NULL,
- `codename` varchar(100) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `content_type_id` (`content_type_id`,`codename`),
- KEY `auth_permission_content_type_id` (`content_type_id`),
- CONSTRAINT `content_type_id_refs_id_728de91f` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=88 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `auth_user` (
- `id` int(11) NOT NULL auto_increment,
- `username` varchar(30) NOT NULL,
- `first_name` varchar(30) NOT NULL,
- `last_name` varchar(30) NOT NULL,
- `email` varchar(75) NOT NULL,
- `password` varchar(128) NOT NULL,
- `is_staff` tinyint(1) NOT NULL,
- `is_active` tinyint(1) NOT NULL,
- `is_superuser` tinyint(1) NOT NULL,
- `last_login` datetime NOT NULL,
- `date_joined` datetime NOT NULL,
- `gold` smallint(6) NOT NULL default '0',
- `silver` smallint(5) unsigned NOT NULL default '0',
- `bronze` smallint(5) unsigned NOT NULL default '0',
- `reputation` int(10) unsigned default '1',
- `gravatar` varchar(128) default NULL,
- `questions_per_page` smallint(5) unsigned default '10',
- `last_seen` datetime default NULL,
- `real_name` varchar(100) default NULL,
- `website` varchar(200) default NULL,
- `location` varchar(100) default NULL,
- `date_of_birth` datetime default NULL,
- `about` text,
- PRIMARY KEY (`id`),
- UNIQUE KEY `username` (`username`)
-) ENGINE=InnoDB AUTO_INCREMENT=104 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `auth_user_groups` (
- `id` int(11) NOT NULL auto_increment,
- `user_id` int(11) NOT NULL,
- `group_id` int(11) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `user_id` (`user_id`,`group_id`),
- KEY `group_id_refs_id_f116770` (`group_id`),
- CONSTRAINT `group_id_refs_id_f116770` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`),
- CONSTRAINT `user_id_refs_id_7ceef80f` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `auth_user_user_permissions` (
- `id` int(11) NOT NULL auto_increment,
- `user_id` int(11) NOT NULL,
- `permission_id` int(11) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `user_id` (`user_id`,`permission_id`),
- KEY `permission_id_refs_id_67e79cb` (`permission_id`),
- CONSTRAINT `permission_id_refs_id_67e79cb` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`),
- CONSTRAINT `user_id_refs_id_dfbab7d` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `award` (
- `id` int(11) NOT NULL auto_increment,
- `user_id` int(11) NOT NULL,
- `badge_id` int(11) NOT NULL,
- `awarded_at` datetime NOT NULL,
- `notified` tinyint(1) NOT NULL,
- `content_type_id` int(11) default NULL,
- `object_id` int(10) default NULL,
- PRIMARY KEY (`id`),
- KEY `award_user_id` (`user_id`),
- KEY `award_badge_id` (`badge_id`),
- CONSTRAINT `badge_id_refs_id_651af0e1` FOREIGN KEY (`badge_id`) REFERENCES `badge` (`id`),
- CONSTRAINT `user_id_refs_id_2d83e9b6` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `badge` (
- `id` int(11) NOT NULL auto_increment,
- `name` varchar(50) NOT NULL,
- `type` smallint(6) NOT NULL,
- `slug` varchar(50) NOT NULL,
- `description` varchar(300) NOT NULL,
- `multiple` tinyint(1) NOT NULL,
- `awarded_count` int(10) unsigned NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `name` (`name`,`type`),
- KEY `badge_slug` (`slug`)
-) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `comment` (
- `id` int(11) NOT NULL auto_increment,
- `content_type_id` int(11) NOT NULL,
- `object_id` int(10) unsigned NOT NULL,
- `user_id` int(11) NOT NULL,
- `comment` varchar(300) NOT NULL,
- `added_at` datetime NOT NULL,
- PRIMARY KEY (`id`),
- KEY `comment_content_type_id` (`content_type_id`),
- KEY `comment_user_id` (`user_id`),
- KEY `content_type_id` (`content_type_id`,`object_id`,`user_id`),
- CONSTRAINT `content_type_id_refs_id_13a5866c` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
- CONSTRAINT `user_id_refs_id_6be725e8` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `django_admin_log` (
- `id` int(11) NOT NULL auto_increment,
- `action_time` datetime NOT NULL,
- `user_id` int(11) NOT NULL,
- `content_type_id` int(11) default NULL,
- `object_id` longtext,
- `object_repr` varchar(200) NOT NULL,
- `action_flag` smallint(5) unsigned NOT NULL,
- `change_message` longtext NOT NULL,
- PRIMARY KEY (`id`),
- KEY `django_admin_log_user_id` (`user_id`),
- KEY `django_admin_log_content_type_id` (`content_type_id`),
- CONSTRAINT `content_type_id_refs_id_288599e6` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
- CONSTRAINT `user_id_refs_id_c8665aa` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `django_authopenid_association` (
- `id` int(11) NOT NULL auto_increment,
- `server_url` longtext NOT NULL,
- `handle` varchar(255) NOT NULL,
- `secret` longtext NOT NULL,
- `issued` int(11) NOT NULL,
- `lifetime` int(11) NOT NULL,
- `assoc_type` longtext NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `django_authopenid_nonce` (
- `id` int(11) NOT NULL auto_increment,
- `server_url` varchar(255) NOT NULL,
- `timestamp` int(11) NOT NULL,
- `salt` varchar(40) NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `django_authopenid_userassociation` (
- `id` int(11) NOT NULL auto_increment,
- `openid_url` varchar(255) NOT NULL,
- `user_id` int(11) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `user_id` (`user_id`),
- CONSTRAINT `user_id_refs_id_163d208d` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `django_authopenid_userpasswordqueue` (
- `id` int(11) NOT NULL auto_increment,
- `user_id` int(11) NOT NULL,
- `new_password` varchar(30) NOT NULL,
- `confirm_key` varchar(40) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `user_id` (`user_id`),
- CONSTRAINT `user_id_refs_id_76bcaaa4` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `django_content_type` (
- `id` int(11) NOT NULL auto_increment,
- `name` varchar(100) NOT NULL,
- `app_label` varchar(100) NOT NULL,
- `model` varchar(100) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `app_label` (`app_label`,`model`)
-) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `django_session` (
- `session_key` varchar(40) NOT NULL,
- `session_data` longtext NOT NULL,
- `expire_date` datetime NOT NULL,
- PRIMARY KEY (`session_key`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `django_site` (
- `id` int(11) NOT NULL auto_increment,
- `domain` varchar(100) NOT NULL,
- `name` varchar(50) NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `favorite_question` (
- `id` int(11) NOT NULL auto_increment,
- `question_id` int(11) NOT NULL,
- `user_id` int(11) NOT NULL,
- `added_at` datetime NOT NULL,
- PRIMARY KEY (`id`),
- KEY `favorite_question_question_id` (`question_id`),
- KEY `favorite_question_user_id` (`user_id`),
- CONSTRAINT `question_id_refs_id_1ebe1cc3` FOREIGN KEY (`question_id`) REFERENCES `question` (`id`),
- CONSTRAINT `user_id_refs_id_52853822` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `flagged_item` (
- `id` int(11) NOT NULL auto_increment,
- `content_type_id` int(11) NOT NULL,
- `object_id` int(10) unsigned NOT NULL,
- `user_id` int(11) NOT NULL,
- `flagged_at` datetime NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `content_type_id` (`content_type_id`,`object_id`,`user_id`),
- KEY `flagged_item_content_type_id` (`content_type_id`),
- KEY `flagged_item_user_id` (`user_id`),
- CONSTRAINT `content_type_id_refs_id_76e44d74` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
- CONSTRAINT `user_id_refs_id_35e3c608` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `question` (
- `id` int(11) NOT NULL auto_increment,
- `title` varchar(300) NOT NULL,
- `author_id` int(11) NOT NULL,
- `added_at` datetime NOT NULL,
- `wiki` tinyint(1) NOT NULL,
- `wikified_at` datetime default NULL,
- `answer_accepted` tinyint(1) NOT NULL,
- `closed` tinyint(1) NOT NULL,
- `closed_by_id` int(11) default NULL,
- `closed_at` datetime default NULL,
- `close_reason` smallint(6) default NULL,
- `deleted` tinyint(1) NOT NULL,
- `deleted_at` datetime default NULL,
- `deleted_by_id` int(11) default NULL,
- `locked` tinyint(1) NOT NULL,
- `locked_by_id` int(11) default NULL,
- `locked_at` datetime default NULL,
- `score` int(11) NOT NULL,
- `answer_count` int(10) unsigned NOT NULL,
- `comment_count` int(10) unsigned NOT NULL,
- `view_count` int(10) unsigned NOT NULL,
- `offensive_flag_count` smallint(6) NOT NULL,
- `favourite_count` int(10) unsigned NOT NULL,
- `last_edited_at` datetime default NULL,
- `last_edited_by_id` int(11) default NULL,
- `last_activity_at` datetime NOT NULL,
- `last_activity_by_id` int(11) NOT NULL,
- `tagnames` varchar(125) NOT NULL,
- `summary` varchar(180) NOT NULL,
- `html` longtext NOT NULL,
- `vote_up_count` int(11) NOT NULL,
- `vote_down_count` int(11) NOT NULL,
- PRIMARY KEY (`id`),
- KEY `question_author_id` (`author_id`),
- KEY `question_closed_by_id` (`closed_by_id`),
- KEY `question_deleted_by_id` (`deleted_by_id`),
- KEY `question_locked_by_id` (`locked_by_id`),
- KEY `question_last_edited_by_id` (`last_edited_by_id`),
- KEY `question_last_activity_by_id` (`last_activity_by_id`),
- CONSTRAINT `author_id_refs_id_56e9d00c` FOREIGN KEY (`author_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `closed_by_id_refs_id_56e9d00c` FOREIGN KEY (`closed_by_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `deleted_by_id_refs_id_56e9d00c` FOREIGN KEY (`deleted_by_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `last_activity_by_id_refs_id_56e9d00c` FOREIGN KEY (`last_activity_by_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `last_edited_by_id_refs_id_56e9d00c` FOREIGN KEY (`last_edited_by_id`) REFERENCES `auth_user` (`id`),
- CONSTRAINT `locked_by_id_refs_id_56e9d00c` FOREIGN KEY (`locked_by_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `question_revision` (
- `id` int(11) NOT NULL auto_increment,
- `question_id` int(11) NOT NULL,
- `revision` int(10) unsigned NOT NULL,
- `title` varchar(300) NOT NULL,
- `author_id` int(11) NOT NULL,
- `revised_at` datetime NOT NULL,
- `tagnames` varchar(125) NOT NULL,
- `summary` varchar(300) NOT NULL,
- `text` longtext NOT NULL,
- PRIMARY KEY (`id`),
- KEY `question_revision_question_id` (`question_id`),
- KEY `question_revision_author_id` (`author_id`)
-) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
-
-
-CREATE TABLE `question_tags` (
- `id` int(11) NOT NULL auto_increment,
- `question_id` int(11) NOT NULL,
- `tag_id` int(11) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `question_id` (`question_id`,`tag_id`),
- KEY `tag_id_refs_id_43fcb953` (`tag_id`),
- CONSTRAINT `question_id_refs_id_266147c6` FOREIGN KEY (`question_id`) REFERENCES `question` (`id`),
- CONSTRAINT `tag_id_refs_id_43fcb953` FOREIGN KEY (`tag_id`) REFERENCES `tag` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `repute` (
- `id` int(11) NOT NULL auto_increment,
- `user_id` int(11) NOT NULL,
- `positive` smallint(6) NOT NULL,
- `negative` smallint(6) NOT NULL,
- `question_id` int(11) NOT NULL,
- `reputed_at` datetime NOT NULL,
- `reputation_type` smallint(6) NOT NULL,
- `reputation` int(11) NOT NULL,
- PRIMARY KEY (`id`),
- KEY `repute_user_id` (`user_id`),
- KEY `repute_question_id` (`question_id`)
-) ENGINE=MyISAM AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `tag` (
- `id` int(11) NOT NULL auto_increment,
- `name` varchar(255) NOT NULL,
- `created_by_id` int(11) NOT NULL,
- `used_count` int(10) unsigned NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `name` (`name`),
- KEY `tag_created_by_id` (`created_by_id`),
- CONSTRAINT `created_by_id_refs_id_47205d6d` FOREIGN KEY (`created_by_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `user_badge` (
- `id` int(10) unsigned NOT NULL auto_increment,
- `user_id` int(10) unsigned NOT NULL,
- `badge_id` int(10) unsigned NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `user_favorite_questions` (
- `id` int(10) unsigned NOT NULL auto_increment,
- `user_id` int(10) unsigned NOT NULL,
- `question_id` int(10) unsigned NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-
-CREATE TABLE `vote` (
- `id` int(11) NOT NULL auto_increment,
- `content_type_id` int(11) NOT NULL,
- `object_id` int(10) unsigned NOT NULL,
- `user_id` int(11) NOT NULL,
- `vote` smallint(6) NOT NULL,
- `voted_at` datetime NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `content_type_id` (`content_type_id`,`object_id`,`user_id`),
- KEY `vote_content_type_id` (`content_type_id`),
- KEY `vote_user_id` (`user_id`),
- CONSTRAINT `content_type_id_refs_id_50124414` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
- CONSTRAINT `user_id_refs_id_760a4df0` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-
-
-SET FOREIGN_KEY_CHECKS = 1;
diff --git a/askbot/sql_scripts/cnprog_new_install_2009_03_31.sql b/askbot/sql_scripts/cnprog_new_install_2009_03_31.sql
deleted file mode 100644
index c2c69f36..00000000
--- a/askbot/sql_scripts/cnprog_new_install_2009_03_31.sql
+++ /dev/null
@@ -1,891 +0,0 @@
-USE cnprog;
-
-
-/************ Update: Tables ***************/
-
-/******************** Add Table: activity ************************/
-
-/* Build Table Structure */
-CREATE TABLE activity
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- activity_type SMALLINT NOT NULL,
- active_at DATETIME NOT NULL,
- content_type_id INTEGER NOT NULL,
- object_id INTEGER UNSIGNED NOT NULL,
- is_auditted TINYINT NULL DEFAULT 0
-) ENGINE=MyISAM AUTO_INCREMENT=103 DEFAULT CHARSET=latin1;
-
-/* Table Items: activity */
-
-/* Add Indexes for: activity */
-CREATE INDEX activity_content_type_id ON activity (content_type_id);
-CREATE INDEX activity_user_id ON activity (user_id);
-
-/******************** Add Table: answer ************************/
-
-/* Build Table Structure */
-CREATE TABLE answer
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- question_id INTEGER NOT NULL,
- author_id INTEGER NOT NULL,
- added_at DATETIME NOT NULL,
- wiki TINYINT NOT NULL,
- wikified_at DATETIME NULL,
- accepted TINYINT NOT NULL,
- deleted TINYINT NOT NULL,
- deleted_by_id INTEGER NULL,
- locked TINYINT NOT NULL,
- locked_by_id INTEGER NULL,
- locked_at DATETIME NULL,
- score INTEGER NOT NULL,
- comment_count INTEGER UNSIGNED NOT NULL,
- offensive_flag_count SMALLINT NOT NULL,
- last_edited_at DATETIME NULL,
- last_edited_by_id INTEGER NULL,
- html LONGTEXT NOT NULL,
- vote_up_count INTEGER NOT NULL,
- vote_down_count INTEGER NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
-
-/* Table Items: answer */
-
-/* Add Indexes for: answer */
-CREATE INDEX answer_author_id ON answer (author_id);
-CREATE INDEX answer_deleted_by_id ON answer (deleted_by_id);
-CREATE INDEX answer_last_edited_by_id ON answer (last_edited_by_id);
-CREATE INDEX answer_locked_by_id ON answer (locked_by_id);
-CREATE INDEX answer_question_id ON answer (question_id);
-
-/******************** Add Table: answer_revision ************************/
-
-/* Build Table Structure */
-CREATE TABLE answer_revision
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- answer_id INTEGER NOT NULL,
- revision INTEGER UNSIGNED NOT NULL,
- author_id INTEGER NOT NULL,
- revised_at DATETIME NOT NULL,
- summary TEXT NOT NULL,
- `text` LONGTEXT NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-
-/* Table Items: answer_revision */
-
-/* Add Indexes for: answer_revision */
-CREATE INDEX answer_revision_answer_id ON answer_revision (answer_id);
-CREATE INDEX answer_revision_author_id ON answer_revision (author_id);
-
-/******************** Add Table: auth_group ************************/
-
-/* Build Table Structure */
-CREATE TABLE auth_group
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- name VARCHAR(80) NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-/* Table Items: auth_group */
-
-/* Add Indexes for: auth_group */
-CREATE UNIQUE INDEX name ON auth_group (name);
-
-/******************** Add Table: auth_group_permissions ************************/
-
-/* Build Table Structure */
-CREATE TABLE auth_group_permissions
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- group_id INTEGER NOT NULL,
- permission_id INTEGER NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-/* Table Items: auth_group_permissions */
-
-/* Add Indexes for: auth_group_permissions */
-CREATE UNIQUE INDEX group_id ON auth_group_permissions (group_id, permission_id);
-CREATE INDEX permission_id_refs_id_5886d21f ON auth_group_permissions (permission_id);
-
-/******************** Add Table: auth_message ************************/
-
-/* Build Table Structure */
-CREATE TABLE auth_message
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- message LONGTEXT NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;
-
-/* Table Items: auth_message */
-
-/* Add Indexes for: auth_message */
-CREATE INDEX auth_message_user_id ON auth_message (user_id);
-
-/******************** Add Table: auth_permission ************************/
-
-/* Build Table Structure */
-CREATE TABLE auth_permission
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- name VARCHAR(50) NOT NULL,
- content_type_id INTEGER NOT NULL,
- codename VARCHAR(100) NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=88 DEFAULT CHARSET=utf8;
-
-/* Table Items: auth_permission */
-
-/* Add Indexes for: auth_permission */
-CREATE INDEX auth_permission_content_type_id ON auth_permission (content_type_id);
-CREATE UNIQUE INDEX content_type_id ON auth_permission (content_type_id, codename);
-
-/******************** Add Table: auth_user ************************/
-
-/* Build Table Structure */
-CREATE TABLE auth_user
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- username VARCHAR(30) NOT NULL,
- first_name VARCHAR(30) NOT NULL,
- last_name VARCHAR(30) NOT NULL,
- email VARCHAR(75) NOT NULL,
- password VARCHAR(128) NOT NULL,
- is_staff TINYINT NOT NULL,
- is_active TINYINT NOT NULL,
- is_superuser TINYINT NOT NULL,
- last_login DATETIME NOT NULL,
- date_joined DATETIME NOT NULL,
- gold SMALLINT NOT NULL DEFAULT 0,
- silver SMALLINT UNSIGNED NOT NULL DEFAULT 0,
- bronze SMALLINT UNSIGNED NOT NULL DEFAULT 0,
- reputation INTEGER UNSIGNED NULL DEFAULT 1,
- gravatar VARCHAR(128) NULL,
- questions_per_page SMALLINT UNSIGNED NULL DEFAULT 10,
- last_seen DATETIME NULL,
- real_name VARCHAR(100) NULL,
- website VARCHAR(200) NULL,
- location VARCHAR(100) NULL,
- date_of_birth DATETIME NULL,
- about TEXT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=104 DEFAULT CHARSET=utf8;
-
-/* Table Items: auth_user */
-
-/* Add Indexes for: auth_user */
-CREATE UNIQUE INDEX username ON auth_user (username);
-
-/******************** Add Table: auth_user_groups ************************/
-
-/* Build Table Structure */
-CREATE TABLE auth_user_groups
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- group_id INTEGER NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-/* Table Items: auth_user_groups */
-
-/* Add Indexes for: auth_user_groups */
-CREATE INDEX group_id_refs_id_f116770 ON auth_user_groups (group_id);
-CREATE UNIQUE INDEX user_id ON auth_user_groups (user_id, group_id);
-
-/******************** Add Table: auth_user_user_permissions ************************/
-
-/* Build Table Structure */
-CREATE TABLE auth_user_user_permissions
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- permission_id INTEGER NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-/* Table Items: auth_user_user_permissions */
-
-/* Add Indexes for: auth_user_user_permissions */
-CREATE INDEX permission_id_refs_id_67e79cb ON auth_user_user_permissions (permission_id);
-CREATE UNIQUE INDEX user_id ON auth_user_user_permissions (user_id, permission_id);
-
-/******************** Add Table: award ************************/
-
-/* Build Table Structure */
-CREATE TABLE award
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- badge_id INTEGER NOT NULL,
- awarded_at DATETIME NOT NULL,
- notified TINYINT NOT NULL,
- content_type_id INTEGER NULL,
- object_id INTEGER NULL
-) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;
-
-/* Table Items: award */
-
-/* Add Indexes for: award */
-CREATE INDEX award_badge_id ON award (badge_id);
-CREATE INDEX award_user_id ON award (user_id);
-
-/******************** Add Table: badge ************************/
-
-/* Build Table Structure */
-CREATE TABLE badge
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- name VARCHAR(50) NOT NULL,
- `type` SMALLINT NOT NULL,
- slug VARCHAR(50) NOT NULL,
- description TEXT NOT NULL,
- multiple TINYINT NOT NULL,
- awarded_count INTEGER UNSIGNED NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
-
-/* Table Items: badge */
-
-/* Add Indexes for: badge */
-CREATE INDEX badge_slug ON badge (slug);
-CREATE UNIQUE INDEX name ON badge (name, `type`);
-
-/******************** Add Table: book ************************/
-
-/* Build Table Structure */
-CREATE TABLE book
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- title VARCHAR(255) NOT NULL,
- short_name VARCHAR(255) NOT NULL,
- author VARCHAR(255) NOT NULL,
- user_id INTEGER NULL,
- price DECIMAL(10, 2) NULL,
- pages SMALLINT NULL,
- published_at DATE NOT NULL,
- publication VARCHAR(255) NOT NULL,
- cover_img VARCHAR(255) NULL,
- tagnames VARCHAR(125) NULL,
- added_at DATETIME NOT NULL,
- last_edited_at DATETIME NOT NULL
-) TYPE=InnoDB;
-
-/* Table Items: book */
-
-/* Add Indexes for: book */
-CREATE UNIQUE INDEX book_short_name_Idx ON book (short_name);
-CREATE INDEX fk_books_auth_user ON book (user_id);
-
-/******************** Add Table: book_author_info ************************/
-
-/* Build Table Structure */
-CREATE TABLE book_author_info
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- blog_url VARCHAR(255) NULL,
- user_id INTEGER NOT NULL,
- added_at DATETIME NOT NULL,
- last_edited_at DATETIME NOT NULL
-) TYPE=InnoDB;
-
-/* Table Items: book_author_info */
-
-/* Add Indexes for: book_author_info */
-CREATE INDEX fk_book_author_info_auth_user ON book_author_info (user_id);
-
-/******************** Add Table: book_author_rss ************************/
-
-/* Build Table Structure */
-CREATE TABLE book_author_rss
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- title VARCHAR(255) NOT NULL,
- url VARCHAR(255) NOT NULL,
- rss_created_at DATETIME NOT NULL,
- user_id INTEGER NOT NULL,
- added_at DATETIME NOT NULL
-) TYPE=InnoDB;
-
-/* Table Items: book_author_rss */
-
-/* Add Indexes for: book_author_rss */
-CREATE INDEX fk_book_author_rss_auth_user ON book_author_rss (user_id);
-
-/******************** Add Table: book_question ************************/
-
-/* Build Table Structure */
-CREATE TABLE book_question
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- book_id INTEGER NOT NULL,
- question_id INTEGER NOT NULL
-) TYPE=InnoDB;
-
-/* Table Items: book_question */
-
-/* Add Indexes for: book_question */
-CREATE INDEX fk_book_question_book ON book_question (book_id);
-CREATE INDEX fk_book_question_question ON book_question (question_id);
-
-/******************** Add Table: `comment` ************************/
-
-/* Build Table Structure */
-CREATE TABLE `comment`
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- content_type_id INTEGER NOT NULL,
- object_id INTEGER UNSIGNED NOT NULL,
- user_id INTEGER NOT NULL,
- `comment` TEXT NOT NULL,
- added_at DATETIME NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
-
-/* Table Items: `comment` */
-
-/* Add Indexes for: comment */
-CREATE INDEX comment_content_type_id ON `comment` (content_type_id);
-CREATE INDEX comment_user_id ON `comment` (user_id);
-CREATE INDEX content_type_id ON `comment` (content_type_id, object_id, user_id);
-
-/******************** Add Table: django_admin_log ************************/
-
-/* Build Table Structure */
-CREATE TABLE django_admin_log
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- action_time DATETIME NOT NULL,
- user_id INTEGER NOT NULL,
- content_type_id INTEGER NULL,
- object_id LONGTEXT NULL,
- object_repr VARCHAR(200) NOT NULL,
- action_flag SMALLINT UNSIGNED NOT NULL,
- change_message LONGTEXT NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-
-/* Table Items: django_admin_log */
-
-/* Add Indexes for: django_admin_log */
-CREATE INDEX django_admin_log_content_type_id ON django_admin_log (content_type_id);
-CREATE INDEX django_admin_log_user_id ON django_admin_log (user_id);
-
-/******************** Add Table: django_authopenid_association ************************/
-
-/* Build Table Structure */
-CREATE TABLE django_authopenid_association
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- server_url LONGTEXT NOT NULL,
- handle VARCHAR(255) NOT NULL,
- secret LONGTEXT NOT NULL,
- issued INTEGER NOT NULL,
- lifetime INTEGER NOT NULL,
- assoc_type LONGTEXT NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-
-/******************** Add Table: django_authopenid_nonce ************************/
-
-/* Build Table Structure */
-CREATE TABLE django_authopenid_nonce
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- server_url VARCHAR(255) NOT NULL,
- `timestamp` INTEGER NOT NULL,
- salt VARCHAR(40) NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8;
-
-/******************** Add Table: django_authopenid_userassociation ************************/
-
-/* Build Table Structure */
-CREATE TABLE django_authopenid_userassociation
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- openid_url VARCHAR(255) NOT NULL,
- user_id INTEGER NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-
-/* Table Items: django_authopenid_userassociation */
-
-/* Add Indexes for: django_authopenid_userassociation */
-CREATE UNIQUE INDEX user_id ON django_authopenid_userassociation (user_id);
-
-/******************** Add Table: django_authopenid_userpasswordqueue ************************/
-
-/* Build Table Structure */
-CREATE TABLE django_authopenid_userpasswordqueue
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- new_password VARCHAR(30) NOT NULL,
- confirm_key VARCHAR(40) NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-/* Table Items: django_authopenid_userpasswordqueue */
-
-/* Add Indexes for: django_authopenid_userpasswordqueue */
-CREATE UNIQUE INDEX user_id ON django_authopenid_userpasswordqueue (user_id);
-
-/******************** Add Table: django_content_type ************************/
-
-/* Build Table Structure */
-CREATE TABLE django_content_type
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- name VARCHAR(100) NOT NULL,
- app_label VARCHAR(100) NOT NULL,
- model VARCHAR(100) NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;
-
-/* Table Items: django_content_type */
-
-/* Add Indexes for: django_content_type */
-CREATE UNIQUE INDEX app_label ON django_content_type (app_label, model);
-
-/******************** Add Table: django_session ************************/
-
-/* Build Table Structure */
-CREATE TABLE django_session
-(
- session_key VARCHAR(40) NOT NULL,
- session_data LONGTEXT NOT NULL,
- expire_date DATETIME NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-/* Table Items: django_session */
-ALTER TABLE django_session ADD CONSTRAINT pkdjango_session
- PRIMARY KEY (session_key);
-
-/******************** Add Table: django_site ************************/
-
-/* Build Table Structure */
-CREATE TABLE django_site
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- domain VARCHAR(100) NOT NULL,
- name VARCHAR(50) NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-
-/******************** Add Table: favorite_question ************************/
-
-/* Build Table Structure */
-CREATE TABLE favorite_question
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- question_id INTEGER NOT NULL,
- user_id INTEGER NOT NULL,
- added_at DATETIME NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-
-/* Table Items: favorite_question */
-
-/* Add Indexes for: favorite_question */
-CREATE INDEX favorite_question_question_id ON favorite_question (question_id);
-CREATE INDEX favorite_question_user_id ON favorite_question (user_id);
-
-/******************** Add Table: flagged_item ************************/
-
-/* Build Table Structure */
-CREATE TABLE flagged_item
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- content_type_id INTEGER NOT NULL,
- object_id INTEGER UNSIGNED NOT NULL,
- user_id INTEGER NOT NULL,
- flagged_at DATETIME NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-
-/* Table Items: flagged_item */
-
-/* Add Indexes for: flagged_item */
-CREATE UNIQUE INDEX content_type_id ON flagged_item (content_type_id, object_id, user_id);
-CREATE INDEX flagged_item_content_type_id ON flagged_item (content_type_id);
-CREATE INDEX flagged_item_user_id ON flagged_item (user_id);
-
-/******************** Add Table: question ************************/
-
-/* Build Table Structure */
-CREATE TABLE question
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- title TEXT NOT NULL,
- author_id INTEGER NOT NULL,
- added_at DATETIME NOT NULL,
- wiki TINYINT NOT NULL,
- wikified_at DATETIME NULL,
- answer_accepted TINYINT NOT NULL,
- closed TINYINT NOT NULL,
- closed_by_id INTEGER NULL,
- closed_at DATETIME NULL,
- close_reason SMALLINT NULL,
- deleted TINYINT NOT NULL,
- deleted_at DATETIME NULL,
- deleted_by_id INTEGER NULL,
- locked TINYINT NOT NULL,
- locked_by_id INTEGER NULL,
- locked_at DATETIME NULL,
- score INTEGER NOT NULL,
- answer_count INTEGER UNSIGNED NOT NULL,
- comment_count INTEGER UNSIGNED NOT NULL,
- view_count INTEGER UNSIGNED NOT NULL,
- offensive_flag_count SMALLINT NOT NULL,
- favourite_count INTEGER UNSIGNED NOT NULL,
- last_edited_at DATETIME NULL,
- last_edited_by_id INTEGER NULL,
- last_activity_at DATETIME NOT NULL,
- last_activity_by_id INTEGER NOT NULL,
- tagnames VARCHAR(125) NOT NULL,
- summary VARCHAR(180) NOT NULL,
- html LONGTEXT NOT NULL,
- vote_up_count INTEGER NOT NULL,
- vote_down_count INTEGER NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;
-
-/* Table Items: question */
-
-/* Add Indexes for: question */
-CREATE INDEX question_author_id ON question (author_id);
-CREATE INDEX question_closed_by_id ON question (closed_by_id);
-CREATE INDEX question_deleted_by_id ON question (deleted_by_id);
-CREATE INDEX question_last_activity_by_id ON question (last_activity_by_id);
-CREATE INDEX question_last_edited_by_id ON question (last_edited_by_id);
-CREATE INDEX question_locked_by_id ON question (locked_by_id);
-
-/******************** Add Table: question_revision ************************/
-
-/* Build Table Structure */
-CREATE TABLE question_revision
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- question_id INTEGER NOT NULL,
- revision INTEGER UNSIGNED NOT NULL,
- title TEXT NOT NULL,
- author_id INTEGER NOT NULL,
- revised_at DATETIME NOT NULL,
- tagnames VARCHAR(125) NOT NULL,
- summary TEXT NOT NULL,
- `text` LONGTEXT NOT NULL
-) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
-
-/* Table Items: question_revision */
-
-/* Add Indexes for: question_revision */
-CREATE INDEX question_revision_author_id ON question_revision (author_id);
-CREATE INDEX question_revision_question_id ON question_revision (question_id);
-
-/******************** Add Table: question_tags ************************/
-
-/* Build Table Structure */
-CREATE TABLE question_tags
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- question_id INTEGER NOT NULL,
- tag_id INTEGER NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;
-
-/* Table Items: question_tags */
-
-/* Add Indexes for: question_tags */
-CREATE UNIQUE INDEX question_id ON question_tags (question_id, tag_id);
-CREATE INDEX tag_id_refs_id_43fcb953 ON question_tags (tag_id);
-
-/******************** Add Table: repute ************************/
-
-/* Build Table Structure */
-CREATE TABLE repute
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- positive SMALLINT NOT NULL,
- negative SMALLINT NOT NULL,
- question_id INTEGER NOT NULL,
- reputed_at DATETIME NOT NULL,
- reputation_type SMALLINT NOT NULL,
- reputation INTEGER NOT NULL
-) ENGINE=MyISAM AUTO_INCREMENT=17 DEFAULT CHARSET=latin1;
-
-/* Table Items: repute */
-
-/* Add Indexes for: repute */
-CREATE INDEX repute_question_id ON repute (question_id);
-CREATE INDEX repute_user_id ON repute (user_id);
-
-/******************** Add Table: tag ************************/
-
-/* Build Table Structure */
-CREATE TABLE tag
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- name VARCHAR(255) NOT NULL,
- created_by_id INTEGER NOT NULL,
- used_count INTEGER UNSIGNED NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;
-
-/* Table Items: tag */
-
-/* Add Indexes for: tag */
-CREATE UNIQUE INDEX name ON tag (name);
-CREATE INDEX tag_created_by_id ON tag (created_by_id);
-
-/******************** Add Table: user_badge ************************/
-
-/* Build Table Structure */
-CREATE TABLE user_badge
-(
- id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- badge_id INTEGER NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-/* Table Items: user_badge */
-
-/* Add Indexes for: user_badge */
-CREATE INDEX fk_user_badge_auth_user ON user_badge (user_id);
-CREATE INDEX fk_user_badge_badge ON user_badge (badge_id);
-
-/******************** Add Table: user_favorite_questions ************************/
-
-/* Build Table Structure */
-CREATE TABLE user_favorite_questions
-(
- id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- question_id INTEGER NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-/* Table Items: user_favorite_questions */
-
-/* Add Indexes for: user_favorite_questions */
-CREATE INDEX fk_user_favorite_questions_auth_user ON user_favorite_questions (user_id);
-CREATE INDEX fk_user_favorite_questions_question ON user_favorite_questions (question_id);
-
-/******************** Add Table: vote ************************/
-
-/* Build Table Structure */
-CREATE TABLE vote
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- content_type_id INTEGER NOT NULL,
- object_id INTEGER UNSIGNED NOT NULL,
- user_id INTEGER NOT NULL,
- vote SMALLINT NOT NULL,
- voted_at DATETIME NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-
-/* Table Items: vote */
-
-/* Add Indexes for: vote */
-CREATE UNIQUE INDEX content_type_id ON vote (content_type_id, object_id, user_id);
-CREATE INDEX vote_content_type_id ON vote (content_type_id);
-CREATE INDEX vote_user_id ON vote (user_id);
-
-
-/************ Add Foreign Keys to Database ***************/
-/*-----------------------------------------------------------
-Warning: Versions of MySQL prior to 4.1.2 require indexes on all columns involved in a foreign key. The following indexes may be required:
-fk_auth_group_permissions_auth_group may require an index on table: auth_group_permissions, column: group_id
-fk_auth_user_groups_auth_user may require an index on table: auth_user_groups, column: user_id
-fk_auth_user_user_permissions_auth_user may require an index on table: auth_user_user_permissions, column: user_id
-fk_question_tags_question may require an index on table: question_tags, column: question_id
------------------------------------------------------------
-*/
-
-/************ Foreign Key: fk_activity_auth_user ***************/
-ALTER TABLE activity ADD CONSTRAINT fk_activity_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: deleted_by_id_refs_id_192b0170 ***************/
-ALTER TABLE answer ADD CONSTRAINT deleted_by_id_refs_id_192b0170
- FOREIGN KEY (deleted_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_answer_auth_user ***************/
-ALTER TABLE answer ADD CONSTRAINT fk_answer_auth_user
- FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_answer_question ***************/
-ALTER TABLE answer ADD CONSTRAINT fk_answer_question
- FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: last_edited_by_id_refs_id_192b0170 ***************/
-ALTER TABLE answer ADD CONSTRAINT last_edited_by_id_refs_id_192b0170
- FOREIGN KEY (last_edited_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: locked_by_id_refs_id_192b0170 ***************/
-ALTER TABLE answer ADD CONSTRAINT locked_by_id_refs_id_192b0170
- FOREIGN KEY (locked_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_answer_revision_auth_user ***************/
-ALTER TABLE answer_revision ADD CONSTRAINT fk_answer_revision_auth_user
- FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_auth_group_permissions_auth_group ***************/
-ALTER TABLE auth_group_permissions ADD CONSTRAINT fk_auth_group_permissions_auth_group
- FOREIGN KEY (group_id) REFERENCES auth_group (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_auth_group_permissions_auth_permission ***************/
-ALTER TABLE auth_group_permissions ADD CONSTRAINT fk_auth_group_permissions_auth_permission
- FOREIGN KEY (permission_id) REFERENCES auth_permission (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_auth_message_auth_user ***************/
-ALTER TABLE auth_message ADD CONSTRAINT fk_auth_message_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_auth_permission_django_content_type ***************/
-ALTER TABLE auth_permission ADD CONSTRAINT fk_auth_permission_django_content_type
- FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_auth_user_groups_auth_group ***************/
-ALTER TABLE auth_user_groups ADD CONSTRAINT fk_auth_user_groups_auth_group
- FOREIGN KEY (group_id) REFERENCES auth_group (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_auth_user_groups_auth_user ***************/
-ALTER TABLE auth_user_groups ADD CONSTRAINT fk_auth_user_groups_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_auth_user_user_permissions_auth_permission ***************/
-ALTER TABLE auth_user_user_permissions ADD CONSTRAINT fk_auth_user_user_permissions_auth_permission
- FOREIGN KEY (permission_id) REFERENCES auth_permission (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_auth_user_user_permissions_auth_user ***************/
-ALTER TABLE auth_user_user_permissions ADD CONSTRAINT fk_auth_user_user_permissions_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_award_auth_user ***************/
-ALTER TABLE award ADD CONSTRAINT fk_award_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_award_badge ***************/
-ALTER TABLE award ADD CONSTRAINT fk_award_badge
- FOREIGN KEY (badge_id) REFERENCES badge (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_books_auth_user ***************/
-ALTER TABLE book ADD CONSTRAINT fk_books_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_book_author_info_auth_user ***************/
-ALTER TABLE book_author_info ADD CONSTRAINT fk_book_author_info_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_book_author_rss_auth_user ***************/
-ALTER TABLE book_author_rss ADD CONSTRAINT fk_book_author_rss_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_book_question_book ***************/
-ALTER TABLE book_question ADD CONSTRAINT fk_book_question_book
- FOREIGN KEY (book_id) REFERENCES book (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_book_question_question ***************/
-ALTER TABLE book_question ADD CONSTRAINT fk_book_question_question
- FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_comment_auth_user ***************/
-ALTER TABLE `comment` ADD CONSTRAINT fk_comment_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_comment_django_content_type ***************/
-ALTER TABLE `comment` ADD CONSTRAINT fk_comment_django_content_type
- FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_django_admin_log_auth_user ***************/
-ALTER TABLE django_admin_log ADD CONSTRAINT fk_django_admin_log_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_django_admin_log_django_content_type ***************/
-ALTER TABLE django_admin_log ADD CONSTRAINT fk_django_admin_log_django_content_type
- FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_django_authopenid_userassociation_auth_user ***************/
-ALTER TABLE django_authopenid_userassociation ADD CONSTRAINT fk_django_authopenid_userassociation_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_django_authopenid_userpasswordqueue_auth_user ***************/
-ALTER TABLE django_authopenid_userpasswordqueue ADD CONSTRAINT fk_django_authopenid_userpasswordqueue_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_favorite_question_auth_user ***************/
-ALTER TABLE favorite_question ADD CONSTRAINT fk_favorite_question_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_favorite_question_question ***************/
-ALTER TABLE favorite_question ADD CONSTRAINT fk_favorite_question_question
- FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_flagged_item_auth_user ***************/
-ALTER TABLE flagged_item ADD CONSTRAINT fk_flagged_item_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_flagged_item_django_content_type ***************/
-ALTER TABLE flagged_item ADD CONSTRAINT fk_flagged_item_django_content_type
- FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: closed_by_id_refs_id_56e9d00c ***************/
-ALTER TABLE question ADD CONSTRAINT closed_by_id_refs_id_56e9d00c
- FOREIGN KEY (closed_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: deleted_by_id_refs_id_56e9d00c ***************/
-ALTER TABLE question ADD CONSTRAINT deleted_by_id_refs_id_56e9d00c
- FOREIGN KEY (deleted_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_question_auth_user ***************/
-ALTER TABLE question ADD CONSTRAINT fk_question_auth_user
- FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: last_activity_by_id_refs_id_56e9d00c ***************/
-ALTER TABLE question ADD CONSTRAINT last_activity_by_id_refs_id_56e9d00c
- FOREIGN KEY (last_activity_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: last_edited_by_id_refs_id_56e9d00c ***************/
-ALTER TABLE question ADD CONSTRAINT last_edited_by_id_refs_id_56e9d00c
- FOREIGN KEY (last_edited_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: locked_by_id_refs_id_56e9d00c ***************/
-ALTER TABLE question ADD CONSTRAINT locked_by_id_refs_id_56e9d00c
- FOREIGN KEY (locked_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_question_revision_auth_user ***************/
-ALTER TABLE question_revision ADD CONSTRAINT fk_question_revision_auth_user
- FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_question_revision_question ***************/
-ALTER TABLE question_revision ADD CONSTRAINT fk_question_revision_question
- FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_question_tags_question ***************/
-ALTER TABLE question_tags ADD CONSTRAINT fk_question_tags_question
- FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_question_tags_tag ***************/
-ALTER TABLE question_tags ADD CONSTRAINT fk_question_tags_tag
- FOREIGN KEY (tag_id) REFERENCES tag (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_repute_auth_user ***************/
-ALTER TABLE repute ADD CONSTRAINT fk_repute_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_repute_question ***************/
-ALTER TABLE repute ADD CONSTRAINT fk_repute_question
- FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_tag_auth_user ***************/
-ALTER TABLE tag ADD CONSTRAINT fk_tag_auth_user
- FOREIGN KEY (created_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_user_badge_auth_user ***************/
-ALTER TABLE user_badge ADD CONSTRAINT fk_user_badge_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_user_badge_badge ***************/
-ALTER TABLE user_badge ADD CONSTRAINT fk_user_badge_badge
- FOREIGN KEY (badge_id) REFERENCES badge (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_user_favorite_questions_auth_user ***************/
-ALTER TABLE user_favorite_questions ADD CONSTRAINT fk_user_favorite_questions_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_user_favorite_questions_question ***************/
-ALTER TABLE user_favorite_questions ADD CONSTRAINT fk_user_favorite_questions_question
- FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_vote_auth_user ***************/
-ALTER TABLE vote ADD CONSTRAINT fk_vote_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_vote_django_content_type ***************/
-ALTER TABLE vote ADD CONSTRAINT fk_vote_django_content_type
- FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION; \ No newline at end of file
diff --git a/askbot/sql_scripts/cnprog_new_install_2009_04_07.sql b/askbot/sql_scripts/cnprog_new_install_2009_04_07.sql
deleted file mode 100644
index ff9016fa..00000000
--- a/askbot/sql_scripts/cnprog_new_install_2009_04_07.sql
+++ /dev/null
@@ -1,24 +0,0 @@
-USE cnprog;
-
-
-/************ Add Foreign Keys to Database ***************/
-
-/************ Foreign Key: fk_activity_auth_user ***************/
-ALTER TABLE activity ADD CONSTRAINT fk_activity_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_question_revision_auth_user ***************/
-ALTER TABLE question_revision ADD CONSTRAINT fk_question_revision_auth_user
- FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_question_revision_question ***************/
-ALTER TABLE question_revision ADD CONSTRAINT fk_question_revision_question
- FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_repute_auth_user ***************/
-ALTER TABLE repute ADD CONSTRAINT fk_repute_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_repute_question ***************/
-ALTER TABLE repute ADD CONSTRAINT fk_repute_question
- FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION; \ No newline at end of file
diff --git a/askbot/sql_scripts/cnprog_new_install_2009_04_09.sql b/askbot/sql_scripts/cnprog_new_install_2009_04_09.sql
deleted file mode 100644
index f4424852..00000000
--- a/askbot/sql_scripts/cnprog_new_install_2009_04_09.sql
+++ /dev/null
@@ -1,904 +0,0 @@
-USE cnprog;
-
-
-/************ Update: Tables ***************/
-
-/******************** Add Table: activity ************************/
-
-/* Build Table Structure */
-CREATE TABLE activity
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- activity_type SMALLINT NOT NULL,
- active_at DATETIME NOT NULL,
- content_type_id INTEGER NOT NULL,
- object_id INTEGER UNSIGNED NOT NULL,
- is_auditted TINYINT NULL DEFAULT 0
-) ENGINE=MyISAM AUTO_INCREMENT=103 DEFAULT CHARSET=latin1;
-
-/* Table Items: activity */
-
-/* Add Indexes for: activity */
-CREATE INDEX activity_content_type_id ON activity (content_type_id);
-CREATE INDEX activity_user_id ON activity (user_id);
-
-/******************** Add Table: answer ************************/
-
-/* Build Table Structure */
-CREATE TABLE answer
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- question_id INTEGER NOT NULL,
- author_id INTEGER NOT NULL,
- added_at DATETIME NOT NULL,
- wiki TINYINT NOT NULL,
- wikified_at DATETIME NULL,
- accepted TINYINT NOT NULL,
- deleted TINYINT NOT NULL,
- deleted_by_id INTEGER NULL,
- locked TINYINT NOT NULL,
- locked_by_id INTEGER NULL,
- locked_at DATETIME NULL,
- score INTEGER NOT NULL,
- comment_count INTEGER UNSIGNED NOT NULL,
- offensive_flag_count SMALLINT NOT NULL,
- last_edited_at DATETIME NULL,
- last_edited_by_id INTEGER NULL,
- html LONGTEXT NOT NULL,
- vote_up_count INTEGER NOT NULL,
- vote_down_count INTEGER NOT NULL,
- accepted_at DATETIME NULL
-) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
-
-/* Table Items: answer */
-
-/* Add Indexes for: answer */
-CREATE INDEX answer_author_id ON answer (author_id);
-CREATE INDEX answer_deleted_by_id ON answer (deleted_by_id);
-CREATE INDEX answer_last_edited_by_id ON answer (last_edited_by_id);
-CREATE INDEX answer_locked_by_id ON answer (locked_by_id);
-CREATE INDEX answer_question_id ON answer (question_id);
-
-/******************** Add Table: answer_revision ************************/
-
-/* Build Table Structure */
-CREATE TABLE answer_revision
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- answer_id INTEGER NOT NULL,
- revision INTEGER UNSIGNED NOT NULL,
- author_id INTEGER NOT NULL,
- revised_at DATETIME NOT NULL,
- summary TEXT NOT NULL,
- `text` LONGTEXT NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-
-/* Table Items: answer_revision */
-
-/* Add Indexes for: answer_revision */
-CREATE INDEX answer_revision_answer_id ON answer_revision (answer_id);
-CREATE INDEX answer_revision_author_id ON answer_revision (author_id);
-
-/******************** Add Table: auth_group ************************/
-
-/* Build Table Structure */
-CREATE TABLE auth_group
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- name VARCHAR(80) NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-/* Table Items: auth_group */
-
-/* Add Indexes for: auth_group */
-CREATE UNIQUE INDEX name ON auth_group (name);
-
-/******************** Add Table: auth_group_permissions ************************/
-
-/* Build Table Structure */
-CREATE TABLE auth_group_permissions
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- group_id INTEGER NOT NULL,
- permission_id INTEGER NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-/* Table Items: auth_group_permissions */
-
-/* Add Indexes for: auth_group_permissions */
-CREATE UNIQUE INDEX group_id ON auth_group_permissions (group_id, permission_id);
-CREATE INDEX permission_id_refs_id_5886d21f ON auth_group_permissions (permission_id);
-
-/******************** Add Table: auth_message ************************/
-
-/* Build Table Structure */
-CREATE TABLE auth_message
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- message LONGTEXT NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;
-
-/* Table Items: auth_message */
-
-/* Add Indexes for: auth_message */
-CREATE INDEX auth_message_user_id ON auth_message (user_id);
-
-/******************** Add Table: auth_permission ************************/
-
-/* Build Table Structure */
-CREATE TABLE auth_permission
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- name VARCHAR(50) NOT NULL,
- content_type_id INTEGER NOT NULL,
- codename VARCHAR(100) NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=88 DEFAULT CHARSET=utf8;
-
-/* Table Items: auth_permission */
-
-/* Add Indexes for: auth_permission */
-CREATE INDEX auth_permission_content_type_id ON auth_permission (content_type_id);
-CREATE UNIQUE INDEX content_type_id ON auth_permission (content_type_id, codename);
-
-/******************** Add Table: auth_user ************************/
-
-/* Build Table Structure */
-CREATE TABLE auth_user
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- username VARCHAR(30) NOT NULL,
- first_name VARCHAR(30) NOT NULL,
- last_name VARCHAR(30) NOT NULL,
- email VARCHAR(75) NOT NULL,
- password VARCHAR(128) NOT NULL,
- is_staff TINYINT NOT NULL,
- is_active TINYINT NOT NULL,
- is_superuser TINYINT NOT NULL,
- last_login DATETIME NOT NULL,
- date_joined DATETIME NOT NULL,
- gold SMALLINT NOT NULL DEFAULT 0,
- silver SMALLINT UNSIGNED NOT NULL DEFAULT 0,
- bronze SMALLINT UNSIGNED NOT NULL DEFAULT 0,
- reputation INTEGER UNSIGNED NULL DEFAULT 1,
- gravatar VARCHAR(128) NULL,
- questions_per_page SMALLINT UNSIGNED NULL DEFAULT 10,
- last_seen DATETIME NULL,
- real_name VARCHAR(100) NULL,
- website VARCHAR(200) NULL,
- location VARCHAR(100) NULL,
- date_of_birth DATETIME NULL,
- about TEXT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=104 DEFAULT CHARSET=utf8;
-
-/* Table Items: auth_user */
-
-/* Add Indexes for: auth_user */
-CREATE UNIQUE INDEX username ON auth_user (username);
-
-/******************** Add Table: auth_user_groups ************************/
-
-/* Build Table Structure */
-CREATE TABLE auth_user_groups
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- group_id INTEGER NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-/* Table Items: auth_user_groups */
-
-/* Add Indexes for: auth_user_groups */
-CREATE INDEX group_id_refs_id_f116770 ON auth_user_groups (group_id);
-CREATE UNIQUE INDEX user_id ON auth_user_groups (user_id, group_id);
-
-/******************** Add Table: auth_user_user_permissions ************************/
-
-/* Build Table Structure */
-CREATE TABLE auth_user_user_permissions
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- permission_id INTEGER NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-/* Table Items: auth_user_user_permissions */
-
-/* Add Indexes for: auth_user_user_permissions */
-CREATE INDEX permission_id_refs_id_67e79cb ON auth_user_user_permissions (permission_id);
-CREATE UNIQUE INDEX user_id ON auth_user_user_permissions (user_id, permission_id);
-
-/******************** Add Table: award ************************/
-
-/* Build Table Structure */
-CREATE TABLE award
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- badge_id INTEGER NOT NULL,
- awarded_at DATETIME NOT NULL,
- notified TINYINT NOT NULL,
- content_type_id INTEGER NULL,
- object_id INTEGER NULL
-) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;
-
-/* Table Items: award */
-
-/* Add Indexes for: award */
-CREATE INDEX award_badge_id ON award (badge_id);
-CREATE INDEX award_user_id ON award (user_id);
-
-/******************** Add Table: badge ************************/
-
-/* Build Table Structure */
-CREATE TABLE badge
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- name VARCHAR(50) NOT NULL,
- `type` SMALLINT NOT NULL,
- slug VARCHAR(50) NOT NULL,
- description TEXT NOT NULL,
- multiple TINYINT NOT NULL,
- awarded_count INTEGER UNSIGNED NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
-
-/* Table Items: badge */
-
-/* Add Indexes for: badge */
-CREATE INDEX badge_slug ON badge (slug);
-CREATE UNIQUE INDEX name ON badge (name, `type`);
-
-/******************** Add Table: book ************************/
-
-/* Build Table Structure */
-CREATE TABLE book
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- title VARCHAR(255) NOT NULL,
- short_name VARCHAR(255) NOT NULL,
- author VARCHAR(255) NOT NULL,
- user_id INTEGER NULL,
- price DECIMAL(10, 2) NULL,
- pages SMALLINT NULL,
- published_at DATE NOT NULL,
- publication VARCHAR(255) NOT NULL,
- cover_img VARCHAR(255) NULL,
- tagnames VARCHAR(125) NULL,
- added_at DATETIME NOT NULL,
- last_edited_at DATETIME NOT NULL
-) TYPE=InnoDB;
-
-/* Table Items: book */
-
-/* Add Indexes for: book */
-CREATE UNIQUE INDEX book_short_name_Idx ON book (short_name);
-CREATE INDEX fk_books_auth_user ON book (user_id);
-
-/******************** Add Table: book_author_info ************************/
-
-/* Build Table Structure */
-CREATE TABLE book_author_info
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- blog_url VARCHAR(255) NULL,
- user_id INTEGER NOT NULL,
- added_at DATETIME NOT NULL,
- last_edited_at DATETIME NOT NULL,
- book_id INTEGER NOT NULL
-) TYPE=InnoDB;
-
-/* Table Items: book_author_info */
-
-/* Add Indexes for: book_author_info */
-CREATE INDEX fk_book_author_info_auth_user ON book_author_info (user_id);
-CREATE INDEX fk_book_author_info_book ON book_author_info (book_id);
-
-/******************** Add Table: book_author_rss ************************/
-
-/* Build Table Structure */
-CREATE TABLE book_author_rss
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- title VARCHAR(255) NOT NULL,
- url VARCHAR(255) NOT NULL,
- rss_created_at DATETIME NOT NULL,
- user_id INTEGER NOT NULL,
- added_at DATETIME NOT NULL,
- book_id INTEGER NOT NULL
-) TYPE=InnoDB;
-
-/* Table Items: book_author_rss */
-
-/* Add Indexes for: book_author_rss */
-CREATE INDEX fk_book_author_rss_auth_user ON book_author_rss (user_id);
-CREATE INDEX fk_book_author_rss_book ON book_author_rss (book_id);
-
-/******************** Add Table: book_question ************************/
-
-/* Build Table Structure */
-CREATE TABLE book_question
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- book_id INTEGER NOT NULL,
- question_id INTEGER NOT NULL
-) TYPE=InnoDB;
-
-/* Table Items: book_question */
-
-/* Add Indexes for: book_question */
-CREATE INDEX fk_book_question_book ON book_question (book_id);
-CREATE INDEX fk_book_question_question ON book_question (question_id);
-
-/******************** Add Table: `comment` ************************/
-
-/* Build Table Structure */
-CREATE TABLE `comment`
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- content_type_id INTEGER NOT NULL,
- object_id INTEGER UNSIGNED NOT NULL,
- user_id INTEGER NOT NULL,
- `comment` TEXT NOT NULL,
- added_at DATETIME NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
-
-/* Table Items: `comment` */
-
-/* Add Indexes for: comment */
-CREATE INDEX comment_content_type_id ON `comment` (content_type_id);
-CREATE INDEX comment_user_id ON `comment` (user_id);
-CREATE INDEX content_type_id ON `comment` (content_type_id, object_id, user_id);
-
-/******************** Add Table: django_admin_log ************************/
-
-/* Build Table Structure */
-CREATE TABLE django_admin_log
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- action_time DATETIME NOT NULL,
- user_id INTEGER NOT NULL,
- content_type_id INTEGER NULL,
- object_id LONGTEXT NULL,
- object_repr VARCHAR(200) NOT NULL,
- action_flag SMALLINT UNSIGNED NOT NULL,
- change_message LONGTEXT NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-
-/* Table Items: django_admin_log */
-
-/* Add Indexes for: django_admin_log */
-CREATE INDEX django_admin_log_content_type_id ON django_admin_log (content_type_id);
-CREATE INDEX django_admin_log_user_id ON django_admin_log (user_id);
-
-/******************** Add Table: django_authopenid_association ************************/
-
-/* Build Table Structure */
-CREATE TABLE django_authopenid_association
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- server_url LONGTEXT NOT NULL,
- handle VARCHAR(255) NOT NULL,
- secret LONGTEXT NOT NULL,
- issued INTEGER NOT NULL,
- lifetime INTEGER NOT NULL,
- assoc_type LONGTEXT NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-
-/******************** Add Table: django_authopenid_nonce ************************/
-
-/* Build Table Structure */
-CREATE TABLE django_authopenid_nonce
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- server_url VARCHAR(255) NOT NULL,
- `timestamp` INTEGER NOT NULL,
- salt VARCHAR(40) NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8;
-
-/******************** Add Table: django_authopenid_userassociation ************************/
-
-/* Build Table Structure */
-CREATE TABLE django_authopenid_userassociation
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- openid_url VARCHAR(255) NOT NULL,
- user_id INTEGER NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-
-/* Table Items: django_authopenid_userassociation */
-
-/* Add Indexes for: django_authopenid_userassociation */
-CREATE UNIQUE INDEX user_id ON django_authopenid_userassociation (user_id);
-
-/******************** Add Table: django_authopenid_userpasswordqueue ************************/
-
-/* Build Table Structure */
-CREATE TABLE django_authopenid_userpasswordqueue
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- new_password VARCHAR(30) NOT NULL,
- confirm_key VARCHAR(40) NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-/* Table Items: django_authopenid_userpasswordqueue */
-
-/* Add Indexes for: django_authopenid_userpasswordqueue */
-CREATE UNIQUE INDEX user_id ON django_authopenid_userpasswordqueue (user_id);
-
-/******************** Add Table: django_content_type ************************/
-
-/* Build Table Structure */
-CREATE TABLE django_content_type
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- name VARCHAR(100) NOT NULL,
- app_label VARCHAR(100) NOT NULL,
- model VARCHAR(100) NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;
-
-/* Table Items: django_content_type */
-
-/* Add Indexes for: django_content_type */
-CREATE UNIQUE INDEX app_label ON django_content_type (app_label, model);
-
-/******************** Add Table: django_session ************************/
-
-/* Build Table Structure */
-CREATE TABLE django_session
-(
- session_key VARCHAR(40) NOT NULL,
- session_data LONGTEXT NOT NULL,
- expire_date DATETIME NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-/* Table Items: django_session */
-ALTER TABLE django_session ADD CONSTRAINT pkdjango_session
- PRIMARY KEY (session_key);
-
-/******************** Add Table: django_site ************************/
-
-/* Build Table Structure */
-CREATE TABLE django_site
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- domain VARCHAR(100) NOT NULL,
- name VARCHAR(50) NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-
-/******************** Add Table: favorite_question ************************/
-
-/* Build Table Structure */
-CREATE TABLE favorite_question
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- question_id INTEGER NOT NULL,
- user_id INTEGER NOT NULL,
- added_at DATETIME NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-
-/* Table Items: favorite_question */
-
-/* Add Indexes for: favorite_question */
-CREATE INDEX favorite_question_question_id ON favorite_question (question_id);
-CREATE INDEX favorite_question_user_id ON favorite_question (user_id);
-
-/******************** Add Table: flagged_item ************************/
-
-/* Build Table Structure */
-CREATE TABLE flagged_item
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- content_type_id INTEGER NOT NULL,
- object_id INTEGER UNSIGNED NOT NULL,
- user_id INTEGER NOT NULL,
- flagged_at DATETIME NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-
-/* Table Items: flagged_item */
-
-/* Add Indexes for: flagged_item */
-CREATE UNIQUE INDEX content_type_id ON flagged_item (content_type_id, object_id, user_id);
-CREATE INDEX flagged_item_content_type_id ON flagged_item (content_type_id);
-CREATE INDEX flagged_item_user_id ON flagged_item (user_id);
-
-/******************** Add Table: question ************************/
-
-/* Build Table Structure */
-CREATE TABLE question
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- title TEXT NOT NULL,
- author_id INTEGER NOT NULL,
- added_at DATETIME NOT NULL,
- wiki TINYINT NOT NULL,
- wikified_at DATETIME NULL,
- answer_accepted TINYINT NOT NULL,
- closed TINYINT NOT NULL,
- closed_by_id INTEGER NULL,
- closed_at DATETIME NULL,
- close_reason SMALLINT NULL,
- deleted TINYINT NOT NULL,
- deleted_at DATETIME NULL,
- deleted_by_id INTEGER NULL,
- locked TINYINT NOT NULL,
- locked_by_id INTEGER NULL,
- locked_at DATETIME NULL,
- score INTEGER NOT NULL,
- answer_count INTEGER UNSIGNED NOT NULL,
- comment_count INTEGER UNSIGNED NOT NULL,
- view_count INTEGER UNSIGNED NOT NULL,
- offensive_flag_count SMALLINT NOT NULL,
- favourite_count INTEGER UNSIGNED NOT NULL,
- last_edited_at DATETIME NULL,
- last_edited_by_id INTEGER NULL,
- last_activity_at DATETIME NOT NULL,
- last_activity_by_id INTEGER NOT NULL,
- tagnames VARCHAR(125) NOT NULL,
- summary VARCHAR(180) NOT NULL,
- html LONGTEXT NOT NULL,
- vote_up_count INTEGER NOT NULL,
- vote_down_count INTEGER NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;
-
-/* Table Items: question */
-
-/* Add Indexes for: question */
-CREATE INDEX question_author_id ON question (author_id);
-CREATE INDEX question_closed_by_id ON question (closed_by_id);
-CREATE INDEX question_deleted_by_id ON question (deleted_by_id);
-CREATE INDEX question_last_activity_by_id ON question (last_activity_by_id);
-CREATE INDEX question_last_edited_by_id ON question (last_edited_by_id);
-CREATE INDEX question_locked_by_id ON question (locked_by_id);
-
-/******************** Add Table: question_revision ************************/
-
-/* Build Table Structure */
-CREATE TABLE question_revision
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- question_id INTEGER NOT NULL,
- revision INTEGER UNSIGNED NOT NULL,
- title TEXT NOT NULL,
- author_id INTEGER NOT NULL,
- revised_at DATETIME NOT NULL,
- tagnames VARCHAR(125) NOT NULL,
- summary TEXT NOT NULL,
- `text` LONGTEXT NOT NULL
-) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
-
-/* Table Items: question_revision */
-
-/* Add Indexes for: question_revision */
-CREATE INDEX question_revision_author_id ON question_revision (author_id);
-CREATE INDEX question_revision_question_id ON question_revision (question_id);
-
-/******************** Add Table: question_tags ************************/
-
-/* Build Table Structure */
-CREATE TABLE question_tags
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- question_id INTEGER NOT NULL,
- tag_id INTEGER NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;
-
-/* Table Items: question_tags */
-
-/* Add Indexes for: question_tags */
-CREATE UNIQUE INDEX question_id ON question_tags (question_id, tag_id);
-CREATE INDEX tag_id_refs_id_43fcb953 ON question_tags (tag_id);
-
-/******************** Add Table: repute ************************/
-
-/* Build Table Structure */
-CREATE TABLE repute
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- positive SMALLINT NOT NULL,
- negative SMALLINT NOT NULL,
- question_id INTEGER NOT NULL,
- reputed_at DATETIME NOT NULL,
- reputation_type SMALLINT NOT NULL,
- reputation INTEGER NOT NULL
-) ENGINE=MyISAM AUTO_INCREMENT=17 DEFAULT CHARSET=latin1;
-
-/* Table Items: repute */
-
-/* Add Indexes for: repute */
-CREATE INDEX repute_question_id ON repute (question_id);
-CREATE INDEX repute_user_id ON repute (user_id);
-
-/******************** Add Table: tag ************************/
-
-/* Build Table Structure */
-CREATE TABLE tag
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- name VARCHAR(255) NOT NULL,
- created_by_id INTEGER NOT NULL,
- used_count INTEGER UNSIGNED NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;
-
-/* Table Items: tag */
-
-/* Add Indexes for: tag */
-CREATE UNIQUE INDEX name ON tag (name);
-CREATE INDEX tag_created_by_id ON tag (created_by_id);
-
-/******************** Add Table: user_badge ************************/
-
-/* Build Table Structure */
-CREATE TABLE user_badge
-(
- id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- badge_id INTEGER NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-/* Table Items: user_badge */
-
-/* Add Indexes for: user_badge */
-CREATE INDEX fk_user_badge_auth_user ON user_badge (user_id);
-CREATE INDEX fk_user_badge_badge ON user_badge (badge_id);
-
-/******************** Add Table: user_favorite_questions ************************/
-
-/* Build Table Structure */
-CREATE TABLE user_favorite_questions
-(
- id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
- user_id INTEGER NOT NULL,
- question_id INTEGER NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-/* Table Items: user_favorite_questions */
-
-/* Add Indexes for: user_favorite_questions */
-CREATE INDEX fk_user_favorite_questions_auth_user ON user_favorite_questions (user_id);
-CREATE INDEX fk_user_favorite_questions_question ON user_favorite_questions (question_id);
-
-/******************** Add Table: vote ************************/
-
-/* Build Table Structure */
-CREATE TABLE vote
-(
- id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
- content_type_id INTEGER NOT NULL,
- object_id INTEGER UNSIGNED NOT NULL,
- user_id INTEGER NOT NULL,
- vote SMALLINT NOT NULL,
- voted_at DATETIME NOT NULL
-) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-
-/* Table Items: vote */
-
-/* Add Indexes for: vote */
-CREATE UNIQUE INDEX content_type_id ON vote (content_type_id, object_id, user_id);
-CREATE INDEX vote_content_type_id ON vote (content_type_id);
-CREATE INDEX vote_user_id ON vote (user_id);
-
-
-/************ Add Foreign Keys to Database ***************/
-/*-----------------------------------------------------------
-Warning: Versions of MySQL prior to 4.1.2 require indexes on all columns involved in a foreign key. The following indexes may be required:
-fk_auth_group_permissions_auth_group may require an index on table: auth_group_permissions, column: group_id
-fk_auth_user_groups_auth_user may require an index on table: auth_user_groups, column: user_id
-fk_auth_user_user_permissions_auth_user may require an index on table: auth_user_user_permissions, column: user_id
-fk_question_tags_question may require an index on table: question_tags, column: question_id
------------------------------------------------------------
-*/
-
-/************ Foreign Key: fk_activity_auth_user ***************/
-ALTER TABLE activity ADD CONSTRAINT fk_activity_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: deleted_by_id_refs_id_192b0170 ***************/
-ALTER TABLE answer ADD CONSTRAINT deleted_by_id_refs_id_192b0170
- FOREIGN KEY (deleted_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_answer_auth_user ***************/
-ALTER TABLE answer ADD CONSTRAINT fk_answer_auth_user
- FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_answer_question ***************/
-ALTER TABLE answer ADD CONSTRAINT fk_answer_question
- FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: last_edited_by_id_refs_id_192b0170 ***************/
-ALTER TABLE answer ADD CONSTRAINT last_edited_by_id_refs_id_192b0170
- FOREIGN KEY (last_edited_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: locked_by_id_refs_id_192b0170 ***************/
-ALTER TABLE answer ADD CONSTRAINT locked_by_id_refs_id_192b0170
- FOREIGN KEY (locked_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_answer_revision_auth_user ***************/
-ALTER TABLE answer_revision ADD CONSTRAINT fk_answer_revision_auth_user
- FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_auth_group_permissions_auth_group ***************/
-ALTER TABLE auth_group_permissions ADD CONSTRAINT fk_auth_group_permissions_auth_group
- FOREIGN KEY (group_id) REFERENCES auth_group (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_auth_group_permissions_auth_permission ***************/
-ALTER TABLE auth_group_permissions ADD CONSTRAINT fk_auth_group_permissions_auth_permission
- FOREIGN KEY (permission_id) REFERENCES auth_permission (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_auth_message_auth_user ***************/
-ALTER TABLE auth_message ADD CONSTRAINT fk_auth_message_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_auth_permission_django_content_type ***************/
-ALTER TABLE auth_permission ADD CONSTRAINT fk_auth_permission_django_content_type
- FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_auth_user_groups_auth_group ***************/
-ALTER TABLE auth_user_groups ADD CONSTRAINT fk_auth_user_groups_auth_group
- FOREIGN KEY (group_id) REFERENCES auth_group (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_auth_user_groups_auth_user ***************/
-ALTER TABLE auth_user_groups ADD CONSTRAINT fk_auth_user_groups_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_auth_user_user_permissions_auth_permission ***************/
-ALTER TABLE auth_user_user_permissions ADD CONSTRAINT fk_auth_user_user_permissions_auth_permission
- FOREIGN KEY (permission_id) REFERENCES auth_permission (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_auth_user_user_permissions_auth_user ***************/
-ALTER TABLE auth_user_user_permissions ADD CONSTRAINT fk_auth_user_user_permissions_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_award_auth_user ***************/
-ALTER TABLE award ADD CONSTRAINT fk_award_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_award_badge ***************/
-ALTER TABLE award ADD CONSTRAINT fk_award_badge
- FOREIGN KEY (badge_id) REFERENCES badge (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_books_auth_user ***************/
-ALTER TABLE book ADD CONSTRAINT fk_books_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_book_author_info_auth_user ***************/
-ALTER TABLE book_author_info ADD CONSTRAINT fk_book_author_info_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_book_author_info_book ***************/
-ALTER TABLE book_author_info ADD CONSTRAINT fk_book_author_info_book
- FOREIGN KEY (book_id) REFERENCES book (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_book_author_rss_auth_user ***************/
-ALTER TABLE book_author_rss ADD CONSTRAINT fk_book_author_rss_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_book_author_rss_book ***************/
-ALTER TABLE book_author_rss ADD CONSTRAINT fk_book_author_rss_book
- FOREIGN KEY (book_id) REFERENCES book (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_book_question_book ***************/
-ALTER TABLE book_question ADD CONSTRAINT fk_book_question_book
- FOREIGN KEY (book_id) REFERENCES book (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_book_question_question ***************/
-ALTER TABLE book_question ADD CONSTRAINT fk_book_question_question
- FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_comment_auth_user ***************/
-ALTER TABLE `comment` ADD CONSTRAINT fk_comment_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_comment_django_content_type ***************/
-ALTER TABLE `comment` ADD CONSTRAINT fk_comment_django_content_type
- FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_django_admin_log_auth_user ***************/
-ALTER TABLE django_admin_log ADD CONSTRAINT fk_django_admin_log_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_django_admin_log_django_content_type ***************/
-ALTER TABLE django_admin_log ADD CONSTRAINT fk_django_admin_log_django_content_type
- FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_django_authopenid_userassociation_auth_user ***************/
-ALTER TABLE django_authopenid_userassociation ADD CONSTRAINT fk_django_authopenid_userassociation_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_django_authopenid_userpasswordqueue_auth_user ***************/
-ALTER TABLE django_authopenid_userpasswordqueue ADD CONSTRAINT fk_django_authopenid_userpasswordqueue_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_favorite_question_auth_user ***************/
-ALTER TABLE favorite_question ADD CONSTRAINT fk_favorite_question_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_favorite_question_question ***************/
-ALTER TABLE favorite_question ADD CONSTRAINT fk_favorite_question_question
- FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_flagged_item_auth_user ***************/
-ALTER TABLE flagged_item ADD CONSTRAINT fk_flagged_item_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_flagged_item_django_content_type ***************/
-ALTER TABLE flagged_item ADD CONSTRAINT fk_flagged_item_django_content_type
- FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: closed_by_id_refs_id_56e9d00c ***************/
-ALTER TABLE question ADD CONSTRAINT closed_by_id_refs_id_56e9d00c
- FOREIGN KEY (closed_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: deleted_by_id_refs_id_56e9d00c ***************/
-ALTER TABLE question ADD CONSTRAINT deleted_by_id_refs_id_56e9d00c
- FOREIGN KEY (deleted_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_question_auth_user ***************/
-ALTER TABLE question ADD CONSTRAINT fk_question_auth_user
- FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: last_activity_by_id_refs_id_56e9d00c ***************/
-ALTER TABLE question ADD CONSTRAINT last_activity_by_id_refs_id_56e9d00c
- FOREIGN KEY (last_activity_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: last_edited_by_id_refs_id_56e9d00c ***************/
-ALTER TABLE question ADD CONSTRAINT last_edited_by_id_refs_id_56e9d00c
- FOREIGN KEY (last_edited_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: locked_by_id_refs_id_56e9d00c ***************/
-ALTER TABLE question ADD CONSTRAINT locked_by_id_refs_id_56e9d00c
- FOREIGN KEY (locked_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_question_revision_auth_user ***************/
-ALTER TABLE question_revision ADD CONSTRAINT fk_question_revision_auth_user
- FOREIGN KEY (author_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_question_revision_question ***************/
-ALTER TABLE question_revision ADD CONSTRAINT fk_question_revision_question
- FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_question_tags_question ***************/
-ALTER TABLE question_tags ADD CONSTRAINT fk_question_tags_question
- FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_question_tags_tag ***************/
-ALTER TABLE question_tags ADD CONSTRAINT fk_question_tags_tag
- FOREIGN KEY (tag_id) REFERENCES tag (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_repute_auth_user ***************/
-ALTER TABLE repute ADD CONSTRAINT fk_repute_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_repute_question ***************/
-ALTER TABLE repute ADD CONSTRAINT fk_repute_question
- FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_tag_auth_user ***************/
-ALTER TABLE tag ADD CONSTRAINT fk_tag_auth_user
- FOREIGN KEY (created_by_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_user_badge_auth_user ***************/
-ALTER TABLE user_badge ADD CONSTRAINT fk_user_badge_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_user_badge_badge ***************/
-ALTER TABLE user_badge ADD CONSTRAINT fk_user_badge_badge
- FOREIGN KEY (badge_id) REFERENCES badge (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_user_favorite_questions_auth_user ***************/
-ALTER TABLE user_favorite_questions ADD CONSTRAINT fk_user_favorite_questions_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_user_favorite_questions_question ***************/
-ALTER TABLE user_favorite_questions ADD CONSTRAINT fk_user_favorite_questions_question
- FOREIGN KEY (question_id) REFERENCES question (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_vote_auth_user ***************/
-ALTER TABLE vote ADD CONSTRAINT fk_vote_auth_user
- FOREIGN KEY (user_id) REFERENCES auth_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION;
-
-/************ Foreign Key: fk_vote_django_content_type ***************/
-ALTER TABLE vote ADD CONSTRAINT fk_vote_django_content_type
- FOREIGN KEY (content_type_id) REFERENCES django_content_type (id) ON UPDATE NO ACTION ON DELETE NO ACTION; \ No newline at end of file
diff --git a/askbot/sql_scripts/drop-all-tables.sh b/askbot/sql_scripts/drop-all-tables.sh
deleted file mode 100644
index 1e55cb1f..00000000
--- a/askbot/sql_scripts/drop-all-tables.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-mysql_username=''
-mysql_database=''
-mysqldump -u $mysql_username -p --add-drop-table --no-data $mysql_database | grep ^DROP
-#| mysql -u[USERNAME] -p[PASSWORD] [DATABASE]
diff --git a/askbot/sql_scripts/drop-auth.sql b/askbot/sql_scripts/drop-auth.sql
deleted file mode 100644
index bc17dce3..00000000
--- a/askbot/sql_scripts/drop-auth.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-drop table auth_group;
-drop table auth_group_permissions;
-drop table auth_message;
-drop table auth_permission;
-drop table auth_user;
-drop table auth_user_groups;
-drop table auth_user_user_permissions;
-
diff --git a/askbot/sql_scripts/pg_fts_install.sql b/askbot/sql_scripts/pg_fts_install.sql
deleted file mode 100644
index d0655134..00000000
--- a/askbot/sql_scripts/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 blog_entry_tsv ON blog_entry USING gin(body_tsv);
-
-UPDATE question SET title = title;
diff --git a/askbot/sql_scripts/update_2009_01_13_001.sql b/askbot/sql_scripts/update_2009_01_13_001.sql
deleted file mode 100644
index 165d1125..00000000
--- a/askbot/sql_scripts/update_2009_01_13_001.sql
+++ /dev/null
@@ -1,62 +0,0 @@
--- phpMyAdmin SQL Dump
--- version 3.0.0-beta
--- http://www.phpmyadmin.net
---
--- Host: localhost
--- Generation Time: Jan 12, 2009 at 08:55 PM
--- Server version: 5.0.67
--- PHP Version: 5.2.6
-
-SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
-
-
-/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
-/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!40101 SET NAMES utf8 */;
-
---
--- Database: `twogeekt_lanai`
---
-
---
--- Dumping data for table `badge`
---
-
-INSERT INTO `badge` (`id`, `name`, `type`, `slug`, `description`, `multiple`, `awarded_count`) VALUES
-(1, '炼狱法师', 3, '炼狱法师', '删除自己有3个以上赞成票的帖子', 1, 0),
-(2, '压力白领', 3, '压力白领', '删除自己有3个以上反对票的帖子', 1, 0),
-(3, '优秀回答', 3, '优秀回答', '回答好评10次以上', 1, 0),
-(4, '优秀问题', 3, '优秀问题', '问题好评10次以上', 1, 0),
-(5, '评论家', 3, '评论家', '评论10次以上', 1, 0),
-(6, '流行问题', 3, '流行问题', '问题的浏览量超过1000人次', 1, 0),
-(7, '巡逻兵', 3, '巡逻兵', '第一次标记垃圾帖子', 1, 0),
-(8, '清洁工', 3, '清洁工', '第一次撤销投票', 1, 0),
-(9, '批评家', 3, '批评家', '第一次反对票', 1, 0),
-(10, '小编', 3, '小编', '第一次编辑更新', 1, 0),
-(11, '村长', 3, '村长', '第一次重新标签', 1, 0),
-(12, '学者', 3, '学者', '第一次标记答案', 1, 0),
-(13, '学生', 3, '学生', '第一次提问并且有一次以上赞成票', 1, 0),
-(14, '支持者', 3, '支持者', '第一次赞成票', 1, 0),
-(15, '教师', 3, '教师', '第一次回答问题并且得到一个以上赞成票', 1, 0),
-(16, '自传作者', 3, '自传作者', '完整填写用户资料所有选项', 1, 0),
-(17, '自学成才', 3, '自学成才', '回答自己的问题并且有3个以上赞成票', 1, 0),
-(18, '最有价值回答', 1, '最有价值回答', '回答超过100次赞成票', 1, 0),
-(19, '最有价值问题', 1, '最有价值问题', '问题超过100次赞成票', 1, 0),
-(20, '万人迷', 1, '万人迷', '问题被100人以上收藏', 1, 0),
-(21, '著名问题', 1, '著名问题', '问题的浏览量超过10000人次', 1, 0),
-(22, 'alpha用户', 2, 'alpha用户', '内测期间的活跃用户', 1, 0),
-(23, '极好回答', 2, '极好回答', '回答超过25次赞成票', 1, 0),
-(24, '极好问题', 2, '极好问题', '问题超过25次赞成票', 1, 0),
-(25, '受欢迎问题', 2, '受欢迎问题', '问题被25人以上收藏', 1, 0),
-(26, '优秀市民', 2, '优秀市民', '投票300次以上', 1, 0),
-(27, '编辑主任', 2, '编辑主任', '编辑了100个帖子', 1, 0),
-(28, '通才', 2, '通才', '在多个标签领域活跃', 1, 0),
-(29, '专家', 2, '专家', '在一个标签领域活跃出众', 1, 0),
-(30, '老鸟', 2, '老鸟', '活跃超过一年的用户', 1, 0),
-(31, '最受关注问题', 2, '最受关注问题', '问题的浏览量超过2500人次', 1, 0),
-(32, '学问家', 2, '学问家', '第一次回答被投赞成票10次以上', 1, 0),
-(33, 'beta用户', 2, 'beta用户', 'beta期间活跃参与', 1, 0),
-(34, '导师', 2, '导师', '被指定为最佳答案并且赞成票40以上', 1, 0),
-(35, '巫师', 2, '巫师', '在提问60天之后回答并且赞成票5次以上', 1, 0),
-(36, '分类专家', 2, '分类专家', '创建的标签被50个以上问题使用', 1, 0);
diff --git a/askbot/sql_scripts/update_2009_01_13_002.sql b/askbot/sql_scripts/update_2009_01_13_002.sql
deleted file mode 100644
index c223cb8c..00000000
--- a/askbot/sql_scripts/update_2009_01_13_002.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE activity ADD COLUMN is_auditted tinyint(1) DEFAULT 0 \ No newline at end of file
diff --git a/askbot/sql_scripts/update_2009_01_18_001.sql b/askbot/sql_scripts/update_2009_01_18_001.sql
deleted file mode 100644
index 6f29fa32..00000000
--- a/askbot/sql_scripts/update_2009_01_18_001.sql
+++ /dev/null
@@ -1,62 +0,0 @@
--- phpMyAdmin SQL Dump
--- version 3.0.0-beta
--- http://www.phpmyadmin.net
---
--- Host: localhost
--- Generation Time: Jan 12, 2009 at 08:55 PM
--- Server version: 5.0.67
--- PHP Version: 5.2.6
-
-SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
-
-
-/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
-/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!40101 SET NAMES utf8 */;
-
---
--- Database: `twogeekt_lanai`
---
-
---
--- Dumping data for table `badge`
---
-
-INSERT INTO `badge` (`id`, `name`, `type`, `slug`, `description`, `multiple`, `awarded_count`) VALUES
-(1, '炼狱法师', 3, '炼狱法师', '删除自己有3个以上赞成票的帖子', 1, 0),
-(2, '压力白领', 3, '压力白领', '删除自己有3个以上反对票的帖子', 1, 0),
-(3, '优秀回答', 3, '优秀回答', '回答好评10次以上', 1, 0),
-(4, '优秀问题', 3, '优秀问题', '问题好评10次以上', 1, 0),
-(5, '评论家', 3, '评论家', '评论10次以上', 0, 0),
-(6, '流行问题', 3, '流行问题', '问题的浏览量超过1000人次', 1, 0),
-(7, '巡逻兵', 3, '巡逻兵', '第一次标记垃圾帖子', 0, 0),
-(8, '清洁工', 3, '清洁工', '第一次撤销投票', 0, 0),
-(9, '批评家', 3, '批评家', '第一次反对票', 0, 0),
-(10, '小编', 3, '小编', '第一次编辑更新', 0, 0),
-(11, '村长', 3, '村长', '第一次重新标签', 0, 0),
-(12, '学者', 3, '学者', '第一次标记答案', 0, 0),
-(13, '学生', 3, '学生', '第一次提问并且有一次以上赞成票', 0, 0),
-(14, '支持者', 3, '支持者', '第一次赞成票', 0, 0),
-(15, '教师', 3, '教师', '第一次回答问题并且得到一个以上赞成票', 0, 0),
-(16, '自传作者', 3, '自传作者', '完整填写用户资料所有选项', 0, 0),
-(17, '自学成才', 3, '自学成才', '回答自己的问题并且有3个以上赞成票', 1, 0),
-(18, '最有价值回答', 1, '最有价值回答', '回答超过100次赞成票', 1, 0),
-(19, '最有价值问题', 1, '最有价值问题', '问题超过100次赞成票', 1, 0),
-(20, '万人迷', 1, '万人迷', '问题被100人以上收藏', 1, 0),
-(21, '著名问题', 1, '著名问题', '问题的浏览量超过10000人次', 1, 0),
-(22, 'alpha用户', 2, 'alpha用户', '内测期间的活跃用户', 0, 0),
-(23, '极好回答', 2, '极好回答', '回答超过25次赞成票', 1, 0),
-(24, '极好问题', 2, '极好问题', '问题超过25次赞成票', 1, 0),
-(25, '受欢迎问题', 2, '受欢迎问题', '问题被25人以上收藏', 1, 0),
-(26, '优秀市民', 2, '优秀市民', '投票300次以上', 0, 0),
-(27, '编辑主任', 2, '编辑主任', '编辑了100个帖子', 0, 0),
-(28, '通才', 2, '通才', '在多个标签领域活跃', 0, 0),
-(29, '专家', 2, '专家', '在一个标签领域活跃出众', 0, 0),
-(30, '老鸟', 2, '老鸟', '活跃超过一年的用户', 0, 0),
-(31, '最受关注问题', 2, '最受关注问题', '问题的浏览量超过2500人次', 1, 0),
-(32, '学问家', 2, '学问家', '第一次回答被投赞成票10次以上', 0, 0),
-(33, 'beta用户', 2, 'beta用户', 'beta期间活跃参与', 0, 0),
-(34, '导师', 2, '导师', '被指定为最佳答案并且赞成票40以上', 1, 0),
-(35, '巫师', 2, '巫师', '在提问60天之后回答并且赞成票5次以上', 1, 0),
-(36, '分类专家', 2, '分类专家', '创建的标签被50个以上问题使用', 1, 0);
diff --git a/askbot/sql_scripts/update_2009_01_24.sql b/askbot/sql_scripts/update_2009_01_24.sql
deleted file mode 100644
index 45b83935..00000000
--- a/askbot/sql_scripts/update_2009_01_24.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TABLE award ADD COLUMN `content_type_id` int(11);
-ALTER TABLE award ADD COLUMN `object_id` int(10); \ No newline at end of file
diff --git a/askbot/sql_scripts/update_2009_01_25_001.sql b/askbot/sql_scripts/update_2009_01_25_001.sql
deleted file mode 100644
index 16c3487b..00000000
--- a/askbot/sql_scripts/update_2009_01_25_001.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TABLE `award` ADD `content_type_id` INT NULL
-ALTER TABLE `award` ADD `object_id` INT NULL
diff --git a/askbot/sql_scripts/update_2009_02_26_001.sql b/askbot/sql_scripts/update_2009_02_26_001.sql
deleted file mode 100644
index a6af5931..00000000
--- a/askbot/sql_scripts/update_2009_02_26_001.sql
+++ /dev/null
@@ -1,19 +0,0 @@
-ALTER TABLE answer ADD COLUMN `accepted_at` datetime default null;
-
-/* Update accepted_at column with answer added datetime for existing data */
-UPDATE answer
-SET accepted_at = added_at
-WHERE accepted = 1 AND accepted_at IS NULL;
-
-/* workround for c# url problem on bluehost server */
-UPDATE tag
-SET name = 'csharp'
-WHERE name = 'c#'
-
-UPDATE question
-SET tagnames = replace(tagnames, 'c#', 'csharp')
-WHERE tagnames like '%c#%'
-
-UPDATE question_revision
-SET tagnames = replace(tagnames, 'c#', 'csharp')
-WHERE tagnames like '%c#%'
diff --git a/askbot/sql_scripts/update_2009_04_10_001.sql b/askbot/sql_scripts/update_2009_04_10_001.sql
deleted file mode 100644
index 8148632a..00000000
--- a/askbot/sql_scripts/update_2009_04_10_001.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-ALTER TABLE Tag ADD COLUMN deleted_at datetime default null;
-ALTER TABLE Tag ADD COLUMN deleted_by_id INTEGER NULL;
-ALTER TABLE Tag ADD COLUMN deleted TINYINT NOT NULL;
diff --git a/askbot/sql_scripts/update_2009_07_05_EF.sql b/askbot/sql_scripts/update_2009_07_05_EF.sql
deleted file mode 100644
index 43c7c2f0..00000000
--- a/askbot/sql_scripts/update_2009_07_05_EF.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-ALTER TABLE auth_user ADD COLUMN email_isvalid TINYINT(1) NOT NULL;
-UPDATE auth_user SET email_isvalid=1;
-ALTER TABLE auth_user ADD COLUMN email_key varchar(32);
diff --git a/askbot/sql_scripts/update_2009_12_24_001.sql b/askbot/sql_scripts/update_2009_12_24_001.sql
deleted file mode 100644
index 3d082c2f..00000000
--- a/askbot/sql_scripts/update_2009_12_24_001.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-alter table question add column `vote_up_count` int(11) NOT NULL;
-alter table question add column `vote_down_count` int(11) NOT NULL;
-
-alter table answer add column `vote_up_count` int(11) NOT NULL;
-alter table answer add column `vote_down_count` int(11) NOT NULL; \ No newline at end of file
diff --git a/askbot/sql_scripts/update_2009_12_27_001.sql b/askbot/sql_scripts/update_2009_12_27_001.sql
deleted file mode 100644
index e2da7d4d..00000000
--- a/askbot/sql_scripts/update_2009_12_27_001.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-ALTER TABLE comment DROP INDEX content_type_id;
-
-ALTER TABLE comment ADD INDEX `content_type_id` (`content_type_id`,`object_id`,`user_id`); \ No newline at end of file
diff --git a/askbot/sql_scripts/update_2009_12_27_002.sql b/askbot/sql_scripts/update_2009_12_27_002.sql
deleted file mode 100644
index a36470bf..00000000
--- a/askbot/sql_scripts/update_2009_12_27_002.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE `vote` ADD `voted_at` DATETIME NOT NULL \ No newline at end of file
diff --git a/askbot/sql_scripts/update_2010_02_22.sql b/askbot/sql_scripts/update_2010_02_22.sql
deleted file mode 100644
index 2778885a..00000000
--- a/askbot/sql_scripts/update_2010_02_22.sql
+++ /dev/null
@@ -1 +0,0 @@
-alter table answer add column deleted_at datetime;
diff --git a/askbot/startup_procedures.py b/askbot/startup_procedures.py
index 0857da38..dffca0f1 100644
--- a/askbot/startup_procedures.py
+++ b/askbot/startup_procedures.py
@@ -3,6 +3,8 @@ in the beginning of models/__init__.py
the purpose of this module is to validate deployment of askbot
+question: why not run these from askbot/__init__.py?
+
the main function is run_startup_tests
"""
from django.db import transaction
@@ -13,13 +15,11 @@ from askbot.models import badges
#todo:
#
# *validate emails in settings.py
-
-def run_startup_tests():
- """function that runs
- all startup tests, mainly checking settings config so far
+def test_askbot_url():
+ """Tests the ASKBOT_URL setting for the
+ well-formedness and raises the ImproperlyConfigured
+ exception, if the setting is not good.
"""
-
- #todo: refactor this when another test arrives
url = settings.ASKBOT_URL
if url != '':
@@ -48,6 +48,48 @@ def run_startup_tests():
msg = 'if ASKBOT_URL setting is not empty, ' + \
'it must not start with /'
+def test_middleware():
+ """Checks that all required middleware classes are
+ installed in the django settings.py file. If that is not the
+ case - raises an ImproperlyConfigured exception.
+ """
+ required_middleware = (
+ 'askbot.middleware.anon_user.ConnectToSessionMessagesMiddleware',
+ 'askbot.middleware.pagesize.QuestionsPageSizeMiddleware',
+ 'askbot.middleware.cancel.CancelActionMiddleware',
+ 'askbot.deps.recaptcha_django.middleware.ReCaptchaMiddleware',
+ 'django.middleware.transaction.TransactionMiddleware',
+ 'askbot.middleware.view_log.ViewLogMiddleware',
+ )
+ #'debug_toolbar.middleware.DebugToolbarMiddleware',
+ missing_middleware = list()
+ for middleware in required_middleware:
+ if middleware not in settings.MIDDLEWARE_CLASSES:
+ missing_middleware.append(middleware)
+
+ debug_toolbar_middleware = 'debug_toolbar.middleware.DebugToolbarMiddleware'
+ if 'debug_toolbar' in settings.INSTALLED_APPS:
+ if debug_toolbar_middleware not in settings.MIDDLEWARE_CLASSES:
+ missing_middleware.append(debug_toolbar_middleware)
+
+ if missing_middleware:
+ error_message = """Please add the following middleware (listed
+after this message) to the MIDDLEWARE_CLASSES variable in your site settings.py file.
+The order the middleware records may be important, please take a look at the example in
+https://github.com/ASKBOT/askbot-devel/blob/master/askbot/setup_templates/settings.py\n\n%s""" \
+ % ', '.join(missing_middleware)
+ raise ImproperlyConfigured(error_message)
+
+
+def run_startup_tests():
+ """function that runs
+ all startup tests, mainly checking settings config so far
+ """
+
+ #todo: refactor this when another test arrives
+ test_askbot_url()
+ test_middleware()
+
@transaction.commit_manually
def run():
"""runs all the startup procedures"""
diff --git a/askbot/tasks.py b/askbot/tasks.py
new file mode 100644
index 00000000..8dfea5b4
--- /dev/null
+++ b/askbot/tasks.py
@@ -0,0 +1,118 @@
+"""Definitions of Celery tasks in Askbot
+in this module there are two types of functions:
+
+* those wrapped with a @task decorator and a ``_celery_task`` suffix - celery tasks
+* those with the same base name, but without the decorator and the name suffix
+ the actual work units run by the task
+
+Celery tasks are special functions in a way that they require all the parameters
+be serializable - so instead of ORM objects we pass object id's and
+instead of query sets - lists of ORM object id's.
+
+That is the reason for having two types of methods here:
+
+* the base methods (those without the decorator and the
+ ``_celery_task`` in the end of the name
+ are work units that are called from the celery tasks.
+* celery tasks - shells that reconstitute the necessary ORM
+ objects and call the base methods
+"""
+from django.contrib.contenttypes.models import ContentType
+from celery.decorators import task
+from askbot.models import Activity
+from askbot.models import User
+from askbot.models import send_instant_notifications_about_activity_in_post
+
+@task(ignore_results = True)
+def record_post_update_celery_task(
+ post_id,
+ post_content_type_id,
+ newly_mentioned_user_id_list = None,
+ updated_by_id = None,
+ timestamp = None,
+ created = False,
+ ):
+ #reconstitute objects from the database
+ updated_by = User.objects.get(id = updated_by_id)
+ post_content_type = ContentType.objects.get(id = post_content_type_id)
+ post = post_content_type.get_object_for_this_type(id = post_id)
+ newly_mentioned_users = User.objects.filter(
+ id__in = newly_mentioned_user_id_list
+ )
+
+
+ record_post_update(
+ post = post,
+ updated_by = updated_by,
+ newly_mentioned_users = newly_mentioned_users,
+ timestamp = timestamp,
+ created = created,
+ )
+
+def record_post_update(
+ post = None,
+ updated_by = None,
+ newly_mentioned_users = None,
+ timestamp = None,
+ created = False
+ ):
+ """Called when a post is updated. Arguments:
+
+ * ``newly_mentioned_users`` - users who are mentioned in the
+ post for the first time
+ * ``created`` - a boolean. True when ``post`` has just been created
+ * remaining arguments are self - explanatory
+
+ The method does two things:
+
+ * records "red envelope" recipients of the post
+ * sends email alerts to all subscribers to the post
+ """
+
+ #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,
+ question = post.get_origin_post()
+ )
+ 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
+ recipients = post.get_response_receivers(
+ exclude_list = [updated_by, ]
+ )
+
+ update_activity.add_recipients(recipients)
+
+ assert(updated_by not in recipients)
+
+ for user in set(recipients) | set(newly_mentioned_users):
+ user.increment_response_count()
+ user.save()
+
+ #todo: weird thing is that only comments need the recipients
+ #todo: debug these calls and then uncomment in the repo
+ #argument to this call
+ notification_subscribers = post.get_instant_notification_subscribers(
+ potential_subscribers = recipients,
+ mentioned_users = newly_mentioned_users,
+ exclude_list = [updated_by, ]
+ )
+ #todo: fix this temporary spam protection plug
+ if created:
+ if not (updated_by.is_administrator() or updated_by.is_moderator()):
+ if updated_by.reputation < 15:
+ notification_subscribers = \
+ [u for u in notification_subscribers if u.is_administrator()]
+ send_instant_notifications_about_activity_in_post(
+ update_activity = update_activity,
+ post = post,
+ recipients = notification_subscribers,
+ )
diff --git a/askbot/templatetags/extra_filters.py b/askbot/templatetags/extra_filters.py
index c3fde996..27ba5fd2 100644
--- a/askbot/templatetags/extra_filters.py
+++ b/askbot/templatetags/extra_filters.py
@@ -1,16 +1,9 @@
-import logging
from django import template
from django.core import exceptions as django_exceptions
from django.utils.translation import ugettext as _
-from django.contrib.humanize.templatetags import humanize
-from django.template import defaultfilters
from askbot import exceptions as askbot_exceptions
from askbot import auth
-from askbot import models
-from askbot.deps.grapefruit import Color
from askbot.conf import settings as askbot_settings
-from askbot.skins import utils as skin_utils
-from askbot.utils import functions
from askbot.utils.slug import slugify
register = template.Library()
@@ -136,22 +129,6 @@ def can_see_offensive_flags(user, post):
return False
@register.filter
-def can_view_user_edit(request_user, target_user):
- return auth.can_view_user_edit(request_user, target_user)
-
-@register.filter
-def can_view_user_votes(request_user, target_user):
- return auth.can_view_user_votes(request_user, target_user)
-
-@register.filter
-def can_view_user_preferences(request_user, target_user):
- return auth.can_view_user_preferences(request_user, target_user)
-
-@register.filter
-def is_user_self(request_user, target_user):
- return auth.is_user_self(request_user, target_user)
-
-@register.filter
def cnprog_intword(number):
try:
if 1000 <= number < 10000:
diff --git a/askbot/templatetags/extra_filters_jinja.py b/askbot/templatetags/extra_filters_jinja.py
index 71965517..8e394345 100644
--- a/askbot/templatetags/extra_filters_jinja.py
+++ b/askbot/templatetags/extra_filters_jinja.py
@@ -1,4 +1,3 @@
-import logging
import datetime
import time
from coffin import template as coffin_template
@@ -8,16 +7,26 @@ from django.contrib.humanize.templatetags import humanize
from django.template import defaultfilters
from askbot import exceptions as askbot_exceptions
from askbot import auth
-from askbot import models
-from askbot.deps.grapefruit import Color
from askbot.conf import settings as askbot_settings
from askbot.skins import utils as skin_utils
from askbot.utils import functions
from askbot.utils.slug import slugify
+from django_countries import countries
+from django_countries import settings as countries_settings
+
register = coffin_template.Library()
@register.filter
+def country_display_name(country_code):
+ country_dict = dict(countries.COUNTRIES)
+ return country_dict[country_code]
+
+@register.filter
+def country_flag_url(country_code):
+ return countries_settings.FLAG_URL % country_code
+
+@register.filter
def collapse(input):
input = str(input)
return ' '.join(input.split())
@@ -202,22 +211,6 @@ def can_see_offensive_flags(user, post):
return False
@register.filter
-def can_view_user_edit(request_user, target_user):
- return auth.can_view_user_edit(request_user, target_user)
-
-@register.filter
-def can_view_user_votes(request_user, target_user):
- return auth.can_view_user_votes(request_user, target_user)
-
-@register.filter
-def can_view_user_preferences(request_user, target_user):
- return auth.can_view_user_preferences(request_user, target_user)
-
-@register.filter
-def is_user_self(request_user, target_user):
- return auth.is_user_self(request_user, target_user)
-
-@register.filter
def cnprog_intword(number):
try:
if 1000 <= number < 10000:
diff --git a/askbot/templatetags/extra_tags.py b/askbot/templatetags/extra_tags.py
index 1a637bd2..9d21ca83 100644
--- a/askbot/templatetags/extra_tags.py
+++ b/askbot/templatetags/extra_tags.py
@@ -1,12 +1,11 @@
import math
from django import template
from django.utils.safestring import mark_safe
-#from askbot.const import *
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
from askbot.utils import functions
from askbot.utils.slug import slugify
-from askbot.skins.loaders import ENV
+from askbot.skins.loaders import get_template
register = template.Library()
@@ -118,10 +117,12 @@ def cnprog_paginator(context):
class IncludeJinja(template.Node):
"""http://www.mellowmorning.com/2010/08/24/"""
- def __init__(self, filename):
+ def __init__(self, filename, request_var):
self.filename = filename
+ self.request_var = template.Variable(request_var)
def render(self, context):
- jinja_template = ENV.get_template(self.filename)
+ request = self.request_var.resolve(context)
+ jinja_template = get_template(self.filename, request)
return jinja_template.render(context)
@register.tag
@@ -129,11 +130,12 @@ def include_jinja(parser, token):
bits = token.contents.split()
#Check if a filename was given
- if len(bits) != 2:
+ if len(bits) != 3:
error_message = '%r tag requires the name of the ' + \
- 'template to be included included'
+ 'template and the request variable'
raise template.TemplateSyntaxError(error_message % bits[0])
filename = bits[1]
+ request_var = bits[2]
#Remove quotes or raise error
if filename[0] in ('"', "'") and filename[-1] == filename[0]:
@@ -141,4 +143,4 @@ def include_jinja(parser, token):
else:
raise template.TemplateSyntaxError('file name must be quoted')
- return IncludeJinja(filename)
+ return IncludeJinja(filename, request_var)
diff --git a/askbot/templatetags/smart_if.py b/askbot/templatetags/smart_if.py
deleted file mode 100644
index ca3b43fe..00000000
--- a/askbot/templatetags/smart_if.py
+++ /dev/null
@@ -1,401 +0,0 @@
-"""
-A smarter {% if %} tag for django templates.
-
-While retaining current Django functionality, it also handles equality,
-greater than and less than operators. Some common case examples::
-
- {% if articles|length >= 5 %}...{% endif %}
- {% if "ifnotequal tag" != "beautiful" %}...{% endif %}
-"""
-import unittest
-from django import template
-
-
-register = template.Library()
-
-
-#==============================================================================
-# Calculation objects
-#==============================================================================
-
-class BaseCalc(object):
- def __init__(self, var1, var2=None, negate=False):
- self.var1 = var1
- self.var2 = var2
- self.negate = negate
-
- def resolve(self, context):
- try:
- var1, var2 = self.resolve_vars(context)
- outcome = self.calculate(var1, var2)
- except:
- outcome = False
- if self.negate:
- return not outcome
- return outcome
-
- def resolve_vars(self, context):
- var2 = self.var2 and self.var2.resolve(context)
- return self.var1.resolve(context), var2
-
- def calculate(self, var1, var2):
- raise NotImplementedError()
-
-
-class Or(BaseCalc):
- def calculate(self, var1, var2):
- return var1 or var2
-
-
-class And(BaseCalc):
- def calculate(self, var1, var2):
- return var1 and var2
-
-
-class Equals(BaseCalc):
- def calculate(self, var1, var2):
- return var1 == var2
-
-
-class Greater(BaseCalc):
- def calculate(self, var1, var2):
- return var1 > var2
-
-
-class GreaterOrEqual(BaseCalc):
- def calculate(self, var1, var2):
- return var1 >= var2
-
-
-class In(BaseCalc):
- def calculate(self, var1, var2):
- return var1 in var2
-
-
-#==============================================================================
-# Tests
-#==============================================================================
-
-class TestVar(object):
- """
- A basic self-resolvable object similar to a Django template variable. Used
- to assist with tests.
- """
- def __init__(self, value):
- self.value = value
-
- def resolve(self, context):
- return self.value
-
-
-class SmartIfTests(unittest.TestCase):
- def setUp(self):
- self.true = TestVar(True)
- self.false = TestVar(False)
- self.high = TestVar(9000)
- self.low = TestVar(1)
-
- def assertCalc(self, calc, context=None):
- """
- Test a calculation is True, also checking the inverse "negate" case.
- """
- context = context or {}
- self.assert_(calc.resolve(context))
- calc.negate = not calc.negate
- self.assertFalse(calc.resolve(context))
-
- def assertCalcFalse(self, calc, context=None):
- """
- Test a calculation is False, also checking the inverse "negate" case.
- """
- context = context or {}
- self.assertFalse(calc.resolve(context))
- calc.negate = not calc.negate
- self.assert_(calc.resolve(context))
-
- def test_or(self):
- self.assertCalc(Or(self.true))
- self.assertCalcFalse(Or(self.false))
- self.assertCalc(Or(self.true, self.true))
- self.assertCalc(Or(self.true, self.false))
- self.assertCalc(Or(self.false, self.true))
- self.assertCalcFalse(Or(self.false, self.false))
-
- def test_and(self):
- self.assertCalc(And(self.true, self.true))
- self.assertCalcFalse(And(self.true, self.false))
- self.assertCalcFalse(And(self.false, self.true))
- self.assertCalcFalse(And(self.false, self.false))
-
- def test_equals(self):
- self.assertCalc(Equals(self.low, self.low))
- self.assertCalcFalse(Equals(self.low, self.high))
-
- def test_greater(self):
- self.assertCalc(Greater(self.high, self.low))
- self.assertCalcFalse(Greater(self.low, self.low))
- self.assertCalcFalse(Greater(self.low, self.high))
-
- def test_greater_or_equal(self):
- self.assertCalc(GreaterOrEqual(self.high, self.low))
- self.assertCalc(GreaterOrEqual(self.low, self.low))
- self.assertCalcFalse(GreaterOrEqual(self.low, self.high))
-
- def test_in(self):
- list_ = TestVar([1,2,3])
- invalid_list = TestVar(None)
- self.assertCalc(In(self.low, list_))
- self.assertCalcFalse(In(self.low, invalid_list))
-
- def test_parse_bits(self):
- var = IfParser([True]).parse()
- self.assert_(var.resolve({}))
- var = IfParser([False]).parse()
- self.assertFalse(var.resolve({}))
-
- var = IfParser([False, 'or', True]).parse()
- self.assert_(var.resolve({}))
-
- var = IfParser([False, 'and', True]).parse()
- self.assertFalse(var.resolve({}))
-
- var = IfParser(['not', False, 'and', 'not', False]).parse()
- self.assert_(var.resolve({}))
-
- var = IfParser(['not', 'not', True]).parse()
- self.assert_(var.resolve({}))
-
- var = IfParser([1, '=', 1]).parse()
- self.assert_(var.resolve({}))
-
- var = IfParser([1, 'not', '=', 1]).parse()
- self.assertFalse(var.resolve({}))
-
- var = IfParser([1, 'not', 'not', '=', 1]).parse()
- self.assert_(var.resolve({}))
-
- var = IfParser([1, '!=', 1]).parse()
- self.assertFalse(var.resolve({}))
-
- var = IfParser([3, '>', 2]).parse()
- self.assert_(var.resolve({}))
-
- var = IfParser([1, '<', 2]).parse()
- self.assert_(var.resolve({}))
-
- var = IfParser([2, 'not', 'in', [2, 3]]).parse()
- self.assertFalse(var.resolve({}))
-
- var = IfParser([1, 'or', 1, '=', 2]).parse()
- self.assert_(var.resolve({}))
-
- def test_boolean(self):
- var = IfParser([True, 'and', True, 'and', True]).parse()
- self.assert_(var.resolve({}))
- var = IfParser([False, 'or', False, 'or', True]).parse()
- self.assert_(var.resolve({}))
- var = IfParser([True, 'and', False, 'or', True]).parse()
- self.assert_(var.resolve({}))
- var = IfParser([False, 'or', True, 'and', True]).parse()
- self.assert_(var.resolve({}))
-
- var = IfParser([True, 'and', True, 'and', False]).parse()
- self.assertFalse(var.resolve({}))
- var = IfParser([False, 'or', False, 'or', False]).parse()
- self.assertFalse(var.resolve({}))
- var = IfParser([False, 'or', True, 'and', False]).parse()
- self.assertFalse(var.resolve({}))
- var = IfParser([False, 'and', True, 'or', False]).parse()
- self.assertFalse(var.resolve({}))
-
- def test_invalid(self):
- self.assertRaises(ValueError, IfParser(['not']).parse)
- self.assertRaises(ValueError, IfParser(['==']).parse)
- self.assertRaises(ValueError, IfParser([1, 'in']).parse)
- self.assertRaises(ValueError, IfParser([1, '>', 'in']).parse)
- self.assertRaises(ValueError, IfParser([1, '==', 'not', 'not']).parse)
- self.assertRaises(ValueError, IfParser([1, 2]).parse)
-
-
-OPERATORS = {
- '=': (Equals, True),
- '==': (Equals, True),
- '!=': (Equals, False),
- '>': (Greater, True),
- '>=': (GreaterOrEqual, True),
- '<=': (Greater, False),
- '<': (GreaterOrEqual, False),
- 'or': (Or, True),
- 'and': (And, True),
- 'in': (In, True),
-}
-BOOL_OPERATORS = ('or', 'and')
-
-
-class IfParser(object):
- error_class = ValueError
-
- def __init__(self, tokens):
- self.tokens = tokens
-
- def _get_tokens(self):
- return self._tokens
-
- def _set_tokens(self, tokens):
- self._tokens = tokens
- self.len = len(tokens)
- self.pos = 0
-
- tokens = property(_get_tokens, _set_tokens)
-
- def parse(self):
- if self.at_end():
- raise self.error_class('No variables provided.')
- var1 = self.get_bool_var()
- while not self.at_end():
- op, negate = self.get_operator()
- var2 = self.get_bool_var()
- var1 = op(var1, var2, negate=negate)
- return var1
-
- def get_token(self, eof_message=None, lookahead=False):
- negate = True
- token = None
- pos = self.pos
- while token is None or token == 'not':
- if pos >= self.len:
- if eof_message is None:
- raise self.error_class()
- raise self.error_class(eof_message)
- token = self.tokens[pos]
- negate = not negate
- pos += 1
- if not lookahead:
- self.pos = pos
- return token, negate
-
- def at_end(self):
- return self.pos >= self.len
-
- def create_var(self, value):
- return TestVar(value)
-
- def get_bool_var(self):
- """
- Returns either a variable by itself or a non-boolean operation (such as
- ``x == 0`` or ``x < 0``).
-
- This is needed to keep correct precedence for boolean operations (i.e.
- ``x or x == 0`` should be ``x or (x == 0)``, not ``(x or x) == 0``).
- """
- var = self.get_var()
- if not self.at_end():
- op_token = self.get_token(lookahead=True)[0]
- if isinstance(op_token, basestring) and (op_token not in
- BOOL_OPERATORS):
- op, negate = self.get_operator()
- return op(var, self.get_var(), negate=negate)
- return var
-
- def get_var(self):
- token, negate = self.get_token('Reached end of statement, still '
- 'expecting a variable.')
- if isinstance(token, basestring) and token in OPERATORS:
- raise self.error_class('Expected variable, got operator (%s).' %
- token)
- var = self.create_var(token)
- if negate:
- return Or(var, negate=True)
- return var
-
- def get_operator(self):
- token, negate = self.get_token('Reached end of statement, still '
- 'expecting an operator.')
- if not isinstance(token, basestring) or token not in OPERATORS:
- raise self.error_class('%s is not a valid operator.' % token)
- if self.at_end():
- raise self.error_class('No variable provided after "%s".' % token)
- op, true = OPERATORS[token]
- if not true:
- negate = not negate
- return op, negate
-
-
-#==============================================================================
-# Actual templatetag code.
-#==============================================================================
-
-class TemplateIfParser(IfParser):
- error_class = template.TemplateSyntaxError
-
- def __init__(self, parser, *args, **kwargs):
- self.template_parser = parser
- return super(TemplateIfParser, self).__init__(*args, **kwargs)
-
- def create_var(self, value):
- return self.template_parser.compile_filter(value)
-
-
-class SmartIfNode(template.Node):
- def __init__(self, var, nodelist_true, nodelist_false=None):
- self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
- self.var = var
-
- def render(self, context):
- if self.var.resolve(context):
- return self.nodelist_true.render(context)
- if self.nodelist_false:
- return self.nodelist_false.render(context)
- return ''
-
- def __repr__(self):
- return "<Smart If node>"
-
- def __iter__(self):
- for node in self.nodelist_true:
- yield node
- if self.nodelist_false:
- for node in self.nodelist_false:
- yield node
-
- def get_nodes_by_type(self, nodetype):
- nodes = []
- if isinstance(self, nodetype):
- nodes.append(self)
- nodes.extend(self.nodelist_true.get_nodes_by_type(nodetype))
- if self.nodelist_false:
- nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype))
- return nodes
-
-
-@register.tag('if')
-def smart_if(parser, token):
- """
- A smarter {% if %} tag for django templates.
-
- While retaining current Django functionality, it also handles equality,
- greater than and less than operators. Some common case examples::
-
- {% if articles|length >= 5 %}...{% endif %}
- {% if "ifnotequal tag" != "beautiful" %}...{% endif %}
-
- Arguments and operators _must_ have a space between them, so
- ``{% if 1>2 %}`` is not a valid smart if tag.
-
- All supported operators are: ``or``, ``and``, ``in``, ``=`` (or ``==``),
- ``!=``, ``>``, ``>=``, ``<`` and ``<=``.
- """
- bits = token.split_contents()[1:]
- var = TemplateIfParser(parser, bits).parse()
- nodelist_true = parser.parse(('else', 'endif'))
- token = parser.next_token()
- if token.contents == 'else':
- nodelist_false = parser.parse(('endif',))
- parser.delete_first_token()
- else:
- nodelist_false = None
- return SmartIfNode(var, nodelist_true, nodelist_false)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/askbot/tests/__init__.py b/askbot/tests/__init__.py
index 1b049df3..1cb8d37b 100644
--- a/askbot/tests/__init__.py
+++ b/askbot/tests/__init__.py
@@ -6,3 +6,5 @@ from askbot.tests.db_api_tests import *
from askbot.tests.skin_tests import *
from askbot.tests.badge_tests import *
from askbot.tests.management_command_tests import *
+from askbot.tests.search_state_tests import *
+from askbot.tests.form_tests import *
diff --git a/askbot/tests/badge_tests.py b/askbot/tests/badge_tests.py
index e8fe8bcc..fdb9d626 100644
--- a/askbot/tests/badge_tests.py
+++ b/askbot/tests/badge_tests.py
@@ -469,3 +469,36 @@ class BadgeTests(AskbotTestCase):
self.u3.toggle_favorite_question(question)
#dont reaward
self.assert_have_badge('stellar-question', self.u1, 1)
+
+ def test_commentator_badge(self):
+ question = self.post_question(user = self.u1)
+ min_comments = settings.COMMENTATOR_BADGE_MIN_COMMENTS
+ for i in xrange(min_comments - 1):
+ self.post_comment(user = self.u1, parent_post = question)
+
+ self.assert_have_badge('commentator', self.u1, 0)
+ self.post_comment(user = self.u1, parent_post = question)
+ self.assert_have_badge('commentator', self.u1, 1)
+ self.post_comment(user = self.u1, parent_post = question)
+ self.assert_have_badge('commentator', self.u1, 1)
+
+ def test_taxonomist_badge(self):
+ self.post_question(user = self.u1, tags = 'test')
+ min_use = settings.TAXONOMIST_BADGE_MIN_USE_COUNT
+ for i in xrange(min_use - 2):
+ self.post_question(user = self.u2, tags = 'test')
+ self.assert_have_badge('taxonomist', self.u1, 0)
+ self.post_question(user = self.u2, tags = 'test')
+ self.assert_have_badge('taxonomist', self.u1, 1)
+
+ def test_enthusiast_badge(self):
+ yesterday = datetime.datetime.now() - datetime.timedelta(1)
+ self.u1.last_seen = yesterday
+ prev_visit_count = settings.ENTHUSIAST_BADGE_MIN_DAYS - 1
+ self.u1.consecutive_days_visit_count = prev_visit_count
+ self.u1.save()
+ self.assert_have_badge('enthusiast', self.u1, 0)
+ self.client.login(method = 'force', user_id = self.u1.id)
+ self.client.get('/')
+ self.assert_have_badge('enthusiast', self.u1, 1)
+
diff --git a/askbot/tests/db_api_tests.py b/askbot/tests/db_api_tests.py
index c4c31fc4..66fb9f9d 100644
--- a/askbot/tests/db_api_tests.py
+++ b/askbot/tests/db_api_tests.py
@@ -5,6 +5,8 @@ e.g. ``some_user.do_something(...)``
"""
from askbot.tests.utils import AskbotTestCase
from askbot import models
+from askbot import const
+from askbot.conf import settings as askbot_settings
import datetime
class DBApiTests(AskbotTestCase):
@@ -53,6 +55,38 @@ class DBApiTests(AskbotTestCase):
1
)
+ def ask_anonymous_question(self):
+ q = self.user.post_question(
+ is_anonymous = True,
+ body_text = 'hahahah',
+ title = 'aouaouaosuoa',
+ tags = 'test'
+ )
+ return self.reload_object(q)
+
+ def test_post_anonymous_question(self):
+ q = self.ask_anonymous_question()
+ self.assertTrue(q.is_anonymous)
+ rev = q.revisions.all()[0]
+ self.assertTrue(rev.is_anonymous)
+
+ def test_reveal_asker_identity(self):
+ q = self.ask_anonymous_question()
+ self.other_user.set_status('m')
+ self.other_user.save()
+ self.other_user.edit_question(
+ question = q,
+ title = 'hahah',
+ body_text = 'hoeuaoea',
+ tags = 'aoeuaoeu',
+ revision_comment = 'hahahah'
+ )
+ q.remove_author_anonymity()
+ q = self.reload_object(q)
+ self.assertFalse(q.is_anonymous)
+ for rev in q.revisions.all():
+ self.assertFalse(rev.is_anonymous)
+
def test_accept_best_answer(self):
self.post_answer(user = self.other_user)
self.user.accept_best_answer(self.answer)
@@ -108,3 +142,198 @@ class DBApiTests(AskbotTestCase):
count = models.Tag.objects.filter(name='one-tag').count()
self.assertEquals(count, 0)
+
+class UserLikeTests(AskbotTestCase):
+ def setUp(self):
+ self.create_user()
+ self.question = self.post_question(tags = 'one two three')
+
+ def test_user_likes_question_via_tags(self):
+ truth_table = (
+ ('good', 'like', True),
+ ('good', 'dislike', False),
+ ('bad', 'like', False),
+ ('bad', 'dislike', True),
+ )
+ tag = models.Tag.objects.get(name = 'one')
+ for item in truth_table:
+ reason = item[0]
+ mt = models.MarkedTag(user = self.user, tag = tag, reason = reason)
+ mt.save()
+ self.assertEquals(
+ self.user.has_affinity_to_question(
+ question = self.question,
+ affinity_type = item[1]
+ ),
+ item[2]
+ )
+ mt.delete()
+
+ def test_user_does_not_care_about_question_no_wildcards(self):
+ askbot_settings.update('USE_WILDCARD_TAGS', False)
+ tag = models.Tag(name = 'five', created_by = self.user)
+ tag.save()
+ mt = models.MarkedTag(user = self.user, tag = tag, reason = 'good')
+ mt.save()
+ self.assertFalse(
+ self.user.has_affinity_to_question(
+ question = self.question,
+ affinity_type = 'like'
+ )
+ )
+
+
+ def setup_wildcard(self, wildcard = None, reason = None):
+ if reason == 'good':
+ self.user.interesting_tags = wildcard
+ self.user.ignored_tags = ''
+ else:
+ self.user.ignored_tags = wildcard
+ self.user.interesting_tags = ''
+ self.user.save()
+ askbot_settings.update('USE_WILDCARD_TAGS', True)
+
+ def assert_affinity_is(self, affinity_type, expectation):
+ self.assertEquals(
+ self.user.has_affinity_to_question(
+ question = self.question,
+ affinity_type = affinity_type
+ ),
+ expectation
+ )
+
+ def test_user_likes_question_via_wildcards(self):
+ self.setup_wildcard('on*', 'good')
+ self.assert_affinity_is('like', True)
+ self.assert_affinity_is('dislike', False)
+
+ self.setup_wildcard('aouaou* o* on* oeu*', 'good')
+ self.assert_affinity_is('like', True)
+ self.assert_affinity_is('dislike', False)
+
+ self.setup_wildcard('on*', 'bad')
+ self.assert_affinity_is('like', False)
+ self.assert_affinity_is('dislike', True)
+
+ self.setup_wildcard('aouaou* o* on* oeu*', 'bad')
+ self.assert_affinity_is('like', False)
+ self.assert_affinity_is('dislike', True)
+
+ self.setup_wildcard('one*', 'good')
+ self.assert_affinity_is('like', True)
+ self.assert_affinity_is('dislike', False)
+
+ self.setup_wildcard('oneone*', 'good')
+ self.assert_affinity_is('like', False)
+ self.assert_affinity_is('dislike', False)
+
+class GlobalTagSubscriberGetterTests(AskbotTestCase):
+ """tests for the :meth:`~askbot.models.Question.get_global_tag_based_subscribers`
+ """
+ def setUp(self):
+ """create two users"""
+ schedule = {'q_all': 'i'}
+ self.u1 = self.create_user(
+ username = 'user1',
+ notification_schedule = schedule
+ )
+ self.u2 = self.create_user(
+ username = 'user2',
+ notification_schedule = schedule
+ )
+ self.question = self.post_question(
+ user = self.u1,
+ tags = "good day"
+ )
+
+ def set_email_tag_filter_strategy(self, strategy):
+ self.u1.email_tag_filter_strategy = strategy
+ self.u1.save()
+ self.u2.email_tag_filter_strategy = strategy
+ self.u2.save()
+
+ def assert_subscribers_are(self, expected_subscribers = None, reason = None):
+ """a special assertion that compares the subscribers
+ on the question with the given set"""
+ subscriptions = models.EmailFeedSetting.objects.filter(
+ feed_type = 'q_all',
+ frequency = 'i'
+ )
+ actual_subscribers = self.question.get_global_tag_based_subscribers(
+ tag_mark_reason = reason,
+ subscription_records = subscriptions
+ )
+ self.assertEquals(actual_subscribers, expected_subscribers)
+
+ def test_nobody_likes_any_tags(self):
+ """no-one had marked tags, so the set
+ of subscribers must be empty
+ """
+ self.assert_subscribers_are(
+ expected_subscribers = set(),
+ reason = 'good'
+ )
+
+ def test_nobody_dislikes_any_tags(self):
+ """since nobody dislikes tags - therefore
+ the set must contain two users"""
+ self.assert_subscribers_are(
+ expected_subscribers = set([self.u1, self.u2]),
+ reason = 'bad'
+ )
+
+ def test_user_likes_tag(self):
+ """user set must contain one person who likes the tag"""
+ self.set_email_tag_filter_strategy(const.INCLUDE_INTERESTING)
+ self.u1.mark_tags(tagnames = ('day',), reason = 'good', action = 'add')
+ self.assert_subscribers_are(
+ expected_subscribers = set([self.u1,]),
+ reason = 'good'
+ )
+
+ def test_user_dislikes_tag(self):
+ """user set must have one user who does not dislike a tag"""
+ self.set_email_tag_filter_strategy(const.EXCLUDE_IGNORED)
+ self.u1.mark_tags(tagnames = ('day',), reason = 'bad', action = 'add')
+ self.assert_subscribers_are(
+ expected_subscribers = set([self.u2,]),
+ reason = 'bad'
+ )
+
+ def test_user_likes_wildcard(self):
+ """user set must contain one person who likes the tag via wildcard"""
+ self.set_email_tag_filter_strategy(const.INCLUDE_INTERESTING)
+ askbot_settings.update('USE_WILDCARD_TAGS', True)
+ self.u1.mark_tags(wildcards = ('da*',), reason = 'good', action = 'add')
+ self.u1.save()
+ self.assert_subscribers_are(
+ expected_subscribers = set([self.u1,]),
+ reason = 'good'
+ )
+
+ def test_user_dislikes_wildcard(self):
+ """user set must have one user who does not dislike the tag via wildcard"""
+ self.set_email_tag_filter_strategy(const.EXCLUDE_IGNORED)
+ askbot_settings.update('USE_WILDCARD_TAGS', True)
+ self.u1.mark_tags(wildcards = ('da*',), reason = 'bad', action = 'add')
+ self.u1.save()
+ self.assert_subscribers_are(
+ expected_subscribers = set([self.u2,]),
+ reason = 'bad'
+ )
+
+ def test_user_dislikes_wildcard_and_matching_tag(self):
+ """user ignores tag "day" and ignores a wildcard "da*"
+ """
+ self.set_email_tag_filter_strategy(const.EXCLUDE_IGNORED)
+ askbot_settings.update('USE_WILDCARD_TAGS', True)
+ self.u1.mark_tags(
+ tagnames = ('day',),
+ wildcards = ('da*',),
+ reason = 'bad',
+ action = 'add'
+ )
+ self.assert_subscribers_are(
+ expected_subscribers = set([self.u2,]),
+ reason = 'bad'
+ )
diff --git a/askbot/tests/email_alert_tests.py b/askbot/tests/email_alert_tests.py
index 56142805..de801967 100644
--- a/askbot/tests/email_alert_tests.py
+++ b/askbot/tests/email_alert_tests.py
@@ -1,6 +1,7 @@
import datetime
import functools
import copy
+import time
from django.conf import settings as django_settings
from django.core import management
import django.core.mail
@@ -9,10 +10,13 @@ from django.test import TestCase
from django.test.client import Client
from askbot.tests import utils
from askbot import models
-from askbot.utils.mail import mail_moderators
+from askbot.utils import mail
+from askbot.conf import settings as askbot_settings
+from askbot import const
def email_alert_test(test_func):
- """decorator for test methods in EmailAlertTests
+ """decorator for test methods in
+ :class:`~askbot.tests.email_alert_tests.EmailAlertTests`
wraps tests with a generic sequence of testing
email alerts on updates to anything relating to
given question
@@ -79,6 +83,22 @@ def setup_email_alert_tests(setup_func):
test_object.setUpUsers()
return wrapped_setup
+class SubjectLineTests(TestCase):
+ """Tests for the email subject line"""
+ def test_set_prefix(self):
+ """set prefix and see if it is there
+ """
+ askbot_settings.update('EMAIL_SUBJECT_PREFIX', 'test prefix')
+ subj = mail.prefix_the_subject_line('hahah')
+ self.assertEquals(subj, 'test prefix hahah')
+
+ def test_can_disable_prefix(self):
+ """set prefix to empty string and make sure
+ that the subject line is not altered"""
+ askbot_settings.update('EMAIL_SUBJECT_PREFIX', '')
+ subj = mail.prefix_the_subject_line('hahah')
+ self.assertEquals(subj, 'hahah')
+
class EmailAlertTests(TestCase):
"""Base class for testing delayed Email notifications
that are triggered by the send_email_alerts
@@ -595,6 +615,7 @@ class LiveInstantSelectedQuestionsEmailAlertTests(EmailAlertTests):
@setup_email_alert_tests
def setUp(self):
self.notification_schedule['q_sel'] = 'i'
+ #first posts yesterday
self.setup_timestamp = datetime.datetime.now() - datetime.timedelta(1)
self.follow_question = True
@@ -711,6 +732,71 @@ class FeedbackTests(utils.AskbotTestCase):
def test_mail_moderators(self):
"""tests askbot.mail_moderators()
"""
- mail_moderators('subject', 'text')
+ mail.mail_moderators('subject', 'text')
self.assert_feedback_works()
+
+class TagFollowedInstantWholeForumEmailAlertTests(utils.AskbotTestCase):
+ def setUp(self):
+ self.create_user(
+ username = 'user1',
+ notification_schedule = {'q_all': 'i'},
+ status = 'm'
+ )
+ self.create_user(
+ username = 'user2',
+ status = 'm'
+ )
+
+ def test_wildcard_catches_new_tag(self):
+ """users asks a question with a brand new tag
+ and other user subscribes to it by wildcard
+ """
+ askbot_settings.update('USE_WILDCARD_TAGS', True)
+ self.user1.email_tag_filter_strategy = const.INCLUDE_INTERESTING
+ self.user1.save()
+ self.user1.mark_tags(
+ wildcards = ('some*',),
+ reason = 'good',
+ action = 'add'
+ )
+ self.user2.post_question(
+ title = 'some title',
+ body_text = 'some text for the question',
+ tags = 'something'
+ )
+ outbox = django.core.mail.outbox
+ self.assertEqual(len(outbox), 1)
+ self.assertEqual(len(outbox[0].recipients()), 1)
+ self.assertTrue(
+ self.user1.email in outbox[0].recipients()
+ )
+
+ def test_tag_based_subscription_on_new_question_works(self):
+ """someone subscribes for an pre-existing tag
+ then another user asks a question with that tag
+ and the subcriber receives an alert
+ """
+ models.Tag(
+ name = 'something',
+ created_by = self.user1
+ ).save()
+
+ self.user1.email_tag_filter_strategy = const.INCLUDE_INTERESTING
+ self.user1.save()
+ self.user1.mark_tags(
+ tagnames = ('something',),
+ reason = 'good',
+ action = 'add'
+ )
+ self.user2.post_question(
+ title = 'some title',
+ body_text = 'some text for the question',
+ tags = 'something'
+ )
+ outbox = django.core.mail.outbox
+ self.assertEqual(len(outbox), 1)
+ self.assertEqual(len(outbox[0].recipients()), 1)
+ self.assertTrue(
+ self.user1.email in outbox[0].recipients()
+ )
diff --git a/askbot/tests/form_tests.py b/askbot/tests/form_tests.py
new file mode 100644
index 00000000..68fb7010
--- /dev/null
+++ b/askbot/tests/form_tests.py
@@ -0,0 +1,228 @@
+from askbot.tests.utils import AskbotTestCase
+from askbot.conf import settings as askbot_settings
+from askbot import forms
+from askbot import models
+
+EMAIL_CASES = (#test should fail if the second item is None
+ ('user@example.com', 'user@example.com'),
+ ('Name Name <name@example.com>', 'name@example.com'),
+ ('"Name Name [example.com]" <name@example.com>', 'name@example.com'),
+ (
+ 'someone <reply+m-4823355-3ae97f4698708d0be6bb087d6d4ce1e5e33ac131@reply.example.com>',
+ 'reply+m-4823355-3ae97f4698708d0be6bb087d6d4ce1e5e33ac131@reply.example.com'
+ ),
+ (
+ 'freddy krueger <someone@example.edu> (by way of somebody else)',
+ 'someone@example.edu'
+ ),
+ (
+ 'Google Anniversary Promotion =?iso-8859-1?Q?=A9_2011?= <someone@example.br>',
+ 'someone@example.br'
+ ),
+ ('=?koi8-r?B?5sHExcXXwSDvzNjHwQ==?= <someone@example.ru>', 'someone@example.ru'),
+ ('root@example.org (Cron Daemon)', 'root@example.org'),
+ ('<summary@example.com>', 'summary@example.com'),
+ ('some text without an email adderess', None)
+)
+SUBJECT_LINE_CASES = (#test fails if second item is None
+ (
+ ' [ tag1;long tag, another] question title',
+ ('tag1 long-tag another', 'question title')
+ ),
+ ('[] question title', None),
+ ('question title', None),
+ (' [question title', None),
+ ('] question title', None),
+)
+
+class AskByEmailFormTests(AskbotTestCase):
+ """Tests :class:`~askbot.forms.AskByEmailForm`
+ form"""
+ def setUp(self):
+ #benign data set that must pass
+ self.data = {
+ 'sender': 'someone@example.com',
+ 'subject': '[tag-one] where is titanic?',
+ 'body_text': 'where is titanic?'
+ }
+ def test_subject_line(self):
+ """loops through various forms of the subject line
+ and makes sure that tags and title are parsed out"""
+ for test_case in SUBJECT_LINE_CASES:
+ self.data['subject'] = test_case[0]
+ form = forms.AskByEmailForm(self.data)
+ output = test_case[1]
+ if output is None:
+ self.assertFalse(form.is_valid())
+ else:
+ self.assertTrue(form.is_valid())
+ self.assertEquals(
+ form.cleaned_data['tagnames'],
+ output[0]
+ )
+ self.assertEquals(
+ form.cleaned_data['title'],
+ output[1]
+ )
+
+ def test_email(self):
+ """loops through variants of the from field
+ in the emails and tests the email address
+ extractor"""
+ for test_case in EMAIL_CASES:
+ self.data['sender'] = test_case[0]
+ expected_result = test_case[1]
+ form = forms.AskByEmailForm(self.data)
+ if expected_result is None:
+ self.assertFalse(form.is_valid())
+ else:
+ self.assertTrue(form.is_valid())
+ self.assertEquals(
+ form.cleaned_data['email'],
+ expected_result
+ )
+
+class TagNamesFieldTests(AskbotTestCase):
+
+ def setUp(self):
+ self.field = forms.TagNamesField()
+ self.user = self.create_user('user1')
+
+ def clean(self, value):
+ return self.field.clean(value).strip().split(' ')
+
+ def assert_tags_equal(self, tag_list1, tag_list2):
+ self.assertEqual(sorted(tag_list1), sorted(tag_list2))
+
+ def test_force_lowercase(self):
+ """FORCE_LOWERCASE setting is on
+ """
+ askbot_settings.update('FORCE_LOWERCASE_TAGS', True)
+ cleaned_tags = self.clean('Tag1 TAG5 tag1 tag5')
+ self.assert_tags_equal(cleaned_tags, ['tag1','tag5'])
+
+ def test_custom_case(self):
+ """FORCE_LOWERCASE setting is off
+ """
+ askbot_settings.update('FORCE_LOWERCASE_TAGS', False)
+ models.Tag(name = 'TAG1', created_by = self.user).save()
+ models.Tag(name = 'Tag2', created_by = self.user).save()
+ cleaned_tags = self.clean('tag1 taG2 TAG1 tag3 tag3')
+ self.assert_tags_equal(cleaned_tags, ['TAG1', 'Tag2', 'tag3'])
+
+class EditQuestionAnonymouslyFormTests(AskbotTestCase):
+ """setup the following truth table
+ on reveal_identity field:
+ is_anon can owner checked result
+
+ """
+ truth_table = (
+ (0, 0, 0, 0, False),
+ (0, 0, 0, 1, False),
+ (0, 0, 1, 0, False),
+ (0, 0, 1, 1, False),
+ (0, 1, 0, 0, False),
+ (0, 1, 0, 1, False),
+ (0, 1, 1, 0, False),
+ (0, 1, 1, 1, False),#all up to this point are False
+ (1, 0, 0, 0, False),
+ (1, 0, 0, 1, 'error'),#not owner
+ (1, 0, 1, 0, 'error'),#rules changed either reload page or check box
+ (1, 0, 1, 1, True),#rules changed - say yes here
+ (1, 1, 0, 0, False),
+ (1, 1, 0, 1, 'error'),
+ (1, 1, 1, 0, False),
+ (1, 1, 1, 1, True),
+ )
+ #legend: is_anon - question is anonymous
+ # can - askbot_settings.ALLOW_ASK_ANONYMOUSLY
+ # owner - editor is question owner
+ # checked - the checkbox "reveal_identity" is marked
+ def setUp(self):
+ self.create_user()
+ self.create_user(
+ username = 'other_user',
+ status = 'm'#must be able to edit
+ )
+ super(EditQuestionAnonymouslyFormTests, self).setUp()
+
+ def setup_data(self, is_anon, can_be_anon, is_owner, box_checked):
+ """sets up data in the same order as shown in the
+ truth table above
+
+ the four positional arguments are in the same order
+ """
+ askbot_settings.update('ALLOW_ASK_ANONYMOUSLY', can_be_anon)
+ question = self.post_question(is_anonymous = is_anon)
+ if is_owner:
+ editor = self.user
+ else:
+ editor = self.other_user
+ data = {
+ 'tags': 'tag1 tag2',
+ 'text': 'ostaousohuosuh',
+ 'title': 'stahosetuhaoeudhuh'
+ }
+ if box_checked:
+ data['reveal_identity'] = 'on'
+ self.form = forms.EditQuestionForm(
+ data,
+ question = question,
+ user = editor,
+ revision = question.get_latest_revision(),
+ )
+
+ def test_reveal_identity_field(self):
+ """runs through the truth table and tests them items by one
+ """
+ current_item = 0
+ for entry in self.truth_table:
+ self.setup_data(*(entry[:4]))
+
+ if self.form.is_valid():
+ result = self.form.cleaned_data['reveal_identity']
+ else:
+ result = 'error'
+
+ error_message = 'failed truth table item %d' % current_item
+ current_item += 1
+
+ expected_result = entry[4]
+ self.assertEquals(result, expected_result, error_message)
+
+class AskFormTests(AskbotTestCase):
+
+ def setup_data(self, allow_anonymous = True, ask_anonymously = None):
+ askbot_settings.update('ALLOW_ASK_ANONYMOUSLY', allow_anonymous)
+ data = {
+ 'title': 'test title',
+ 'text': 'test content',
+ 'tags': 'test',
+ }
+ if ask_anonymously == True:
+ data['ask_anonymously'] = 'on'
+ self.form = forms.AskForm(data)
+ self.form.full_clean()
+
+ def assert_anon_is(self, value):
+ self.assertEquals(
+ self.form.cleaned_data['ask_anonymously'],
+ value
+ )
+
+ def test_ask_anonymously_disabled(self):
+ """test that disabled anon postings yields False"""
+ self.setup_data(ask_anonymously = True, allow_anonymous = False)
+ self.assert_anon_is(False)
+
+ def test_ask_anonymously_field_positive(self):
+ """check that the 'yes' selection goes through
+ """
+ self.setup_data(ask_anonymously = True)
+ self.assert_anon_is(True)
+
+ def test_ask_anonymously_field_negative(self):
+ """check that the 'no' selection goes through
+ """
+ self.setup_data(ask_anonymously = False)
+ self.assert_anon_is(False)
diff --git a/askbot/tests/page_load_tests.py b/askbot/tests/page_load_tests.py
index 1c794f7c..ab02efa8 100644
--- a/askbot/tests/page_load_tests.py
+++ b/askbot/tests/page_load_tests.py
@@ -1,23 +1,30 @@
-from django.test import TestCase, signals
-from jinja2.environment import Template as Jinja2Template
+from django.test import TestCase
+from django.test import signals
from django.template import defaultfilters
from django.core.urlresolvers import reverse
+import coffin
import coffin.template
from askbot import models
from askbot.utils.slug import slugify
+from askbot.deployment import package_utils
import sys
-#note - this code can be run only once
-ORIG_JINJA2_RENDERER = Jinja2Template.render
-def instrumented_render(template_object, *args, **kwargs):
- context = dict(*args, **kwargs)
- signals.template_rendered.send(
- sender=template_object,
- template=template_object,
- context=context
- )
- return ORIG_JINJA2_RENDERER(template_object, *args, **kwargs)
-Jinja2Template.render = instrumented_render
+def patch_jinja2():
+ from jinja2 import Template
+ ORIG_JINJA2_RENDERER = Template.render
+ def instrumented_render(template_object, *args, **kwargs):
+ context = dict(*args, **kwargs)
+ signals.template_rendered.send(
+ sender=template_object,
+ template=template_object,
+ context=context
+ )
+ return ORIG_JINJA2_RENDERER(template_object, *args, **kwargs)
+ Template.render = instrumented_render
+
+(CMAJOR, CMINOR, CMICRO) = package_utils.get_coffin_version()
+if CMAJOR == 0 and CMINOR == 3 and CMICRO < 4:
+ patch_jinja2()
class PageLoadTestCase(TestCase):
def try_url(
@@ -56,7 +63,7 @@ class PageLoadTests(PageLoadTestCase):
self.assertEqual(response.status_code, 200)
self.failUnless(len(response.redirect_chain) == 1)
self.failUnless(response.redirect_chain[0][0].endswith('/questions/'))
- self.assertEquals(response.template.name, 'questions.html')
+ self.assertEquals(response.template.name, 'main_page.html')
def proto_test_non_user_urls(self):
"""test all reader views thoroughly
@@ -82,67 +89,62 @@ class PageLoadTests(PageLoadTestCase):
#todo: test different sort methods and scopes
self.try_url(
'questions',
- template='questions.html'
+ template='main_page.html'
)
self.try_url(
'questions',
data={'start_over':'true'},
- template='questions.html'
+ template='main_page.html'
)
self.try_url(
'questions',
data={'scope':'unanswered'},
- template='questions.html'
- )
- self.try_url(
- 'questions',
- data={'scope':'all'},
- template='questions.html'
+ template='main_page.html'
)
self.try_url(
'questions',
data={'scope':'favorite'},
- template='questions.html'
+ template='main_page.html'
)
self.try_url(
'questions',
- data={'scope':'unanswered', 'sort':'latest'},
- template='questions.html'
+ data={'scope':'unanswered', 'sort':'age-desc'},
+ template='main_page.html'
)
self.try_url(
'questions',
- data={'scope':'unanswered', 'sort':'oldest'},
- template='questions.html'
+ data={'scope':'unanswered', 'sort':'age-asc'},
+ template='main_page.html'
)
self.try_url(
'questions',
- data={'scope':'unanswered', 'sort':'active'},
- template='questions.html'
+ data={'scope':'unanswered', 'sort':'activity-desc'},
+ template='main_page.html'
)
self.try_url(
'questions',
- data={'scope':'unanswered', 'sort':'inactive'},
- template='questions.html'
+ data={'scope':'unanswered', 'sort':'activity-asc'},
+ template='main_page.html'
)
self.try_url(
'questions',
- data={'sort':'hottest'},
- template='questions.html'
+ data={'sort':'answers-desc'},
+ template='main_page.html'
)
self.try_url(
'questions',
- data={'sort':'coldest'},
- template='questions.html'
+ data={'sort':'answers-asc'},
+ template='main_page.html'
)
self.try_url(
'questions',
- data={'sort':'mostvoted'},
- template='questions.html'
+ data={'sort':'votes-desc'},
+ template='main_page.html'
)
self.try_url(
'questions',
- data={'sort':'leastvoted'},
- template='questions.html'
+ data={'sort':'votes-asc'},
+ template='main_page.html'
)
self.try_url(
'question',
@@ -236,6 +238,11 @@ class PageLoadTests(PageLoadTestCase):
status_code=200,
follow=True,
)
+ self.try_url(
+ 'faq',
+ template='faq.html',
+ status_code=200,
+ )
def test_non_user_urls(self):
self.proto_test_non_user_urls()
@@ -252,13 +259,13 @@ class PageLoadTests(PageLoadTestCase):
'user_profile',
kwargs={'id': 2, 'slug': name_slug},
data={'sort':'stats'},
- template='user_stats.html'
+ template='user_profile/user_stats.html'
)
self.try_url(
'user_profile',
kwargs={'id': 2, 'slug': name_slug},
data={'sort':'recent'},
- template='user_recent.html'
+ template='user_profile/user_recent.html'
)
self.try_url(
'user_profile',
@@ -271,7 +278,7 @@ class PageLoadTests(PageLoadTestCase):
'user_profile',
kwargs={'id': 2, 'slug': name_slug},
data={'sort':'reputation'},
- template='user_reputation.html'
+ template='user_profile/user_reputation.html'
)
self.try_url(
'user_profile',
@@ -284,7 +291,7 @@ class PageLoadTests(PageLoadTestCase):
'user_profile',
kwargs={'id': 2, 'slug': name_slug},
data={'sort':'favorites'},
- template='user_favorites.html'
+ template='user_profile/user_favorites.html'
)
self.try_url(
'user_profile',
diff --git a/askbot/tests/permission_assertion_tests.py b/askbot/tests/permission_assertion_tests.py
index 0918e8b5..83476c79 100644
--- a/askbot/tests/permission_assertion_tests.py
+++ b/askbot/tests/permission_assertion_tests.py
@@ -1,3 +1,4 @@
+import datetime
from django.test import TestCase
from django.core import exceptions
from askbot.tests import utils
@@ -28,13 +29,14 @@ class PermissionAssertionTestCase(TestCase):
email = 'other@test.com'
)
- def post_question(self, author = None):
+ def post_question(self, author = None, timestamp = None):
if author is None:
author = self.user
return author.post_question(
title = 'test question title',
body_text = 'test question body',
- tags = 'test'
+ tags = 'test',
+ timestamp = timestamp
)
def post_answer(self, question = None, author = None):
@@ -90,7 +92,8 @@ class SeeOffensiveFlagsPermissionAssertionTests(utils.AskbotTestCase):
def test_admin_can_see_flags(self):
question = self.post_question()
- self.other_user.is_superuser = True
+ self.other_user.set_admin_status()
+ self.other_user.save()
assert(self.other_user.reputation < self.min_rep)
self.assertTrue(
template_filters.can_see_offensive_flags(
@@ -222,7 +225,8 @@ class DeleteAnswerPermissionAssertionTests(utils.AskbotTestCase):
def test_low_rep_admin_can_delete(self):
self.post_answer(user = self.other_user)
- self.user.is_superuser = True
+ self.user.set_admin_status()
+ self.user.save()
assert(self.user.reputation < self.min_rep)
self.assert_can_delete()
@@ -337,7 +341,8 @@ class CloseQuestionPermissionAssertionTests(utils.AskbotTestCase):
)
def test_low_rep_admin_can_close(self):
- self.other_user.is_superuser = True
+ self.other_user.set_admin_status()
+ self.other_user.save()
assert(self.other_user.reputation < self.min_rep)
self.assert_can_close(user = self.other_user)
@@ -442,7 +447,7 @@ class ReopenQuestionPermissionAssertionTests(utils.AskbotTestCase):
self.assert_cannot_reopen(user = self.other_user)
def test_low_rep_admin_can_reopen(self):
- self.other_user.is_superuser = True
+ self.other_user.set_admin_status()
self.assert_can_reopen(user = self.other_user)
def test_low_rep_moderator_can_reopen(self):
@@ -515,12 +520,14 @@ class EditQuestionPermissionAssertionTests(utils.AskbotTestCase):
self.assert_user_cannot(user = self.other_user)
def test_admin_can_edit(self):
- self.other_user.is_superuser = True
+ self.other_user.set_admin_status()
+ self.other_user.save()
self.assert_other_can()
def test_admin_can_edit_deleted(self):
self.post.deleted = True
- self.other_user.is_superuser = True
+ self.other_user.set_admin_status()
+ self.other_user.save()
self.assert_other_can()
def test_mod_can_edit(self):
@@ -773,7 +780,8 @@ class FlagOffensivePermissionAssertionTests(PermissionAssertionTestCase):
def test_admin_has_no_limit_for_flags_per_day(self):
max_flags = askbot_settings.MAX_FLAGS_PER_USER_PER_DAY
other_user = self.create_other_user()
- other_user.is_superuser = True
+ other_user.set_admin_status()
+ other_user.save()
for i in range(max_flags + 1):
question = self.post_question()
other_user.flag_post(question)
@@ -808,11 +816,12 @@ class FlagOffensivePermissionAssertionTests(PermissionAssertionTestCase):
def low_rep_administrator_can_flag(self):
assert(self.user.reputation < self.min_rep)
- self.user.is_superuser = True
+ self.user.set_admin_status()
self.assert_user_can_flag()
def test_superuser_cannot_flag_question_twice(self):
- self.user.is_superuser = True
+ self.user.set_admin_status()
+ self.user.save()
self.user.flag_post(post = self.question)
self.assertRaises(
exceptions.PermissionDenied,
@@ -829,7 +838,8 @@ class FlagOffensivePermissionAssertionTests(PermissionAssertionTestCase):
)
def test_superuser_cannot_flag_answer_twice(self):
- self.user.is_superuser = True
+ self.user.set_admin_status()
+ self.user.save()
self.user.flag_post(post = self.answer)
self.assertRaises(
exceptions.PermissionDenied,
@@ -1017,7 +1027,8 @@ class CommentPermissionAssertionTests(PermissionAssertionTestCase):
parent_post = question,
body_text = 'test comment'
)
- self.other_user.is_superuser = True
+ self.other_user.set_admin_status()
+ self.other_user.save()
self.other_user.delete_comment(comment)
self.assertTrue(
template_filters.can_delete_comment(
@@ -1149,7 +1160,8 @@ class CommentPermissionAssertionTests(PermissionAssertionTestCase):
def test_low_rep_admin_can_comment_others_question(self):
question = self.post_question()
- self.other_user.is_superuser = True
+ self.other_user.set_admin_status()
+ self.other_user.save()
assert(self.other_user.is_administrator())
assert(self.other_user.reputation < self.min_rep)
comment = self.other_user.post_comment(
@@ -1181,6 +1193,104 @@ class CommentPermissionAssertionTests(PermissionAssertionTestCase):
)
)
+ def assert_user_can_edit_previous_comment(
+ self,
+ old_timestamp = None,
+ original_poster = None
+ ):
+ """oriposts a question and a comment at
+ an old timestamp, then posts another comment now
+ then user tries to edit the first comment
+ """
+ self.other_user.set_admin_status()
+ self.other_user.save()
+
+ if original_poster is None:
+ original_poster = self.user
+
+ question = self.post_question(
+ author = original_poster,
+ timestamp = old_timestamp
+ )
+ comment1 = original_poster.post_comment(
+ parent_post = question,
+ timestamp = old_timestamp,
+ body_text = 'blah'
+ )
+ comment2 = self.other_user.post_comment(#post this one with the current timestamp
+ parent_post = question,
+ body_text = 'blah'
+ )
+ self.user.assert_can_edit_comment(comment1)
+
+ def assert_user_can_edit_very_old_comment(self, original_poster = None):
+ """tries to edit comment in the most restictive situation
+ """
+ askbot_settings.update('USE_TIME_LIMIT_TO_EDIT_COMMENT', True)
+ askbot_settings.update('MINUTES_TO_EDIT_COMMENT', 0)
+ old_timestamp = datetime.datetime.now() - datetime.timedelta(1)
+ self.assert_user_can_edit_previous_comment(
+ old_timestamp = old_timestamp,
+ original_poster = original_poster
+ )
+
+
+ def test_admin_can_edit_very_old_comment(self):
+ self.user.set_admin_status()
+ self.user.save()
+ self.assert_user_can_edit_very_old_comment(original_poster = self.other_user)
+
+ def test_moderator_can_edit_very_old_comment(self):
+ self.user.set_status('m')
+ self.user.save()
+ self.assert_user_can_edit_very_old_comment(original_poster = self.other_user)
+
+ def test_regular_user_cannot_edit_very_old_comment(self):
+ self.assertRaises(
+ exceptions.PermissionDenied,
+ self.assert_user_can_edit_very_old_comment,
+ original_poster = self.user
+ )
+
+ def test_regular_user_can_edit_reasonably_old_comment(self):
+ self.user.set_status('a')
+ self.user.save()
+ askbot_settings.update('USE_TIME_LIMIT_TO_EDIT_COMMENT', True)
+ askbot_settings.update('MINUTES_TO_EDIT_COMMENT', 10)
+ #about 3 min ago
+ old_timestamp = datetime.datetime.now() - datetime.timedelta(0, 200)
+ self.assert_user_can_edit_previous_comment(
+ old_timestamp = old_timestamp,
+ original_poster = self.user
+ )
+
+ def test_disable_comment_edit_time_limit(self):
+ self.user.set_status('a')
+ self.user.save()
+ askbot_settings.update('USE_TIME_LIMIT_TO_EDIT_COMMENT', False)
+ askbot_settings.update('MINUTES_TO_EDIT_COMMENT', 10)
+ old_timestamp = datetime.datetime.now() - datetime.timedelta(365)#a year ago
+ self.assert_user_can_edit_previous_comment(
+ old_timestamp = old_timestamp,
+ original_poster = self.user
+ )
+
+
+ def test_regular_user_can_edit_last_comment(self):
+ """and a very old last comment"""
+ self.user.set_status('a')
+ self.user.save()
+ askbot_settings.update('USE_TIME_LIMIT_TO_EDIT_COMMENT', True)
+ askbot_settings.update('MINUTES_TO_EDIT_COMMENT', 10)
+ old_timestamp = datetime.datetime.now() - datetime.timedelta(1)
+ question = self.post_question(author = self.user, timestamp = old_timestamp)
+ comment = self.user.post_comment(
+ parent_post = question,
+ body_text = 'blah',
+ timestamp = old_timestamp
+ )
+ self.user.assert_can_edit_comment(comment)
+
#def user_assert_can_post_comment(self, parent_post):
#def user_assert_can_delete_comment(self, comment = None):
@@ -1272,12 +1382,14 @@ class AcceptBestAnswerPermissionAssertionTests(utils.AskbotTestCase):
def test_admin_cannot_accept_others_answer(self):
self.other_post_answer()
self.create_user(username = 'third_user')
- self.third_user.is_superuser = True
+ self.third_user.set_admin_status()
+ self.third_user.save()
self.assert_user_cannot(user = self.third_user)
def test_admin_cannot_accept_own_answer(self):
self.other_post_answer()
- self.other_user.is_superuser = True
+ self.other_user.set_admin_status()
+ self.other_user.save()
self.assert_user_cannot(user = self.other_user)
class VotePermissionAssertionTests(PermissionAssertionTestCase):
@@ -1433,7 +1545,8 @@ class UploadPermissionAssertionTests(PermissionAssertionTestCase):
def test_low_rep_administrator_can_upload(self):
assert(self.user.reputation < self.min_rep)
- self.user.is_superuser = True
+ self.user.set_admin_status()
+ self.user.save()
try:
self.user.assert_can_upload_file()
except exceptions.PermissionDenied:
diff --git a/askbot/tests/search_state_tests.py b/askbot/tests/search_state_tests.py
new file mode 100644
index 00000000..bb1423ca
--- /dev/null
+++ b/askbot/tests/search_state_tests.py
@@ -0,0 +1,60 @@
+from django.test import TestCase
+from django.contrib.auth.models import AnonymousUser
+from askbot.search.state_manager import SearchState, ViewLog
+from askbot import const
+
+DEFAULT_SORT = const.DEFAULT_POST_SORT_METHOD
+class SearchStateTests(TestCase):
+ def setUp(self):
+ self.state = SearchState()
+ self.log = ViewLog()
+
+ def visit_page(self, page_name):
+ """page_name is name of the view function
+ that is to be "visited"
+ """
+ self.log.set_current(page_name)
+
+ def update(self, data, user = None):
+ self.visit_page('questions')
+ if user is None:
+ user = AnonymousUser()
+ self.state.update(data, self.log, user)
+
+ def add_tag(self, tag):
+ self.update({'tags': set([tag])})
+
+ def remove_tag(self, tag):
+ self.update({'remove_tag': tag})
+
+ def assert_tags_are(self, *args):
+ self.assertEqual(self.state.tags, set(args))
+
+ def test_add_remove_tags(self):
+ self.add_tag('tag1')
+ self.assert_tags_are('tag1')
+ self.add_tag('tag2')
+ self.assert_tags_are('tag1', 'tag2')
+ self.add_tag('tag3')
+ self.assert_tags_are('tag1', 'tag2', 'tag3')
+ self.remove_tag('tag3')
+ self.assert_tags_are('tag1', 'tag2')
+ self.remove_tag('tag2')
+ self.assert_tags_are('tag1')
+ self.remove_tag('tag1')
+ self.assertEqual(len(self.state.tags), 0)
+
+ def test_query_and_tags1(self):
+ self.update({'query': 'hahaha'})
+ self.add_tag('tag1')
+ self.assertEquals(self.state.query, 'hahaha')
+ self.assert_tags_are('tag1')
+ self.update({'reset_query':True})
+ self.assertEquals(self.state.query, None)
+ self.assert_tags_are('tag1')
+
+ def test_auto_reset_sort(self):
+ self.update({'sort': 'age-asc'})
+ self.assertEquals(self.state.sort, 'age-asc')
+ self.update({})
+ self.assertEquals(self.state.sort, DEFAULT_SORT)
diff --git a/askbot/tests/skin_tests.py b/askbot/tests/skin_tests.py
index 978f45b1..660daa4e 100644
--- a/askbot/tests/skin_tests.py
+++ b/askbot/tests/skin_tests.py
@@ -36,6 +36,7 @@ class SkinTests(TestCase):
'test_skin'
)
shutil.rmtree(test_skin_dir)
+ askbot_settings.update('ASKBOT_DEFAULT_SKIN', 'default')
def assert_default_logo_in_skin(self, skin_name):
url = skin_utils.get_media_url(askbot_settings.SITE_LOGO_URL)
diff --git a/askbot/tests/utils.py b/askbot/tests/utils.py
index 6942ce29..0c18e661 100644
--- a/askbot/tests/utils.py
+++ b/askbot/tests/utils.py
@@ -12,7 +12,26 @@ def create_user(
reputation = 1
):
"""Creates a user and sets default update subscription
- settings"""
+ settings
+
+ ``notification_schedule`` is a dictionary with keys
+ the same as in keys in
+ :attr:`~askbot.models.EmailFeedSetting.FEED_TYPES`:
+
+ * 'q_ask' - questions that user asks
+ * 'q_all' - enture forum, tag filtered
+ * 'q_ans' - questions that user answers
+ * 'q_sel' - questions that user decides to follow
+ * 'm_and_c' - comments and mentions of user anywhere
+
+ and values as keys in
+ :attr:`~askbot.models.EmailFeedSetting.FEED_TYPES`:
+
+ * 'i' - instantly
+ * 'd' - daily
+ * 'w' - weekly
+ * 'n' - never
+ """
user = models.User.objects.create_user(username, email)
user.reputation = reputation
if date_joined is not None:
@@ -77,12 +96,15 @@ class AskbotTestCase(TestCase):
body_text = 'test question body text',
tags = 'test',
wiki = False,
+ is_anonymous = False,
follow = False,
timestamp = None
):
"""posts and returns question on behalf
of user. If user is not given, it will be self.user
+ ``tags`` is a string with tagnames
+
if follow is True, question is followed by the poster
"""
@@ -94,6 +116,7 @@ class AskbotTestCase(TestCase):
body_text = body_text,
tags = tags,
wiki = wiki,
+ is_anonymous = is_anonymous,
timestamp = timestamp
)
@@ -102,6 +125,11 @@ class AskbotTestCase(TestCase):
return question
+ def reload_object(self, obj):
+ """reloads model object from the database
+ """
+ return obj.__class__.objects.get(id = obj.id)
+
def post_answer(
self,
user = None,
diff --git a/askbot/urls.py b/askbot/urls.py
index 2071a27b..b70fdd0f 100644
--- a/askbot/urls.py
+++ b/askbot/urls.py
@@ -10,7 +10,6 @@ from askbot.feed import RssLastestQuestionsFeed
from askbot.sitemap import QuestionsSitemap
from django.utils.translation import ugettext as _
from django.conf import settings
-from askbot.conf import settings as askbot_settings
admin.autodiscover()
feeds = {
@@ -40,6 +39,8 @@ urlpatterns = patterns('',
{'document_root': os.path.join(settings.PROJECT_ROOT, 'askbot', 'upfiles').replace('\\','/')},
name='uploaded_file',
),
+ #no translation for this url!!
+ url(r'import-data/$', views.writers.import_data, name='import_data'),
url(r'^%s$' % _('about/'), views.meta.about, name='about'),
url(r'^%s$' % _('faq/'), views.meta.faq, name='faq'),
url(r'^%s$' % _('privacy/'), views.meta.privacy, name='privacy'),
@@ -61,6 +62,11 @@ urlpatterns = patterns('',
name='questions'
),
url(
+ r'^api/get_questions/',
+ views.commands.api_get_questions,
+ name = 'api_get_questions'
+ ),
+ url(
r'^%s%s$' % (_('questions/'), _('ask/')),
views.writers.ask,
name='ask'
@@ -112,11 +118,6 @@ urlpatterns = patterns('',
name='edit_comment'
),
url(#ajax only
- r'^%s$' % _('command/'),
- views.commands.ajax_command,
- name='call_ajax'
- ),
- url(#ajax only
r'^comment/delete/$',
views.writers.delete_comment,
name='delete_comment'
@@ -138,23 +139,43 @@ urlpatterns = patterns('',
name='tags'
),
url(#ajax only
- r'^%s%s(?P<tag>[^/]+)/$' % (_('mark-tag/'),_('interesting/')),
+ r'^%s%s$' % ('mark-tag/', 'interesting/'),
views.commands.mark_tag,
kwargs={'reason':'good','action':'add'},
name='mark_interesting_tag'
),
url(#ajax only
- r'^%s%s(?P<tag>[^/]+)/$' % (_('mark-tag/'),_('ignored/')),
+ r'^%s%s$' % ('mark-tag/', 'ignored/'),
views.commands.mark_tag,
kwargs={'reason':'bad','action':'add'},
name='mark_ignored_tag'
),
url(#ajax only
- r'^%s(?P<tag>[^/]+)/$' % _('unmark-tag/'),
+ r'^unmark-tag/',
views.commands.mark_tag,
kwargs={'action':'remove'},
name='unmark_tag'
),
+ url(#ajax only
+ r'^set-tag-filter-strategy/',
+ views.commands.set_tag_filter_strategy,
+ name = 'set_tag_filter_strategy'
+ ),
+ url(
+ r'^get-tags-by-wildcard/',
+ views.commands.get_tags_by_wildcard,
+ name = 'get_tags_by_wildcard'
+ ),
+ url(
+ r'^get-tag-list/',
+ views.commands.get_tag_list,
+ name = 'get_tag_list'
+ ),
+ url(
+ r'^%s$' % _('subscribe-for-tags/'),
+ views.commands.subscribe_for_tags,
+ name = 'subscribe_for_tags'
+ ),
url(
r'^%s$' % _('users/'),
views.users.users,
@@ -199,7 +220,6 @@ urlpatterns = patterns('',
),
#upload url is ajax only
url( r'^%s$' % _('upload/'), views.writers.upload, name='upload'),
- url(r'^%s$' % _('search/'), views.readers.search, name='search'),
url(r'^%s$' % _('feedback/'), views.meta.feedback, name='feedback'),
(r'^%s' % _('account/'), include('askbot.deps.django_authopenid.urls')),
#url(r'^feeds/rss/$', RssLastestQuestionsFeed, name="latest_questions_feed"),
@@ -227,4 +247,25 @@ urlpatterns = patterns('',
},
name = 'custom_js'
),
+ url(
+ r'^jsi18n/$',
+ 'django.views.i18n.javascript_catalog',
+ {'packages': ('askbot',)},
+ name = 'askbot_jsi18n'
+ ),
)
+
+if 'avatar' in settings.INSTALLED_APPS:
+ #unforturately we have to wire avatar urls here,
+ #because views add and change are adapted to
+ #use jinja2 templates
+ urlpatterns += (
+ url('^avatar/add/$', views.avatar_views.add, name='avatar_add'),
+ url('^avatar/change/$', views.avatar_views.change, name='avatar_change'),
+ url('^avatar/delete/$', views.avatar_views.delete, name='avatar_delete'),
+ url(#this urs we inherit from the original avatar app
+ '^avatar/render_primary/(?P<user>[\+\w]+)/(?P<size>[\d]+)/$',
+ 'avatar.views.render_primary',
+ name='avatar_render_primary'
+ ),
+ )
diff --git a/askbot/utils/console.py b/askbot/utils/console.py
index f0dab45e..041fc839 100644
--- a/askbot/utils/console.py
+++ b/askbot/utils/console.py
@@ -1,7 +1,7 @@
"""functions that directly handle user input
"""
+import sys
import time
-import os
from askbot.utils import path
def choice_dialog(prompt_phrase, choices = None, invalid_phrase = None):
@@ -48,3 +48,14 @@ def open_new_file(prompt_phrase, extension = '', hint = None):
file_object = path.create_file_if_does_not_exist(file_path, print_warning = True)
return file_object
+
+def print_progress(format_string, progress):
+ """print dynamic output of progress of some
+ operation to the console and clear the output with
+ a backspace character to have the number increment
+ in-place"""
+ output = format_string % progress
+ sys.stdout.write(output)
+ sys.stdout.flush()
+ sys.stdout.write('\b' * len(output))
+
diff --git a/askbot/utils/email.py b/askbot/utils/email.py
index 8f719e82..34b11c45 100644
--- a/askbot/utils/email.py
+++ b/askbot/utils/email.py
@@ -1,11 +1,18 @@
from django.core.mail import EmailMultiAlternatives
-from django.conf import settings
+from django.conf import settings as django_settings
from django.template import loader, Context
from django.utils.html import strip_tags
from threading import Thread
-def send_email(subject, recipients, template, context={}, sender=settings.DEFAULT_FROM_EMAIL, txt_template=None):
- context['settings'] = settings
+def send_email(
+ subject,
+ recipients,
+ template,
+ context = {},
+ sender = django_settings.DEFAULT_FROM_EMAIL,
+ txt_template = None
+ ):
+ context['settings'] = django_settings
html_body = loader.get_template(template).render(Context(context))
if txt_template is None:
diff --git a/askbot/utils/http.py b/askbot/utils/http.py
new file mode 100644
index 00000000..8a3ccd22
--- /dev/null
+++ b/askbot/utils/http.py
@@ -0,0 +1,45 @@
+"""http-related utilities for askbot
+"""
+from copy import copy
+
+def hide_passwords(data):
+ """replaces content of values that may contain passsword
+ with XXXXXX for better security"""
+ if not data:
+ return data
+
+ #names of the fields are taken from forms
+ #askbot.utils.forms.SetPasswordForm
+ #askbat.deps.django_authopenid.forms.LoginForm
+ #todo: forms need to be consolidated and names of the fields normalized
+ fields = (
+ 'password',
+ 'password1',
+ 'password2',
+ 'new_password',
+ 'new_password_retyped'
+ )
+
+ for field in fields:
+ if field in data:
+ data[field] = 'XXXXXX'
+
+ return data
+
+def get_request_info(request):
+ """return a reasonable string with the key contents of request object
+ this function is intended for the use in logs and debugging
+ all passwords will be obfuscated
+ """
+ info = 'path: %s\n' % request.get_full_path()
+ info += 'method: %s\n' % request.method
+ data = None
+ if request.method == 'GET':
+ data = request.GET
+ elif request.method == 'POST':
+ data = request.POST
+ data = hide_passwords(copy(data))
+ info += 'data: %s\n' % str(data)
+ info += 'host: %s\n' % request.get_host()
+ info += 'user: %s\n' % request.user
+ return info
diff --git a/askbot/utils/mail.py b/askbot/utils/mail.py
index dee7f74b..1c78e81d 100644
--- a/askbot/utils/mail.py
+++ b/askbot/utils/mail.py
@@ -7,8 +7,30 @@ from django.core import mail
from django.conf import settings as django_settings
from askbot.conf import settings as askbot_settings
from askbot import exceptions
+from askbot import const
#todo: maybe send_mail functions belong to models
#or the future API
+def prefix_the_subject_line(subject):
+ """prefixes the subject line with the
+ EMAIL_SUBJECT_LINE_PREFIX either from
+ from live settings, which take default from django
+ """
+ prefix = askbot_settings.EMAIL_SUBJECT_PREFIX.strip()
+ if prefix != '':
+ subject = prefix + ' ' + subject
+ return subject
+
+def extract_first_email_address(text):
+ """extract first matching email address
+ from text string
+ returns ``None`` if there are no matches
+ """
+ match = const.EMAIL_REGEX.search(text)
+ if match:
+ return match.group(0)
+ else:
+ return None
+
def send_mail(
subject_line = None,
body_text = None,
@@ -18,7 +40,9 @@ def send_mail(
headers = None,
raise_on_failure = False,
):
- """sends email message
+ """
+ todo: remove parameters not relevant to the function
+ sends email message
logs email sending activity
and any errors are reported as critical
in the main log file
@@ -68,6 +92,7 @@ def mail_moderators(
try:
mail.send_mail(subject_line, body_text, from_email, recipient_list)
+ pass
except smtplib.SMTPException, error:
logging.critical(unicode(error))
if raise_on_failure == True:
diff --git a/askbot/version.py b/askbot/version.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/askbot/version.py
diff --git a/askbot/views/__init__.py b/askbot/views/__init__.py
index 578bd1a5..b9aaf8a9 100644
--- a/askbot/views/__init__.py
+++ b/askbot/views/__init__.py
@@ -6,3 +6,6 @@ from askbot.views import writers
from askbot.views import commands
from askbot.views import users
from askbot.views import meta
+from django.conf import settings
+if 'avatar' in settings.INSTALLED_APPS:
+ from askbot.views import avatar_views
diff --git a/askbot/views/avatar_views.py b/askbot/views/avatar_views.py
new file mode 100644
index 00000000..ea16380d
--- /dev/null
+++ b/askbot/views/avatar_views.py
@@ -0,0 +1,186 @@
+"""this is an unfortunate copy-paste (mostly)
+from the avatar app - the reason is that django-avatar app
+does not support jinja templates
+"""
+from django.http import HttpResponseRedirect
+from django.template import RequestContext
+from django.utils.translation import ugettext as _
+from django.conf import settings
+
+from django.contrib.auth.decorators import login_required
+
+from avatar.forms import PrimaryAvatarForm, DeleteAvatarForm, UploadAvatarForm
+from avatar.models import Avatar
+from avatar.settings import AVATAR_MAX_AVATARS_PER_USER, AVATAR_DEFAULT_SIZE
+from avatar.util import get_primary_avatar, get_default_avatar_url
+
+from askbot.skins.loaders import render_into_skin
+
+notification = False
+if 'notification' in settings.INSTALLED_APPS:
+ from notification import models as notification
+
+friends = False
+if 'friends' in settings.INSTALLED_APPS:
+ friends = True
+ from friends.models import Friendship
+
+def _get_next(request):
+ """
+ The part that's the least straightforward about views in this module is how they
+ determine their redirects after they have finished computation.
+
+ In short, they will try and determine the next place to go in the following order:
+
+ 1. If there is a variable named ``next`` in the *POST* parameters, the view will
+ redirect to that variable's value.
+ 2. If there is a variable named ``next`` in the *GET* parameters, the view will
+ redirect to that variable's value.
+ 3. If Django can determine the previous page from the HTTP headers, the view will
+ redirect to that previous page.
+ """
+ next = request.POST.get('next', request.GET.get('next',
+ request.META.get('HTTP_REFERER', None)))
+ if not next:
+ next = request.path
+ return next
+
+def _notification_updated(request, avatar):
+ notification.send([request.user], "avatar_updated",
+ {"user": request.user, "avatar": avatar})
+ if friends:
+ notification.send((x['friend'] for x in
+ Friendship.objects.friends_for_user(request.user)),
+ "avatar_friend_updated",
+ {"user": request.user, "avatar": avatar}
+ )
+
+def _get_avatars(user):
+ # Default set. Needs to be sliced, but that's it. Keep the natural order.
+ avatars = user.avatar_set.all()
+
+ # Current avatar
+ primary_avatar = avatars.order_by('-primary')[:1]
+ if primary_avatar:
+ avatar = primary_avatar[0]
+ else:
+ avatar = None
+
+ if AVATAR_MAX_AVATARS_PER_USER == 1:
+ avatars = primary_avatar
+ else:
+ # Slice the default set now that we used the queryset for the primary avatar
+ avatars = avatars[:AVATAR_MAX_AVATARS_PER_USER]
+ return (avatar, avatars)
+
+@login_required
+def add(request, extra_context=None, next_override=None,
+ upload_form=UploadAvatarForm, *args, **kwargs):
+ if extra_context is None:
+ extra_context = {}
+ avatar, avatars = _get_avatars(request.user)
+ upload_avatar_form = upload_form(request.POST or None,
+ request.FILES or None, user=request.user)
+ if request.method == "POST" and 'avatar' in request.FILES:
+ if upload_avatar_form.is_valid():
+ avatar = Avatar(
+ user = request.user,
+ primary = True,
+ )
+ image_file = request.FILES['avatar']
+ avatar.avatar.save(image_file.name, image_file)
+ avatar.save()
+ request.user.message_set.create(
+ message=_("Successfully uploaded a new avatar."))
+ if notification:
+ _notification_updated(request, avatar)
+ return HttpResponseRedirect(next_override or _get_next(request))
+ data = {
+ 'avatar': avatar,
+ 'avatars': avatars,
+ 'upload_avatar_form': upload_avatar_form,
+ 'next': next_override or _get_next(request),
+ 'view_user': request.user,
+ 'page_class': 'avatar-page',
+ }
+ if extra_context:
+ data.update(extra_context)
+
+ return render_into_skin('avatar/add.html', data, request)
+
+@login_required
+def change(request, extra_context=None, next_override=None,
+ upload_form=UploadAvatarForm, primary_form=PrimaryAvatarForm,
+ *args, **kwargs):
+ if extra_context is None:
+ extra_context = {}
+ avatar, avatars = _get_avatars(request.user)
+ if avatar:
+ kwargs = {'initial': {'choice': avatar.id}}
+ else:
+ kwargs = {}
+ upload_avatar_form = upload_form(user=request.user, **kwargs)
+ primary_avatar_form = primary_form(request.POST or None,
+ user=request.user, avatars=avatars, **kwargs)
+ if request.method == "POST":
+ updated = False
+ if 'choice' in request.POST and primary_avatar_form.is_valid():
+ avatar = Avatar.objects.get(id=
+ primary_avatar_form.cleaned_data['choice'])
+ avatar.primary = True
+ avatar.save()
+ updated = True
+ request.user.message_set.create(
+ message=_("Successfully updated your avatar."))
+ if updated and notification:
+ _notification_updated(request, avatar)
+ return HttpResponseRedirect(next_override or _get_next(request))
+ data = {
+ 'avatar': avatar,
+ 'avatars': avatars,
+ 'upload_avatar_form': upload_avatar_form,
+ 'primary_avatar_form': primary_avatar_form,
+ 'next': next_override or _get_next(request),
+ 'view_user': request.user,
+ 'page_class': 'avatar-page',
+ }
+ if extra_context:
+ data.update(extra_context)
+
+ return render_into_skin('avatar/change.html', data, request)
+
+@login_required
+def delete(request, extra_context=None, next_override=None, *args, **kwargs):
+ if extra_context is None:
+ extra_context = {}
+ avatar, avatars = _get_avatars(request.user)
+ delete_avatar_form = DeleteAvatarForm(request.POST or None,
+ user=request.user, avatars=avatars)
+ if request.method == 'POST':
+ if delete_avatar_form.is_valid():
+ ids = delete_avatar_form.cleaned_data['choices']
+ if unicode(avatar.id) in ids and avatars.count() > len(ids):
+ # Find the next best avatar, and set it as the new primary
+ for a in avatars:
+ if unicode(a.id) not in ids:
+ a.primary = True
+ a.save()
+ if notification:
+ _notification_updated(request, a)
+ break
+ Avatar.objects.filter(id__in=ids).delete()
+ request.user.message_set.create(
+ message=_("Successfully deleted the requested avatars."))
+ return HttpResponseRedirect(next_override or _get_next(request))
+ data = {
+ 'avatar': avatar,
+ 'avatars': avatars,
+ 'delete_avatar_form': delete_avatar_form,
+ 'next': next_override or _get_next(request),
+ 'view_user': request.user,
+ 'page_class': 'avatar-page',
+ }
+ if extra_context:
+ data.update(extra_context)
+
+ return render_into_skin('avatar/confirm_delete.html', data, request)
diff --git a/askbot/views/commands.py b/askbot/views/commands.py
index 302f0200..8d16c35f 100644
--- a/askbot/views/commands.py
+++ b/askbot/views/commands.py
@@ -5,25 +5,21 @@ This module contains most (but not all) processors for Ajax requests.
Not so clear if this subdivision was necessary as separation of Ajax and non-ajax views
is not always very clean.
"""
-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.conf import settings as django_settings
from django.core import exceptions
+from django.core.urlresolvers import reverse
+from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseRedirect
-from django.http import HttpResponseForbidden
-from django.shortcuts import get_object_or_404, render_to_response
+from django.forms import ValidationError
+from django.shortcuts import get_object_or_404
+from django.utils import simplejson
from django.utils.translation import ugettext as _
-from django.template import RequestContext
from askbot import models
-from askbot.forms import CloseForm
-from askbot import auth
-from django.core.urlresolvers import reverse
-from django.contrib.auth.decorators import login_required
-from askbot.utils.decorators import ajax_only, ajax_login_required
-from askbot.templatetags import extra_filters as template_filters
-from askbot.skins.loaders import ENV
+from askbot import forms
+from askbot.conf import should_show_sort_by_relevance
+from askbot.conf import settings as askbot_settings
+from askbot.utils import decorators
+from askbot.skins.loaders import render_into_skin
from askbot import const
import logging
@@ -334,43 +330,145 @@ def vote(request, id):
return HttpResponse(data, mimetype="application/json")
#internally grouped views - used by the tagging system
-@ajax_login_required
-def mark_tag(request, tag=None, **kwargs):#tagging system
+@decorators.ajax_login_required
+def mark_tag(request, **kwargs):#tagging system
action = kwargs['action']
- ts = models.MarkedTag.objects.filter(user=request.user, tag__name=tag)
- if action == 'remove':
- logging.debug('deleting tag %s' % tag)
- ts.delete()
- else:
- reason = kwargs['reason']
- if len(ts) == 0:
- try:
- t = models.Tag.objects.get(name=tag)
- mt = models.MarkedTag(user=request.user, reason=reason, tag=t)
- mt.save()
- except:
- pass
+ post_data = simplejson.loads(request.raw_post_data)
+ raw_tagnames = post_data['tagnames']
+ reason = kwargs.get('reason', None)
+ #separate plain tag names and wildcard tags
+
+ tagnames, wildcards = forms.clean_marked_tagnames(raw_tagnames)
+ cleaned_tagnames, cleaned_wildcards = request.user.mark_tags(
+ tagnames,
+ wildcards,
+ reason = reason,
+ action = action
+ )
+
+ #lastly - calculate tag usage counts
+ tag_usage_counts = dict()
+ for name in tagnames:
+ if name in cleaned_tagnames:
+ tag_usage_counts[name] = 1
+ else:
+ tag_usage_counts[name] = 0
+
+ for name in wildcards:
+ if name in cleaned_wildcards:
+ tag_usage_counts[name] = models.Tag.objects.filter(
+ name__startswith = name[:-1]
+ ).count()
else:
- ts.update(reason=reason)
- return HttpResponse(simplejson.dumps(''), mimetype="application/json")
+ tag_usage_counts[name] = 0
+
+ return HttpResponse(simplejson.dumps(tag_usage_counts), mimetype="application/json")
-@ajax_login_required
-def ajax_toggle_ignored_questions(request):#ajax tagging and tag-filtering system
- if request.user.hide_ignored_questions:
- new_hide_setting = False
+#@decorators.ajax_only
+@decorators.get_only
+def get_tags_by_wildcard(request):
+ """returns an json encoded array of tag names
+ in the response to a wildcard tag name
+ """
+ matching_tags = models.Tag.objects.get_by_wildcards(
+ [request.GET['wildcard'],]
+ )
+ count = matching_tags.count()
+ names = matching_tags.values_list('name', flat = True)[:20]
+ re_data = simplejson.dumps({'tag_count': count, 'tag_names': list(names)})
+ return HttpResponse(re_data, mimetype = 'application/json')
+
+@decorators.get_only
+def get_tag_list(request):
+ """returns tags to use in the autocomplete
+ function
+ """
+ tag_names = models.Tag.objects.filter(
+ deleted = False
+ ).values_list(
+ 'name', flat = True
+ )
+ output = '\n'.join(tag_names)
+ return HttpResponse(output, mimetype = "text/plain")
+
+def subscribe_for_tags(request):
+ """process subscription of users by tags"""
+ #todo - use special separator to split tags
+ tag_names = request.REQUEST.get('tags','').strip().split()
+ pure_tag_names, wildcards = forms.clean_marked_tagnames(tag_names)
+ if request.user.is_authenticated():
+ if request.method == 'POST':
+ if 'ok' in request.POST:
+ request.user.mark_tags(
+ pure_tag_names,
+ wildcards,
+ reason = 'good',
+ action = 'add'
+ )
+ request.user.message_set.create(
+ message = _('Your tag subscription was saved, thanks!')
+ )
+ else:
+ message = _(
+ 'Tag subscription was canceled (<a href="%(url)s">undo</a>).'
+ ) % {'url': request.path + '?tags=' + request.REQUEST['tags']}
+ request.user.message_set.create(message = message)
+ return HttpResponseRedirect(reverse('index'))
+ else:
+ data = {'tags': tag_names}
+ return render_into_skin('subscribe_for_tags.html', data, request)
else:
- new_hide_setting = True
- request.user.hide_ignored_questions = new_hide_setting
- request.user.save()
+ all_tag_names = pure_tag_names + wildcards
+ message = _('Please sign in to subscribe for: %(tags)s') \
+ % {'tags': ', '.join(all_tag_names)}
+ request.user.message_set.create(message = message)
+ request.session['subscribe_for_tags'] = (pure_tag_names, wildcards)
+ return HttpResponseRedirect(reverse('user_signin'))
+
+
+@decorators.get_only
+def api_get_questions(request):
+ """json api for retrieving questions
+ todo - see if it is possible to integrate this with the
+ questions view
+ """
+ form = forms.AdvancedSearchForm(request.GET)
+ if form.is_valid():
+ query = form.cleaned_data['query']
+ questions = models.Question.objects.get_by_text_query(query)
+ if should_show_sort_by_relevance():
+ questions = questions.extra(order_by = ['-relevance'])
+ questions = questions.distinct()
+ page_size = form.cleaned_data.get('page_size', 30)
+ questions = questions[:page_size]
+
+
+ question_list = list()
+ for question in questions:
+ question_list.append({
+ 'url': question.get_absolute_url(),
+ 'title': question.title,
+ 'answer_count': question.answer_count
+ })
+ json_data = simplejson.dumps(question_list)
+ return HttpResponse(json_data, mimetype = "application/json")
+ else:
+ raise ValidationError('InvalidInput')
-@ajax_only
-def ajax_command(request):
- """view processing ajax commands - note "vote" and view others do it too
+
+@decorators.ajax_login_required
+def set_tag_filter_strategy(request):
+ """saves data in the ``User.display_tag_filter_strategy``
+ for the current user
"""
- if 'command' not in request.POST:
- raise exceptions.PermissionDenied(_('Bad request'))
- if request.POST['command'] == 'toggle-ignored-questions':
- return ajax_toggle_ignored_questions(request)
+ filter_type = request.POST['filter_type']
+ filter_value = int(request.POST['filter_value'])
+ assert(filter_type == 'display')
+ assert(filter_value in dict(const.TAG_FILTER_STRATEGY_CHOICES))
+ request.user.display_tag_filter_strategy = filter_value
+ request.user.save()
+ return HttpResponse('', mimetype = "application/json")
+
@login_required
def close(request, id):#close question
@@ -380,7 +478,7 @@ def close(request, id):#close question
question = get_object_or_404(models.Question, id=id)
try:
if request.method == 'POST':
- form = CloseForm(request.POST)
+ form = forms.CloseForm(request.POST)
if form.is_valid():
reason = form.cleaned_data['reason']
@@ -391,11 +489,12 @@ def close(request, id):#close question
return HttpResponseRedirect(question.get_absolute_url())
else:
request.user.assert_can_close_question(question)
- form = CloseForm()
- template = ENV.get_template('close.html')
- data = {'form': form, 'question': question}
- context = RequestContext(request, data)
- return HttpResponse(template.render(context))
+ form = forms.CloseForm()
+ data = {
+ 'question': question,
+ 'form': form,
+ }
+ return render_into_skin('close.html', data, request)
except exceptions.PermissionDenied, e:
request.user.message_set.create(message = unicode(e))
return HttpResponseRedirect(question.get_absolute_url())
@@ -423,9 +522,7 @@ def reopen(request, id):#re-open question
'closed_by_profile_url': closed_by_profile_url,
'closed_by_username': closed_by_username,
}
- context = RequestContext(request, data)
- template = ENV.get_template('reopen.html')
- return HttpResponse(template.render(context))
+ return render_into_skin('reopen.html', data, request)
except exceptions.PermissionDenied, e:
request.user.message_set.create(message = unicode(e))
diff --git a/askbot/views/meta.py b/askbot/views/meta.py
index 9a3b89ae..0e67f08f 100644
--- a/askbot/views/meta.py
+++ b/askbot/views/meta.py
@@ -16,15 +16,13 @@ from askbot.utils.forms import get_next_url
from askbot.utils.mail import mail_moderators
from askbot.models import BadgeData, Award, User
from askbot.models import badges as badge_data
-from askbot.skins.loaders import ENV
+from askbot.skins.loaders import render_into_skin
from askbot.conf import settings as askbot_settings
from askbot import skins
-import askbot
def generic_view(request, template = None, page_class = None):
- template = ENV.get_template(template)
- context = RequestContext(request, {'page_class': page_class})
- return HttpResponse(template.render(context))
+ """this may be not necessary, since it is just a rewrite of render_into_skin"""
+ return render_into_skin(template, {'page_class': page_class}, request)
def config_variable(request, variable_name = None, mimetype = None):
"""Print value from the configuration settings
@@ -43,19 +41,16 @@ def server_error(request, template='500.html'):
return generic_view(request, template)
def faq(request):
- template = ENV.get_template('faq.html')
data = {
- 'view_name':'faq',
'gravatar_faq_url': reverse('faq') + '#gravatar',
#'send_email_key_url': reverse('send_email_key'),
'ask_question_url': reverse('ask'),
'page_class': 'meta',
}
- context = RequestContext(request, data)
- return HttpResponse(template.render(context))
+ return render_into_skin('faq.html', data, request)
def feedback(request):
- data = {'view_name':'feedback', 'page_class': 'meta'}
+ data = {'page_class': 'meta'}
form = None
if request.method == "POST":
form = FeedbackForm(request.POST)
@@ -73,32 +68,17 @@ def feedback(request):
form = FeedbackForm(initial={'next':get_next_url(request)})
data['form'] = form
- context = RequestContext(request, data)
- template = ENV.get_template('feedback.html')
- return HttpResponse(template.render(context))
+ return render_into_skin('feedback.html', data, request)
feedback.CANCEL_MESSAGE=_('We look forward to hearing your feedback! Please, give it next time :)')
def privacy(request):
- context = RequestContext(request, {'view_name':'privacy', 'page_class': 'meta'})
- template = ENV.get_template('privacy.html')
- return HttpResponse(template.render(context))
-
-def logout(request):#refactor/change behavior?
-#currently you click logout and you get
-#to this view which actually asks you again - do you really want to log out?
-#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 forum, but
-#if you really want to log out -> go to your openid provider
+ return render_into_skin('privacy.html', {'page_class': 'meta'}, request)
+
+def logout(request):
data = {
- 'view_name':'logout',
- 'next' : get_next_url(request),
'page_class': 'meta',
}
- context = RequestContext(request, data)
- template = ENV.get_template('logout.html')
- return HttpResponse(template.render(context))
+ return render_into_skin('logout.html', data, request)
def badges(request):#user status/reputation system
#todo: supplement database data with the stuff from badges.py
@@ -113,16 +93,14 @@ def badges(request):#user status/reputation system
).distinct()
#my_badges.query.group_by = ['badge_id']
- template = ENV.get_template('badges.html')
data = {
'active_tab': 'badges',
'badges' : badges,
- 'view_name': 'badges',
+ 'page_class': 'meta',
'mybadges' : my_badges,
'feedback_faq_url' : reverse('feedback'),
}
- context = RequestContext(request, data)
- return HttpResponse(template.render(context))
+ return render_into_skin('badges.html', data, request)
def badge(request, id):
#todo: supplement database data with the stuff from badges.py
@@ -136,16 +114,13 @@ def badge(request, id):
'-last_awarded_at'
)
- template = ENV.get_template('badge.html')
data = {
- 'view_name': badge,
'active_tab': 'badges',
'badge_recipients' : badge_recipients,
'badge' : badge,
'page_class': 'meta',
}
- context = RequestContext(request, data)
- return HttpResponse(template.render(context))
+ return render_into_skin('badge.html', data, request)
def media(request, skin, resource):
"""view that serves static media from any skin
diff --git a/askbot/views/readers.py b/askbot/views/readers.py
index 6fb2fd43..20a0df58 100644
--- a/askbot/views/readers.py
+++ b/askbot/views/readers.py
@@ -9,43 +9,33 @@ allow adding new comments via Ajax form post.
import datetime
import logging
import urllib
-from django.conf import settings
-from django.shortcuts import render_to_response, get_object_or_404
-from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden, Http404
+from django.shortcuts import get_object_or_404
+from django.http import HttpResponseRedirect, HttpResponse, Http404
from django.core.paginator import Paginator, EmptyPage, InvalidPage
-from django.template import RequestContext, Context
-from django.template import defaultfilters
-from django.utils.html import *
+from django.template import Context
from django.utils.http import urlencode
from django.utils import simplejson
from django.utils.translation import ugettext as _
from django.utils.translation import ungettext
from django.utils import translation
from django.core.urlresolvers import reverse
-from django.views.decorators.cache import cache_page
from django.core import exceptions as django_exceptions
from django.contrib.humanize.templatetags import humanize
import askbot
from askbot import exceptions
-from askbot.utils.html import sanitize_html
-#from lxml.html.diff import htmldiff
from askbot.utils.diff import textDiff as htmldiff
from askbot.forms import AdvancedSearchForm, AnswerForm, ShowQuestionForm
from askbot import models
from askbot.models.badges import award_badges_signal
from askbot import const
-from askbot import auth
-from askbot.utils import markup
-from askbot.utils.forms import get_next_url
from askbot.utils import functions
from askbot.utils.decorators import anonymous_forbidden, ajax_only, get_only
from askbot.search.state_manager import SearchState
from askbot.templatetags import extra_tags
from askbot.templatetags import extra_filters
import askbot.conf
-from askbot.conf import settings as askbot_settings
-from askbot.skins.loaders import ENV #jinja2 template loading enviroment
+from askbot.skins.loaders import render_into_skin, get_template#jinja2 template loading enviroment
# used in index page
#todo: - take these out of const or settings
@@ -57,19 +47,6 @@ DEFAULT_PAGE_SIZE = 60
# used in questions
# used in answers
-#system to display main content
-def _get_tags_cache_json():#service routine used by views requiring tag list in the javascript space
- """returns list of all tags in json format
- no caching yet, actually
- """
- tags = models.Tag.objects.filter(deleted=False).all()
- tags_list = []
- for tag in tags:
- dic = {'n': tag.name, 'c': tag.used_count}
- tags_list.append(dic)
- tags = simplejson.dumps(tags_list)
- return tags
-
#refactor? - we have these
#views that generate a listing of questions in one way or another:
#index, unanswered, questions, search, tag
@@ -86,39 +63,22 @@ def questions(request):
List of Questions, Tagged questions, and Unanswered questions.
matching search query or user selection
"""
+ #before = datetime.datetime.now()
#don't allow to post to this view
if request.method == 'POST':
raise Http404
- #todo: redo SearchState to accept input from
- #view_log, session and request parameters
- search_state = request.session.get('search_state', SearchState())
-
- view_log = request.session['view_log']
-
- if view_log.get_previous(1) != 'questions':
- if view_log.get_previous(2) != 'questions':
- #print 'user stepped too far, resetting search state'
- search_state.reset()
-
- if request.user.is_authenticated():
- search_state.set_logged_in()
-
+ #update search state
form = AdvancedSearchForm(request.GET)
- #todo: form is used only for validation...
if form.is_valid():
- search_state.update_from_user_input(
- form.cleaned_data,
- request.GET,
- )
- #todo: better put these in separately then analyze
- #what neesd to be done, otherwise there are two routines
- #that take request.GET I don't like this use of parameters
- #another weakness is that order of routine calls matters here
- search_state.relax_stickiness( request.GET, view_log )
-
- request.session['search_state'] = search_state
- request.session.modified = True
+ user_input = form.cleaned_data
+ else:
+ user_input = None
+ search_state = request.session.get('search_state', SearchState())
+ view_log = request.session['view_log']
+ search_state.update(user_input, view_log, request.user)
+ request.session['search_state'] = search_state
+ request.session.modified = True
#force reset for debugging
#search_state.reset()
@@ -154,16 +114,25 @@ def questions(request):
if request.is_ajax():
q_count = paginator.count
- question_counter = ungettext(
- '%(q_num)s question',
- '%(q_num)s questions',
- q_count
- ) % {
- 'q_num': humanize.intcomma(q_count),
- }
+ if search_state.tags:
+ question_counter = ungettext(
+ '%(q_num)s question, tagged',
+ '%(q_num)s questions, tagged',
+ q_count
+ ) % {
+ 'q_num': humanize.intcomma(q_count),
+ }
+ else:
+ question_counter = ungettext(
+ '%(q_num)s question',
+ '%(q_num)s questions',
+ q_count
+ ) % {
+ 'q_num': humanize.intcomma(q_count),
+ }
if q_count > search_state.page_size:
- paginator_tpl = ENV.get_template('paginator.html')
+ paginator_tpl = get_template('blocks/paginator.html', request)
#todo: remove this patch on context after all templates are moved to jinja
paginator_context['base_url'] = request.path + '?sort=%s&' % search_state.sort
data = {
@@ -172,9 +141,17 @@ def questions(request):
paginator_html = paginator_tpl.render(Context(data))
else:
paginator_html = ''
+ search_tags = list()
+ if search_state.tags:
+ search_tags = list(search_state.tags)
+ query_data = {
+ 'tags': search_tags,
+ 'sort_order': search_state.sort
+ }
ajax_data = {
#current page is 1 by default now
#because ajax is only called by update in the search button
+ 'query_data': query_data,
'paginator': paginator_html,
'question_counter': question_counter,
'questions': list(),
@@ -228,6 +205,10 @@ def questions(request):
else:
views_class = 'some-views'
+ country_code = None
+ if author.country and author.show_country:
+ country_code = author.country.code
+
question_data = {
'title': question.title,
'summary': question.summary,
@@ -268,6 +249,8 @@ def questions(request):
),
'u_bronze_badge_symbol': const.BADGE_DISPLAY_SYMBOL,
'u_bronze_css_class': bronze_badge_css_class,
+ 'u_country_code': country_code,
+ 'u_is_anonymous': question.is_anonymous,
}
ajax_data['questions'].append(question_data)
@@ -276,8 +259,6 @@ def questions(request):
mimetype = 'application/json'
)
- tags_autocomplete = _get_tags_cache_json()
-
reset_method_count = 0
if search_state.query:
reset_method_count += 1
@@ -286,61 +267,39 @@ def questions(request):
if meta_data.get('author_name',None):
reset_method_count += 1
- template_context = RequestContext(request, {
- 'language_code': translation.get_language(),
- 'reset_method_count': reset_method_count,
- 'view_name': 'questions',
+ template_data = {
'active_tab': 'questions',
- 'questions' : page,
- 'contributors' : contributors,
'author_name' : meta_data.get('author_name',None),
- 'tab_id' : search_state.sort,
- 'questions_count' : paginator.count,
- 'tags' : related_tags,
- 'query': search_state.query,
- 'search_tags' : search_state.tags,
- 'tags_autocomplete' : tags_autocomplete,
+ 'contributors' : contributors,
+ 'context' : paginator_context,
'is_unanswered' : False,#remove this from template
'interesting_tag_names': meta_data.get('interesting_tag_names',None),
'ignored_tag_names': meta_data.get('ignored_tag_names',None),
- 'sort': search_state.sort,
- 'show_sort_by_relevance': askbot.conf.should_show_sort_by_relevance(),
+ 'language_code': translation.get_language(),
+ 'name_of_anonymous_user' : models.get_name_of_anonymous_user(),
+ 'page_class': 'main-page',
+ 'query': search_state.query,
+ 'questions' : page,
+ 'questions_count' : paginator.count,
+ 'reset_method_count': reset_method_count,
'scope': search_state.scope,
- 'context' : paginator_context,
- })
+ 'show_sort_by_relevance': askbot.conf.should_show_sort_by_relevance(),
+ 'search_tags' : search_state.tags,
+ 'sort': search_state.sort,
+ 'tab_id' : search_state.sort,
+ 'tags' : related_tags,
+ 'tag_filter_strategy_choices': const.TAG_FILTER_STRATEGY_CHOICES,
+ }
assert(request.is_ajax() == False)
#ajax request is handled in a separate branch above
#before = datetime.datetime.now()
- template = ENV.get_template('questions.html')
- response = HttpResponse(template.render(template_context))
+ response = render_into_skin('main_page.html', template_data, request)
#after = datetime.datetime.now()
#print after - before
return response
-def search(request): #generates listing of questions matching a search query - including tags and just words
- """redirects to people and tag search pages
- todo: eliminate this altogether and instead make
- search "tab" sensitive automatically - the radio-buttons
- are useless under the search bar
- """
- if request.method == "GET":
- search_type = request.GET.get('t')
- query = request.GET.get('query')
- try:
- page = int(request.GET.get('page', '1'))
- except ValueError:
- page = 1
- if search_type == 'tag':
- return HttpResponseRedirect(reverse('tags') + '?' + urlencode({'q':query.strip(),'page': page}))
- elif search_type == 'user':
- return HttpResponseRedirect(reverse('users') + '?' + urlencode({'q':query.strip(),'page': page}))
- else:
- raise Http404
- else:
- raise Http404
-
def tags(request):#view showing a listing of available tags - plain list
stag = ""
is_paginated = True
@@ -351,9 +310,17 @@ def tags(request):#view showing a listing of available tags - plain list
page = 1
if request.method == "GET":
- stag = request.GET.get("q", "").strip()
+ stag = request.GET.get("query", "").strip()
if stag != '':
- objects_list = Paginator(models.Tag.objects.filter(deleted=False).exclude(used_count=0).extra(where=['name like %s'], params=['%' + stag + '%']), DEFAULT_PAGE_SIZE)
+ objects_list = Paginator(
+ models.Tag.objects.filter(
+ deleted=False,
+ name__icontains=stag
+ ).exclude(
+ used_count=0
+ ),
+ DEFAULT_PAGE_SIZE
+ )
else:
if sortby == "name":
objects_list = Paginator(models.Tag.objects.all().filter(deleted=False).exclude(used_count=0).order_by("name"), DEFAULT_PAGE_SIZE)
@@ -377,17 +344,15 @@ def tags(request):#view showing a listing of available tags - plain list
}
paginator_context = extra_tags.cnprog_paginator(paginator_data)
data = {
- 'view_name':'tags',
'active_tab': 'tags',
+ 'page_class': 'tags-page',
'tags' : tags,
'stag' : stag,
'tab_id' : sortby,
'keywords' : stag,
'paginator_context' : paginator_context
}
- context = RequestContext(request, data)
- template = ENV.get_template('tags.html')
- return HttpResponse(template.render(context))
+ return render_into_skin('tags.html', data, request)
def question(request, id):#refactor - long subroutine. display question body, answers and comments
"""view that displays body of the question and
@@ -410,8 +375,6 @@ def question(request, id):#refactor - long subroutine. display question body, an
#in the case if the permalinked items or their parents are gone - redirect
#redirect also happens if id of the object's origin post != requested id
show_post = None #used for permalinks
- #import pdb
- #pdb.set_trace()
if show_comment is not None:
#comments
try:
@@ -501,7 +464,7 @@ def question(request, id):#refactor - long subroutine. display question body, an
objects_list = Paginator(filtered_answers, const.ANSWERS_PAGE_SIZE)
if show_page > objects_list.num_pages:
- return HttpResponseRediect(question.get_absolute_url())
+ return HttpResponseRedirect(question.get_absolute_url())
page_objects = objects_list.page(show_page)
#count visits
@@ -566,7 +529,7 @@ def question(request, id):#refactor - long subroutine. display question body, an
data = {
- 'view_name': 'question',
+ 'page_class': 'question-page',
'active_tab': 'questions',
'question' : question,
'question_vote' : question_vote,
@@ -584,11 +547,7 @@ def question(request, id):#refactor - long subroutine. display question body, an
'show_comment': show_comment,
'comment_order_number': comment_order_number
}
- if request.user.is_authenticated():
- data['tags_autocomplete'] = _get_tags_cache_json()
- context = RequestContext(request, data)
- template = ENV.get_template('question.html')
- return HttpResponse(template.render(context))
+ return render_into_skin('question.html', data, request)
def revisions(request, id, object_name=None):
assert(object_name in ('Question', 'Answer'))
@@ -603,14 +562,12 @@ def revisions(request, id, object_name=None):
else:
revision.diff = htmldiff(revisions[i-1].html, revision.html)
data = {
- 'view_name':'answer_revisions',
+ 'page_class':'revisions-page',
'active_tab':'questions',
'post': post,
'revisions': revisions,
}
- context = RequestContext(request, data)
- template = ENV.get_template('revisions.html')
- return HttpResponse(template.render(context))
+ return render_into_skin('revisions.html', data, request)
@ajax_only
@anonymous_forbidden
diff --git a/askbot/views/users.py b/askbot/views/users.py
index 03877974..0db7124e 100644
--- a/askbot/views/users.py
+++ b/askbot/views/users.py
@@ -10,30 +10,27 @@ import calendar
import functools
import datetime
import logging
-from django.db.models import Sum, Count
+from django.db.models import Count
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator, EmptyPage, InvalidPage
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
+from django.shortcuts import get_object_or_404
+from django.http import HttpResponse
from django.http import HttpResponseRedirect, Http404
from django.utils.translation import ugettext as _
-from django.utils import simplejson
from django.conf import settings as django_settings
-import askbot
from askbot.utils.slug import slugify
from askbot.utils.html import sanitize_html
from askbot.utils.mail import send_mail
-from askbot import auth
+from askbot.utils.http import get_request_info
from askbot import forms
from askbot import const
from askbot.conf import settings as askbot_settings
from askbot import models
from askbot import exceptions
from askbot.models.badges import award_badges_signal
-from askbot.skins.loaders import ENV
+from askbot.skins.loaders import render_into_skin
from askbot.templatetags import extra_tags
question_type = ContentType.objects.get_for_model(models.Question)
@@ -69,7 +66,7 @@ def owner_or_moderator_required(f):
def users(request):
is_paginated = True
sortby = request.GET.get('sort', 'reputation')
- suser = request.REQUEST.get('q', "")
+ suser = request.REQUEST.get('query', "")
try:
page = int(request.GET.get('page', '1'))
except ValueError:
@@ -96,9 +93,8 @@ def users(request):
else:
sortby = "reputation"
objects_list = Paginator(
- models.User.objects.extra(
- where=['username like %s'],
- params=['%' + suser + '%']
+ models.User.objects.filter(
+ username__icontains = suser
).order_by(
'-reputation'
),
@@ -124,15 +120,14 @@ def users(request):
paginator_context = extra_tags.cnprog_paginator(paginator_data)
data = {
'active_tab': 'users',
+ 'page_class': 'users-page',
'users' : users_page,
'suser' : suser,
'keywords' : suser,
'tab_id' : sortby,
'paginator_context' : paginator_context
}
- template = ENV.get_template('users.html')
- context = RequestContext(request, data)
- return HttpResponse(template.render(context))
+ return render_into_skin('users.html', data, request)
def user_moderate(request, subject):
"""user subview for moderation
@@ -212,6 +207,7 @@ def user_moderate(request, subject):
)
data = {
'active_tab': 'users',
+ 'page_class': 'user-profile-page',
'tab_name': 'moderation',
'tab_description': _('moderate this user'),
'page_title': _('moderate user'),
@@ -224,9 +220,7 @@ def user_moderate(request, subject):
'user_rep_changed': user_rep_changed,
'user_status_changed': user_status_changed
}
- context = RequestContext(request, data)
- template = ENV.get_template('user_moderate.html')
- return HttpResponse(template.render(context))
+ return render_into_skin('user_profile/user_moderate.html', data, request)
#non-view function
def set_new_email(user, new_email, nomessage=False):
@@ -260,6 +254,8 @@ def edit_user(request, id):
user.location = sanitize_html(form.cleaned_data['city'])
user.date_of_birth = form.cleaned_data.get('birthday', None)
user.about = sanitize_html(form.cleaned_data['about'])
+ user.country = form.cleaned_data['country']
+ user.show_country = form.cleaned_data['show_country']
user.save()
# send user updated signal if full fields have been updated
@@ -273,17 +269,20 @@ def edit_user(request, id):
form = forms.EditUserForm(user)
data = {
'active_tab': 'users',
+ 'page_class': 'user-profile-edit-page',
'form' : form,
'gravatar_faq_url' : reverse('faq') + '#gravatar',
}
- context = RequestContext(request, data)
- template = ENV.get_template('user_edit.html')
- return HttpResponse(template.render(context))
+ return render_into_skin('user_profile/user_edit.html', data, request)
def user_stats(request, user):
+ question_filter = {'author': user}
+ if request.user != user:
+ question_filter['is_anonymous'] = False
+
questions = models.Question.objects.filter(
- author = user
+ **question_filter
).order_by(
'-score', '-last_activity_at'
).select_related(
@@ -372,6 +371,8 @@ def user_stats(request, user):
data = {
'active_tab':'users',
+ 'page_class': 'user-profile-page',
+ 'support_custom_avatars': ('avatar' in django_settings.INSTALLED_APPS),
'tab_name' : 'stats',
'tab_description' : _('user profile'),
'page_title' : _('user profile overview'),
@@ -390,9 +391,7 @@ def user_stats(request, user):
'awarded_badge_counts': dict(awarded_badge_counts),
'total_awards' : total_awards,
}
- context = RequestContext(request, data)
- template = ENV.get_template('user_stats.html')
- return HttpResponse(template.render(context))
+ return render_into_skin('user_profile/user_stats.html', data, request)
def user_recent(request, user):
@@ -657,15 +656,14 @@ def user_recent(request, user):
data = {
'active_tab': 'users',
+ 'page_class': 'user-profile-page',
'tab_name' : 'recent',
'tab_description' : _('recent user activity'),
'page_title' : _('profile - recent activity'),
'view_user' : user,
'activities' : activities[:const.USER_VIEW_DATA_SIZE]
}
- context = RequestContext(request, data)
- template = ENV.get_template('user_recent.html')
- return HttpResponse(template.render(context))
+ return render_into_skin('user_profile/user_recent.html', data, request)
@owner_or_moderator_required
def user_responses(request, user):
@@ -724,6 +722,7 @@ def user_responses(request, user):
data = {
'active_tab':'users',
+ 'page_class': 'user-profile-page',
'tab_name' : 'inbox',
'inbox_section':section,
'tab_description' : _('comments and answers to others questions'),
@@ -731,9 +730,7 @@ def user_responses(request, user):
'view_user' : user,
'responses' : response_list,
}
- context = RequestContext(request, data)
- template = ENV.get_template('user_inbox.html')
- return HttpResponse(template.render(context))
+ return render_into_skin('user_profile/user_inbox.html', data, request)
@owner_or_moderator_required
def user_votes(request, user):
@@ -790,15 +787,14 @@ def user_votes(request, user):
data = {
'active_tab':'users',
+ 'page_class': 'user-profile-page',
'tab_name' : 'votes',
'tab_description' : _('user vote record'),
'page_title' : _('profile - votes'),
'view_user' : user,
'votes' : votes[:const.USER_VIEW_DATA_SIZE]
}
- context = RequestContext(request, data)
- template = ENV.get_template('user_votes.html')
- return HttpResponse(template.render(context))
+ return render_into_skin('user_profile/user_votes.html', data, request)
def user_reputation(request, user):
reputes = models.Repute.objects.filter(user=user).order_by('-reputed_at')
@@ -808,8 +804,6 @@ def user_reputation(request, user):
'question__id',
'user__username'
)
- #reputes = reputates.annotate(positive=Sum("positive"), negative=Sum("negative"))
-
#prepare data for the graph
rep_list = []
#last values go in first
@@ -829,6 +823,7 @@ def user_reputation(request, user):
data = {
'active_tab':'users',
+ 'page_class': 'user-profile-page',
'tab_name': 'reputation',
'tab_description': _('user reputation in the community'),
'page_title': _('profile - user reputation'),
@@ -836,9 +831,7 @@ def user_reputation(request, user):
'reputation': reputes,
'reps': reps
}
- context = RequestContext(request, data)
- template = ENV.get_template('user_reputation.html')
- return HttpResponse(template.render(context))
+ return render_into_skin('user_profile/user_reputation.html', data, request)
def user_favorites(request, user):
favorited_q_id_list= models.FavoriteQuestion.objects.filter(
@@ -858,6 +851,7 @@ def user_favorites(request, user):
)[:const.USER_VIEW_DATA_SIZE]
data = {
'active_tab':'users',
+ 'page_class': 'user-profile-page',
'tab_name' : 'favorites',
'tab_description' : _('users favorite questions'),
'page_title' : _('profile - favorite questions'),
@@ -865,13 +859,12 @@ def user_favorites(request, user):
'favorited_myself': favorited_q_id_list,
'view_user' : user
}
- context = RequestContext(request, data)
- template = ENV.get_template('user_favorites.html')
- return HttpResponse(template.render(context))
+ return render_into_skin('user_profile/user_favorites.html', data, request)
@owner_or_moderator_required
def user_email_subscriptions(request, user):
+ logging.debug(get_request_info(request))
if request.method == 'POST':
email_feeds_form = forms.EditUserEmailFeedsForm(request.POST)
tag_filter_form = forms.TagFilterSelectionForm(request.POST, instance=user)
@@ -897,9 +890,9 @@ def user_email_subscriptions(request, user):
tag_filter_form = forms.TagFilterSelectionForm(instance=user)
action_status = None
- template = ENV.get_template('user_email_subscriptions.html')
data = {
'active_tab': 'users',
+ 'page_class': 'user-profile-page',
'tab_name': 'email_subscriptions',
'tab_description': _('email subscription settings'),
'page_title': _('profile - email subscriptions'),
@@ -908,8 +901,11 @@ def user_email_subscriptions(request, user):
'tag_filter_selection_form': tag_filter_form,
'action_status': action_status,
}
- context = RequestContext(request, data)
- return HttpResponse(template.render(context))
+ return render_into_skin(
+ 'user_profile/user_email_subscriptions.html',
+ data,
+ request
+ )
user_view_call_table = {
'stats': user_stats,
diff --git a/askbot/views/writers.py b/askbot/views/writers.py
index 0e294b4a..56b37154 100644
--- a/askbot/views/writers.py
+++ b/askbot/views/writers.py
@@ -4,16 +4,18 @@
This module contains views that allow adding, editing, and deleting main textual content.
"""
-import os.path
-import time
import datetime
-import random
import logging
+import os
+import os.path
+import random
+import sys
+import tempfile
+import time
from django.core.files.storage import FileSystemStorage
-from django.shortcuts import render_to_response, get_object_or_404
+from django.shortcuts import 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 import simplejson
from django.utils.html import strip_tags
from django.utils.translation import ugettext as _
@@ -21,14 +23,13 @@ from django.core.urlresolvers import reverse
from django.core import exceptions
from django.conf import settings
-from askbot import auth
-from askbot.views.readers import _get_tags_cache_json
from askbot import forms
from askbot import models
-from askbot.skins.loaders import ENV
+from askbot.skins.loaders import render_into_skin
from askbot.utils.decorators import ajax_only
from askbot.utils.functions import diff_date
from askbot.templatetags import extra_filters_jinja as template_filters
+from askbot.importers.stackexchange import management as stackexchange#todo: may change
# used in index page
INDEX_PAGE_SIZE = 20
@@ -45,7 +46,6 @@ def upload(request):#ajax upload file to a question or answer
"""view that handles file upload via Ajax
"""
- f = request.FILES['file-upload']
# check upload permission
result = ''
error = ''
@@ -59,6 +59,7 @@ def upload(request):#ajax upload file to a question or answer
request.user.assert_can_upload_file()
# check file type
+ f = request.FILES['file-upload']
file_extension = os.path.splitext(f.name)[1].lower()
if not file_extension in settings.ASKBOT_ALLOWED_UPLOAD_FILE_TYPES:
file_types = "', '".join(settings.ASKBOT_ALLOWED_UPLOAD_FILE_TYPES)
@@ -108,6 +109,81 @@ def upload(request):#ajax upload file to a question or answer
return HttpResponse(xml, mimetype="application/xml")
+def __import_se_data(dump_file):
+ """non-view function that imports the SE data
+ in the future may import other formats as well
+
+ In this function stdout is temporarily
+ redirected, so that the underlying importer management
+ command could stream the output to the browser
+
+ todo: maybe need to add try/except clauses to restore
+ the redirects in the exceptional situations
+ """
+
+ fake_stdout = tempfile.NamedTemporaryFile()
+ real_stdout = sys.stdout
+ sys.stdout = fake_stdout
+
+ importer = stackexchange.ImporterThread(dump_file = dump_file.name)
+ importer.start()
+
+ #run a loop where we'll be reading output of the
+ #importer tread and yielding it to the caller
+ read_stdout = open(fake_stdout.name, 'r')
+ file_pos = 0
+ fd = read_stdout.fileno()
+ yield '<html><body><style>* {font-family: sans;} p {font-size: 12px; line-height: 16px; margin: 0; padding: 0;}</style><h1>Importing your data. This may take a few minutes...</h1>'
+ while importer.isAlive():
+ c_size = os.fstat(fd).st_size
+ if c_size > file_pos:
+ line = read_stdout.readline()
+ yield '<p>' + line + '</p>'
+ file_pos = read_stdout.tell()
+
+ fake_stdout.close()
+ read_stdout.close()
+ dump_file.close()
+ sys.stdout = real_stdout
+ yield '<p>Done. Please, <a href="%s">Visit Your Forum</a></p></body></html>' % reverse('index')
+
+
+def import_data(request):
+ """a view allowing the site administrator
+ upload stackexchange data
+ """
+ #allow to use this view to site admins
+ #or when the forum in completely empty
+ if request.user.is_anonymous() or (not request.user.is_administrator()):
+ if models.Question.objects.count() > 0:
+ raise Http404
+
+ if request.method == 'POST':
+ #if not request.is_ajax():
+ # raise Http404
+
+ form = forms.DumpUploadForm(request.POST, request.FILES)
+ if form.is_valid():
+ dump_file = form.cleaned_data['dump_file']
+ dump_storage = tempfile.NamedTemporaryFile()
+
+ #save the temp file
+ for chunk in dump_file.chunks():
+ dump_storage.write(chunk)
+ dump_storage.flush()
+
+ return HttpResponse(__import_se_data(dump_storage))
+ #yield HttpResponse(_('StackExchange import complete.'), mimetype='text/plain')
+ #dump_storage.close()
+ else:
+ form = forms.DumpUploadForm()
+
+ data = {
+ 'dump_upload_form': form,
+ 'need_configuration': (not stackexchange.is_ready())
+ }
+ return render_into_skin('import_data.html', data, request)
+
#@login_required #actually you can post anonymously, but then must register
def ask(request):#view used to ask a new question
"""a view to ask a new question
@@ -120,7 +196,6 @@ def ask(request):#view used to ask a new question
if request.method == "POST":
form = forms.AskForm(request.POST)
if form.is_valid():
-
timestamp = datetime.datetime.now()
#todo: move this to clean_title
title = form.cleaned_data['title'].strip()
@@ -128,17 +203,18 @@ def ask(request):#view used to ask a new question
#todo: move this to clean_tagnames
tagnames = form.cleaned_data['tags'].strip()
text = form.cleaned_data['text']
+ ask_anonymously = form.cleaned_data['ask_anonymously']
if request.user.is_authenticated():
-
try:
question = request.user.post_question(
- title = title,
- body_text = text,
- tags = tagnames,
- wiki = wiki,
- timestamp = timestamp
- )
+ title = title,
+ body_text = text,
+ tags = tagnames,
+ wiki = wiki,
+ is_anonymous = ask_anonymously,
+ timestamp = timestamp
+ )
return HttpResponseRedirect(question.get_absolute_url())
except exceptions.PermissionDenied, e:
request.user.message_set.create(message = unicode(e))
@@ -153,6 +229,7 @@ def ask(request):#view used to ask a new question
title = title,
tagnames = tagnames,
wiki = wiki,
+ is_anonymous = ask_anonymously,
text = text,
summary = summary,
added_at = timestamp,
@@ -174,16 +251,13 @@ def ask(request):#view used to ask a new question
query = search_state.query
form.initial['title'] = query
- tags = _get_tags_cache_json()
- template = ENV.get_template('ask.html')
data = {
'active_tab': 'ask',
+ 'page_class': 'ask-page',
'form' : form,
- 'tags' : tags,
'email_validation_faq_url':reverse('faq') + '#validate',
}
- context = RequestContext(request, data)
- return HttpResponse(template.render(context))
+ return render_into_skin('ask.html', data, request)
@login_required
def retag_question(request, id):
@@ -202,7 +276,10 @@ def retag_question(request, id):
tags = form.cleaned_data['tags']
)
if request.is_ajax():
- response_data = {'success': True}
+ response_data = {
+ 'success': True,
+ 'new_tags': question.tagnames
+ }
data = simplejson.dumps(response_data)
return HttpResponse(data, mimetype="application/json")
else:
@@ -221,11 +298,8 @@ def retag_question(request, id):
'active_tab': 'questions',
'question': question,
'form' : form,
- 'tags' : _get_tags_cache_json(),
}
- context = RequestContext(request, data)
- template = ENV.get_template('question_retag.html')
- return HttpResponse(template.render(context))
+ return render_into_skin('question_retag.html', data, request)
except exceptions.PermissionDenied, e:
if request.is_ajax():
response_data = {
@@ -248,44 +322,75 @@ def edit_question(request, id):
try:
request.user.assert_can_edit_question(question)
if request.method == 'POST':
- if 'select_revision' in request.POST:#revert-type edit
- # user has changed revistion number
- revision_form = forms.RevisionForm(question, latest_revision, request.POST)
+ if 'select_revision' in request.POST:
+ #revert-type edit - user selected previous revision
+ revision_form = forms.RevisionForm(
+ question,
+ latest_revision,
+ request.POST
+ )
if revision_form.is_valid():
# Replace with those from the selected revision
- form = forms.EditQuestionForm(question,
- models.QuestionRevision.objects.get(question=question,
- revision=revision_form.cleaned_data['revision']))
+ rev_id = revision_form.cleaned_data['revision']
+ selected_revision = models.QuestionRevision.objects.get(
+ question = question,
+ revision = rev_id
+ )
+ form = forms.EditQuestionForm(
+ question = question,
+ user = request.user,
+ revision = selected_revision
+ )
else:
- form = forms.EditQuestionForm(question, latest_revision, request.POST)
+ form = forms.EditQuestionForm(
+ request.POST,
+ question = question,
+ user = request.user,
+ revision = latest_revision
+ )
else:#new content edit
# Always check modifications against the latest revision
- form = forms.EditQuestionForm(question, latest_revision, request.POST)
+ form = forms.EditQuestionForm(
+ request.POST,
+ question = question,
+ revision = latest_revision,
+ user = request.user,
+ )
if form.is_valid():
if form.has_changed():
+
+ if form.cleaned_data['reveal_identity']:
+ question.remove_author_anonymity()
+
+ is_anon_edit = form.cleaned_data['stay_anonymous']
+ is_wiki = form.cleaned_data.get('wiki', question.wiki)
request.user.edit_question(
- question = question,
- title = form.cleaned_data['title'],
- body_text = form.cleaned_data['text'],
- revision_comment = form.cleaned_data['summary'],
- tags = form.cleaned_data['tags'],
- wiki = form.cleaned_data.get('wiki', question.wiki)
- )
+ question = question,
+ title = form.cleaned_data['title'],
+ body_text = form.cleaned_data['text'],
+ revision_comment = form.cleaned_data['summary'],
+ tags = form.cleaned_data['tags'],
+ wiki = is_wiki,
+ edit_anonymously = is_anon_edit,
+ )
return HttpResponseRedirect(question.get_absolute_url())
else:
+ #request type was "GET"
revision_form = forms.RevisionForm(question, latest_revision)
- form = forms.EditQuestionForm(question, latest_revision)
+ form = forms.EditQuestionForm(
+ question = question,
+ revision = latest_revision,
+ user = request.user
+ )
data = {
+ 'page_class': 'edit-question-page',
'active_tab': 'questions',
'question': question,
'revision_form': revision_form,
'form' : form,
- 'tags' : _get_tags_cache_json()
}
- context = RequestContext(request, data)
- template = ENV.get_template('question_edit.html')
- return HttpResponse(template.render(context))
+ return render_into_skin('question_edit.html', data, request)
except exceptions.PermissionDenied, e:
request.user.message_set.create(message = unicode(e))
@@ -334,15 +439,13 @@ def edit_answer(request, id):
else:
revision_form = forms.RevisionForm(answer, latest_revision)
form = forms.EditAnswerForm(answer, latest_revision)
- template = ENV.get_template('answer_edit.html')
data = {
'active_tab': 'questions',
'answer': answer,
'revision_form': revision_form,
'form': form,
}
- context = RequestContext(request, data)
- return HttpResponse(template.render(context))
+ return render_into_skin('answer_edit.html', data, request)
except exceptions.PermissionDenied, e:
request.user.message_set.create(message = unicode(e))
diff --git a/setup.py b/setup.py
index 7807995b..5f6c018d 100644
--- a/setup.py
+++ b/setup.py
@@ -7,9 +7,9 @@ import sys
#you might want to install django-debug-toolbar as well
install_requires = [
- 'django==1.1.2',
+ 'django>=1.1.2',
'Jinja2',
- 'Coffin==0.3.0',
+ 'Coffin>=0.3',
'South>=0.7.1',
'oauth2',
'recaptcha-client',
@@ -19,9 +19,14 @@ install_requires = [
'django-threaded-multihost',
'django-robots',
'unidecode',
+ 'django-countries==1.0.5',
+ 'django-celery==2.2.3',
+ 'django-kombu==0.9.2',
]
-import askbot
+#todo: have a dirty version retriever that
+#parses it out from askbot/__init__.py but does not
+#import it as there are issues
WIN_PLATFORMS = ('win32', 'cygwin',)
if sys.platform not in WIN_PLATFORMS:
@@ -29,7 +34,7 @@ if sys.platform not in WIN_PLATFORMS:
setup(
name = "askbot",
- version = askbot.get_version(),
+ version = '0.6.76',#remember to manually set this correctly
description = 'Question and Answer forum, like StackOverflow, written in python and Django',
packages = find_packages(),
author = 'Evgeny.Fadeev',
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 00000000..d0be6511
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,4 @@
+[tox]
+envlist=py26,py25,py27
+[testenv]
+commands=python manage.py test askbot