diff options
27 files changed, 288 insertions, 48 deletions
diff --git a/askbot/__init__.py b/askbot/__init__.py index 4ca440d7..d56557d9 100644 --- a/askbot/__init__.py +++ b/askbot/__init__.py @@ -9,7 +9,7 @@ import smtplib import sys import logging -VERSION = (0, 7, 19) +VERSION = (0, 7, 20) #necessary for interoperability of django and coffin try: diff --git a/askbot/conf/login_providers.py b/askbot/conf/login_providers.py index 56423ca4..a97baa9d 100644 --- a/askbot/conf/login_providers.py +++ b/askbot/conf/login_providers.py @@ -5,6 +5,7 @@ from askbot.conf.settings_wrapper import settings from askbot.deps import livesettings from django.utils.translation import ugettext as _ from django.conf import settings as django_settings +from askbot.skins import utils as skin_utils LOGIN_PROVIDERS = livesettings.ConfigurationGroup( 'LOGIN_PROVIDERS', @@ -29,6 +30,38 @@ settings.register( ) ) +settings.register( + livesettings.BooleanValue( + LOGIN_PROVIDERS, + 'SIGNIN_WORDPRESS_SITE_ENABLED', + default = False, + description=_('Activate to allow login with self-hosted wordpress site'), + help_text=_('to activate this feature you must fill out the wordpress xml-rpc setting bellow') + ) +) + +settings.register( + livesettings.URLValue( + LOGIN_PROVIDERS, + 'WORDPRESS_SITE_URL', + default = '', + description=_('Fill it with the wordpress url to the xml-rpc, normally http://mysite.com/xmlrpc.php'), + help_text=_('To enable, go to Settings->Writing->Remote Publishing and check the box for XML-RPC') + ) +) + +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 + ) +) + providers = ( 'local', 'AOL', diff --git a/askbot/conf/social_sharing.py b/askbot/conf/social_sharing.py index 0ea5f9be..db01fb49 100644 --- a/askbot/conf/social_sharing.py +++ b/askbot/conf/social_sharing.py @@ -40,6 +40,15 @@ settings.register( settings.register( BooleanValue( SOCIAL_SHARING, + 'ENABLE_SHARING_IDENTICA', + default=True, + description=_('Check to enable sharing of questions on Identi.ca') + ) +) + +settings.register( + BooleanValue( + SOCIAL_SHARING, 'ENABLE_SHARING_GOOGLE', default=True, description=_('Check to enable sharing of questions on Google+') diff --git a/askbot/deps/django_authopenid/backends.py b/askbot/deps/django_authopenid/backends.py index a9eee8e5..e608086c 100644 --- a/askbot/deps/django_authopenid/backends.py +++ b/askbot/deps/django_authopenid/backends.py @@ -30,6 +30,8 @@ class AuthBackend(object): 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 ): """this authentication function supports many login methods @@ -149,6 +151,16 @@ class AuthBackend(object): except UserAssociation.DoesNotExist: return None + elif method == 'wordpress_site': + try: + custom_wp_openid_url = '%s?user_id=%s' % (wordpress_url, wp_user_id) + assoc = UserAssociation.objects.get( + openid_url = custom_wp_openid_url, + provider_name = 'wordpress_site' + ) + user = assoc.user + except UserAssociation.DoesNotExist: + return None elif method == 'force': return self.get_user(user_id) else: diff --git a/askbot/deps/django_authopenid/forms.py b/askbot/deps/django_authopenid/forms.py index d9bb7261..c4507272 100644 --- a/askbot/deps/django_authopenid/forms.py +++ b/askbot/deps/django_authopenid/forms.py @@ -215,6 +215,8 @@ class LoginForm(forms.Form): elif provider_type == 'facebook': self.cleaned_data['login_type'] = 'facebook' #self.do_clean_oauth_fields() + elif provider_type == 'wordpress_site': + self.cleaned_data['login_type'] = 'wordpress_site' return self.cleaned_data diff --git a/askbot/deps/django_authopenid/util.py b/askbot/deps/django_authopenid/util.py index 0226f56c..4468a6d2 100644 --- a/askbot/deps/django_authopenid/util.py +++ b/askbot/deps/django_authopenid/util.py @@ -34,7 +34,7 @@ from models import Association, Nonce __all__ = ['OpenID', 'DjangoOpenIDStore', 'from_openid_response', 'clean_next'] -ALLOWED_LOGIN_TYPES = ('password', 'oauth', 'openid-direct', 'openid-username') +ALLOWED_LOGIN_TYPES = ('password', 'oauth', 'openid-direct', 'openid-username', 'wordpress') class OpenID: def __init__(self, openid_, issued, attrs=None, sreg_=None): @@ -163,6 +163,8 @@ def use_password_login(): either if USE_RECAPTCHA is false of if recaptcha keys are set correctly """ + if askbot_settings.SIGNIN_WORDPRESS_SITE_ENABLED: + return True if askbot_settings.USE_RECAPTCHA: if askbot_settings.RECAPTCHA_KEY and askbot_settings.RECAPTCHA_SECRET: return True @@ -436,7 +438,14 @@ def get_enabled_major_login_providers(): if matches: return matches.group(1) raise OAuthError() - + + if askbot_settings.SIGNIN_WORDPRESS_SITE_ENABLED and askbot_settings.WORDPRESS_SITE_URL: + data['wordpress_site'] = { + 'name': 'wordpress_site', + 'display_name': 'Self hosted wordpress blog', #need to be added as setting. + 'icon_media_path': askbot_settings.WORDPRESS_SITE_ICON, + 'type': 'wordpress_site', + } if askbot_settings.LINKEDIN_KEY and askbot_settings.LINKEDIN_SECRET: data['linkedin'] = { 'name': 'linkedin', diff --git a/askbot/deps/django_authopenid/views.py b/askbot/deps/django_authopenid/views.py index 5610a7fb..63c3b1f0 100644 --- a/askbot/deps/django_authopenid/views.py +++ b/askbot/deps/django_authopenid/views.py @@ -59,6 +59,14 @@ try: except ImportError: from yadis import xri +try: + from xmlrpclib import Fault as WpFault + from wordpress_xmlrpc import Client + from wordpress_xmlrpc.methods.users import GetUserInfo +except ImportError: + pass + + import urllib from askbot import forms as askbot_forms from askbot.deps.django_authopenid import util @@ -438,6 +446,28 @@ def signin(request): ) % {'provider': 'Facebook'} request.user.message_set.create(message = msg) + elif login_form.cleaned_data['login_type'] == 'wordpress_site': + #here wordpress_site means for a self hosted wordpress blog not a wordpress.com blog + wp = Client(askbot_settings.WORDPRESS_SITE_URL, login_form.cleaned_data['username'], login_form.cleaned_data['password']) + try: + wp_user = wp.call(GetUserInfo()) + custom_wp_openid_url = '%s?user_id=%s' % (wp.url, wp_user.user_id) + user = authenticate( + method = 'wordpress_site', + wordpress_url = wp.url, + wp_user_id = wp_user.user_id + ) + return finalize_generic_signin( + request = request, + user = user, + user_identifier = custom_wp_openid_url, + login_provider_name = provider_name, + redirect_url = next_url + ) + except WpFault, e: + logging.critical(unicode(e)) + msg = _('The login password combination was not correct') + request.user.message_set.create(message = msg) else: #raise 500 error - unknown login type pass diff --git a/askbot/deps/livesettings/values.py b/askbot/deps/livesettings/values.py index 740d9884..6372e656 100644 --- a/askbot/deps/livesettings/values.py +++ b/askbot/deps/livesettings/values.py @@ -21,7 +21,7 @@ import os __all__ = ['BASE_GROUP', 'ConfigurationGroup', 'Value', 'BooleanValue', 'DecimalValue', 'DurationValue', 'FloatValue', 'IntegerValue', 'ModuleValue', 'PercentValue', 'PositiveIntegerValue', 'SortedDotDict', - 'StringValue', 'ImageValue', 'LongStringValue', 'MultipleStringValue'] + 'StringValue', 'ImageValue', 'LongStringValue', 'MultipleStringValue', 'URLValue'] _WARN = {} @@ -545,6 +545,14 @@ class StringValue(Value): to_editor = to_python +class URLValue(Value): + + class field(forms.URLField): + + def __init__(self, *args, **kwargs): + kwargs['required'] = False + forms.URLField.__init__(self, *args, **kwargs) + class LongStringValue(Value): class field(forms.CharField): diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst new file mode 100644 index 00000000..523a011f --- /dev/null +++ b/askbot/doc/source/changelog.rst @@ -0,0 +1,46 @@ +Changes in Askbot +================= + +Development version (not yet on pypi) +------------------------------------- +* First user automatically becomes site administrator (Adolfo Fitoria) + +0.7.20 (Current Version) +------------------------ +* Added support for login via self-hosted Wordpress site (Adolfo Fitoria) +* Allowed basic markdown in the comments (Adolfo Fitoria) +* Added this changelog (Adolfo Fitoria) +* Added support for threaded emails (Benoit Lavigne) +* A few more Spanish translation strings (Byron Corrales) +* Social sharing support on identi.ca (Rantadeep Debnath) + +0.7.19 +------ +* Changed the Favorite question function for Follow question. +* Fixed issues with page load time. +* Added notify me checkbox to the sidebar. +* Removed MySql dependency from setup.py +* Fixed Facebook login. +* `Fixed "Moderation tab is misaligned" issue reported by methner. <http://askbot.org/en/question/587/moderation-tab-is-misaligned-fixed>`_ +* Fixed bug in follow users and changed the follow button design. + +0.7.18 +------ +* `Added multiple capitalization to username mentions(reported by niles) <http://askbot.org/en/question/580/allow-alternate-capitalizations-in-user-links>`_ + +0.7.17 +------ +* Adding test for UserNameField. +* Adding test for markup functions. + +0.7.16 +------ +* Admins can add aministrators too. +* Added a postgres driver version check in the start procedures due to a bug in psycopg2 2.4.2. +* New inbox system style (`bug reported by Tomasz P. Szynalski <http://askbot.org/en/question/470/answerscomments-are-listed-twice-in-the-inbox>`_). + +0.7.15 +------ +* Fixed integration with Django 1.1. +* Fixed bugs in setup script. +* Fixed pypi bugs. diff --git a/askbot/doc/source/conf.py b/askbot/doc/source/conf.py index 09fe821f..d8848317 100644 --- a/askbot/doc/source/conf.py +++ b/askbot/doc/source/conf.py @@ -61,16 +61,16 @@ master_doc = 'index' # General information about the project. project = u'Askbot' -copyright = u'2010, Askbot Project' +copyright = u'2011, Askbot Project' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. -# # The short X.Y version. -version = '0.6' +from askbot import get_version +version = get_version() # The full version, including alpha/beta/rc tags. -release = '0.6' +release = get_version() # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/askbot/doc/source/index.rst b/askbot/doc/source/index.rst index 2653b2df..98dbf777 100644 --- a/askbot/doc/source/index.rst +++ b/askbot/doc/source/index.rst @@ -27,6 +27,7 @@ at the forum_ or by email at admin@askbot.org Appendix E: Customizing skin in askbot <customizing-skin-in-askbot> Footnotes <footnotes> Contributors <contributors> + Changelog<changelog> Some background information: Askbot is written in Python on top of the Django platform. Code of Askbot grew out of CNPROG project originally written by diff --git a/askbot/doc/source/initialize-database-tables.rst b/askbot/doc/source/initialize-database-tables.rst index 26993985..f1281816 100644 --- a/askbot/doc/source/initialize-database-tables.rst +++ b/askbot/doc/source/initialize-database-tables.rst @@ -38,9 +38,13 @@ Connect to the Django development server with your Web browser. The address is t Once the fresh copy of Askbot appears in your browser, create a new account at the site. This will be your administrator account. -Finally, turn the newly added user into a superuser by running:: +.. deprecated:: 0.7.20. + Finally, turn the newly added user into a superuser by running:: - python manage.py add_admin 1 + python manage.py add_admin 1 + +.. versionadded:: 0.7.20. + In the new version of Askbot the first user you create on the site will be added as administrator. Here number 1 is the numeric id of the first user, enter a different number, if it is indeed different. diff --git a/askbot/doc/source/optional-modules.rst b/askbot/doc/source/optional-modules.rst index 1da5a349..164f2f8c 100644 --- a/askbot/doc/source/optional-modules.rst +++ b/askbot/doc/source/optional-modules.rst @@ -123,3 +123,16 @@ Also, settings ``MEDIA_ROOT`` and ``MEDIA_URL`` will need to be added to your `` Version of the ``avatar`` application available at pypi may not be up to date, so please take the development version from the github repository + +Wordpress Integration +===================== + +To enable authentication for self hosted wordpress sites(wordpress.com blogs will work with openid login). To enable it follow the following steps: + +* Check if you have the package `"python_wordpress_xmlrpc <http://pypi.python.org/pypi/python-wordpress-xmlrpc/1.4>`_ from pypi. +* Go to your wordpress blog admin panel and serch for: Settings->Writing->Remote Publishing then check the box for XML-RPC. +* Go back to your askbot site settings and click on *Login Provider Settings* and then activate the option *Activate to allow login with self-hosted wordpress site*, +* Input your blog url to the xmlrpc.php file it will look something like this http://yoursite.com/xmlrpc.php +* Upload an icon for display in the login area. + +After doing this steps you should be able to login with your self hosted wordpress site user/password combination. diff --git a/askbot/importers/stackexchange/management/commands/load_stackexchange.py b/askbot/importers/stackexchange/management/commands/load_stackexchange.py index a226bd61..20155e36 100644 --- a/askbot/importers/stackexchange/management/commands/load_stackexchange.py +++ b/askbot/importers/stackexchange/management/commands/load_stackexchange.py @@ -3,6 +3,7 @@ DEBUGME = False import os import re import sys +from unidecode import unidecode import zipfile from datetime import datetime from django.core.management.base import BaseCommand, CommandError @@ -735,7 +736,7 @@ class Command(BaseCommand): def _report_missing_badges(self): d = self._missing_badges unused = [name for name in d.keys() if d[name] == 0] - dropped = [name for name in d.keys() if d[name] > 0] + dropped = [unidecode(name) for name in d.keys() if d[name] > 0] print 'Warning - following unsupported badges were dropped:' print ', '.join(dropped) sys.stdout.flush() diff --git a/askbot/locale/es/LC_MESSAGES/django.po b/askbot/locale/es/LC_MESSAGES/django.po index 1b8d68f3..869b3d58 100644 --- a/askbot/locale/es/LC_MESSAGES/django.po +++ b/askbot/locale/es/LC_MESSAGES/django.po @@ -159,7 +159,7 @@ msgstr "" #: forms.py:261 msgid "Cannot change status of another moderator" -msgstr "" +msgstr "No esta permitido cambiar el estado de otro moderador" #: forms.py:267 #, python-format @@ -172,7 +172,7 @@ msgstr "" #: forms.py:283 msgid "Message text" -msgstr "" +msgstr "Mensaje de Texto" #: forms.py:360 msgid "Your name:" @@ -457,11 +457,11 @@ msgstr "" #: conf/external_keys.py:58 msgid "Recaptcha public key" -msgstr "" +msgstr "Llave pública de Recaptcha" #: conf/external_keys.py:66 msgid "Recaptcha private key" -msgstr "" +msgstr "Llave privada de Recaptcha" #: conf/external_keys.py:68 msgid "" @@ -472,7 +472,7 @@ msgstr "" #: conf/external_keys.py:80 msgid "Facebook public API key" -msgstr "" +msgstr "Llave pública para API de Facebook" #: conf/external_keys.py:82 msgid "" @@ -558,16 +558,16 @@ msgstr "" #: conf/forum_data_rules.py:29 msgid "Maximum length of tag (number of characters)" -msgstr "" +msgstr "Tamaño máximo de una etiqueta (número de caracteres)" #: conf/forum_data_rules.py:39 msgid "Default max number of comments to display under posts" -msgstr "" +msgstr "Cantidad máxima por defecto, de comentarios a mostrarse para cada entrada" #: conf/forum_data_rules.py:50 #, python-format msgid "Maximum comment length, must be < %(max_len)s" -msgstr "" +msgstr "Tamaño máximo de un comentario, debe ser menor a %(max_len)s" #: conf/forum_data_rules.py:60 msgid "Minimum length of search term for Ajax search" @@ -579,11 +579,11 @@ msgstr "" #: conf/forum_data_rules.py:70 msgid "Maximum number of tags per question" -msgstr "" +msgstr "Número máximo de etiquetas por cada pregunta" #: conf/forum_data_rules.py:82 msgid "Number of questions to list by default" -msgstr "" +msgstr "Número máximo de preguntas a listar por defecto" #: conf/forum_data_rules.py:92 #, fuzzy @@ -654,7 +654,7 @@ msgstr "comentar" #: conf/minimum_reputation.py:56 msgid "Delete comments posted by others" -msgstr "" +msgstr "Borrar comentarios creados por otros usuarios" #: conf/minimum_reputation.py:65 #, fuzzy @@ -674,7 +674,7 @@ msgstr "Cerrar pregunta" #: conf/minimum_reputation.py:92 msgid "Retag questions posted by other people" -msgstr "" +msgstr "Re-etiquetar las preguntas creadas por otros usuarios" #: conf/minimum_reputation.py:101 #, fuzzy diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py index d87b5ce9..5407b1e2 100644 --- a/askbot/models/__init__.py +++ b/askbot/models/__init__.py @@ -1310,14 +1310,11 @@ def user_post_answer( minutes = int(diff.seconds/60) if days > 2: - if date.year == now.year: - date_token = date.strftime("%b %d") + if asked.year == now.year: + date_token = asked.strftime("%b %d") else: - date_token = date.strftime("%b %d '%y") - if use_on_prefix: - left = _('on %(date)s') % { 'date': date_token } - else: - left = date_token + date_token = asked.strftime("%b %d '%y") + left = _('on %(date)s') % { 'date': date_token } elif days == 2: left = _('in two days') elif days == 1: @@ -2271,7 +2268,8 @@ def send_instant_notifications_about_activity_in_post( body_text = body_text, recipient_list = [user.email], related_object = origin_post, - activity_type = const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT + activity_type = const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT, + headers = mail.thread_headers(post, origin_post, update_activity.activity_type) ) @@ -2572,7 +2570,13 @@ def update_user_has_custom_avatar_flag(instance, **kwargs): def set_user_has_valid_gravatar_flag(instance, **kwargs): instance.update_has_valid_gravatar() +def make_admin_if_first_user(instance, **kwargs): + user_count = User.objects.all().count() + if user_count == 0: + instance.set_admin_status() + #signal for User model save changes +django_signals.pre_save.connect(make_admin_if_first_user, sender=User) django_signals.pre_save.connect(calculate_gravatar_hash, sender=User) django_signals.post_save.connect(add_missing_subscriptions, sender=User) #django_signals.post_save.connect(set_user_has_valid_gravatar_flag, sender=User) diff --git a/askbot/models/meta.py b/askbot/models/meta.py index 7cccbcd6..463db0cc 100644 --- a/askbot/models/meta.py +++ b/askbot/models/meta.py @@ -91,7 +91,7 @@ class Comment(base.MetaContent, base.UserContent): offensive_flag_count = models.IntegerField(default = 0) _urlize = True - _use_markdown = False + _use_markdown = True _escape_html = True is_anonymous = False #comments are never anonymous - may change diff --git a/askbot/skins/default/media/images/sprite.png b/askbot/skins/default/media/images/sprite.png Binary files differindex fadc0f28..1a0fbc78 100644 --- a/askbot/skins/default/media/images/sprite.png +++ b/askbot/skins/default/media/images/sprite.png diff --git a/askbot/skins/default/media/jquery-openid/jquery.openid.js b/askbot/skins/default/media/jquery-openid/jquery.openid.js index c8349e8e..bb76fcd6 100644 --- a/askbot/skins/default/media/jquery-openid/jquery.openid.js +++ b/askbot/skins/default/media/jquery-openid/jquery.openid.js @@ -410,6 +410,10 @@ $.fn.authenticator = function() { signin_page.find('input.password'), start_password_login_or_change ); + setup_event_handlers( + signin_page.find('input.wordpress_site'), + start_password_login_or_change + ); setup_event_handlers(account_recovery_link, start_account_recovery); diff --git a/askbot/skins/default/media/js/post.js b/askbot/skins/default/media/js/post.js index 70cbe824..8216c10a 100644 --- a/askbot/skins/default/media/js/post.js +++ b/askbot/skins/default/media/js/post.js @@ -1040,6 +1040,12 @@ EditCommentForm.prototype.createDom = function(){ this._textarea = $('<textarea></textarea>'); this._textarea.attr('id', this._id); + this._help_text = $('<span></span>').attr('class', 'help-text'); + this._help_text.html(gettext('Markdown is allowed in the comments')); + div.append(this._help_text); + + this._help_text = $('<div></div>').attr('class', 'clearfix'); + div.append(this._help_text); this._element.append(div); div.append(this._textarea); @@ -1524,6 +1530,10 @@ var socialSharing = function(){ var SERVICE_DATA = { //url - template for the sharing service url, params are for the popup + identica: { + url: "http://identi.ca/index.php?action=newnotice&status_textarea={TEXT}", + params: "width=820, height=526,toolbar=1,status=1,resizable=1,scrollbars=1" + }, twitter: { url: "http://twitter.com/share?url={URL}&ref=twitbtn&text={TEXT}", params: "width=820,height=526,toolbar=1,status=1,resizable=1,scrollbars=1" @@ -1559,11 +1569,13 @@ var socialSharing = function(){ var fb = $('a.facebook-share') var tw = $('a.twitter-share'); var ln = $('a.linkedin-share'); + var ica = $('a.identica-share'); copyAltToTitle(fb); copyAltToTitle(tw); setupButtonEventHandlers(fb, function(){share_page("facebook")}); setupButtonEventHandlers(tw, function(){share_page("twitter")}); setupButtonEventHandlers(ln, function(){share_page("linkedin")}); + setupButtonEventHandlers(ica, function(){share_page("identica")}); } } }(); diff --git a/askbot/skins/default/media/js/utils.js b/askbot/skins/default/media/js/utils.js index 9f1c3d9f..c49da02b 100644 --- a/askbot/skins/default/media/js/utils.js +++ b/askbot/skins/default/media/js/utils.js @@ -55,8 +55,10 @@ var showMessage = function(element, msg, where) { var makeKeyHandler = function(key, callback){ return function(e){ if ((e.which && e.which == key) || (e.keyCode && e.keyCode == key)){ - callback(); - return false; + if(!e.shiftKey){ + callback(); + return false; + } } }; }; diff --git a/askbot/skins/default/media/style/style.css b/askbot/skins/default/media/style/style.css index c7d9eefb..7627be5e 100644 --- a/askbot/skins/default/media/style/style.css +++ b/askbot/skins/default/media/style/style.css @@ -1180,6 +1180,12 @@ div.comment .upvote:hover { text-decoration: none; } +.comments .help-text{ + float: right; + text-align:right; + color: gray; +} + span.text-counter { margin-right: 20px; } @@ -2331,7 +2337,7 @@ img.flag { vertical-align: text-bottom; } -.facebook-share.icon, .twitter-share.icon, .linkedin-share.icon { +.facebook-share.icon, .twitter-share.icon, .linkedin-share.icon, .identica-share.icon { background: url(../images/sprite.png) no-repeat; display:block; text-indent:-100em; @@ -2341,6 +2347,9 @@ img.flag { .facebook-share.icon { background-position: -25px 0px; } +.identica-share.icon { + background-position: -85px 0px; +} .twitter-share.icon { margin-top:10px; background-position: 0px 0px; diff --git a/askbot/skins/default/templates/authopenid/signin.html b/askbot/skins/default/templates/authopenid/signin.html index f3483bfa..37636207 100644 --- a/askbot/skins/default/templates/authopenid/signin.html +++ b/askbot/skins/default/templates/authopenid/signin.html @@ -64,7 +64,7 @@ logged_in = user.is_authenticated()
)
}}
- {% if use_password_login==True %}
+ {% if use_password_login == True %}
<fieldset
id="password-fs"
{% if user.is_anonymous() %}
diff --git a/askbot/skins/default/templates/macros.html b/askbot/skins/default/templates/macros.html index 273ccdaf..fa15426f 100644 --- a/askbot/skins/default/templates/macros.html +++ b/askbot/skins/default/templates/macros.html @@ -415,17 +415,6 @@ poor design of the data or methods on data objects #} {%- macro question_summary(question, extra_class=None) -%} <div class="short-summary{% if extra_class %} {{extra_class}}{% endif %}"> <div class="counts"> - <div class="favorites - {% if question.favourite_count == 0 -%} - no-favorites - {%else -%} - some-favorites - {%- endif -%}"> - <span class="item-count">{{question.favourite_count|humanize_counter}}</span> - <div> - {% trans cnt=question.favourite_count %}follower{% pluralize %}followers{%endtrans%}</b> - </div> - </div> <div class="views {% if question.view_count == 0 -%} no-views diff --git a/askbot/skins/default/templates/question.html b/askbot/skins/default/templates/question.html index e4d7c458..06cd1332 100644 --- a/askbot/skins/default/templates/question.html +++ b/askbot/skins/default/templates/question.html @@ -55,6 +55,7 @@ {% if settings.ENABLE_SHARING_TWITTER %}{{ macros.share(site = 'twitter', icon = True) }}{% endif %} {% if settings.ENABLE_SHARING_FACEBOOK %}{{ macros.share(site = 'facebook', icon = True) }}{% endif %} {% if settings.ENABLE_SHARING_LINKEDIN %}{{ macros.share(site = 'linkedin', icon = True) }}{% endif %} + {% if settings.ENABLE_SHARING_IDENTICA %}{{ macros.share(site = 'identica', icon = True) }}{% endif %} {% if settings.ENABLE_SHARING_GOOGLE %}<g:plusone size="small" count="false"></g:plusone>{% endif %} </div> </td> @@ -297,7 +298,8 @@ {% if settings.ENABLE_SHARING_TWITTER %}{{ macros.share(site = 'twitter', site_label = 'Twitter') }},{% endif %} {% if settings.ENABLE_SHARING_FACEBOOK %}{{ macros.share(site = 'facebook', site_label = 'Facebook') }},{% endif %} {% if settings.ENABLE_SHARING_LINKEDIN %}{{ macros.share(site = 'linkedin', site_label = 'LinkedIn') }},{% endif %} - {%- if settings.ENABLE_SHARING_TWITTER or settings.ENABLE_SHARING_FACEBOOK or settings.ENABLE_SHARING_LINKEDIN -%} + {% if settings.ENABLE_SHARING_IDENTICA %}{{ macros.share(site = 'identica', site_label = 'Identi.ca') }},{% endif %} + {%- if settings.ENABLE_SHARING_TWITTER or settings.ENABLE_SHARING_FACEBOOK or settings.ENABLE_SHARING_LINKEDIN or settings.ENABLE_SHARING_IDENTICA -%} {% trans %} or{% endtrans %} {% endif %} <a href="mailto:?subject={{ settings.APP_SHORT_NAME|urlencode }}&body={{ question_url }}">{% trans %}email{% endtrans %}</a>. diff --git a/askbot/startup_procedures.py b/askbot/startup_procedures.py index 3e272aa7..bb269600 100644 --- a/askbot/startup_procedures.py +++ b/askbot/startup_procedures.py @@ -21,6 +21,9 @@ PREAMBLE = """\n * * ************************""" +def askbot_warning(line): + print >> sys.stderr, PREAMBLE + '\n' + line + def format_as_text_tuple_entries(items): """prints out as entries or tuple containing strings ready for copy-pasting into say django settings file""" @@ -148,12 +151,23 @@ def test_postgres(): else: pass #TODO: test new django dictionary databases +def test_encoding(): + """prints warning if encoding error is not UTF-8""" + if hasattr(sys.stdout, 'encoding'): + if sys.stdout.encoding != 'UTF-8': + askbot_warning( + 'Your output encoding is not UTF-8, there may be ' + 'issues with the software when anything is printed ' + 'to the terminal or log files' + ) + def run_startup_tests(): """function that runs all startup tests, mainly checking settings config so far """ #todo: refactor this when another test arrives + test_encoding() test_modules() test_askbot_url() test_i18n() diff --git a/askbot/utils/mail.py b/askbot/utils/mail.py index d41d666a..ae655f4c 100644 --- a/askbot/utils/mail.py +++ b/askbot/utils/mail.py @@ -31,6 +31,42 @@ def extract_first_email_address(text): else: return None +def thread_headers(post, orig_post, update): + suffix_id = django_settings.SERVER_EMAIL + if update == const.TYPE_ACTIVITY_ASK_QUESTION: + id = "NQ-%s-%s" % (post.id, suffix_id) + headers = {'Message-ID': id} + elif update == const.TYPE_ACTIVITY_ANSWER: + id = "NA-%s-%s" % (post.id, suffix_id) + orig_id = "NQ-%s-%s" % (orig_post.id, suffix_id) + headers = {'Message-ID': id, + 'In-Reply-To': orig_id} + elif update == const.TYPE_ACTIVITY_UPDATE_QUESTION: + id = "UQ-%s-%s-%s" % (post.id, post.last_edited_at, suffix_id) + orig_id = "NQ-%s-%s" % (orig_post.id, suffix_id) + headers = {'Message-ID': id, + 'In-Reply-To': orig_id} + elif update == const.TYPE_ACTIVITY_COMMENT_QUESTION: + id = "CQ-%s-%s" % (post.id, suffix_id) + orig_id = "NQ-%s-%s" % (orig_post.id, suffix_id) + headers = {'Message-ID': id, + 'In-Reply-To': orig_id} + elif update == const.TYPE_ACTIVITY_UPDATE_ANSWER: + id = "UA-%s-%s-%s" % (post.id, post.last_edited_at, suffix_id) + orig_id = "NQ-%s-%s" % (orig_post.id, suffix_id) + headers = {'Message-ID': id, + 'In-Reply-To': orig_id} + elif update == const.TYPE_ACTIVITY_COMMENT_ANSWER: + id = "CA-%s-%s" % (post.id, suffix_id) + orig_id = "NQ-%s-%s" % (orig_post.id, suffix_id) + headers = {'Message-ID': id, + 'In-Reply-To': orig_id} + else: + # Unknown type -> Can't set headers + return {} + + return headers + def send_mail( subject_line = None, body_text = None, |