diff options
30 files changed, 204 insertions, 172 deletions
diff --git a/askbot/__init__.py b/askbot/__init__.py index d4727712..7b12329c 100644 --- a/askbot/__init__.py +++ b/askbot/__init__.py @@ -9,7 +9,7 @@ import smtplib import sys import logging -VERSION = (0, 7, 36) +VERSION = (0, 7, 37) #keys are module names used by python imports, #values - the package qualifier to use for pip diff --git a/askbot/conf/license.py b/askbot/conf/license.py index 20a2743f..faf50697 100644 --- a/askbot/conf/license.py +++ b/askbot/conf/license.py @@ -76,8 +76,6 @@ settings.register( LICENSE_SETTINGS, 'LICENSE_LOGO_URL', description = _('License logo image'), - upload_directory = django_settings.ASKBOT_FILE_UPLOAD_DIR, - upload_url = '/' + django_settings.ASKBOT_UPLOADED_FILES_URL, default = '/images/cc-by-sa.png', url_resolver = skin_utils.get_media_url ) diff --git a/askbot/conf/login_providers.py b/askbot/conf/login_providers.py index b6073eea..3fab7d6a 100644 --- a/askbot/conf/login_providers.py +++ b/askbot/conf/login_providers.py @@ -56,8 +56,6 @@ settings.register( livesettings.ImageValue( LOGIN_PROVIDERS, 'WORDPRESS_SITE_ICON', - upload_directory=django_settings.ASKBOT_FILE_UPLOAD_DIR, - upload_url='/' + django_settings.ASKBOT_UPLOADED_FILES_URL, default='/images/logo.gif', description=_('Upload your icon'), url_resolver=skin_utils.get_media_url diff --git a/askbot/conf/skin_general_settings.py b/askbot/conf/skin_general_settings.py index 387ac1f6..ccecdaba 100644 --- a/askbot/conf/skin_general_settings.py +++ b/askbot/conf/skin_general_settings.py @@ -25,8 +25,6 @@ settings.register( 'To change the logo, select new file, ' 'then submit this whole form.' ), - upload_directory = django_settings.ASKBOT_FILE_UPLOAD_DIR, - upload_url = django_settings.ASKBOT_URL + '/' + django_settings.ASKBOT_UPLOADED_FILES_URL, default = '/images/logo.gif', url_resolver = skin_utils.get_media_url ) @@ -58,9 +56,7 @@ settings.register( 'about favicon ' 'at <a href="%(favicon_info_url)s">this page</a>.' ) % {'favicon_info_url': const.DEPENDENCY_URLS['favicon']}, - upload_directory = django_settings.ASKBOT_FILE_UPLOAD_DIR, allowed_file_extensions = ('ico',),#only allow .ico files - upload_url = '/' + django_settings.ASKBOT_UPLOADED_FILES_URL, default = '/images/favicon.gif', url_resolver = skin_utils.get_media_url ) @@ -75,8 +71,6 @@ settings.register( 'An 88x38 pixel image that is used on the login screen ' 'for the password login button.' ), - upload_directory = django_settings.ASKBOT_FILE_UPLOAD_DIR, - upload_url = '/' + django_settings.ASKBOT_UPLOADED_FILES_URL, default = '/images/pw-login.gif', url_resolver = skin_utils.get_media_url ) diff --git a/askbot/conf/user_settings.py b/askbot/conf/user_settings.py index cec13083..321d38f9 100644 --- a/askbot/conf/user_settings.py +++ b/askbot/conf/user_settings.py @@ -27,6 +27,15 @@ settings.register( settings.register( livesettings.BooleanValue( USER_SETTINGS, + 'EDITABLE_EMAIL', + default = True, + description = _('Allow users change own email addresses') + ) +) + +settings.register( + livesettings.BooleanValue( + USER_SETTINGS, 'ALLOW_ACCOUNT_RECOVERY_BY_EMAIL', default = True, description = _('Allow account recovery by email') @@ -61,8 +70,6 @@ settings.register( 'To change the avatar image, select new file, ' 'then submit this whole form.' ), - upload_directory = django_settings.ASKBOT_FILE_UPLOAD_DIR, - upload_url = '/' + django_settings.ASKBOT_UPLOADED_FILES_URL, default = '/images/nophoto.png', url_resolver = skin_utils.get_media_url ) diff --git a/askbot/deps/livesettings/values.py b/askbot/deps/livesettings/values.py index 9587a16d..e5516d8b 100644 --- a/askbot/deps/livesettings/values.py +++ b/askbot/deps/livesettings/values.py @@ -4,6 +4,7 @@ http://code.google.com/p/django-values/ """ from decimal import Decimal from django import forms +from django.conf import settings as django_settings from django.core.exceptions import ImproperlyConfigured from django.utils import simplejson from django.utils.datastructures import SortedDict @@ -600,8 +601,14 @@ class ImageValue(StringValue): 'allowed_file_extensions', ('jpg', 'gif', 'png') ) - self.upload_directory = kwargs.pop('upload_directory') - self.upload_url = kwargs.pop('upload_url') + self.upload_directory = kwargs.pop( + 'upload_directory', + django_settings.MEDIA_ROOT + ) + self.upload_url = kwargs.pop( + 'upload_url', + django_settings.MEDIA_URL + ) self.url_resolver = kwargs.pop('url_resolver', None) super(ImageValue, self).__init__(*args, **kwargs) @@ -632,13 +639,20 @@ class ImageValue(StringValue): """uploaded_file is an instance of django UploadedFile object """ - #1) come up with a file name + #0) initialize file storage + file_storage_class = storage.get_storage_class() - file_storage = storage.FileSystemStorage( - location = self.upload_directory, - base_url = self.upload_url - ) + storage_settings = {} + if django_settings.DEFAULT_FILE_STORAGE == \ + 'django.core.files.storage.FileSystemStorage': + storage_settings = { + 'location': self.upload_directory, + 'base_url': self.upload_url + } + + file_storage = file_storage_class(**storage_settings) + #1) come up with a file name #todo: need better function here to calc name file_name = file_storage.get_available_name(uploaded_file.name) file_storage.save(file_name, uploaded_file) diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst index c228e158..ce18fe11 100644 --- a/askbot/doc/source/changelog.rst +++ b/askbot/doc/source/changelog.rst @@ -1,8 +1,8 @@ Changes in Askbot ================= -Development version (not released yet) --------------------------------------- +0.7.37 (Jan 8, 2012) +-------------------- * added basic slugification treatment to question titles with ``ALLOW_UNICODE_SLUGS = True`` (Evgeny) * added verification of the project directory name to @@ -15,6 +15,10 @@ Development version (not released yet) text to live settings and allowed body-less questions (Radim Řehůřek, Evgeny) * allowed disabling use of gravatar site-wide (Rosandra Cuello Suñol) * when internal login app is disabled - links to login/logout/add-remove-login-methods are gone (Evgeny) +* replaced setting `ASKBOT_FILE_UPLOAD_DIR` with django's `MEDIA_ROOT` (Evgeny) +* replaced setting `ASKBOT_UPLOADED_FILES_URL` with django's `MEDIA_URL` (Evgeny) +* allowed changing file storage backend for file uploads by configuration (Evgeny) +* file uploads to amazon S3 now work with proper configuration (Evgeny) 0.7.36 (Dec 20, 2011) --------------------- diff --git a/askbot/doc/source/contributors.rst b/askbot/doc/source/contributors.rst index 6285d9a6..30e31175 100644 --- a/askbot/doc/source/contributors.rst +++ b/askbot/doc/source/contributors.rst @@ -39,7 +39,7 @@ Programming and documentation Translations ------------ * Mike Chen, Sailing Cai, suyu8776 - Chinese -* Bruno Sarlo, Adolfo Fitoria - Spanish +* Bruno Sarlo, Adolfo Fitoria, Francisco Espinoza - Spanish * Evgeny Kalinin - Russian * Evgeny Fadeev - English * Oktay Yildiz, Onur Mat, Cemre - Turkish diff --git a/askbot/forms.py b/askbot/forms.py index 00735b72..019e5f83 100644 --- a/askbot/forms.py +++ b/askbot/forms.py @@ -920,7 +920,6 @@ class EditAnswerForm(forms.Form): class EditUserForm(forms.Form): email = forms.EmailField( label=u'Email', - help_text=_('this email will be linked to gravatar'), required=True, max_length=255, widget=forms.TextInput(attrs={'size' : 35}) diff --git a/askbot/locale/es/LC_MESSAGES/django.po b/askbot/locale/es/LC_MESSAGES/django.po index d5a88e1d..b88131cc 100644 --- a/askbot/locale/es/LC_MESSAGES/django.po +++ b/askbot/locale/es/LC_MESSAGES/django.po @@ -22,7 +22,7 @@ msgstr "" #: exceptions.py:13 #, fuzzy msgid "Sorry, but anonymous visitors cannot access this function" -msgstr "usuarios anónimos no pueden votar" +msgstr "Lo sentimos pero los usuarios anónimos no pueden acceder a esta función" #: feed.py:26 feed.py:100 msgid " - " @@ -40,16 +40,16 @@ msgstr "últimas preguntas" #: forms.py:74 #, fuzzy msgid "select country" -msgstr "Eliminar cuenta" +msgstr "seleccione país" #: forms.py:83 msgid "Country" -msgstr "" +msgstr "País" #: forms.py:91 #, fuzzy msgid "Country field is required" -msgstr "este campo es requerido" +msgstr "El campo País es requerido" #: forms.py:104 skins/default/templates/widgets/answer_edit_tips.html:45 #: skins/default/templates/widgets/answer_edit_tips.html:49 @@ -66,8 +66,8 @@ msgstr "por favor ingrese un título descriptivo para su pregunta" #, fuzzy, python-format msgid "title must be > %d character" msgid_plural "title must be > %d characters" -msgstr[0] "el título debe contener más de 10 carácteres" -msgstr[1] "el título debe contener más de 10 carácteres" +msgstr[0] "el título debe contener más de %d carácter" +msgstr[1] "el título debe contener más de %d carácteres" #: forms.py:131 msgid "content" @@ -88,10 +88,10 @@ msgid_plural "" "Tags are short keywords, with no spaces within. Up to %(max_tags)d tags can " "be used." msgstr[0] "" -"Las etiquetas son claves cortas, con o sin espacios. Puedes usar más de 5 " -"etiquetas." +"Las etiquetas son claves cortas, sin espacios. Puedes usar hasta %(max_tags)d " +"etiqueta." msgstr[1] "" -"Las etiquetas son claves cortas, con o sin espacios. Puedes usar más de 5 " +"Las etiquetas son claves cortas, sin espacios. Puedes usar hasta %(max_tags)d " "etiquetas." #: forms.py:201 skins/default/templates/question_retag.html:58 @@ -102,35 +102,35 @@ msgstr "etiquetas requeridas" #, fuzzy, python-format msgid "please use %(tag_count)d tag or less" msgid_plural "please use %(tag_count)d tags or less" -msgstr[0] "por favor, use 5 etiquetas o menos" -msgstr[1] "por favor, use 5 etiquetas o menos" +msgstr[0] "por favor, use %(tag_count)d etiqueta o menos" +msgstr[1] "por favor, use %(tag_count)d etiquetas o menos" #: forms.py:218 #, python-format msgid "At least one of the following tags is required : %(tags)s" -msgstr "" +msgstr "Al menos una de las siguientes etiquetas se requieren : %(tags)s" #: forms.py:227 #, fuzzy, 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] "las etiquetas deben contener menos de 20 carácteres" -msgstr[1] "las etiquetas deben contener menos de 20 carácteres" +msgstr[0] "las etiquetas deben contener menos de %(max_chars)d carácter" +msgstr[1] "las etiquetas deben contener menos de %(max_chars)d carácteres" #: forms.py:235 msgid "use-these-chars-in-tags" -msgstr "" +msgstr "usa-estos-caracteres-en-las-etiquetas" #: forms.py:270 msgid "community wiki (karma is not awarded & many others can edit wiki post)" -msgstr "" +msgstr "wiki comunitaria (no se premia karma y cualquiera puede editar la publicación wiki)" #: forms.py:271 msgid "" "if you choose community wiki option, the question and answer do not generate " "points and name of author will not be shown" msgstr "" -"si marcas la opción Wiki, la pregunta y las respuestas no generan puntos y " +"si marcas la opción Wiki comunitaria,la pregunta y las respuestas no generan puntos y " "el nombre del autor no se muestra" #: forms.py:287 @@ -147,7 +147,7 @@ msgstr "" #: forms.py:364 msgid "Enter number of points to add or subtract" -msgstr "" +msgstr "Ingrese el número de puntos a añadir o quitar" #: forms.py:378 const/__init__.py:250 msgid "approved" @@ -160,7 +160,7 @@ msgstr "visto" #: forms.py:380 const/__init__.py:252 #, fuzzy msgid "suspended" -msgstr "actualizado" +msgstr "pausado" #: forms.py:381 const/__init__.py:253 msgid "blocked" @@ -169,26 +169,26 @@ msgstr "bloqueado" #: forms.py:383 #, fuzzy msgid "administrator" -msgstr "administración" +msgstr "administrador" #: forms.py:384 const/__init__.py:249 #, fuzzy msgid "moderator" -msgstr "moderar-usuario/" +msgstr "moderador" #: forms.py:404 #, fuzzy msgid "Change status to" -msgstr "Cambiar etiquetas" +msgstr "Cambiar estado a" #: forms.py:431 msgid "which one?" -msgstr "" +msgstr "Cuál?" #: forms.py:452 #, fuzzy msgid "Cannot change own status" -msgstr "no se puede votar por sus propias publicaciones" +msgstr "No puede cambiar su propio estado" #: forms.py:458 msgid "Cannot turn other user to moderator" @@ -201,62 +201,64 @@ msgstr "No tiene permitido cambiar el estado de otro moderador" #: forms.py:471 #, fuzzy msgid "Cannot change status to admin" -msgstr "no se puede votar por sus propias publicaciones" +msgstr "No puede cambiar el estado a admin" #: forms.py:477 #, python-format msgid "" "If you wish to change %(username)s's status, please make a meaningful " "selection." -msgstr "" +msgstr "Si desea cambiar el estado de %(username), por favor, haga una selección " +"apropiada." #: forms.py:486 msgid "Subject line" -msgstr "Sujeto" +msgstr "Línea del tema" #: forms.py:493 msgid "Message text" -msgstr "Mensaje de Texto" +msgstr "Texto del mensaje" #: forms.py:579 #, fuzzy msgid "Your name (optional):" -msgstr "Tu nombre:" +msgstr "Su nombre (opcional):" #: forms.py:580 #, fuzzy msgid "Email:" -msgstr "no enviar emails" +msgstr "Correo electrónico:" #: forms.py:582 msgid "Your message:" -msgstr "Tu mensaje:" +msgstr "Su mensaje:" #: forms.py:587 msgid "I don't want to give my email or receive a response:" -msgstr "" +msgstr "No deseo dar mi correo electrónico o recibir una respuesta:" #: forms.py:609 msgid "Please mark \"I dont want to give my mail\" field." -msgstr "" +msgstr "Por favor, marque el campo \"No deseo dar mi correo electrónico\"." #: forms.py:648 msgid "ask anonymously" -msgstr "" +msgstr "pregunte anónimamente" #: forms.py:650 msgid "Check if you do not want to reveal your name when asking this question" -msgstr "" +msgstr "Compruebe si no desea revelar su nombre cuando realice esta pregunta" #: forms.py:810 msgid "" "You have asked this question anonymously, if you decide to reveal your " "identity, please check this box." -msgstr "" +msgstr "Ha solicitado realizar esta pregunta anónimamente, si decide revelar su " +"identidad, por favor marque esta caja." #: forms.py:814 msgid "reveal identity" -msgstr "" +msgstr "revelar identidad" #: forms.py:872 msgid "" diff --git a/askbot/setup_templates/settings.py b/askbot/setup_templates/settings.py index 715e6ce8..27ee77dc 100644 --- a/askbot/setup_templates/settings.py +++ b/askbot/setup_templates/settings.py @@ -68,7 +68,8 @@ LANGUAGE_CODE = 'en' # Absolute path to the directory that holds media. # Example: "/home/media/media.lawrence.com/" -ASKBOT_FILE_UPLOAD_DIR = os.path.join(os.path.dirname(__file__), 'askbot', 'upfiles') +MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'askbot', 'upfiles') +MEDIA_URL = '/upfiles/' PROJECT_ROOT = os.path.dirname(__file__) @@ -167,9 +168,6 @@ INSTALLED_APPS = ( 'djkombu', 'followit', #'avatar',#experimental use git clone git://github.com/ericflo/django-avatar.git$ - #requires setting of MEDIA_ROOT and MEDIA_URL - #values of which can be the same as ASKBOT_FILE_UPLOAD_DIR and ASKBOT_UPLOADED_FILES_URL, - #respectively ) @@ -209,7 +207,6 @@ LOGIN_URL = '/%s%s%s' % (ASKBOT_URL,_('account/'),_('signin/')) LOGIN_REDIRECT_URL = ASKBOT_URL #adjust if needed #note - it is important that upload dir url is NOT translated!!! #also, this url must not have the leading slash -ASKBOT_UPLOADED_FILES_URL = 'upfiles/' ALLOW_UNICODE_SLUGS = False ASKBOT_USE_STACKEXCHANGE_URLS = False #mimic url scheme of stackexchange diff --git a/askbot/setup_templates/settings.py.mustache b/askbot/setup_templates/settings.py.mustache index 69da823a..4b01b4df 100644 --- a/askbot/setup_templates/settings.py.mustache +++ b/askbot/setup_templates/settings.py.mustache @@ -68,7 +68,8 @@ LANGUAGE_CODE = 'en' # Absolute path to the directory that holds media. # Example: "/home/media/media.lawrence.com/" -ASKBOT_FILE_UPLOAD_DIR = os.path.join(os.path.dirname(__file__), 'askbot', 'upfiles') +MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'askbot', 'upfiles') +MEDIA_URL = '/upfiles/' PROJECT_ROOT = os.path.dirname(__file__) @@ -166,9 +167,6 @@ INSTALLED_APPS = ( 'djkombu', 'followit', #'avatar',#experimental use git clone git://github.com/ericflo/django-avatar.git$ - #requires setting of MEDIA_ROOT and MEDIA_URL - #values of which can be the same as ASKBOT_FILE_UPLOAD_DIR and ASKBOT_UPLOADED_FILES_URL, - #respectively ) @@ -208,7 +206,6 @@ LOGIN_URL = '/%s%s%s' % (ASKBOT_URL,_('account/'),_('signin/')) LOGIN_REDIRECT_URL = ASKBOT_URL #adjust, if needed #note - it is important that upload dir url is NOT translated!!! #also, this url must not have the leading slash -ASKBOT_UPLOADED_FILES_URL = 'upfiles/' ALLOW_UNICODE_SLUGS = False ASKBOT_USE_STACKEXCHANGE_URLS = False #mimic url scheme of stackexchange diff --git a/askbot/setup_templates/urls.py b/askbot/setup_templates/urls.py index 2ec69cf0..8c92f6d1 100644 --- a/askbot/setup_templates/urls.py +++ b/askbot/setup_templates/urls.py @@ -14,6 +14,11 @@ urlpatterns = patterns('', (r'^settings/', include('askbot.deps.livesettings.urls')), (r'^followit/', include('followit.urls')), (r'^robots.txt$', include('robots.urls')), + url( # TODO: replace with django.conf.urls.static ? + r'^%s(?P<path>.*)$' % settings.MEDIA_URL[1:], + 'django.views.static.serve', + {'document_root': settings.MEDIA_ROOT.replace('\\','/')}, + ), ) if 'rosetta' in settings.INSTALLED_APPS: diff --git a/askbot/skins/common/media/js/editor.js b/askbot/skins/common/media/js/editor.js index f5b1e2af..e580f9f6 100644 --- a/askbot/skins/common/media/js/editor.js +++ b/askbot/skins/common/media/js/editor.js @@ -42,11 +42,11 @@ function ajaxFileUpload(imageUrl, startUploadHandler) url: askbot['urls']['upload'], secureuri:false, fileElementId:'file-upload', - dataType: 'xml', + dataType: 'json', success: function (data, status) { - var fileURL = $(data).find('file_url').text(); - var error = $(data).find('error').text(); + var fileURL = data['file_url']; + var error = data['error']; if(error != ''){ alert(error); if (startUploadHandler){ @@ -57,7 +57,6 @@ function ajaxFileUpload(imageUrl, startUploadHandler) }else{ imageUrl.attr('value', fileURL); } - }, error: function (data, status, e) { diff --git a/askbot/skins/default/templates/about.html b/askbot/skins/default/templates/about.html deleted file mode 100644 index d5d1b949..00000000 --- a/askbot/skins/default/templates/about.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "two_column_body.html" %} -<!-- template about.html --> -{% block title %}{% spaceless %}{% trans site_name=settings.APP_SHORT_NAME %}About {{site_name}}{% endtrans %}{% endspaceless %}{% endblock %} -{% block content %} -<h1 class="section-title">{% trans site_name=settings.APP_SHORT_NAME %}About {{site_name}}{% endtrans %}</h1> -<div class="content"> - {{settings.FORUM_ABOUT}} -</div> -{% endblock %} -<!-- end template about.html --> diff --git a/askbot/skins/default/templates/base.html b/askbot/skins/default/templates/base.html index 1102007b..8287f5ba 100644 --- a/askbot/skins/default/templates/base.html +++ b/askbot/skins/default/templates/base.html @@ -17,6 +17,11 @@ <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 "custom_header.html" ignore missing %} + {% if settings.CUSTOM_HEADER|trim != '' %} + <div id="custom-header"> + {{settings.CUSTOM_HEADER}} + </div> + {% endif %} {% include "widgets/header.html" %} {# Logo, user tool navigation and meta navitation #} {% include "widgets/secondary_header.html" %} {# Scope selector, search input and ask button #} <div class="content-wrapper"> diff --git a/askbot/skins/default/templates/faq.html b/askbot/skins/default/templates/faq.html deleted file mode 100644 index 51873a06..00000000 --- a/askbot/skins/default/templates/faq.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "two_column_body.html" %} -<!-- template faq.html --> -{% block title %}{% spaceless %}{% trans %}FAQ{% endtrans %}{% endspaceless %}{% endblock %} -{% block content %} -<div class="content"> -<h1 class="section-title">FAQ</h1> - {{forum_faq}} -</div> -{% endblock %} -<!-- end template faq.html --> diff --git a/askbot/skins/default/templates/meta/bottom_scripts.html b/askbot/skins/default/templates/meta/bottom_scripts.html index ad7bffa1..9a78d8a0 100644 --- a/askbot/skins/default/templates/meta/bottom_scripts.html +++ b/askbot/skins/default/templates/meta/bottom_scripts.html @@ -76,7 +76,7 @@ </script> {% if settings.USE_CUSTOM_JS %} <script - src="{% url "custom_js"%}?{{ settings.MEDIA_RESOURCE_REVISION }}" + src="{% url "custom_js"%}?v={{ settings.MEDIA_RESOURCE_REVISION }}" type="text/javascript" ></script> {% endif %} diff --git a/askbot/skins/default/templates/privacy.html b/askbot/skins/default/templates/privacy.html deleted file mode 100644 index e9b6f58b..00000000 --- a/askbot/skins/default/templates/privacy.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "two_column_body.html" %} -<!-- privacy.html --> -{% block title %}{% spaceless %}{% trans %}Privacy policy{% endtrans %}{% endspaceless %}{% endblock %} -{% block content %} -<h1 class="section-title">{% trans %}Privacy policy{% endtrans %}</h1> -{{settings.FORUM_PRIVACY}} -{% endblock %} -<!-- end privacy.html --> diff --git a/askbot/skins/default/templates/static_page.html b/askbot/skins/default/templates/static_page.html new file mode 100644 index 00000000..c537e199 --- /dev/null +++ b/askbot/skins/default/templates/static_page.html @@ -0,0 +1,10 @@ +{% extends "two_column_body.html" %} +<!-- template static_page.html --> +{% block title %}{% spaceless %}{{title}}{% endspaceless %}{% endblock %} +{% block content %} +<div class="content"> + <h1 class="section-title">{{title}}</h1> + {{content}} +</div> +{% endblock %} +<!-- end template static_page.html --> diff --git a/askbot/skins/default/templates/user_profile/user_edit.html b/askbot/skins/default/templates/user_profile/user_edit.html index daaa3663..94a1d58d 100644 --- a/askbot/skins/default/templates/user_profile/user_edit.html +++ b/askbot/skins/default/templates/user_profile/user_edit.html @@ -42,17 +42,24 @@ {{ form.username }} <span class="form-error"></span> {{ form.username.errors }} </td> {% else %} - {{ request.user.username }} + {{ view_user.username }} {% endif %} </td> </tr> <tr> - <td>{{ form.email.label_tag() }}:</td> - <td>{{ form.email }} <span class="form-error"></span> {{ form.email.errors }} </td> - </tr> - <tr> - <td></td> - <td class="title-desc">{{ form.email.help_text }}</td> + <td> + {{ form.email.label_tag() }}: + </td> + <td> + {% if settings.EDITABLE_EMAIL %} + {{ form.email }} + <span class="form-error"></span> + {{ form.email.errors }} + {% else %} + {{ view_user.email }} + {% trans %}(cannot be changed){% endtrans %} + {% endif %} + </td> </tr> <tr> <td>{{ form.realname.label_tag() }}:</td> diff --git a/askbot/skins/default/templates/widgets/header.html b/askbot/skins/default/templates/widgets/header.html index d4e7d66a..52e528bc 100644 --- a/askbot/skins/default/templates/widgets/header.html +++ b/askbot/skins/default/templates/widgets/header.html @@ -7,7 +7,6 @@ <div class="content-wrapper"> <div id="userToolsNav"> {% include "widgets/user_navigation.html" %} - {{settings.CUSTOM_HEADER}} </div> {% if settings.SHOW_LOGO %} {% include "widgets/logo.html" %} diff --git a/askbot/skins/utils.py b/askbot/skins/utils.py index da3a8a06..50c0d4fb 100644 --- a/askbot/skins/utils.py +++ b/askbot/skins/utils.py @@ -98,18 +98,23 @@ def get_media_url(url, ignore_missing = False): #before = datetime.datetime.now() url = urllib.unquote(unicode(url)) while url[0] == '/': url = url[1:] + + #a hack allowing urls media stored on external locations to + #just pass through unchanged + if url.startswith('http://') or url.startswith('https://'): + return url #todo: handles case of multiple skin directories #if file is in upfiles directory, then give that url_copy = url - if url_copy.startswith(django_settings.ASKBOT_UPLOADED_FILES_URL): + if url_copy.startswith(django_settings.MEDIA_URL[1:]): file_path = url_copy.replace( - django_settings.ASKBOT_UPLOADED_FILES_URL, + django_settings.MEDIA_URL[1:], '', 1 ) file_path = os.path.join( - django_settings.ASKBOT_FILE_UPLOAD_DIR, + django_settings.MEDIA_ROOT, file_path ) if os.path.isfile(file_path): diff --git a/askbot/startup_procedures.py b/askbot/startup_procedures.py index 9c962f2a..05426898 100644 --- a/askbot/startup_procedures.py +++ b/askbot/startup_procedures.py @@ -211,6 +211,17 @@ def test_celery(): "in your settings.py file" ) +def test_media_url(): + """makes sure that setting `MEDIA_URL` + has leading slash""" + 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 + \ + "\nMEDIA_URL parameter must be a unique url on the site\n" + "and must start with a slash - e.g. /media/ or http(s)://" + ) + class SettingsTester(object): """class to test contents of the settings.py file""" @@ -228,14 +239,25 @@ class SettingsTester(object): self.requirements = requirements - def test_setting(self, name, value = None, message = None): + def test_setting(self, name, + value = None, message = None, + test_for_absence = False, + replace_hint = None + ): """if setting does is not present or if the value != required_value, adds an error message """ - if not hasattr(self.settings, name): - self.messages.append(message) - elif value and getattr(self.settings, name) != value: - self.messages.append(message) + if test_for_absence: + if hasattr(self.settings, name): + if replace_hint: + value = getattr(self.settings, name) + message += replace_hint % value + self.messages.append(message) + else: + if not hasattr(self.settings, name): + self.messages.append(message) + elif value and getattr(self.settings, name) != value: + self.messages.append(message) def run(self): for setting_name in self.requirements: @@ -278,9 +300,20 @@ def run_startup_tests(): 'where you want to send users after they log in\n' 'a reasonable default is\n' 'LOGIN_REDIRECT_URL = ASKBOT_URL' + }, + 'ASKBOT_FILE_UPLOAD_DIR': { + 'test_for_absence': True, + 'message': 'Please replace setting ASKBOT_FILE_UPLOAD_DIR ', + 'replace_hint': "with MEDIA_ROOT = '%s'" + }, + 'ASKBOT_UPLOADED_FILES_URL': { + 'test_for_absence': True, + 'message': 'Please replace setting ASKBOT_UPLOADED_FILES_URL ', + 'replace_hint': "with MEDIA_URL = '/%s'" } }) settings_tester.run() + test_media_url() @transaction.commit_manually def run(): diff --git a/askbot/tests/page_load_tests.py b/askbot/tests/page_load_tests.py index 3ecc126f..d92d0e0c 100644 --- a/askbot/tests/page_load_tests.py +++ b/askbot/tests/page_load_tests.py @@ -122,11 +122,11 @@ class PageLoadTestCase(AskbotTestCase): self.try_url( 'about', status_code=status_code, - template='about.html') + template='static_page.html') self.try_url( 'privacy', status_code=status_code, - template='privacy.html') + template='static_page.html') self.try_url('logout', template='authopenid/logout.html') #todo: test different tabs self.try_url( diff --git a/askbot/tests/skin_tests.py b/askbot/tests/skin_tests.py index f8e940ee..ecbea77d 100644 --- a/askbot/tests/skin_tests.py +++ b/askbot/tests/skin_tests.py @@ -65,11 +65,6 @@ class SkinTests(TestCase): new_logo = UploadedFile(file = logo_file) askbot_settings.update('SITE_LOGO_URL', new_logo) logo_url = askbot_settings.SITE_LOGO_URL - self.assertTrue( - logo_url.startswith( - django_settings.ASKBOT_URL + \ - '/' + django_settings.ASKBOT_UPLOADED_FILES_URL - ) - ) + self.assertTrue(logo_url.startswith(django_settings.MEDIA_URL)) response = self.client.get(logo_url) self.assertTrue(response.status_code == 200) diff --git a/askbot/urls.py b/askbot/urls.py index 4bfab225..cf7d3fe6 100644 --- a/askbot/urls.py +++ b/askbot/urls.py @@ -41,12 +41,6 @@ urlpatterns = patterns('', views.meta.media, name='askbot_media', ), - url( # TODO: replace with django.conf.urls.static ? - r'^%s(?P<path>.*)$' % settings.ASKBOT_UPLOADED_FILES_URL, - 'django.views.static.serve', - {'document_root': settings.ASKBOT_FILE_UPLOAD_DIR.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'), diff --git a/askbot/utils/markup.py b/askbot/utils/markup.py index 3ebea3e4..ac96ec74 100644 --- a/askbot/utils/markup.py +++ b/askbot/utils/markup.py @@ -11,15 +11,11 @@ from markdown2 import Markdown #url taken from http://regexlib.com/REDetails.aspx?regexp_id=501 by Brian Bothwell URL_RE = re.compile("((?<!(href|.src|data)=['\"])((http|https|ftp)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&%\$#\=~_\-]+))*))") -LINK_PATTERNS = [ - (URL_RE, r'\1'), -] - - def get_parser(): """returns an instance of configured ``markdown2`` parser """ extras = ['link-patterns', 'video'] + if askbot_settings.ENABLE_MATHJAX or \ askbot_settings.MARKUP_CODE_FRIENDLY: extras.append('code-friendly') @@ -30,12 +26,17 @@ def get_parser(): #pip install -e git+git://github.com/andryuha/python-markdown2.git extras.append('video') + link_patterns = [ + (URL_RE, r'\1'), + ] if askbot_settings.ENABLE_AUTO_LINKING: pattern_list = askbot_settings.AUTO_LINK_PATTERNS.split('\n') url_list = askbot_settings.AUTO_LINK_URLS.split('\n') pairs = zip(pattern_list, url_list)#always takes equal number of items for item in pairs: - LINK_PATTERNS.append( + if item[0].strip() =='' or item[1].strip() == '': + continue + link_patterns.append( ( re.compile(item[0].strip()), item[1].strip() @@ -57,7 +58,7 @@ def get_parser(): return Markdown( html4tags=True, extras=extras, - link_patterns = LINK_PATTERNS + link_patterns = link_patterns ) diff --git a/askbot/views/meta.py b/askbot/views/meta.py index 493ab8ec..6415077a 100644 --- a/askbot/views/meta.py +++ b/askbot/views/meta.py @@ -29,11 +29,17 @@ def config_variable(request, variable_name = None, mimetype = None): """Print value from the configuration settings as response content. All parameters are required. """ + #todo add http header-based caching here!!! output = getattr(askbot_settings, variable_name, '') return HttpResponse(output, mimetype = mimetype) def about(request, template='about.html'): - return generic_view(request, template = template, page_class = 'meta') + title = _('About %(site)s') % {'site': askbot_settings.APP_SHORT_NAME} + data = { + 'title': title, + 'content': askbot_settings.FORUM_ABOUT + } + return render_into_skin('static_page.html', data, request) def page_not_found(request, template='404.html'): return generic_view(request, template) @@ -42,30 +48,19 @@ def server_error(request, template='500.html'): return generic_view(request, template) def faq(request): - if getattr(askbot_settings, 'FORUM_FAQ',''): - text = _(getattr(askbot_settings, 'FORUM_FAQ','')) + if askbot_settings.FORUM_FAQ.strip() != '': + return render_into_skin( + 'static_page.html', + {'title': _('FAQ'), 'content': askbot_settings.FORUM_FAQ}, + request + ) + else: data = { 'gravatar_faq_url': reverse('faq') + '#gravatar', - #'send_email_key_url': reverse('send_email_key'), - 'ask_question_url': reverse('ask'), - 'page_class': 'meta', - } - forum_faq = render_text_into_skin(text, data, request) - data_out = { - 'gravatar_faq_url': reverse('faq') + '#gravatar', - #'send_email_key_url': reverse('send_email_key'), 'ask_question_url': reverse('ask'), 'page_class': 'meta', - 'forum_faq' : forum_faq, } - return render_into_skin('faq.html', data_out, request) - data = { - 'gravatar_faq_url': reverse('faq') + '#gravatar', - #'send_email_key_url': reverse('send_email_key'), - 'ask_question_url': reverse('ask'), - 'page_class': 'meta', - } - return render_into_skin('faq_static.html', data, request) + return render_into_skin('faq_static.html', data, request) @csrf.csrf_protect def feedback(request): @@ -94,7 +89,11 @@ def feedback(request): feedback.CANCEL_MESSAGE=_('We look forward to hearing your feedback! Please, give it next time :)') def privacy(request): - return render_into_skin('privacy.html', {'page_class': 'meta'}, request) + data = { + 'title': _('Privacy policy'), + 'content': askbot_settings.FORUM_PRIVACY + } + return render_into_skin('static_page.html', data, request) def badges(request):#user status/reputation system #todo: supplement database data with the stuff from badges.py diff --git a/askbot/views/writers.py b/askbot/views/writers.py index f8da2181..916c0e17 100644 --- a/askbot/views/writers.py +++ b/askbot/views/writers.py @@ -12,7 +12,7 @@ import random import sys import tempfile import time -from django.core.files.storage import FileSystemStorage +from django.core.files.storage import get_storage_class from django.shortcuts import get_object_or_404 from django.contrib.auth.decorators import login_required from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden, Http404 @@ -78,10 +78,7 @@ def upload(request):#ajax upload file to a question or answer str(random.randint(0,100000)) ) + file_extension - file_storage = FileSystemStorage( - location = settings.ASKBOT_FILE_UPLOAD_DIR, - base_url = reverse('uploaded_file', kwargs = {'path':''}), - ) + file_storage = get_storage_class()() # use default storage to store file file_storage.save(new_file_name, f) # check file size @@ -106,11 +103,12 @@ def upload(request):#ajax upload file to a question or answer result = '' file_url = '' - #<result><msg><![CDATA[%s]]></msg><error><![CDATA[%s]]></error><file_url>%s</file_url></result> - xml_template = "<result><msg><![CDATA[%s]]></msg><error><![CDATA[%s]]></error><file_url>%s</file_url></result>" - xml = xml_template % (result, error, file_url) - - return HttpResponse(xml, mimetype="application/xml") + data = simplejson.dumps({ + 'result': result, + 'error': error, + 'file_url': file_url + }) + return HttpResponse(data, mimetype = 'application/json') def __import_se_data(dump_file): """non-view function that imports the SE data |