summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-03-11 23:26:54 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-03-11 23:26:54 -0400
commit420cae564a7f3d4225c660b8743929fee542c6c6 (patch)
tree6dbdb6d564e82b81f5b7dbab42afcfa03b09d0e3
parentd0b17e48f2bf3d8da0ee1e1e33648addaa557e1e (diff)
parentf2c2196d0fede2ecb06dc6cf571ea818d8999c59 (diff)
downloadaskbot-420cae564a7f3d4225c660b8743929fee542c6c6.tar.gz
askbot-420cae564a7f3d4225c660b8743929fee542c6c6.tar.bz2
askbot-420cae564a7f3d4225c660b8743929fee542c6c6.zip
Merge branch 'github-master'
-rw-r--r--askbot/conf/__init__.py1
-rw-r--r--askbot/conf/external_keys.py35
-rw-r--r--askbot/conf/ldap.py93
-rw-r--r--askbot/conf/site_settings.py1
-rw-r--r--askbot/deps/django_authopenid/backends.py100
-rw-r--r--askbot/deps/django_authopenid/views.py38
-rw-r--r--askbot/doc/source/changelog.rst2
-rw-r--r--askbot/doc/source/contributors.rst1
-rw-r--r--askbot/management/commands/initialize_ldap_logins.py68
-rw-r--r--askbot/models/badges.py5
-rw-r--r--askbot/models/post.py6
-rw-r--r--askbot/models/repute.py18
-rw-r--r--askbot/setup_templates/settings.py.mustache2
-rw-r--r--askbot/skins/default/templates/main_page/tab_bar.html2
-rw-r--r--askbot/skins/default/templates/user_profile/user_edit.html19
-rw-r--r--askbot/startup_procedures.py60
-rw-r--r--askbot/utils/html.py4
-rw-r--r--askbot/views/meta.py3
-rw-r--r--askbot/views/users.py12
19 files changed, 282 insertions, 188 deletions
diff --git a/askbot/conf/__init__.py b/askbot/conf/__init__.py
index de1eeccc..dff91d8e 100644
--- a/askbot/conf/__init__.py
+++ b/askbot/conf/__init__.py
@@ -9,6 +9,7 @@ import askbot.conf.flatpages
import askbot.conf.site_settings
import askbot.conf.license
import askbot.conf.external_keys
+import askbot.conf.ldap
import askbot.conf.skin_general_settings
import askbot.conf.sidebar_main
import askbot.conf.sidebar_question
diff --git a/askbot/conf/external_keys.py b/askbot/conf/external_keys.py
index a673534a..24a43265 100644
--- a/askbot/conf/external_keys.py
+++ b/askbot/conf/external_keys.py
@@ -53,6 +53,8 @@ settings.register(
)
)
+
+
settings.register(
livesettings.StringValue(
EXTERNAL_KEYS,
@@ -160,36 +162,3 @@ settings.register(
description=_('ident.ca consumer secret'),
)
)
-
-settings.register(
- livesettings.BooleanValue(
- EXTERNAL_KEYS,
- 'USE_LDAP_FOR_PASSWORD_LOGIN',
- description=_('Use LDAP authentication for the password login'),
- defaut=False
- )
-)
-
-settings.register(
- livesettings.StringValue(
- EXTERNAL_KEYS,
- 'LDAP_PROVIDER_NAME',
- description=_('LDAP service provider name')
- )
-)
-
-settings.register(
- livesettings.StringValue(
- EXTERNAL_KEYS,
- 'LDAP_URL',
- description=_('URL for the LDAP service')
- )
-)
-
-settings.register(
- livesettings.LongStringValue(
- EXTERNAL_KEYS,
- 'HOW_TO_CHANGE_LDAP_PASSWORD',
- description=_('Explain how to change LDAP password')
- )
-)
diff --git a/askbot/conf/ldap.py b/askbot/conf/ldap.py
new file mode 100644
index 00000000..077ff792
--- /dev/null
+++ b/askbot/conf/ldap.py
@@ -0,0 +1,93 @@
+"""Settings for LDAP login for Askbot"""
+from askbot.conf.settings_wrapper import settings
+from askbot.conf.super_groups import EXTERNAL_SERVICES
+from askbot.deps import livesettings
+from django.utils.translation import ugettext as _
+
+LDAP_SETTINGS = livesettings.ConfigurationGroup(
+ 'LDAP_SETTINGS',
+ _('LDAP login configuration'),
+ super_group = EXTERNAL_SERVICES
+ )
+
+settings.register(
+ livesettings.BooleanValue(
+ LDAP_SETTINGS,
+ 'USE_LDAP_FOR_PASSWORD_LOGIN',
+ description=_('Use LDAP authentication for the password login'),
+ defaut=False
+ )
+)
+
+settings.register(
+ livesettings.StringValue(
+ LDAP_SETTINGS,
+ 'LDAP_URL',
+ description=_('LDAP URL'),
+ default="ldap://<host>:<port>"
+ )
+)
+
+settings.register(
+ livesettings.StringValue(
+ LDAP_SETTINGS,
+ 'LDAP_BASEDN',
+ description=_('LDAP BASE DN')
+ )
+)
+
+settings.register(
+ livesettings.StringValue(
+ LDAP_SETTINGS,
+ 'LDAP_SEARCH_SCOPE',
+ description=_('LDAP Search Scope'),
+ default="subs"
+ )
+)
+
+settings.register(
+ livesettings.StringValue(
+ LDAP_SETTINGS,
+ 'LDAP_USERID_FIELD',
+ description=_('LDAP Server USERID field name'),
+ default="uid"
+ )
+)
+
+settings.register(
+ livesettings.StringValue(
+ LDAP_SETTINGS,
+ 'LDAP_COMMONNAME_FIELD',
+ description=_('LDAP Server "Common Name" field name'),
+ default="cn"
+ )
+)
+
+settings.register(
+ livesettings.StringValue(
+ LDAP_SETTINGS,
+ 'LDAP_EMAIL_FIELD',
+ description=_('LDAP Server EMAIL field name'),
+ default="mail"
+ )
+)
+
+# May be necessary, but not handled properly.
+# --> Commenting out until handled properly in backends.ldap_authenticate()
+#settings.register(
+# livesettings.StringValue(
+# LDAP_SETTINGS,
+# 'LDAP_PROXYDN',
+# description=_('LDAP PROXY DN'),
+# default=""
+# )
+#)
+#
+#settings.register(
+# livesettings.StringValue(
+# LDAP_SETTINGS,
+# 'LDAP_PROXYDN_PASSWORD',
+# description=_('LDAP PROXY DN Password'),
+# defalut="",
+# )
+#)
diff --git a/askbot/conf/site_settings.py b/askbot/conf/site_settings.py
index 8cd73b3d..c64ea952 100644
--- a/askbot/conf/site_settings.py
+++ b/askbot/conf/site_settings.py
@@ -63,7 +63,6 @@ settings.register(
livesettings.StringValue(
QA_SITE_SETTINGS,
'APP_URL',
- default='http://askbot.org',
description=_(
'Base URL for your Q&A forum, must start with '
'http or https'
diff --git a/askbot/deps/django_authopenid/backends.py b/askbot/deps/django_authopenid/backends.py
index 9f8f1dfd..f3d8f64b 100644
--- a/askbot/deps/django_authopenid/backends.py
+++ b/askbot/deps/django_authopenid/backends.py
@@ -9,6 +9,84 @@ from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import ugettext as _
from askbot.deps.django_authopenid.models import UserAssociation
from askbot.deps.django_authopenid import util
+from askbot.conf import settings as askbot_settings
+
+log = logging.getLogger('configuration')
+
+
+def ldap_authenticate(username, password):
+ """
+ Authenticate using ldap
+
+ python-ldap must be installed
+ http://pypi.python.org/pypi/python-ldap/2.4.6
+ """
+ import ldap
+ user_information = None
+ try:
+ ldap_session = ldap.initialize(askbot_settings.LDAP_URL)
+ ldap_session.protocol_version = ldap.VERSION3
+ user_filter = "({0}={1})".format(askbot_settings.LDAP_USERID_FIELD,
+ username)
+ # search ldap directory for user
+ res = ldap_session.search_s(askbot_settings.LDAP_BASEDN, ldap.SCOPE_SUBTREE, user_filter, None)
+ if res: # User found in LDAP Directory
+ user_dn = res[0][0]
+ user_information = res[0][1]
+ ldap_session.simple_bind_s(user_dn, password) # <-- will throw ldap.INVALID_CREDENTIALS if fails
+ ldap_session.unbind_s()
+
+ exact_username = user_information[askbot_settings.LDAP_USERID_FIELD][0]
+
+ # Assuming last, first order
+ # --> may be different
+ last_name, first_name = user_information[askbot_settings.LDAP_COMMONNAME_FIELD][0].rsplit(" ", 1)
+ email = user_information[askbot_settings.LDAP_EMAIL_FIELD][0]
+ try:
+ user = User.objects.get(username__exact=exact_username)
+ # always update user profile to synchronize with ldap server
+ user.set_password(password)
+ user.first_name = first_name
+ user.last_name = last_name
+ user.email = email
+ user.save()
+ except User.DoesNotExist:
+ # create new user in local db
+ user = User()
+ user.username = exact_username
+ user.set_password(password)
+ user.first_name = first_name
+ user.last_name = last_name
+ user.email = email
+ user.is_staff = False
+ user.is_superuser = False
+ user.is_active = True
+ user.save()
+
+ log.info('Created New User : [{0}]'.format(exact_username))
+ return user
+ else:
+ # Maybe a user created internally (django admin user)
+ try:
+ user = User.objects.get(username__exact=username)
+ if user.check_password(password):
+ return user
+ else:
+ return None
+ except User.DoesNotExist:
+ return None
+
+ except ldap.INVALID_CREDENTIALS, e:
+ return None # Will fail login on return of None
+ except ldap.LDAPError, e:
+ log.error("LDAPError Exception")
+ log.exception(e)
+ return None
+ except Exception, e:
+ log.error("Unexpected Exception Occurred")
+ log.exception(e)
+ return None
+
class AuthBackend(object):
"""Authenticator's authentication backend class
@@ -22,15 +100,14 @@ class AuthBackend(object):
def authenticate(
self,
- username = None,#for 'password'
- password = None,#for 'password'
+ username = None,#for 'password' and 'ldap'
+ password = None,#for 'password' and 'ldap'
user_id = None,#for 'force'
provider_name = None,#required with all except email_key
openid_url = None,
email_key = None,
oauth_user_id = None,#used with oauth
facebook_user_id = None,#user with facebook
- ldap_user_id = None,#for ldap
wordpress_url = None, # required for self hosted wordpress
wp_user_id = None, # required for self hosted wordpress
method = None,#requried parameter
@@ -40,6 +117,7 @@ class AuthBackend(object):
from the signature of the function call
"""
login_providers = util.get_enabled_login_providers()
+ assoc = None # UserAssociation not needed for ldap
if method == 'password':
if login_providers[provider_name]['type'] != 'password':
raise ImproperlyConfigured('login provider must use password')
@@ -156,14 +234,7 @@ class AuthBackend(object):
return None
elif method == 'ldap':
- try:
- assoc = UserAssociation.objects.get(
- openid_url = ldap_user_id,
- provider_name = provider_name
- )
- user = assoc.user
- except UserAssociation.DoesNotExist:
- return None
+ user = ldap_authenticate(username, password)
elif method == 'wordpress_site':
try:
@@ -180,9 +251,10 @@ class AuthBackend(object):
else:
raise TypeError('only openid and password supported')
- #update last used time
- assoc.last_used_timestamp = datetime.datetime.now()
- assoc.save()
+ if assoc:
+ #update last used time
+ assoc.last_used_timestamp = datetime.datetime.now()
+ assoc.save()
return user
def get_user(self, user_id):
diff --git a/askbot/deps/django_authopenid/views.py b/askbot/deps/django_authopenid/views.py
index bb0b4986..22be8460 100644
--- a/askbot/deps/django_authopenid/views.py
+++ b/askbot/deps/django_authopenid/views.py
@@ -310,30 +310,26 @@ def signin(request):
password_action = login_form.cleaned_data['password_action']
if askbot_settings.USE_LDAP_FOR_PASSWORD_LOGIN:
assert(password_action == 'login')
- ldap_provider_name = askbot_settings.LDAP_PROVIDER_NAME
username = login_form.cleaned_data['username']
- if util.ldap_check_password(
- username,
- login_form.cleaned_data['password']
- ):
- user = authenticate(
- ldap_user_id = username,
- provider_name = ldap_provider_name,
- method = 'ldap'
- )
- if user is not None:
- login(request, user)
- return HttpResponseRedirect(next_url)
- else:
- return finalize_generic_signin(
- request = request,
- user = user,
- user_identifier = username,
- login_provider_name = ldap_provider_name,
- redirect_url = next_url
+ password = login_form.cleaned_data['password']
+ # will be None if authentication fails
+ user = authenticate(
+ username=username,
+ password=password,
+ method = 'ldap'
)
+ if user is not None:
+ login(request, user)
+ return HttpResponseRedirect(next_url)
else:
- login_form.set_password_login_error()
+ return finalize_generic_signin(
+ request = request,
+ user = user,
+ user_identifier = username,
+ login_provider_name = ldap_provider_name,
+ redirect_url = next_url
+ )
+
else:
if password_action == 'login':
user = authenticate(
diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst
index a8e695a6..68d3c6b1 100644
--- a/askbot/doc/source/changelog.rst
+++ b/askbot/doc/source/changelog.rst
@@ -20,6 +20,8 @@ Development version (not released yet)
* Added test on maximum length of title working for utf-8 text (Evgeny)
* Added caching and invalidation to the question page (Evgeny)
* Added a management command delete_contextless_activities (Evgeny)
+* LDAP login configuration (github user `monkut <https://github.com/monkut>`_)
+* Check order of middleware classes (Daniel Mican)
0.7.39 (Jan 11, 2012)
---------------------
diff --git a/askbot/doc/source/contributors.rst b/askbot/doc/source/contributors.rst
index a0b91518..eea61b31 100644
--- a/askbot/doc/source/contributors.rst
+++ b/askbot/doc/source/contributors.rst
@@ -35,6 +35,7 @@ Programming and documentation
* `hjwp <https://github.com/hjwp>`_
* `Jacob Oscarson <http://www.aspektratio.net>`_
* `Radim Řehůřek <https://github.com/piskvorky>`_
+* `monkut <https://github.com/monkut>`_
Translations
------------
diff --git a/askbot/management/commands/initialize_ldap_logins.py b/askbot/management/commands/initialize_ldap_logins.py
deleted file mode 100644
index 96ee74e5..00000000
--- a/askbot/management/commands/initialize_ldap_logins.py
+++ /dev/null
@@ -1,68 +0,0 @@
-"""Management command to create LDAP login method for all users.
-Please see description of the command in its ``help_text``.
-"""
-import datetime
-from django.core.management.base import CommandError
-from django.utils.translation import ugettext as _
-from askbot.management import NoArgsJob
-from askbot import models
-from askbot.deps.django_authopenid.models import UserAssociation
-from askbot.conf import settings as askbot_settings
-
-def create_ldap_login_for_user(user):
- """a unit job that creates LDAP account record for
- the user, assuming that his or her LDAP user name
- is the same as the user name on the forum site.
- If the record already exists, LDAP provider name
- will be updated according to the live setting,
- otherwise a new record will be created.
- Always returns ``True``.
- """
- ldap_url = askbot_settings.LDAP_URL
- ldap_provider_name = askbot_settings.LDAP_PROVIDER_NAME
- if '' in (ldap_url, ldap_provider_name):
- raise CommandError(
- 'Please, first set up LDAP settings '
- 'at url /settings/EXTERNAL_KEYS,'
- 'relative to the base url of your forum site'
- )
- try:
- assoc = UserAssociation.objects.get(
- openid_url = user.username,
- user = user
- )
- except UserAssociation.DoesNotExist:
- assoc = UserAssociation(
- openid_url = user.username,
- user = user
- )
- assoc.provider_name = ldap_provider_name
- assoc.last_used_timestamp = datetime.datetime.now()
- assoc.save()
- return True
-
-class Command(NoArgsJob):
- """definition of the job that
- runs through all users and creates LDAP login
- methods, assuming that LDAP user ID's are the same
- as values ``~askbot.User.username``
- """
- help = _(
- 'This command may help you migrate to LDAP '
- 'password authentication by creating a record '
- 'for LDAP association with each user account. '
- 'There is an assumption that ldap user id\'s are '
- 'the same as user names registered at the site. '
- 'Before running this command it is necessary to '
- 'set up LDAP parameters in the "External keys" section '
- 'of the site settings.'
- )
- def __init__(self, *args, **kwargs):
- self.batches = ({
- 'title': 'Initializing LDAP logins for all users: ',
- 'query_set': models.User.objects.all(),
- 'function': create_ldap_login_for_user,
- 'changed_count_message': 'Created LDAP logins for %d users',
- 'nothing_changed_message': 'All users already have LDAP login methods'
- },)
- super(Command, self).__init__(*args, **kwargs)
diff --git a/askbot/models/badges.py b/askbot/models/badges.py
index b909b7e1..61149df3 100644
--- a/askbot/models/badges.py
+++ b/askbot/models/badges.py
@@ -878,6 +878,11 @@ def init_badges():
#from the __init__ function?
for key in BADGES.keys():
get_badge(key).get_stored_data()
+ #remove any badges from the database
+ #that are no longer in the BADGES dictionary
+ BadgeData.objects.exclude(
+ slug__in = map(slugify, BADGES.keys())
+ ).delete()
award_badges_signal = Signal(
providing_args=[
diff --git a/askbot/models/post.py b/askbot/models/post.py
index d9cd9a5e..2b78e7a1 100644
--- a/askbot/models/post.py
+++ b/askbot/models/post.py
@@ -486,8 +486,8 @@ class Post(models.Model):
if self.is_comment():
#todo: implement a custom delete method on these
#all this should pack into Activity.responses.filter( somehow ).delete()
- activity_types = const.RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY
- activity_types += (const.TYPE_ACTIVITY_MENTION,)
+ #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
@@ -495,7 +495,7 @@ class Post(models.Model):
activities = Activity.objects.filter(
content_type = comment_content_type,
object_id = self.id,
- activity_type__in = activity_types
+ #activity_type__in = activity_types
)
recipients = set()
diff --git a/askbot/models/repute.py b/askbot/models/repute.py
index dce907ac..c9c1b8bf 100644
--- a/askbot/models/repute.py
+++ b/askbot/models/repute.py
@@ -13,25 +13,27 @@ class BadgeData(models.Model):
awarded_count = models.PositiveIntegerField(default=0)
awarded_to = models.ManyToManyField(User, through='Award', related_name='badges')
+ def _get_meta_data(self):
+ """retrieves badge metadata stored
+ in a file"""
+ from askbot.models import badges
+ return badges.get_badge(self.slug)
+
@property
def name(self):
- from askbot.models import badges
- return badges.get_badge(self.slug).name
+ return self._get_meta_data().name
@property
def description(self):
- from askbot.models import badges
- return badges.get_badge(self.slug).description
+ return self._get_meta_data().description
@property
def css_class(self):
- from askbot.models import badges
- return badges.get_badge(self.slug).css_class
+ return self._get_meta_data().css_class
def get_type_display(self):
- from askbot.models import badges
#todo - rename "type" -> "level" in this model
- return badges.get_badge(self.slug).get_level_display()
+ return self._get_meta_data().get_level_display()
class Meta:
app_label = 'askbot'
diff --git a/askbot/setup_templates/settings.py.mustache b/askbot/setup_templates/settings.py.mustache
index 19fd3c61..71ccf0f2 100644
--- a/askbot/setup_templates/settings.py.mustache
+++ b/askbot/setup_templates/settings.py.mustache
@@ -222,7 +222,7 @@ djcelery.setup_loader()
DOMAIN_NAME = '{{domain_name}}'
CSRF_COOKIE_NAME = '{{domain_name}}_csrf'
-CSRF_COOKIE_DOMAIN = DOMAIN_NAME
+CSRF_COOKIE_DOMAIN = DOMAIN_NAME #note that this can be edited
STATIC_ROOT = os.path.join(PROJECT_ROOT, "static")
STATICFILES_DIRS = (os.path.join(ASKBOT_ROOT, 'skins'),)
diff --git a/askbot/skins/default/templates/main_page/tab_bar.html b/askbot/skins/default/templates/main_page/tab_bar.html
index e08232bb..8b666155 100644
--- a/askbot/skins/default/templates/main_page/tab_bar.html
+++ b/askbot/skins/default/templates/main_page/tab_bar.html
@@ -1,6 +1,6 @@
{% import "macros.html" as macros %}
{% load extra_filters_jinja %}
-{% cache 0 "scope_sort_tabs" search_tags request.user scope sort query context.page language_code %}
+{% cache 0 "scope_sort_tabs" search_tags request.user author_name scope sort query context.page language_code %}
<a class="rss"
{% if feed_url %}
href="{{settings.APP_URL}}{{feed_url}}"
diff --git a/askbot/skins/default/templates/user_profile/user_edit.html b/askbot/skins/default/templates/user_profile/user_edit.html
index 94a1d58d..7735ba93 100644
--- a/askbot/skins/default/templates/user_profile/user_edit.html
+++ b/askbot/skins/default/templates/user_profile/user_edit.html
@@ -40,7 +40,7 @@
<td>
{% if settings.EDITABLE_SCREEN_NAME %}
{{ form.username }}
- <span class="form-error"></span> {{ form.username.errors }} </td>
+ <span class="form-error"> {{ form.username.errors }} </span></td>
{% else %}
{{ view_user.username }}
{% endif %}
@@ -53,8 +53,7 @@
<td>
{% if settings.EDITABLE_EMAIL %}
{{ form.email }}
- <span class="form-error"></span>
- {{ form.email.errors }}
+ <span class="form-error">{{ form.email.errors }}</span>
{% else %}
{{ view_user.email }}
{% trans %}(cannot be changed){% endtrans %}
@@ -63,27 +62,27 @@
</tr>
<tr>
<td>{{ form.realname.label_tag() }}:</td>
- <td>{{ form.realname }} <span class="form-error"></span> {{ form.realname.errors }} </td>
+ <td>{{ form.realname }} <span class="form-error"> {{ form.realname.errors }} </span></td>
</tr>
<tr>
<td>{{ form.website.label_tag() }}:</td>
- <td>{{ form.website }} <span class="form-error"></span> {{ form.website.errors }} </td>
+ <td>{{ form.website }} <span class="form-error"> {{ form.website.errors }} </span></td>
</tr>
<tr>
<td>{{ form.city.label_tag() }}:</td>
- <td>{{ form.city }} <span class="form-error"></span> {{ form.city.errors }} </td>
+ <td>{{ form.city }} <span class="form-error"> {{ form.city.errors }} </span></td>
</tr>
<tr>
<td>{{ form.country.label_tag() }}:</td>
- <td>{{ form.country }} <span class="form-error"></span> {{ form.country.errors }} </td>
+ <td>{{ form.country }} <span class="form-error"> {{ form.country.errors }} </span></td>
</tr>
<tr>
<td>{{ form.show_country.label_tag() }}:</td>
- <td>{{ form.show_country }} <span class="form-error"></span> {{ form.show_country.errors }} </td>
+ <td>{{ form.show_country }} <span class="form-error"> {{ form.show_country.errors }} </span></td>
</tr>
<tr>
<td>{{ form.birthday.label_tag() }}:</td>
- <td>{{ form.birthday }} <span class="form-error"></span> {{ form.birthday.errors }} </td>
+ <td>{{ form.birthday }} <span class="form-error"> {{ form.birthday.errors }} </span></td>
</tr>
<tr>
<td></td>
@@ -95,7 +94,7 @@
</tr>
<tr>
<td style="vertical-align:top">{{ form.about.label_tag() }}:</td>
- <td>{{ form.about }} <span class="form-error"></span> {{ form.about.errors }} </td>
+ <td>{{ form.about }} <span class="form-error"> {{ form.about.errors }} </span></td>
</tr>
</table>
<div style="margin:30px 0 60px 0">
diff --git a/askbot/startup_procedures.py b/askbot/startup_procedures.py
index 4c76be2c..b4b36e35 100644
--- a/askbot/startup_procedures.py
+++ b/askbot/startup_procedures.py
@@ -109,7 +109,7 @@ def test_middleware():
installed in the django settings.py file. If that is not the
case - raises an AskbotConfigError exception.
"""
- required_middleware = (
+ required_middleware = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
@@ -117,37 +117,47 @@ def test_middleware():
'askbot.middleware.forum_mode.ForumModeMiddleware',
'askbot.middleware.cancel.CancelActionMiddleware',
'django.middleware.transaction.TransactionMiddleware',
- 'askbot.middleware.view_log.ViewLogMiddleware',
- )
+ ]
if 'debug_toolbar' in django_settings.INSTALLED_APPS:
- required_middleware += (
+ required_middleware.append(
'debug_toolbar.middleware.DebugToolbarMiddleware',
)
-
- installed_middleware_set = set(django_settings.MIDDLEWARE_CLASSES)
- missing_middleware_set = set(required_middleware) - installed_middleware_set
-
- if missing_middleware_set:
- error_message = """\n\nPlease add the following middleware (listed after this message)
+ required_middleware.extend([
+ 'askbot.middleware.view_log.ViewLogMiddleware',
+ 'askbot.middleware.spaceless.SpacelessMiddleware',
+ ])
+ found_middleware = [x for x in django_settings.MIDDLEWARE_CLASSES
+ if x in required_middleware]
+ if found_middleware != required_middleware:
+ # either middleware is out of order or it's missing an item
+ missing_middleware_set = set(required_middleware) - set(found_middleware)
+ middleware_text = ''
+ if missing_middleware_set:
+ error_message = """\n\nPlease 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
+The order the middleware records is important, please take a look at the example in
https://github.com/ASKBOT/askbot-devel/blob/master/askbot/setup_templates/settings.py:\n\n"""
- middleware_text = format_as_text_tuple_entries(missing_middleware_set)
+ middleware_text = format_as_text_tuple_entries(missing_middleware_set)
+ else:
+ # middleware is out of order
+ error_message = """\n\nPlease check the order of middleware closely.
+The order the middleware records is important, please take a look at the example in
+https://github.com/ASKBOT/askbot-devel/blob/master/askbot/setup_templates/settings.py
+for the correct order.\n\n"""
raise AskbotConfigError(error_message + middleware_text)
#middleware that was used in the past an now removed
- canceled_middleware = (
- 'askbot.deps.recaptcha_django.middleware.ReCaptchaMiddleware',
- )
- #'debug_toolbar.middleware.DebugToolbarMiddleware',
-
- remove_middleware_set = set(canceled_middleware) \
- & installed_middleware_set
- if remove_middleware_set:
+ canceled_middleware = [
+ 'askbot.deps.recaptcha_django.middleware.ReCaptchaMiddleware'
+ ]
+
+ invalid_middleware = [x for x in canceled_middleware
+ if x in django_settings.MIDDLEWARE_CLASSES]
+ if invalid_middleware:
error_message = """\n\nPlease remove the following middleware entries from
the list of MIDDLEWARE_CLASSES in your settings.py - these are not used any more:\n\n"""
- middleware_text = format_as_text_tuple_entries(remove_middleware_set)
+ middleware_text = format_as_text_tuple_entries(invalid_middleware)
raise AskbotConfigError(error_message + middleware_text)
def try_import(module_name, pypi_package_name):
@@ -356,7 +366,11 @@ def test_staticfiles():
askbot_root = os.path.dirname(askbot.__file__)
skin_dir = os.path.abspath(os.path.join(askbot_root, 'skins'))
- if skin_dir not in map(os.path.abspath, django_settings.STATICFILES_DIRS):
+
+ # django_settings.STATICFILES_DIRS can have strings or tuples
+ staticfiles_dirs = [d[1] if isinstance(d, tuple) else d
+ for d in django_settings.STATICFILES_DIRS]
+ if skin_dir not in map(os.path.abspath, staticfiles_dirs):
errors.append(
'Add to STATICFILES_DIRS list of your settings.py file:\n'
" '%s'," % skin_dir
@@ -368,7 +382,7 @@ def test_staticfiles():
'Directory specified with settning ASKBOT_EXTRA_SKINS_DIR '
'must exist and contain your custom skins for askbot.'
)
- if extra_skins_dir not in django_settings.STATICFILES_DIRS:
+ if extra_skins_dir not in staticfiles_dirs:
errors.append(
'Add ASKBOT_EXTRA_SKINS_DIR to STATICFILES_DIRS entry in '
'your settings.py file.\n'
diff --git a/askbot/utils/html.py b/askbot/utils/html.py
index f6c168fb..f91fa980 100644
--- a/askbot/utils/html.py
+++ b/askbot/utils/html.py
@@ -28,10 +28,10 @@ class HTMLSanitizerMixin(sanitizer.HTMLSanitizerMixin):
class HTMLSanitizer(tokenizer.HTMLTokenizer, HTMLSanitizerMixin):
def __init__(self, stream, encoding=None, parseMeta=True, useChardet=True,
- lowercaseElementName=True, lowercaseAttrName=True):
+ lowercaseElementName=True, lowercaseAttrName=True, **kwargs):
tokenizer.HTMLTokenizer.__init__(self, stream, encoding, parseMeta,
useChardet, lowercaseElementName,
- lowercaseAttrName)
+ lowercaseAttrName, **kwargs)
def __iter__(self):
for token in tokenizer.HTMLTokenizer.__iter__(self):
diff --git a/askbot/views/meta.py b/askbot/views/meta.py
index ac06b7e0..b2f09cf4 100644
--- a/askbot/views/meta.py
+++ b/askbot/views/meta.py
@@ -6,7 +6,7 @@ This module contains a collection of views displaying all sorts of secondary and
from django.shortcuts import render_to_response, get_object_or_404
from django.core.urlresolvers import reverse
from django.template import RequestContext, Template
-from django.http import HttpResponseRedirect, HttpResponse
+from django.http import HttpResponseRedirect, HttpResponse, Http404
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext as _
from django.views import static
@@ -127,6 +127,7 @@ def badges(request):#user status/reputation system
def badge(request, id):
#todo: supplement database data with the stuff from badges.py
badge = get_object_or_404(BadgeData, id=id)
+
badge_recipients = User.objects.filter(
award_user__badge = badge
).annotate(
diff --git a/askbot/views/users.py b/askbot/views/users.py
index 154df7d8..c625aeab 100644
--- a/askbot/views/users.py
+++ b/askbot/views/users.py
@@ -354,8 +354,16 @@ def user_stats(request, user, context):
for award in user_awards:
# Fetch content object
if award.content_type_id == post_type.id:
- award.content_object = awarded_posts_map[award.object_id]
- award.content_object_is_post = True
+ #here we go around a possibility of awards
+ #losing the content objects when the content
+ #objects are deleted for some reason
+ awarded_post = awarded_posts_map.get(award.object_id, None)
+ if awarded_post is not None:
+ #protect from awards that are associated with deleted posts
+ award.content_object = awarded_post
+ award.content_object_is_post = True
+ else:
+ award.content_object_is_post = False
else:
award.content_object_is_post = False