summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-01-16 10:20:39 -0300
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-01-16 10:20:39 -0300
commit03f752ba7f0b6398cfd4712654b5a6b348f73e2f (patch)
treea1fde5880db4d0da360cda7de6c886dfa7cd1360
parent76568d4c401c1787d21637fd0f7e944ae8ce200b (diff)
parent3035bd461f02ff238ddcede43ccea428fd03c20c (diff)
downloadaskbot-03f752ba7f0b6398cfd4712654b5a6b348f73e2f.tar.gz
askbot-03f752ba7f0b6398cfd4712654b5a6b348f73e2f.tar.bz2
askbot-03f752ba7f0b6398cfd4712654b5a6b348f73e2f.zip
merged the master branch
-rwxr-xr-x.gitignore4
-rw-r--r--askbot/__init__.py2
-rw-r--r--askbot/context.py3
-rw-r--r--askbot/deployment/__init__.py7
-rw-r--r--askbot/deps/django_authopenid/util.py64
-rw-r--r--askbot/deps/django_authopenid/views.py5
-rw-r--r--askbot/doc/source/changelog.rst14
-rw-r--r--askbot/doc/source/deployment.rst29
-rw-r--r--askbot/management/commands/send_email_alerts.py27
-rw-r--r--askbot/setup_templates/settings.py15
-rw-r--r--askbot/setup_templates/settings.py.mustache16
-rw-r--r--askbot/skins/common/media/js/utils.js2
-rw-r--r--askbot/skins/common/templates/authopenid/signin.html4
-rw-r--r--askbot/skins/common/templates/debug_header.html27
-rw-r--r--askbot/skins/default/templates/base.html1
-rw-r--r--askbot/skins/default/templates/close.html2
-rw-r--r--askbot/skins/default/templates/meta/bottom_scripts.html1
-rw-r--r--askbot/skins/default/templates/question.html2
-rw-r--r--askbot/skins/default/templates/question/question_card.html3
-rw-r--r--askbot/skins/default/templates/question/sidebar.html2
-rw-r--r--askbot/skins/default/templates/question_retag.html2
-rw-r--r--askbot/skins/default/templates/question_widget.html2
-rw-r--r--askbot/skins/default/templates/reopen.html2
-rw-r--r--askbot/skins/default/templates/revisions.html2
-rw-r--r--askbot/skins/default/templates/user_profile/user_recent.html4
-rw-r--r--askbot/skins/default/templates/user_profile/user_stats.html50
-rw-r--r--askbot/skins/default/templates/widgets/ask_form.html2
-rw-r--r--askbot/skins/utils.py9
-rw-r--r--askbot/startup_procedures.py190
-rw-r--r--[-rwxr-xr-x]askbot/tests/images/logo.gifbin910 -> 910 bytes
-rw-r--r--askbot/tests/skin_tests.py6
-rw-r--r--askbot/urls.py5
-rw-r--r--askbot/utils/functions.py8
-rw-r--r--askbot/views/meta.py11
34 files changed, 394 insertions, 129 deletions
diff --git a/.gitignore b/.gitignore
index 5364c8e4..dc9e2f72 100755
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
db
rebuild-locales.pl
/src
+/static
cache/??
run
*.wsgi
@@ -15,6 +16,7 @@ settings.py
*.iml
lint
env
+/static
django
django/*
nbproject
@@ -42,4 +44,4 @@ askbot/skins/common/media/mathjax/
run
recaptcha
/.ve
-/db.sq3 \ No newline at end of file
+/db.sq3
diff --git a/askbot/__init__.py b/askbot/__init__.py
index 7b12329c..2989d660 100644
--- a/askbot/__init__.py
+++ b/askbot/__init__.py
@@ -9,7 +9,7 @@ import smtplib
import sys
import logging
-VERSION = (0, 7, 37)
+VERSION = (0, 7, 39)
#keys are module names used by python imports,
#values - the package qualifier to use for pip
diff --git a/askbot/context.py b/askbot/context.py
index 17ab35bd..41298fc1 100644
--- a/askbot/context.py
+++ b/askbot/context.py
@@ -2,6 +2,7 @@
from the django settings, all parameters from the askbot livesettings
and the application available for the templates
"""
+import sys
from django.conf import settings
import askbot
from askbot import api
@@ -15,8 +16,10 @@ def application_settings(request):
my_settings = askbot_settings.as_dict()
my_settings['LANGUAGE_CODE'] = getattr(request, 'LANGUAGE_CODE', settings.LANGUAGE_CODE)
my_settings['ASKBOT_URL'] = settings.ASKBOT_URL
+ my_settings['STATIC_URL'] = settings.STATIC_URL
my_settings['ASKBOT_CSS_DEVEL'] = getattr(settings, 'ASKBOT_CSS_DEVEL', False)
my_settings['DEBUG'] = settings.DEBUG
+ my_settings['USING_RUNSERVER'] = 'runserver' in sys.argv
my_settings['ASKBOT_VERSION'] = askbot.get_version()
my_settings['LOGIN_URL'] = url_utils.get_login_url()
my_settings['LOGOUT_URL'] = url_utils.get_logout_url()
diff --git a/askbot/deployment/__init__.py b/askbot/deployment/__init__.py
index 6f7a86f6..8832cd01 100644
--- a/askbot/deployment/__init__.py
+++ b/askbot/deployment/__init__.py
@@ -3,6 +3,7 @@ module for deploying askbot
"""
import os.path
import sys
+import django
from optparse import OptionParser
from askbot.utils import console
from askbot.deployment import messages
@@ -126,6 +127,12 @@ def deploy_askbot(directory, options):
path_utils.create_path(directory)
+ if django.VERSION[0] == 1 and django.VERSION[1] < 3:
+ #force people install the django-staticfiles app
+ context['staticfiles_app'] = ''
+ else:
+ context['staticfiles_app'] = "'django.contrib.staticfiles',"
+
path_utils.deploy_into(
directory,
new_project = create_new_project,
diff --git a/askbot/deps/django_authopenid/util.py b/askbot/deps/django_authopenid/util.py
index 4468a6d2..28f6b2dd 100644
--- a/askbot/deps/django_authopenid/util.py
+++ b/askbot/deps/django_authopenid/util.py
@@ -29,7 +29,7 @@ try:
except:
from yadis import xri
-import time, base64, hashlib, operator, logging
+import time, base64, hmac, hashlib, operator, logging
from models import Association, Nonce
__all__ = ['OpenID', 'DjangoOpenIDStore', 'from_openid_response', 'clean_next']
@@ -787,30 +787,54 @@ class FacebookError(Exception):
"""
pass
-def get_facebook_user_id(request):
- try:
- key = askbot_settings.FACEBOOK_KEY
- secret = askbot_settings.FACEBOOK_SECRET
+def urlsafe_b64decode(input):
+ length = len(input)
+ return base64.urlsafe_b64decode(
+ input.ljust(length + length % 4, '=')
+ )
- fb_cookie = request.COOKIES['fbs_%s' % key]
- fb_response = dict(cgi.parse_qsl(fb_cookie))
+def parse_signed_facebook_request(signed_request, secret):
+ """
+ Parse signed_request given by Facebook (usually via POST),
+ decrypt with app secret.
- signature = None
- payload = ''
- for key in sorted(fb_response.keys()):
- if key != 'sig':
- payload += '%s=%s' % (key, fb_response[key])
+ Arguments:
+ signed_request -- Facebook's signed request given through POST
+ secret -- Application's app_secret required to decrpyt signed_request
- if 'sig' in fb_response:
- if md5(payload + secret).hexdigest() != fb_response['sig']:
- raise ValueError('signature does not match')
- else:
- raise ValueError('no signature in facebook response')
+ slightly edited copy from https://gist.github.com/1190267
+ """
+
+ if "." in signed_request:
+ esig, payload = signed_request.split(".")
+ else:
+ return {}
- if 'uid' not in fb_response:
- raise ValueError('no user id in facebook response')
+ sig = urlsafe_b64decode(str(esig))
+ data = simplejson.loads(urlsafe_b64decode(str(payload)))
- return fb_response['uid']
+ if not isinstance(data, dict):
+ raise ValueError("Pyload is not a json string!")
+ return {}
+
+ if data["algorithm"].upper() == "HMAC-SHA256":
+ if hmac.new(str(secret), str(payload), hashlib.sha256).digest() == sig:
+ return data
+ else:
+ raise ValueError("Not HMAC-SHA256 encrypted!")
+
+ return {}
+
+def get_facebook_user_id(request):
+ try:
+ key = askbot_settings.FACEBOOK_KEY
+ fb_cookie = request.COOKIES['fbsr_%s' % key]
+ if not fb_cookie:
+ raise ValueError('cannot access facebook cookie')
+
+ secret = askbot_settings.FACEBOOK_SECRET
+ response = parse_signed_facebook_request(fb_cookie, secret)
+ return response['user_id']
except Exception, e:
raise FacebookError(e)
diff --git a/askbot/deps/django_authopenid/views.py b/askbot/deps/django_authopenid/views.py
index 8cb30365..bb0b4986 100644
--- a/askbot/deps/django_authopenid/views.py
+++ b/askbot/deps/django_authopenid/views.py
@@ -48,6 +48,7 @@ from django.utils.safestring import mark_safe
from django.core.mail import send_mail
from recaptcha_works.decorators import fix_recaptcha_remote_ip
from askbot.skins.loaders import render_into_skin, get_template
+from urlparse import urlparse
from openid.consumer.consumer import Consumer, \
SUCCESS, CANCEL, FAILURE, SETUP_NEEDED
@@ -1084,8 +1085,10 @@ def _send_email_key(user):
to user's email address
"""
subject = _("Recover your %(site)s account") % {'site': askbot_settings.APP_SHORT_NAME}
+
+ url = urlparse(askbot_settings.APP_URL)
data = {
- 'validation_link': askbot_settings.APP_URL + \
+ 'validation_link': url.scheme + '://' + url.netloc + \
reverse(
'user_account_recover',
kwargs={'key':user.email_key}
diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst
index ce18fe11..b4b810d6 100644
--- a/askbot/doc/source/changelog.rst
+++ b/askbot/doc/source/changelog.rst
@@ -1,6 +1,20 @@
Changes in Askbot
=================
+Development version (not released yet)
+--------------------------------------
+* Made email recovery link work when askbot is deployed on subdirectory (Evgeny)
+* Added tests for the CSRF_COOKIE_DOMAIN setting in the startup_procedures (Evgeny)
+* Askbot now respects django's staticfiles app (Radim Řehůřek, Evgeny)
+
+0.7.39 (Jan 11, 2012)
+---------------------
+* restored facebook login after FB changed the procedure (Evgeny)
+
+0.7.38 (Jan 11, 2012)
+---------------------
+* xss vulnerability fix, issue found by Radim Řehůřek (Evgeny)
+
0.7.37 (Jan 8, 2012)
--------------------
* added basic slugification treatment to question titles with
diff --git a/askbot/doc/source/deployment.rst b/askbot/doc/source/deployment.rst
index 8baa99c0..1ca7553f 100644
--- a/askbot/doc/source/deployment.rst
+++ b/askbot/doc/source/deployment.rst
@@ -6,18 +6,30 @@ Deploying Askbot
Deploying askbot (assuming that it is already installed) entails:
+* collecting static media files
* setting correct file access permissions
* configuring the webserver to work with your application
This document currently explains the configuration under Apache and mod_wsgi_.
+Collecting static media files
+-----------------------------
+Static media must be collected into a single location with a command::
+
+ python manage.py collectstatic
+
+There are several options on where to put the static files - the simplest is
+a local directory, but it is also possible to use a dedicated static files
+storage or a CDN, for more information see django documentation about
+serving static files.
+
Setting up file access permissions
----------------------------------
Webserver process must be able to write to the following locations within your project::
- log/
- askbot/upfiles
+ log/
+ askbot/upfiles
If you know user name or the group name under which the webserver runs,
you can make those directories writable by setting the permissons
@@ -26,11 +38,11 @@ accordingly:
For example, if you are using Linux installation of apache webserver running under
group name 'apache' you could do the following::
- cd /path/to/django-project
- cd .. #go one level up
- chown -R yourlogin:apache django-project
- chmod -R g+w django-project/askbot/upfiles
- chmod -R g+w django-project/log
+ cd /path/to/django-project
+ cd .. #go one level up
+ chown -R yourlogin:apache django-project
+ chmod -R g+w django-project/askbot/upfiles
+ chmod -R g+w django-project/log
If your account somehow limits you from running such commands - please consult your
system administrator.
@@ -71,9 +83,8 @@ Settings below are not perfect but may be a good starting point::
#aliases to serve static media directly
#will probably need adjustment
- Alias /m/ /usr/local/lib/python2.6/site-packages/askbot/skins/
+ Alias /static/ /path/to/django-project/static/
Alias /upfiles/ /path/to/django-project/askbot/upfiles/
- Alias /admin/media/ /usr/local/lib/python2.6/site-packages/django/contrib/admin/media/
<DirectoryMatch "/path/to/django-project/askbot/skins/([^/]+)/media">
Order deny,allow
Allow from all
diff --git a/askbot/management/commands/send_email_alerts.py b/askbot/management/commands/send_email_alerts.py
index d7966e83..c17c678e 100644
--- a/askbot/management/commands/send_email_alerts.py
+++ b/askbot/management/commands/send_email_alerts.py
@@ -453,33 +453,6 @@ class Command(NoArgsCommand):
# 'the askbot and see what\'s new!<br>'
# )
- text += _(
- 'Please visit the askbot and see what\'s new! '
- 'Could you spread the word about it - '
- 'can somebody you know help answering those questions or '
- 'benefit from posting one?'
- )
-
- feeds = EmailFeedSetting.objects.filter(subscriber = user)
- feed_freq = [feed.frequency for feed in feeds]
- text += '<p></p>'
- if 'd' in feed_freq:
- text += _('Your most frequent subscription setting is \'daily\' '
- 'on selected questions. If you are receiving more than one '
- 'email per day'
- 'please tell about this issue to the askbot administrator.'
- )
- elif 'w' in feed_freq:
- text += _('Your most frequent subscription setting is \'weekly\' '
- 'if you are receiving this email more than once a week '
- 'please report this issue to the askbot administrator.'
- )
- text += ' '
- text += _(
- 'There is a chance that you may be receiving links seen '
- 'before - due to a technicality that will eventually go away. '
- )
-
link = url_prefix + reverse(
'user_subscriptions',
kwargs = {
diff --git a/askbot/setup_templates/settings.py b/askbot/setup_templates/settings.py
index ed51d2c4..6d263816 100644
--- a/askbot/setup_templates/settings.py
+++ b/askbot/setup_templates/settings.py
@@ -3,11 +3,13 @@ import os.path
import logging
import sys
import askbot
+import site
#this line is added so that we can import pre-packaged askbot dependencies
-sys.path.append(os.path.join(os.path.dirname(askbot.__file__), 'deps'))
+ASKBOT_ROOT = os.path.abspath(os.path.dirname(askbot.__file__))
+site.addsitedir(os.path.join(ASKBOT_ROOT, 'deps'))
-DEBUG = False#set to True to enable debugging
+DEBUG = True#set to True to enable debugging
TEMPLATE_DEBUG = False#keep false when debugging jinja2 templates
INTERNAL_IPS = ('127.0.0.1',)
@@ -69,14 +71,16 @@ LANGUAGE_CODE = 'en'
# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'askbot', 'upfiles')
-MEDIA_URL = '/upfiles/'
+MEDIA_URL = '/upfiles/'#url to uploaded media
+STATIC_URL = '/m/'#url to project static files
PROJECT_ROOT = os.path.dirname(__file__)
+STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static')#path to files collected by collectstatic
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
-ADMIN_MEDIA_PREFIX = '/admin/media/'
+ADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/'#must be this value
# Make up some unique string, and don't share it with anybody.
SECRET_KEY = 'sdljdfjkldsflsdjkhsjkldgjlsdgfs s '
@@ -149,6 +153,7 @@ INSTALLED_APPS = (
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
+ 'django.contrib.staticfiles',
#all of these are needed for the askbot
'django.contrib.admin',
@@ -218,3 +223,5 @@ djcelery.setup_loader()
CSRF_COOKIE_NAME = 'askbot_csrf'
CSRF_COOKIE_DOMAIN = ''#enter domain name here - e.g. example.com
+
+STATICFILES_DIRS = ( os.path.join(ASKBOT_ROOT, 'skins'),)
diff --git a/askbot/setup_templates/settings.py.mustache b/askbot/setup_templates/settings.py.mustache
index 0575266c..19fd3c61 100644
--- a/askbot/setup_templates/settings.py.mustache
+++ b/askbot/setup_templates/settings.py.mustache
@@ -3,11 +3,13 @@ import os.path
import logging
import sys
import askbot
+import site
#this line is added so that we can import pre-packaged askbot dependencies
-sys.path.append(os.path.join(os.path.dirname(askbot.__file__), 'deps'))
+ASKBOT_ROOT = os.path.abspath(os.path.dirname(askbot.__file__))
+site.addsitedir(os.path.join(ASKBOT_ROOT, 'deps'))
-DEBUG = False#set to True to enable debugging
+DEBUG = True#set to True to enable debugging
TEMPLATE_DEBUG = False#keep false when debugging jinja2 templates
INTERNAL_IPS = ('127.0.0.1',)
@@ -66,17 +68,19 @@ SITE_ID = 1
USE_I18N = True
LANGUAGE_CODE = 'en'
-# Absolute path to the directory that holds media.
+# Absolute path to the directory that holds uploaded media
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'askbot', 'upfiles')
MEDIA_URL = '/upfiles/'
+STATIC_URL = '/m/'#this must be different from MEDIA_URL
PROJECT_ROOT = os.path.dirname(__file__)
+STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static')
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
-ADMIN_MEDIA_PREFIX = '/admin/media/'
+ADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/'
# Make up some unique string, and don't share it with anybody.
SECRET_KEY = 'sdljdfjkldsflsdjkhsjkldgjlsdgfs s '
@@ -148,6 +152,7 @@ INSTALLED_APPS = (
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
+ {{ staticfiles_app }}
#all of these are needed for the askbot
'django.contrib.admin',
@@ -218,3 +223,6 @@ DOMAIN_NAME = '{{domain_name}}'
CSRF_COOKIE_NAME = '{{domain_name}}_csrf'
CSRF_COOKIE_DOMAIN = DOMAIN_NAME
+
+STATIC_ROOT = os.path.join(PROJECT_ROOT, "static")
+STATICFILES_DIRS = (os.path.join(ASKBOT_ROOT, 'skins'),)
diff --git a/askbot/skins/common/media/js/utils.js b/askbot/skins/common/media/js/utils.js
index 0b9957a0..9e02b5d4 100644
--- a/askbot/skins/common/media/js/utils.js
+++ b/askbot/skins/common/media/js/utils.js
@@ -1,6 +1,6 @@
//var $, scriptUrl, askbotSkin
var mediaUrl = function(resource){
- return scriptUrl + 'm/' + askbotSkin + '/' + resource;
+ return askbot['settings']['static_url'] + askbotSkin + '/' + resource;
};
var cleanUrl = function(url){
diff --git a/askbot/skins/common/templates/authopenid/signin.html b/askbot/skins/common/templates/authopenid/signin.html
index 305574f0..7fdbe203 100644
--- a/askbot/skins/common/templates/authopenid/signin.html
+++ b/askbot/skins/common/templates/authopenid/signin.html
@@ -11,14 +11,14 @@
{% endif %}
{% if answer %}
<div class="message">
- {% trans title=answer.question.thread.title, summary=answer.summary %}
+ {% trans title=answer.question.title|escape, summary=answer.summary|escape %}
Your answer to {{title}} {{summary}} will be posted once you log in
{% endtrans %}
</div>
{% endif %}
{% if question %}
<div class="message">
- {% trans title=question.title, summary=question.summary %}Your question
+ {% trans title=question.title|escape, summary=question.summary|escape %}Your question
{{title}} {{summary}} will be posted once you log in
{% endtrans %}
</div>
diff --git a/askbot/skins/common/templates/debug_header.html b/askbot/skins/common/templates/debug_header.html
new file mode 100644
index 00000000..e1230265
--- /dev/null
+++ b/askbot/skins/common/templates/debug_header.html
@@ -0,0 +1,27 @@
+{% if settings.USING_RUNSERVER %}
+ {% if settings.DEBUG == False %}
+ <div>
+ <p>
+ You are seeing this message because you are using Django runserver
+ and DEBUG_MODE is False. Runserver should not be used in production.
+ </p>
+ <p>
+ To serve static media in production - please run:
+ <pre>python manage.py collectstatic</pre>
+ </p>
+ <p>
+ If you do not see page styling - set DEBUG_MODE = True.
+ </p>
+ </div>
+ {% endif %}
+{% else %}
+ {% if settings.DEBUG == True %}
+ <div>
+ <p>
+ Debug mode is on, do not use it in production.
+ To turn it off, use DEBUG = False in your
+ settings.py file.
+ </p>
+ </div>
+ {% endif %}
+{% endif %}
diff --git a/askbot/skins/default/templates/base.html b/askbot/skins/default/templates/base.html
index 8287f5ba..39b89fe8 100644
--- a/askbot/skins/default/templates/base.html
+++ b/askbot/skins/default/templates/base.html
@@ -16,6 +16,7 @@
{% endspaceless %}
<body class="{% block body_class %}{% endblock %}{% if user_messages %} user-messages{% endif %}{% if page_class %} {{page_class}}{% endif %}{% if request.user.is_anonymous() %} anon{% endif %} lang-{{settings.LANGUAGE_CODE}}">
{% include "widgets/system_messages.html" %}
+ {% include "debug_header.html" %}
{% include "custom_header.html" ignore missing %}
{% if settings.CUSTOM_HEADER|trim != '' %}
<div id="custom-header">
diff --git a/askbot/skins/default/templates/close.html b/askbot/skins/default/templates/close.html
index d8160865..bac2b3ee 100644
--- a/askbot/skins/default/templates/close.html
+++ b/askbot/skins/default/templates/close.html
@@ -4,7 +4,7 @@
{% block content %}
<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>
+ <strong>{{ question.get_question_title()|escape }}</strong></a>
</p>
<form id="fmclose" action="{% url close question.id %}" method="post" >{% csrf_token %}
<p>
diff --git a/askbot/skins/default/templates/meta/bottom_scripts.html b/askbot/skins/default/templates/meta/bottom_scripts.html
index 24a79478..dd5cb202 100644
--- a/askbot/skins/default/templates/meta/bottom_scripts.html
+++ b/askbot/skins/default/templates/meta/bottom_scripts.html
@@ -28,6 +28,7 @@
askbot['urls']['follow_user'] = '/followit/follow/user/{{'{{'}}userId{{'}}'}}/';
askbot['urls']['unfollow_user'] = '/followit/unfollow/user/{{'{{'}}userId{{'}}'}}/';
askbot['urls']['user_signin'] = '{{ settings.LOGIN_URL }}';
+ askbot['settings']['static_url'] = '{{ settings.STATIC_URL }}';
</script>
<script
type="text/javascript"
diff --git a/askbot/skins/default/templates/question.html b/askbot/skins/default/templates/question.html
index 0c4ce4cc..33c0e11f 100644
--- a/askbot/skins/default/templates/question.html
+++ b/askbot/skins/default/templates/question.html
@@ -1,6 +1,6 @@
{% extends "two_column_body.html" %}
<!-- question.html -->
-{% block title %}{% spaceless %}{{ thread.get_title(question) }}{% endspaceless %}{% endblock %}
+{% block title %}{% spaceless %}{{ question.get_question_title()|escape }}{% endspaceless %}{% endblock %}
{% block meta_description %}
<meta name="description" content="{{question.summary|striptags|escape}}" />
{% endblock %}
diff --git a/askbot/skins/default/templates/question/question_card.html b/askbot/skins/default/templates/question/question_card.html
index d71ff69b..ff4ada1d 100644
--- a/askbot/skins/default/templates/question/question_card.html
+++ b/askbot/skins/default/templates/question/question_card.html
@@ -9,8 +9,7 @@
</div>
<div class="question-content">
- <h1><a href="{{ question.get_absolute_url() }}">{{ thread.get_title(question) }}</a></h1>
- {# ==== START: question/question_tags.html" #}
+ <h1><a href="{{ question.get_absolute_url() }}">{{ thread.get_title(question)|escape }}</a></h1>
{% include "question/question_tags.html" %}
{# ==== END: question/question_tags.html" #}
diff --git a/askbot/skins/default/templates/question/sidebar.html b/askbot/skins/default/templates/question/sidebar.html
index c2eb3842..bc6a58c9 100644
--- a/askbot/skins/default/templates/question/sidebar.html
+++ b/askbot/skins/default/templates/question/sidebar.html
@@ -64,7 +64,7 @@
<div class="questions-related">
{% for thread_dict in similar_threads.data() %}
<p>
- <a href="{{ thread_dict.url }}">{{ thread_dict.title }}</a>
+ <a href="{{ thread_dict.url }}">{{ thread_dict.title|escape }}</a>
</p>
{% endfor %}
</div>
diff --git a/askbot/skins/default/templates/question_retag.html b/askbot/skins/default/templates/question_retag.html
index c8981f72..d15813e5 100644
--- a/askbot/skins/default/templates/question_retag.html
+++ b/askbot/skins/default/templates/question_retag.html
@@ -5,7 +5,7 @@
<h1>{% trans %}Change tags{% endtrans %} [<a href="{{ question.get_absolute_url() }}">{% trans %}back{% endtrans %}</a>]</h1>
<form id="fmretag" action="{% url retag_question question.id %}" method="post" >{% csrf_token %}
<h2>
- {{ question.thread.get_title() }}
+ {{ question.thread.get_title()|escape }}
</h2>
<div id="description" class="edit-content-html">
{{ question.html }}
diff --git a/askbot/skins/default/templates/question_widget.html b/askbot/skins/default/templates/question_widget.html
index 0aee8f05..65ee8b64 100644
--- a/askbot/skins/default/templates/question_widget.html
+++ b/askbot/skins/default/templates/question_widget.html
@@ -12,7 +12,7 @@
<ul>
{% for thread in threads %}
<li><a href="{{settings.APP_URL}}{{ thread.get_absolute_url() }}">
- {{ thread.title }}</a></li>
+ {{ thread.title|escape }}</a></li>
{% endfor %}
</ul>
</div>
diff --git a/askbot/skins/default/templates/reopen.html b/askbot/skins/default/templates/reopen.html
index 46c86e8b..d1ccc313 100644
--- a/askbot/skins/default/templates/reopen.html
+++ b/askbot/skins/default/templates/reopen.html
@@ -5,7 +5,7 @@
<h1>{% trans %}Reopen question{% endtrans %}</h1>
<p>{% trans %}Title{% endtrans %}:
<a href="{{ question.get_absolute_url() }}">
- <span class="big">{{ question.get_question_title() }}</span>
+ <span class="big">{{ question.get_question_title()|escape }}</span>
</a>
</p>
<p>{% trans %}This question has been closed by
diff --git a/askbot/skins/default/templates/revisions.html b/askbot/skins/default/templates/revisions.html
index a4e429a4..07b98b5b 100644
--- a/askbot/skins/default/templates/revisions.html
+++ b/askbot/skins/default/templates/revisions.html
@@ -30,7 +30,7 @@
<td width="200px" style="vertical-align:middle">
{% if revision.summary %}
<div class="summary">
- <span>{{ revision.summary }}</span>
+ <span>{{ revision.summary|escape }}</span>
</div>
{% endif %}
{% if request.user|can_edit_post(post) %}
diff --git a/askbot/skins/default/templates/user_profile/user_recent.html b/askbot/skins/default/templates/user_profile/user_recent.html
index a8fd4890..bace94d8 100644
--- a/askbot/skins/default/templates/user_profile/user_recent.html
+++ b/askbot/skins/default/templates/user_profile/user_recent.html
@@ -20,11 +20,11 @@
</a>
{% if act.content_object.post_type == 'question' %}
{% set question=act.content_object %}
- (<a title="{{question.summary|collapse}}"
+ (<a title="{{question.summary|collapse|escape}}"
href="{% url question question.id %}{{question.thread.title|slugify}}">{% trans %}source{% endtrans %}</a>)
{% elif act.content_object.post_type == 'answer' %}
{% set answer=act.content_object %}
- (<a title="{{answer.text|collapse}}"
+ (<a title="{{answer.text|collapse|escape}}"
href="{% url question answer.thread._question_post().id %}{{answer.thread.title|slugify}}#{{answer.id}}">{% trans %}source{% endtrans %}</a>)
{% endif %}
{% else %}
diff --git a/askbot/skins/default/templates/user_profile/user_stats.html b/askbot/skins/default/templates/user_profile/user_stats.html
index 0b85f648..793bce77 100644
--- a/askbot/skins/default/templates/user_profile/user_stats.html
+++ b/askbot/skins/default/templates/user_profile/user_stats.html
@@ -18,7 +18,7 @@
<div class="user-stats-table">
{% for top_answer in top_answers %}
<div class="answer-summary">
- <a title="{{ top_answer.summary|collapse }}"
+ <a title="{{ top_answer.summary|collapse|escape }}"
href="{% url question top_answer.thread._question_post().id %}{{ top_answer.thread.title|slugify }}#{{ top_answer.id }}">
<span class="answer-votes {% if top_answer.accepted() %}answered-accepted{% endif %}"
title="{% trans answer_score=top_answer.score %}the answer has been voted for {{ answer_score }} times{% endtrans %} {% if top_answer.accepted() %}{% trans %}this answer has been selected as correct{% endtrans %}{%endif%}">
@@ -27,7 +27,7 @@
</a>
<div class="answer-link">
{% spaceless %}
- <a href="{% url question top_answer.thread._question_post().id %}{{ top_answer.thread.title|slugify }}#{{top_answer.id}}">{{ top_answer.thread.title }}</a>
+ <a href="{% url question top_answer.thread._question_post().id %}{{ top_answer.thread.title|slugify }}#{{top_answer.id}}">{{ top_answer.thread.title|escape }}</a>
{% endspaceless %}
{% if top_answer.comment_count > 0 %}
<span>
@@ -122,6 +122,7 @@
{% endif %}
{% endfor %}
</ul>
+<<<<<<< HEAD
{% if loop.index is divisibleby 3 %}
</td></tr>
<tr><td style="line-height:35px">
@@ -131,6 +132,51 @@
</tr>
</table>
</div>
+=======
+ </td>
+ </tr>
+ </table>
+ </div>
+ <a name="badges"></a>
+ {% spaceless %}
+ <h2>{% trans counter=total_awards %}<span class="count">{{counter}}</span> Badge{% pluralize %}<span class="count">{{counter}}</span> Badges{% endtrans %}</h2>
+ {% endspaceless %}
+ <div class="user-stats-table badges">
+ <table>
+ <tr>
+ <td style="line-height:35px">
+ {% for badge in badges %}{# todo: translate badge name properly #}
+ <a
+ href="{{badge.get_absolute_url()}}"
+ title="{% trans description=badge.description %}{{description}}{% endtrans %}"
+ class="medal"
+ ><span class="{{ badge.css_class }}">&#9679;</span>&nbsp;{% trans name=badge.name %}{{name}}{% endtrans %}
+ </a>&nbsp;
+ <span class="tag-number">&#215;
+ <span class="badge-context-toggle">{{ badge.award_badge.count()|intcomma }}</span>
+ </span>
+ <ul id="badge-context-{{ badge.id }}" class="badge-context-list" style="display:none">
+ {% for award in badge.award_badge.filter(user = view_user) %}
+ {% if award.content_type in (question_type, answer_type) %}
+ <li>
+ <a
+ title="{{ award.content_object.get_snippet()|collapse }}"
+ href="{{ award.content_object.get_absolute_url() }}"
+ >{% if award.content_type == answer_type %}{% trans %}Answer to:{% endtrans %}{% endif %} {{ award.content_object.get_origin_post().title|escape }}</a>
+ </li>
+ {% endif %}
+ {% endfor %}
+ </ul>
+ {% if loop.index is divisibleby 3 %}
+ </td></tr>
+ <tr><td style="line-height:35px">
+ {% endif %}
+ {% endfor %}
+ </td>
+ </tr>
+ </table>
+ </div>
+>>>>>>> master
{% endblock %}
{% block endjs %}
{{ super() }}
diff --git a/askbot/skins/default/templates/widgets/ask_form.html b/askbot/skins/default/templates/widgets/ask_form.html
index 18196d93..17dc89f5 100644
--- a/askbot/skins/default/templates/widgets/ask_form.html
+++ b/askbot/skins/default/templates/widgets/ask_form.html
@@ -14,7 +14,7 @@
{% endif %}
{% endif %}
<input id="id_title" class="questionTitleInput" name="title" autocomplete="off"
- value="{% if form.initial.title %}{{form.initial.title}}{% endif %}"/>
+ value="{% if form.initial.title %}{{form.initial.title|escape}}{% endif %}"/>
<span class="form-error">{{ form.title.errors }}</span>
</div>
<div class="title-desc">
diff --git a/askbot/skins/utils.py b/askbot/skins/utils.py
index 50c0d4fb..520fa2f7 100644
--- a/askbot/skins/utils.py
+++ b/askbot/skins/utils.py
@@ -154,13 +154,8 @@ def get_media_url(url, ignore_missing = False):
logging.critical(log_message)
return None
- url = use_skin + '/media/' + url
- url = '///' + django_settings.ASKBOT_URL + 'm/' + url
- url = os.path.normpath(url).replace(
- '\\', '/'
- ).replace(
- '///', '/'
- )
+ url = django_settings.STATIC_URL + use_skin + '/media/' + url
+ url = os.path.normpath(url).replace('\\', '/')
if resource_revision:
url += '?v=%d' % resource_revision
diff --git a/askbot/startup_procedures.py b/askbot/startup_procedures.py
index 448f8a29..966e98e2 100644
--- a/askbot/startup_procedures.py
+++ b/askbot/startup_procedures.py
@@ -9,22 +9,58 @@ the main function is run_startup_tests
"""
import sys
import os
+import re
+import askbot
from django.db import transaction
from django.conf import settings as django_settings
from django.core.exceptions import ImproperlyConfigured
from askbot.utils.loading import load_module
+from askbot.utils.functions import enumerate_string_list
+from urlparse import urlparse
PREAMBLE = """\n
************************
* *
* Askbot self-test *
* *
-************************"""
+************************\n
+"""
+
+FOOTER = """\n
+If necessary, type ^C (Ctrl-C) to stop the program.
+"""
+
+class AskbotConfigError(ImproperlyConfigured):
+ """Prints an error with a preamble and possibly a footer"""
+ def __init__(self, error_message):
+ msg = PREAMBLE + error_message
+ if sys.__stdin__.isatty():
+ #print footer only when askbot is run from the shell
+ msg += FOOTER
+ super(AskbotConfigError, self).__init__(msg)
def askbot_warning(line):
"""prints a warning with the nice header, but does not quit"""
print >> sys.stderr, PREAMBLE + '\n' + line
+def print_errors(error_messages, header = None, footer = None):
+ """if there is one or more error messages,
+ raise ``class:AskbotConfigError`` with the human readable
+ contents of the message
+ * ``header`` - text to show above messages
+ * ``footer`` - text to show below messages
+ """
+ if len(error_messages) == 0: return
+ if len(error_messages) > 1:
+ error_messages = enumerate_string_list(error_messages)
+
+ message = ''
+ if header: message += header + '\n'
+ message += 'Please attend to the following:\n\n'
+ message += '\n\n'.join(error_messages)
+ if footer: message += '\n\n' + footer
+ raise AskbotConfigError(message)
+
def format_as_text_tuple_entries(items):
"""prints out as entries or tuple containing strings
ready for copy-pasting into say django settings file"""
@@ -45,21 +81,21 @@ def test_askbot_url():
pass
else:
msg = 'setting ASKBOT_URL must be of string or unicode type'
- raise ImproperlyConfigured(msg)
+ raise AskbotConfigError(msg)
if url == '/':
msg = 'value "/" for ASKBOT_URL is invalid. '+ \
'Please, either make ASKBOT_URL an empty string ' + \
'or a non-empty path, ending with "/" but not ' + \
'starting with "/", for example: "forum/"'
- raise ImproperlyConfigured(msg)
+ raise AskbotConfigError(msg)
else:
try:
assert(url.endswith('/'))
except AssertionError:
msg = 'if ASKBOT_URL setting is not empty, ' + \
'it must end with /'
- raise ImproperlyConfigured(msg)
+ raise AskbotConfigError(msg)
try:
assert(not url.startswith('/'))
except AssertionError:
@@ -69,7 +105,7 @@ def test_askbot_url():
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.
+ case - raises an AskbotConfigError exception.
"""
required_middleware = (
'django.contrib.sessions.middleware.SessionMiddleware',
@@ -95,7 +131,7 @@ 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"""
middleware_text = format_as_text_tuple_entries(missing_middleware_set)
- raise ImproperlyConfigured(PREAMBLE + error_message + middleware_text)
+ raise AskbotConfigError(error_message + middleware_text)
#middleware that was used in the past an now removed
@@ -110,7 +146,7 @@ https://github.com/ASKBOT/askbot-devel/blob/master/askbot/setup_templates/settin
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)
- raise ImproperlyConfigured(PREAMBLE + error_message + middleware_text)
+ raise AskbotConfigError(error_message + middleware_text)
def try_import(module_name, pypi_package_name):
"""tries importing a module and advises to install
@@ -123,7 +159,7 @@ def try_import(module_name, pypi_package_name):
message += '\n\nTo install all the dependencies at once, type:'
message += '\npip install -r askbot_requirements.txt\n'
message += '\nType ^C to quit.'
- raise ImproperlyConfigured(message)
+ raise AskbotConfigError(message)
def test_modules():
"""tests presence of required modules"""
@@ -139,7 +175,7 @@ def test_postgres():
import psycopg2
version = psycopg2.__version__.split(' ')[0].split('.')
if version == ['2', '4', '2']:
- raise ImproperlyConfigured(
+ raise AskbotConfigError(
'Please install psycopg2 version 2.4.1,\n version 2.4.2 has a bug'
)
elif version > ['2', '4', '2']:
@@ -169,7 +205,7 @@ def test_template_loader():
loader that used to send a warning"""
old_template_loader = 'askbot.skins.loaders.load_template_source'
if old_template_loader in django_settings.TEMPLATE_LOADERS:
- raise ImproperlyConfigured(PREAMBLE + \
+ raise AskbotConfigError(
"\nPlease change: \n"
"'askbot.skins.loaders.load_template_source', to\n"
"'askbot.skins.loaders.filesystem_load_template_source',\n"
@@ -187,7 +223,7 @@ def test_celery():
if broker_backend is None:
if broker_transport is None:
- raise ImproperlyConfigured(PREAMBLE + \
+ raise AskbotConfigError(
"\nPlease add\n"
'BROKER_TRANSPORT = "djkombu.transport.DatabaseTransport"\n'
"or other valid value to your settings.py file"
@@ -197,7 +233,7 @@ def test_celery():
return
if broker_backend != broker_transport:
- raise ImproperlyConfigured(PREAMBLE + \
+ raise AskbotConfigError(
"\nPlease rename setting BROKER_BACKEND to BROKER_TRANSPORT\n"
"in your settings.py file\n"
"If you have both in your settings.py - then\n"
@@ -205,7 +241,7 @@ def test_celery():
)
if hasattr(django_settings, 'BROKER_BACKEND') and not hasattr(django_settings, 'BROKER_TRANSPORT'):
- raise ImproperlyConfigured(PREAMBLE + \
+ raise AskbotConfigError(
"\nPlease rename setting BROKER_BACKEND to BROKER_TRANSPORT\n"
"in your settings.py file"
)
@@ -216,7 +252,7 @@ def test_media_url():
media_url = django_settings.MEDIA_URL
#todo: add proper url validation to MEDIA_URL setting
if not (media_url.startswith('/') or media_url.startswith('http')):
- raise ImproperlyConfigured(PREAMBLE + \
+ raise AskbotConfigError(
"\nMEDIA_URL parameter must be a unique url on the site\n"
"and must start with a slash - e.g. /media/ or http(s)://"
)
@@ -265,11 +301,129 @@ class SettingsTester(object):
**self.requirements[setting_name]
)
if len(self.messages) != 0:
- raise ImproperlyConfigured(
- PREAMBLE +
+ raise AskbotConfigError(
'\n\nTime to do some maintenance of your settings.py:\n\n* ' +
'\n\n* '.join(self.messages)
)
+
+def test_staticfiles():
+ """tests configuration of the staticfiles app"""
+ errors = list()
+ import django
+ django_version = django.VERSION
+ if django_version[0] == 1 and django_version[1] < 3:
+ staticfiles_app_name = 'staticfiles'
+ wrong_staticfiles_app_name = 'django.contrib.staticfiles'
+ try_import('staticfiles', 'django-staticfiles')
+ import staticfiles
+ if staticfiles.__version__[0] != 1:
+ raise AskbotConfigError(
+ 'Please use the newest available version of '
+ 'django-staticfiles app, type\n'
+ 'pip install --upgrade django-staticfiles'
+ )
+ if not hasattr(django_settings, 'STATICFILES_STORAGE'):
+ raise AskbotConfigError(
+ 'Configure STATICFILES_STORAGE setting as desired, '
+ 'a reasonable default is\n'
+ "STATICFILES_STORAGE = 'staticfiles.storage.StaticFilesStorage'"
+ )
+ else:
+ staticfiles_app_name = 'django.contrib.staticfiles'
+ wrong_staticfiles_app_name = 'staticfiles'
+
+ if staticfiles_app_name not in django_settings.INSTALLED_APPS:
+ errors.append(
+ 'Add to the INSTALLED_APPS section of your settings.py:\n'
+ " '%s'," % staticfiles_app_name
+ )
+ if wrong_staticfiles_app_name in django_settings.INSTALLED_APPS:
+ errors.append(
+ 'Remove from the INSTALLED_APPS section of your settings.py:\n'
+ " '%s'," % wrong_staticfiles_app_name
+ )
+ static_url = django_settings.STATIC_URL
+ if static_url is None or str(static_url).strip() == '':
+ errors.append(
+ 'Add STATIC_URL setting to your settings.py file. '
+ 'The setting must be a url at which static files '
+ 'are accessible.'
+ )
+ url = urlparse(static_url).path
+ if not (url.startswith('/') and url.endswith('/')):
+ #a simple check for the url
+ errors.append(
+ 'Path in the STATIC_URL must start and end with the /.'
+ )
+ if django_settings.ADMIN_MEDIA_PREFIX != static_url + 'admin/':
+ errors.append(
+ 'Set ADMIN_MEDIA_PREFIX as: \n'
+ " ADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/'"
+ )
+
+ 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):
+ errors.append(
+ 'Add to STATICFILES_DIRS list of your settings.py file:\n'
+ " '%s'," % skin_dir
+ )
+ extra_skins_dir = getattr(django_settings, 'ASKBOT_EXTRA_SKINS_DIR', None)
+ if extra_skins_dir is not None:
+ if not os.path.isdir(extra_skins_dir):
+ errors.append(
+ '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:
+ errors.append(
+ 'Add ASKBOT_EXTRA_SKINS_DIR to STATICFILES_DIRS entry in '
+ 'your settings.py file.\n'
+ 'NOTE: it might be necessary to move the line with '
+ 'ASKBOT_EXTRA_SKINS_DIR just above STATICFILES_DIRS.'
+ )
+
+ if errors:
+ errors.append(
+ 'Run command (after fixing the above errors)\n'
+ ' python manage.py collectstatic\n'
+ )
+ print_errors(errors)
+ if django_settings.DEBUG and django_settings.STATICFILES_STORAGE == \
+ 'django.contrib.staticfiles.storage.StaticFilesStorage':
+ if not os.path.isdir(django_settings.STATIC_ROOT):
+ askbot_warning(
+ 'Please run command\n\n'
+ ' python manage.py collectstatic'
+
+ )
+
+def test_csrf_cookie_domain():
+ """makes sure that csrf cookie domain setting is acceptable"""
+ #todo: maybe use the same steps to clean domain name
+ csrf_cookie_domain = django_settings.CSRF_COOKIE_DOMAIN
+ if csrf_cookie_domain == 'localhost':
+ raise ImproperlyConfigured(
+ PREAMBLE +
+ '\n\nPlease do not use value "localhost" for the setting '
+ 'CSRF_COOKIE_DOMAIN\n'
+ 'instead use 127.0.0.1, a real IP '
+ 'address or domain name.'
+ '\nThe value must match the network location you type in the '
+ 'web browser to reach your site.'
+ )
+ if re.match(r'https?://', csrf_cookie_domain):
+ raise ImproperlyConfigured(
+ PREAMBLE +
+ '\n\nplease remove http(s):// prefix in the CSRF_COOKIE_DOMAIN '
+ 'setting'
+ )
+ if ':' in csrf_cookie_domain:
+ raise ImproperlyConfigured(
+ PREAMBLE +
+ '\n\nPlease do not use port number in the CSRF_COOKIE_DOMAIN '
+ 'setting'
+ )
def run_startup_tests():
"""function that runs
@@ -284,6 +438,8 @@ def run_startup_tests():
#test_postgres()
test_middleware()
test_celery()
+ test_csrf_cookie_domain()
+ test_staticfiles()
settings_tester = SettingsTester({
'CACHE_MIDDLEWARE_ANONYMOUS_ONLY': {
'value': True,
@@ -319,7 +475,7 @@ def run():
"""runs all the startup procedures"""
try:
run_startup_tests()
- except ImproperlyConfigured, error:
+ except AskbotConfigError, error:
transaction.rollback()
print error
sys.exit(1)
diff --git a/askbot/tests/images/logo.gif b/askbot/tests/images/logo.gif
index 8540e12b..8540e12b 100755..100644
--- a/askbot/tests/images/logo.gif
+++ b/askbot/tests/images/logo.gif
Binary files differ
diff --git a/askbot/tests/skin_tests.py b/askbot/tests/skin_tests.py
index ecbea77d..5226e6d6 100644
--- a/askbot/tests/skin_tests.py
+++ b/askbot/tests/skin_tests.py
@@ -41,13 +41,9 @@ class SkinTests(TestCase):
def assert_default_logo_in_skin(self, skin_name):
url = skin_utils.get_media_url(askbot_settings.SITE_LOGO_URL)
self.assertTrue('/' + skin_name + '/' in url)
- response = self.client.get(url)
- self.assertTrue(response.status_code == 200)
def test_default_skin_logo(self):
- """make sure that default logo
- is where it is expected
- """
+ """make sure that default logo is where it is expected"""
self.assert_default_logo_in_skin('default')
def test_switch_to_custom_skin_logo(self):
diff --git a/askbot/urls.py b/askbot/urls.py
index de7b3026..bcae5c85 100644
--- a/askbot/urls.py
+++ b/askbot/urls.py
@@ -36,11 +36,6 @@ urlpatterns = patterns('',
{'sitemaps': sitemaps},
name='sitemap'
),
- url(
- r'^m/(?P<skin>[^/]+)/media/(?P<resource>.*)$',
- views.meta.media,
- name='askbot_media',
- ),
#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'),
diff --git a/askbot/utils/functions.py b/askbot/utils/functions.py
index f47f0d2a..6042414c 100644
--- a/askbot/utils/functions.py
+++ b/askbot/utils/functions.py
@@ -11,6 +11,14 @@ def get_from_dict_or_object(source, key):
return getattr(source, key)
+def enumerate_string_list(strings):
+ """for a list or a tuple ('one', 'two',) return
+ a list formatted as ['1) one', '2) two',]
+ """
+ numbered_strings = enumerate(strings, start = 1)
+ return [ '%d) %s' % item for item in numbered_strings ]
+
+
def is_iterable(thing):
if hasattr(thing, '__iter__'):
return True
diff --git a/askbot/views/meta.py b/askbot/views/meta.py
index 6415077a..884ec5e4 100644
--- a/askbot/views/meta.py
+++ b/askbot/views/meta.py
@@ -136,14 +136,3 @@ def badge(request, id):
'page_class': 'meta',
}
return render_into_skin('badge.html', data, request)
-
-def media(request, skin, resource):
- """view that serves static media from any skin
- uses django static serve view, where document root is
- adjusted according to the current skin selection
-
- in production this views should be by-passed via server configuration
- for the better efficiency of serving static files
- """
- dir = skins.utils.get_path_to_skin(skin)
- return static.serve(request, '/media/' + resource, document_root = dir)