summaryrefslogtreecommitdiffstats
path: root/askbot
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-08-26 01:17:00 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-08-26 01:17:00 -0400
commit13938b91e0875f38be59074db37af4d1eba57d51 (patch)
tree2cba49510466300278654d26606b384a59c4f6f6 /askbot
parent053b69a69ad8aa788f813f382f58d9d1f0fa1b42 (diff)
downloadaskbot-13938b91e0875f38be59074db37af4d1eba57d51.tar.gz
askbot-13938b91e0875f38be59074db37af4d1eba57d51.tar.bz2
askbot-13938b91e0875f38be59074db37af4d1eba57d51.zip
basic account recovery seems to work
Diffstat (limited to 'askbot')
-rw-r--r--askbot/__init__.py55
-rw-r--r--askbot/deps/django_authopenid/forms.py10
-rw-r--r--askbot/deps/django_authopenid/urls.py1
-rw-r--r--askbot/deps/django_authopenid/views.py367
-rw-r--r--askbot/exceptions.py6
-rw-r--r--askbot/locale/en/LC_MESSAGES/django.mobin25465 -> 25486 bytes
-rw-r--r--askbot/locale/en/LC_MESSAGES/django.po18
-rw-r--r--askbot/management/commands/fix_revisionless_posts.py25
-rw-r--r--askbot/management/commands/send_email_alerts.py86
-rw-r--r--askbot/models/__init__.py62
-rw-r--r--askbot/models/question.py7
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/jquery.openid.js2
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/openid.css7
-rw-r--r--askbot/skins/default/templates/authopenid/complete.html93
-rwxr-xr-xaskbot/skins/default/templates/authopenid/signin.html334
-rw-r--r--askbot/skins/default/templates/base.html4
-rw-r--r--askbot/tests/email_alert_tests.py38
-rw-r--r--askbot/views/users.py33
18 files changed, 775 insertions, 373 deletions
diff --git a/askbot/__init__.py b/askbot/__init__.py
index 4095646b..184ddbf9 100644
--- a/askbot/__init__.py
+++ b/askbot/__init__.py
@@ -1,10 +1,63 @@
"""
:synopsis: the Django Q&A forum application
+
+Functions in the askbot module perform various
+basic actions on behalf of the forum application
"""
import os
+import smtplib
+from django.core import mail
+from django.conf import settings as django_settings
+from askbot import exceptions
def get_install_directory():
+ """returns path to directory
+ where code of the askbot django application
+ is installed
+ """
return os.path.dirname(__file__)
def get_version():
- return '0.6.9'
+ """returns version of the askbot app
+ this version is meaningful for pypi only
+ """
+ return '0.6.10'
+
+def send_mail(
+ subject_line = None,
+ body_text = None,
+ recipient_list = None,
+ activity_type = None,
+ related_object = None,
+ headers = None,
+ raise_on_failure = False,
+ ):
+ """sends email message
+ logs email sending activity
+ and any errors are reported as critical
+ in the main log file
+
+ related_object is not mandatory, other arguments
+ are. related_object (if given, will be saved in
+ the activity record)
+
+ if raise_on_failure is True, exceptions.EmailNotSent is raised
+ """
+ print subject_line
+ print body_text
+ try:
+ msg = mail.EmailMessage(
+ subject_line,
+ body_text,
+ django_settings.DEFAULT_FROM_EMAIL,
+ recipient_list,
+ headers = headers
+ )
+ msg.content_subtype = 'html'
+ msg.send()
+ if related_object is not None:
+ assert(activity_type is not None)
+ except Exception, e:
+ logging.critical(unicode(e))
+ if raise_on_failure == True:
+ raise exceptions.EmailNotSent(unicode(e))
diff --git a/askbot/deps/django_authopenid/forms.py b/askbot/deps/django_authopenid/forms.py
index 2cfa9d31..d89796b7 100644
--- a/askbot/deps/django_authopenid/forms.py
+++ b/askbot/deps/django_authopenid/forms.py
@@ -241,7 +241,7 @@ class ChangePasswordForm(SetPasswordForm):
raise forms.ValidationError(_("Old password is incorrect. \
Please enter the correct password."))
return self.cleaned_data['oldpw']
-
+
class ChangeEmailForm(forms.Form):
""" change email form """
email = UserEmailField(skip_clean=True)
@@ -270,6 +270,14 @@ class ChangeEmailForm(forms.Form):
in our database. Please choose another.')
else:
return self.cleaned_data['email']
+
+class AccountRecoveryForm(forms.Form):
+ """with this form user enters email address and
+ receives an account recovery link in email
+
+ this form merely checks that entered email
+ """
+ email = forms.EmailField()
class ChangeopenidForm(forms.Form):
""" change openid form """
diff --git a/askbot/deps/django_authopenid/urls.py b/askbot/deps/django_authopenid/urls.py
index b4293031..5357a808 100644
--- a/askbot/deps/django_authopenid/urls.py
+++ b/askbot/deps/django_authopenid/urls.py
@@ -38,6 +38,7 @@ urlpatterns = patterns('askbot.deps.django_authopenid.views',
url(r'^%s%s$' % (_('email/'),_('validate/')), 'changeemail', name='user_validateemail',kwargs = {'action':'validate'}),
url(r'^%s%s$' % (_('email/'), _('change/')), 'changeemail', name='user_changeemail'),
url(r'^%s%s$' % (_('email/'), _('sendkey/')), 'send_email_key', name='send_email_key'),
+ url(r'^%s(?P<key>[\dabcdef]{32})?$' % _('recover/'), 'account_recover', name='user_account_recover'),
url(r'^%s%s(?P<id>\d+)/(?P<key>[\dabcdef]{32})/$' % (_('email/'), _('verify/')), 'verifyemail', name='user_verifyemail'),
url(r'^%s$' % _('openid/'), 'changeopenid', name='user_changeopenid'),
url(r'^%s$' % _('delete/'), 'delete', name='user_delete'),
diff --git a/askbot/deps/django_authopenid/views.py b/askbot/deps/django_authopenid/views.py
index 83b360d9..9ffd048a 100644
--- a/askbot/deps/django_authopenid/views.py
+++ b/askbot/deps/django_authopenid/views.py
@@ -61,12 +61,10 @@ except ImportError:
import re
import urllib
-from askbot.forms import SimpleEmailSubscribeForm
+from askbot import forms as askbot_forms
from askbot.deps.django_authopenid.util import OpenID, DjangoOpenIDStore, from_openid_response
from askbot.deps.django_authopenid.models import UserAssociation, UserPasswordQueue, ExternalLoginData
-from askbot.deps.django_authopenid.forms import OpenidSigninForm, ClassicLoginForm, OpenidRegisterForm, \
- OpenidVerifyForm, ClassicRegisterForm, ChangePasswordForm, ChangeEmailForm, \
- ChangeopenidForm, DeleteForm, EmailPasswordForm
+from askbot.deps.django_authopenid import forms
import logging
from askbot.utils.forms import get_next_url
@@ -80,6 +78,9 @@ def login(request,user):
if settings.USE_EXTERNAL_LEGACY_LOGIN == True:
EXTERNAL_LOGIN_APP.api.login(request,user)
+ if not hasattr(user, 'backend'):
+ user.backend = "django.contrib.auth.backends.ModelBackend"
+
#1) get old session key
session_key = request.session.session_key
#2) get old search state
@@ -119,8 +120,13 @@ def get_url_host(request):
def get_full_url(request):
return get_url_host(request) + request.get_full_path()
-def ask_openid(request, openid_url, redirect_to, on_failure=None,
- sreg_request=None):
+def ask_openid(
+ request,
+ openid_url,
+ redirect_to,
+ on_failure=None,
+ sreg_request=None
+ ):
""" basic function to ask openid and return response """
request.encoding = 'UTF-8'
on_failure = on_failure or signin_failure
@@ -132,7 +138,7 @@ def ask_openid(request, openid_url, redirect_to, on_failure=None,
settings, 'OPENID_DISALLOW_INAMES', False
):
msg = _("i-names are not supported")
- logging.debug('openid failed becaise i-names are not supported')
+ logging.debug('openid failed because i-names are not supported')
return on_failure(request, msg)
consumer = Consumer(request.session, DjangoOpenIDStore())
try:
@@ -148,6 +154,7 @@ def ask_openid(request, openid_url, redirect_to, on_failure=None,
auth_request.addExtension(sreg_request)
redirect_url = auth_request.redirectURL(trust_root, redirect_to)
logging.debug('redirecting to %s' % redirect_url)
+ print 'redirecting to %s' % redirect_url
return HttpResponseRedirect(redirect_url)
def complete(request, on_success=None, on_failure=None, return_to=None):
@@ -203,8 +210,12 @@ def not_authenticated(func):
return func(request, *args, **kwargs)
return decorated
-@not_authenticated
-def signin(request,newquestion=False,newanswer=False):
+#@not_authenticated
+def signin(
+ request,
+ newquestion = False,
+ newanswer = False,
+ ):
"""
signin page. It manages the legacy authentification (user/password)
and openid authentification
@@ -216,23 +227,27 @@ def signin(request,newquestion=False,newanswer=False):
logging.debug('in signin view')
request.encoding = 'UTF-8'
on_failure = signin_failure
- email_feeds_form = SimpleEmailSubscribeForm()
- next = get_next_url(request)
- form_signin = OpenidSigninForm(initial={'next':next})
- form_auth = ClassicLoginForm(initial={'next':next})
+ email_feeds_form = askbot_forms.SimpleEmailSubscribeForm()
+ initial_data = {'next': get_next_url(request)}
+ openid_login_form = forms.OpenidSigninForm(initial = initial_data)
+ password_login_form = forms.ClassicLoginForm(initial = initial_data)
+
+ print request.method
if request.method == 'POST':
+ print 'have post'
#'blogin' - password login
- if 'blogin' in request.POST.keys():
+ if 'blogin' in request.POST:
+ print 'blogin'
logging.debug('processing classic login form submission')
- form_auth = ClassicLoginForm(request.POST)
- if form_auth.is_valid():
+ password_login_form = forms.ClassicLoginForm(request.POST)
+ if password_login_form.is_valid():
#have login and password and need to login through external website
if settings.USE_EXTERNAL_LEGACY_LOGIN == True:
- username = form_auth.cleaned_data['username']
- password = form_auth.cleaned_data['password']
- next = form_auth.cleaned_data['next']
- if form_auth.get_user() == None:
+ username = password_login_form.cleaned_data['username']
+ password = password_login_form.cleaned_data['password']
+ next = password_login_form.cleaned_data['next']
+ if password_login_form.get_user() == None:
#need to create internal user
#1) save login and password temporarily in session
@@ -247,9 +262,9 @@ def signin(request,newquestion=False,newanswer=False):
#if so, we have to prompt the user to pick a different name
username_taken = User.is_username_taken(screen_name)
- email_feeds_form = SimpleEmailSubscribeForm()
+ email_feeds_form = askbot_forms.SimpleEmailSubscribeForm()
form_data = {'username':screen_name,'email':email,'next':next}
- form = OpenidRegisterForm(initial=form_data)
+ form = forms.OpenidRegisterForm(initial=form_data)
template_data = {'form1':form,'username':screen_name,\
'email_feeds_form':email_feeds_form,\
'provider':mark_safe(settings.EXTERNAL_LEGACY_LOGIN_PROVIDER_NAME),\
@@ -260,23 +275,23 @@ def signin(request,newquestion=False,newanswer=False):
context_instance=RequestContext(request))
else:
#user existed, external password is ok
- user = form_auth.get_user()
+ user = password_login_form.get_user()
login(request,user)
response = HttpResponseRedirect(get_next_url(request))
EXTERNAL_LOGIN_APP.api.set_login_cookies(response,user)
return response
else:
#regular password authentication
- user = form_auth.get_user()
+ user = password_login_form.get_user()
login(request, user)
return HttpResponseRedirect(get_next_url(request))
- elif 'bnewaccount' in request.POST.keys():
+ elif 'bnewaccount' in request.POST:
logging.debug('processing classic (login/password) create account form submission')
#register externally logged in password user with a new local account
if settings.USE_EXTERNAL_LEGACY_LOGIN == True:
- form = OpenidRegisterForm(request.POST)
- email_feeds_form = SimpleEmailSubscribeForm(request.POST)
+ form = forms.OpenidRegisterForm(request.POST)
+ email_feeds_form = askbot_forms.SimpleEmailSubscribeForm(request.POST)
form1_is_valid = form.is_valid()
form2_is_valid = email_feeds_form.is_valid()
if form1_is_valid and form2_is_valid:
@@ -306,6 +321,8 @@ def signin(request,newquestion=False,newanswer=False):
del request.session['external_password']
return HttpResponseServerError()
else:
+ #register after authenticating with external login
+ #provider
username = request.POST.get('username',None)
provider = mark_safe(settings.EXTERNAL_LEGACY_LOGIN_PROVIDER_NAME)
username_taken = User.is_username_taken(username)
@@ -318,12 +335,14 @@ def signin(request,newquestion=False,newanswer=False):
else:
raise Http404
- elif 'bsignin' in request.POST.keys() or 'openid_username' in request.POST.keys():
+ elif 'bsignin' in request.POST or 'openid_username' in request.POST:
+ print request.POST
logging.debug('processing signin with openid submission')
- form_signin = OpenidSigninForm(request.POST)
- if form_signin.is_valid():
+ openid_login_form = forms.OpenidSigninForm(request.POST)
+ if openid_login_form.is_valid():
+ print 'openid form is valid'
logging.debug('OpenidSigninForm is valid')
- next = form_signin.cleaned_data['next']
+ next = openid_login_form.cleaned_data['next']
sreg_req = sreg.SRegRequest(optional=['nickname', 'email'])
redirect_to = "%s%s?%s" % (
get_url_host(request),
@@ -331,42 +350,94 @@ def signin(request,newquestion=False,newanswer=False):
urllib.urlencode({'next':next})
)
return ask_openid(request,
- form_signin.cleaned_data['openid_url'],
+ openid_login_form.cleaned_data['openid_url'],
redirect_to,
on_failure=signin_failure,
sreg_request=sreg_req)
else:
+ print 'openid form is not valid'
logging.debug('OpenidSigninForm is NOT valid! -> redisplay login view')
-
+
+ if request.method == 'GET' and request.user.is_authenticated():
+ view_subtype = 'change_openid'
+ else:
+ view_subtype = 'default'
+
+ return show_signin_view(
+ request,
+ password_login_form = password_login_form,
+ openid_login_form = openid_login_form,
+ view_subtype = view_subtype
+ )
+
+def show_signin_view(
+ request,
+ password_login_form = None,
+ openid_login_form = None,
+ account_recovery_form = None,
+ account_recovery_message = None,
+ view_subtype = 'default'
+ ):
+ """url-less utility function that populates
+ context of template 'authopenid/signin.html'
+ and returns its rendered output
+ """
+
+ allowed_subtypes = ('default', 'add_openid', 'email_sent', 'change_openid')
+ assert(view_subtype in allowed_subtypes)
+
+ initial_data = {'next': get_next_url(request)}
+
+ if password_login_form is None:
+ password_login_form = forms.ClassicLoginForm(initial = initial_data)
+ if openid_login_form is None:
+ openid_login_form = forms.OpenidSigninForm(initial = initial_data)
+ if account_recovery_form is None:
+ account_recovery_form = forms.AccountRecoveryForm()#initial = initial_data)
+
#if request is GET
if request.method == 'GET':
logging.debug('request method was GET')
- question = None
- if newquestion == True:
- from askbot.models import AnonymousQuestion as AQ
- session_key = request.session.session_key
- logging.debug('retrieving anonymously posted question associated with session %s' % session_key)
- qlist = AQ.objects.filter(session_key=session_key).order_by('-added_at')
- if len(qlist) > 0:
- question = qlist[0]
- answer = None
- if newanswer == True:
- from askbot.models import AnonymousAnswer as AA
- session_key = request.session.session_key
- logging.debug('retrieving posted answer associated with session %s' % session_key)
- alist = AA.objects.filter(session_key=session_key).order_by('-added_at')
- if len(alist) > 0:
- answer = alist[0]
+
+ #todo: this sthuff must be executed on some signal
+ #because askbot should have nothing to do with the login app
+ from askbot.models import AnonymousQuestion as AQ
+ session_key = request.session.session_key
+ logging.debug('retrieving anonymously posted question associated with session %s' % session_key)
+ qlist = AQ.objects.filter(session_key=session_key).order_by('-added_at')
+ if len(qlist) > 0:
+ question = qlist[0]
+ else:
+ question = None
+
+ from askbot.models import AnonymousAnswer as AA
+ session_key = request.session.session_key
+ logging.debug('retrieving posted answer associated with session %s' % session_key)
+ alist = AA.objects.filter(session_key=session_key).order_by('-added_at')
+ if len(alist) > 0:
+ answer = alist[0]
+ else:
+ answer = None
+
+ if view_subtype == 'default' or view_subtype == 'email_sent':
+ page_title = _('Please click any of the icons below to sign in')
+ elif view_subtype == 'change_openid':
+ page_title = _('If you wish, please change your login method')
+ elif view_subtype == 'add_openid':
+ page_title = _('Please wait a second! Your account is recovered, but ...')
logging.debug('showing signin view')
return render_to_response('authopenid/signin.html', {
+ 'page_class': 'openid-signin',
+ 'view_subtype': view_subtype, #add_openid|default
+ 'page_title': page_title,
'question':question,
'answer':answer,
- 'form1': form_auth,
- 'form2': form_signin,
- 'msg': request.GET.get('msg',''),
- 'sendpw_url': reverse('user_sendpw'),
- 'fb_api_key': askbot_settings.FB_API_KEY,
+ 'password_login_form': password_login_form,
+ 'openid_login_form': openid_login_form,
+ 'account_recovery_form': account_recovery_form,
+ 'openid_error_message': request.REQUEST.get('msg',''),
+ 'account_recovery_message': account_recovery_message,
}, context_instance=RequestContext(request))
def complete_signin(request):
@@ -393,10 +464,47 @@ def signin_success(request, identity_url, openid_response):
logging.debug('trying to get user associated with this openid...')
rel = UserAssociation.objects.get(openid_url__exact = str(openid_))
logging.debug('success')
- except:
- logging.debug('failed --> try to register brand new user')
- # try to register this new user
- return register(request)
+ print 'found openid in database'
+ if request.user.is_authenticated() and rel.user != request.user:
+ print 'thief'
+ logging.critical(
+ 'possible account theft attempt by %s,%d to %s %d' % \
+ (
+ request.user.username,
+ request.user.id,
+ rel.user.username,
+ rel.user.id
+ )
+ )
+ raise Http404
+ else:
+ print 'good'
+ logging.debug('success')
+ except UserAssociation.DoesNotExist:
+ if request.user.is_anonymous():
+ print 'need to register'
+ logging.debug('failed --> try to register brand new user')
+ # try to register this new user
+ return register(request)
+ else:
+ #store openid association
+ print 'was logged in, but no stored openid yet'
+ try:
+ user_assoc = UserAssociation.objects.get(user = request.user)
+ user_assoc.openid_url = str(openid_)
+ print 'found matching user with other openid'
+ except UserAssociation.DoesNotExist:
+ print 'creatin new openid method'
+ user_assoc = UserAssociation(
+ user = request.user,
+ openid_url = openid_
+ )
+ user_assoc.save()
+ print 'saved association'
+ message = _('New login method saved. Thanks!')
+ request.user.message_set.create(message = message)
+ #set "account recovered" message
+ return HttpResponseRedirect(get_next_url(request))
user_ = rel.user
if user_.is_active:
user_.backend = "django.contrib.auth.backends.ModelBackend"
@@ -413,7 +521,7 @@ def is_association_exist(openid_url):
is_exist = True
try:
uassoc = UserAssociation.objects.get(openid_url__exact = openid_url)
- except:
+ except UserAssociation.DoesNotExist:
is_exist = False
logging.debug(str(is_exist))
return is_exist
@@ -423,8 +531,8 @@ def register(request):
"""
register an openid.
- If user is already a member he can associate its openid with
- its account.
+ If user is already a member he can associate their openid with
+ their account.
A new account could also be created and automaticaly associated
to the openid.
@@ -443,16 +551,16 @@ def register(request):
nickname = openid_.sreg.get('nickname', '')
email = openid_.sreg.get('email', '')
- form1 = OpenidRegisterForm(initial={
+ openid_register_form = forms.OpenidRegisterForm(initial={
'next': next,
'username': nickname,
'email': email,
})
- form2 = OpenidVerifyForm(initial={
+ openid_verify_form = forms.OpenidVerifyForm(initial={
'next': next,
'username': nickname,
})
- email_feeds_form = SimpleEmailSubscribeForm()
+ email_feeds_form = askbot_forms.SimpleEmailSubscribeForm()
user_ = None
is_redirect = False
@@ -460,20 +568,21 @@ def register(request):
if request.method == 'POST':
if 'bnewaccount' in request.POST.keys():
logging.debug('trying to create new account associated with openid')
- form1 = OpenidRegisterForm(request.POST)
- email_feeds_form = SimpleEmailSubscribeForm(request.POST)
- if not form1.is_valid():
+ openid_register_form = forms.OpenidRegisterForm(request.POST)
+ email_feeds_form = askbot_forms.SimpleEmailSubscribeForm(request.POST)
+ if not openid_register_form.is_valid():
logging.debug('OpenidRegisterForm is INVALID')
elif not email_feeds_form.is_valid():
logging.debug('SimpleEmailSubscribeForm is INVALID')
else:
logging.debug('OpenidRegisterForm and SimpleEmailSubscribeForm are valid')
- next = form1.cleaned_data['next']
+ next = openid_register_form.cleaned_data['next']
is_redirect = True
- logging.debug('creatng new django user %s ...' % form1.cleaned_data['username'])
+ logging.debug('creatng new django user %s ...' % \
+ openid_register_form.cleaned_data['username'])
tmp_pwd = User.objects.make_random_password()
- user_ = User.objects.create_user(form1.cleaned_data['username'],
- form1.cleaned_data['email'], tmp_pwd)
+ user_ = User.objects.create_user(openid_register_form.cleaned_data['username'],
+ openid_register_form.cleaned_data['email'], tmp_pwd)
user_.set_unusable_password()
# make association with openid
@@ -490,12 +599,12 @@ def register(request):
email_feeds_form.save(user_)
elif 'bverify' in request.POST.keys():
logging.debug('processing OpenidVerify form')
- form2 = OpenidVerifyForm(request.POST)
- if form2.is_valid():
+ openid_verify_form = forms.OpenidVerifyForm(request.POST)
+ if openid_verify_form.is_valid():
logging.debug('form is valid')
is_redirect = True
- next = form2.cleaned_data['next']
- user_ = form2.get_user()
+ next = openid_verify_form.cleaned_data['next']
+ user_ = openid_verify_form.get_user()
logging.debug('creating new openid user association %s <--> %s' \
% (user_.username, str(openid_)))
uassoc = UserAssociation(openid_url=str(openid_),
@@ -542,8 +651,8 @@ def register(request):
logging.debug('printing authopenid/complete.html output')
return render_to_response('authopenid/complete.html', {
- 'form1': form1,
- 'form2': form2,
+ 'openid_register_form': openid_register_form,
+ 'openid_verify_form': openid_verify_form,
'email_feeds_form': email_feeds_form,
'provider':mark_safe(provider_logo),
'username': nickname,
@@ -560,13 +669,13 @@ def signin_failure(request, message):
"""
logging.debug('')
next = get_next_url(request)
- form_signin = OpenidSigninForm(initial={'next': next})
- form_auth = ClassicLoginForm(initial={'next': next})
+ openid_login_form = forms.OpenidSigninForm(initial={'next': next})
+ password_login_form = forms.ClassicLoginForm(initial={'next': next})
return render_to_response('authopenid/signin.html', {
'msg': message,
- 'form1': form_auth,
- 'form2': form_signin,
+ 'password_login_form': password_login_form,
+ 'openid_login_form': openid_login_form,
}, context_instance=RequestContext(request))
@not_authenticated
@@ -585,8 +694,8 @@ def signup(request):
next = get_next_url(request)
logging.debug('request method was %s' % request.method)
if request.method == 'POST':
- form = ClassicRegisterForm(request.POST)
- email_feeds_form = SimpleEmailSubscribeForm(request.POST)
+ form = forms.ClassicRegisterForm(request.POST)
+ email_feeds_form = askbot_forms.SimpleEmailSubscribeForm(request.POST)
#validation outside if to remember form values
logging.debug('validating classic register form')
@@ -630,8 +739,8 @@ def signup(request):
else:
logging.debug('create classic account forms were invalid')
else:
- form = ClassicRegisterForm(initial={'next':next})
- email_feeds_form = SimpleEmailSubscribeForm()
+ form = forms.ClassicRegisterForm(initial={'next':next})
+ email_feeds_form = askbot_forms.SimpleEmailSubscribeForm()
logging.debug('printing legacy signup form')
return render_to_response('authopenid/signup.html', {
'form': form,
@@ -715,7 +824,7 @@ def changepw(request):
raise Http404
if request.POST:
- form = ChangePasswordForm(request.POST, user=user_)
+ form = forms.ChangePasswordForm(request.POST, user=user_)
if form.is_valid():
user_.set_password(form.cleaned_data['password1'])
user_.save()
@@ -725,7 +834,7 @@ def changepw(request):
urlquote_plus(msg))
return HttpResponseRedirect(redirect)
else:
- form = ChangePasswordForm(user=user_)
+ form = forms.ChangePasswordForm(user=user_)
return render_to_response('authopenid/changepw.html', {'form': form },
context_instance=RequestContext(request))
@@ -762,7 +871,10 @@ def _send_email_key(user):
message_template = loader.get_template('authopenid/email_validation.txt')
import settings
message_context = Context({
- 'validation_link': askbot_settings.APP_URL + reverse('user_verifyemail', kwargs={'id':user.id,'key':user.email_key})
+ 'validation_link': askbot_settings.APP_URL + reverse(
+ 'user_account_recover',
+ kwargs={'key':user.email_key}
+ )
})
message = message_template.render(message_context)
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email])
@@ -802,6 +914,69 @@ def send_email_key(request):
return validation_email_sent(request)
else:
raise Http404
+
+def account_recover(request, key = None):
+ """view similar to send_email_key, except
+ it allows user to recover an account by entering
+ his/her email address
+
+ this view will both - send the recover link and
+ process it
+
+ url name 'user_account_recover'
+ """
+ if request.method == 'POST':
+ form = forms.AccountRecoveryForm(request.POST)
+ if form.is_valid():
+ email = form.cleaned_data['email']
+ try:
+ user = User.objects.get(email = email)
+ send_new_email_key(user, nomessage = True)
+ message = _(
+ 'Please check your email and visit the enclosed link.'
+ )
+ return show_signin_view(
+ request,
+ account_recovery_message = message,
+ view_subtype = 'email_sent'
+ )
+ except User.DoesNotExist:
+ message = _(
+ 'Sorry we cound not find this email it our database. '
+ 'If you think that this is an error - please contact '
+ 'the site administrator'
+ )
+ return show_signin_view(
+ request,
+ account_recovery_message = message,
+ account_recovery_form = form
+ )
+ else:
+ message = _('Please enter a valid email address')
+ return show_signin_view(
+ request,
+ account_recovery_message = message,
+ account_recovery_form = form
+ )
+ else:
+ if key is None:
+ raise Http404
+ try:
+ user = User.objects.get(email_key = key)
+ user.email_key = None #delete the key so that nobody could use it again
+ #todo: add email_key_timestamp field
+ #and check key age
+ login(request, user)
+ return show_signin_view(request, view_subtype = 'add_openid')
+
+ except User.DoesNotExist:
+ message = _('Sorry this account recovery key has '
+ 'expired or is invalid, please request a new one'
+ )
+ return show_signin_view(
+ request,
+ account_recovery_message = message,
+ )
#internal server view used as return value by other views
@@ -852,7 +1027,7 @@ def changeemail(request, action='change'):
msg = _('your email was not changed')
request.user.message_set.create(message=msg)
return HttpResponseRedirect(get_next_url(request))
- form = ChangeEmailForm(request.POST, user=user_)
+ form = forms.ChangeEmailForm(request.POST, user=user_)
if form.is_valid():
new_email = form.cleaned_data['email']
if new_email != user_.email:
@@ -869,7 +1044,7 @@ def changeemail(request, action='change'):
return complete(request, emailopenid_success,
emailopenid_failure, redirect_to)
else:
- form = ChangeEmailForm(initial={'email': user_.email},
+ form = forms.ChangeEmailForm(initial={'email': user_.email},
user=user_)
output = render_to_response('authopenid/changeemail.html', {
@@ -949,7 +1124,7 @@ def changeopenid(request):
redirect_to = get_url_host(request) + reverse('user_changeopenid')
if request.POST and has_openid:
- form = ChangeopenidForm(request.POST, user=user_)
+ form = forms.ChangeopenidForm(request.POST, user=user_)
if form.is_valid():
return ask_openid(request, form.cleaned_data['openid_url'],
redirect_to, on_failure=changeopenid_failure)
@@ -958,7 +1133,7 @@ def changeopenid(request):
return complete(request, changeopenid_success,
changeopenid_failure, redirect_to)
- form = ChangeopenidForm(initial={'openid_url': openid_url }, user=user_)
+ form = forms.ChangeopenidForm(initial={'openid_url': openid_url }, user=user_)
return render_to_response('authopenid/changeopenid.html', {
'form': form,
'has_openid': has_openid,
@@ -1024,7 +1199,7 @@ def delete(request):
redirect_to = get_url_host(request) + reverse('user_delete')
if request.POST:
- form = DeleteForm(request.POST, user=user_)
+ form = forms.DeleteForm(request.POST, user=user_)
if form.is_valid():
if not form.test_openid:
user_.delete()
@@ -1036,7 +1211,7 @@ def delete(request):
return complete(request, deleteopenid_success, deleteopenid_failure,
redirect_to)
- form = DeleteForm(user=user_)
+ form = forms.DeleteForm(user=user_)
msg = request.GET.get('msg','')
return render_to_response('authopenid/delete.html', {
@@ -1100,7 +1275,7 @@ def sendpw(request):
msg = request.GET.get('msg','')
logging.debug('request method is %s' % request.method)
if request.method == 'POST':
- form = EmailPasswordForm(request.POST)
+ form = forms.EmailPasswordForm(request.POST)
if form.is_valid():
logging.debug('EmailPasswordForm is valid')
new_pw = User.objects.make_random_password()
@@ -1133,7 +1308,7 @@ def sendpw(request):
[form.user_cache.email])
msg = _("A new password and the activation link were sent to your email address.")
else:
- form = EmailPasswordForm()
+ form = forms.EmailPasswordForm()
logging.debug('showing reset password form')
return render_to_response('authopenid/sendpw.html', {
diff --git a/askbot/exceptions.py b/askbot/exceptions.py
index 0e7cb712..eb4541bd 100644
--- a/askbot/exceptions.py
+++ b/askbot/exceptions.py
@@ -12,3 +12,9 @@ class DuplicateCommand(exceptions.PermissionDenied):
"""
pass
+class EmailNotSent(exceptions.ImproperlyConfigured):
+ """raised when email cannot be sent
+ due to some mis-configurations on the server
+ """
+ pass
+
diff --git a/askbot/locale/en/LC_MESSAGES/django.mo b/askbot/locale/en/LC_MESSAGES/django.mo
index 29699e7b..892d2f27 100644
--- a/askbot/locale/en/LC_MESSAGES/django.mo
+++ b/askbot/locale/en/LC_MESSAGES/django.mo
Binary files differ
diff --git a/askbot/locale/en/LC_MESSAGES/django.po b/askbot/locale/en/LC_MESSAGES/django.po
index 469a10b5..2ff3fe6a 100644
--- a/askbot/locale/en/LC_MESSAGES/django.po
+++ b/askbot/locale/en/LC_MESSAGES/django.po
@@ -4759,8 +4759,8 @@ msgstr ""
#: skins/default/templates/authopenid/signin.html:42
msgid "Click to sign in through any of these services."
msgstr ""
-"<p><span class=\"big strong\">Please select your favorite login method below."
-"</span></p><p><font color=\"gray\">External login services use <a href="
+"<h2>Please click any of the icons below to sign in.</h2>"
+"<font color=\"gray\">External login services use <a href="
"\"http://openid.net\"><b>OpenID</b></a> technology, where your password "
"always stays confidential between you and your login provider and you don't "
"have to remember another one.</font></p>"
@@ -4777,23 +4777,23 @@ msgstr ""
#: skins/default/templates/authopenid/signin.html:144
msgid "Enter your <span id=\"enter_your_what\">Provider user name</span>"
msgstr ""
-"<span class=\"big strong\">Enter your </span><span id=\"enter_your_what\" "
-"class='big strong'>Provider user name</span><br/><span class='grey'>(or "
-"select another login method above)</span>"
+"<h2>Please, enter your </span><span id=\"enter_your_what\" "
+">Provider user name</span>, then sign in.</h2><p><span class='grey'>(or "
+"select another login method above)</span></p>"
#: skins/default/templates/authopenid/signin.html:151
msgid ""
"Enter your <a class=\"openid_logo\" href=\"http://openid.net\">OpenID</a> "
"web address"
msgstr ""
-"<span class=\"big strong\">Enter your <a class=\"openid_logo\" href=\"http://"
-"openid.net\">OpenID</a> web address</span><br/><span class='grey'>(or choose "
-"another login method above)</span>"
+"<h2>Please, enter your <a class=\"openid_logo\" href=\"http://"
+"openid.net\">OpenID</a> url, then sign in</h2><p><span class='grey'>(or choose "
+"another login method above)</span></p>"
#: skins/default/templates/authopenid/signin.html:153
#: skins/default/templates/authopenid/signin.html:166
msgid "Login"
-msgstr ""
+msgstr "Sign in"
#: skins/default/templates/authopenid/signin.html:157
msgid "Enter your login name and password"
diff --git a/askbot/management/commands/fix_revisionless_posts.py b/askbot/management/commands/fix_revisionless_posts.py
new file mode 100644
index 00000000..47b06a5f
--- /dev/null
+++ b/askbot/management/commands/fix_revisionless_posts.py
@@ -0,0 +1,25 @@
+"""
+"""
+from django.core.management.base import NoArgsCommand
+from django.db.models import signals
+from askbot import models
+
+class Command(NoArgsCommand):
+ """Command class for "fix_answer_counts"
+ """
+
+ def remove_save_signals(self):
+ """removes signals on model pre-save and
+ post-save, so that there are no side-effects
+ besides actually updating the answer counts
+ """
+ signals.pre_save.receivers = []
+ signals.post_save.receivers = []
+
+ def handle(self, *arguments, **options):
+ """function that handles the command job
+ """
+ self.remove_save_signals()
+ questions = models.Question.objects.all()
+ for question in questions:
+ question.update_answer_count()
diff --git a/askbot/management/commands/send_email_alerts.py b/askbot/management/commands/send_email_alerts.py
index a5144d32..fcdac21e 100644
--- a/askbot/management/commands/send_email_alerts.py
+++ b/askbot/management/commands/send_email_alerts.py
@@ -1,13 +1,14 @@
+import logging
+import datetime
from django.core.management.base import NoArgsCommand
from django.db import connection
from django.db.models import Q, F
+import askbot
from askbot.models import User, Question, Answer, Tag, QuestionRevision
from askbot.models import AnswerRevision, Activity, EmailFeedSetting
from askbot.models import Comment
-from django.core.mail import EmailMessage
from django.utils.translation import ugettext as _
from django.utils.translation import ungettext
-import datetime
from django.conf import settings
from askbot.conf import settings as askbot_settings
from django.utils.datastructures import SortedDict
@@ -72,6 +73,51 @@ def format_action_count(string, number, output):
if number > 0:
output.append(_(string) % {'num':number})
+def get_update_subject_line(question_dict):
+ """forms a subject line based on up to five most
+ frequently used tags in the question_dict
+
+ question_dict is an instance of SortedDict,
+ where questions are keys and values are meta_data
+ accumulated during the question filtering
+ """
+ #todo: in python 2.6 there is collections.Counter() thing
+ #which would be very useful here
+ tag_counts = dict()
+ updated_questions = question_dict.keys()
+ for question in updated_questions:
+ tag_names = question.get_tag_names()
+ for tag_name in tag_names:
+ if tag_name in tag_counts:
+ tag_counts[tag_name] += 1
+ else:
+ tag_counts[tag_name] = 1
+ tag_list = tag_counts.keys()
+ #sort in descending order
+ tag_list.sort(lambda x, y: cmp(tag_counts[y], tag_counts[x]))
+
+ question_count = len(updated_questions)
+ #note that double quote placement is important here
+ if len(tag_list) == 1:
+ last_topic = ''
+ elif len(tag_list) <= 5:
+ last_topic = _('" and "%s"') % tag_list.pop()
+ else:
+ tag_list = tag_list[:5]
+ last_topic = _('" and more')
+
+ topics = '"' + '", "'.join(tag_list) + last_topic
+
+ subject_line = ungettext(
+ '%(question_count)d updated question about %(topics)s',
+ '%(question_count)d updated questions about %(topics)s',
+ question_count
+ ) % {
+ 'question_count': question_count,
+ 'topics': topics
+ }
+ return subject_line
+
class Command(NoArgsCommand):
def handle_noargs(self, **options):
try:
@@ -407,15 +453,14 @@ class Command(NoArgsCommand):
if len(q_list.keys()) == 0:
continue
num_q = 0
- num_moot = 0
- for meta_data in q_list.values():
+ for question, meta_data in q_list.items():
if meta_data['skip']:
- num_moot = True
+ del q_list[question]
else:
num_q += 1
if num_q > 0:
url_prefix = askbot_settings.APP_URL
- subject = _('email update message subject')
+ subject_line = get_update_subject_line(q_list)
#todo: send this to special log
#print 'have %d updated questions for %s' % (num_q, user.username)
text = ungettext('%(name)s, this is an update message header for %(num)d question',
@@ -479,26 +524,17 @@ class Command(NoArgsCommand):
'There is a chance that you may be receiving links seen '
'before - due to a technicality that will eventually go away. '
)
- # text += '</p>'
- #if num_moot > 0:
- # text += '<p></p>'
- # text += ungettext('There is also one question which was recently '\
- # +'updated but you might not have seen its latest version.',
- # 'There are also %(num)d more questions which were recently updated '\
- # +'but you might not have seen their latest version.',num_moot) \
- # % {'num':num_moot,}
- # text += _('Perhaps you could look up previously sent askbot reminders in your mailbox.')
- # text += '</p>'
link = url_prefix + user.get_profile_url() + '?sort=email_subscriptions'
text += _('go to %(email_settings_link)s to change frequency of email updates or %(admin_email)s administrator') \
% {'email_settings_link':link, 'admin_email':settings.ADMINS[0][1]}
- if DEBUG_THIS_COMMAND == False:
- msg = EmailMessage(
- subject,
- text,
- settings.DEFAULT_FROM_EMAIL,
- [user.email]
- )
- msg.content_subtype = 'html'
- msg.send()
+ if DEBUG_THIS_COMMAND == True:
+ recipient_email = settings.ADMINS[0][1]
+ else:
+ recipient_email = user.email
+
+ askbot.send_mail(
+ subject_line = subject_line,
+ body_text = text,
+ recipient_list = [recipient_email]
+ )
diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py
index e04718a4..fc53c3b6 100644
--- a/askbot/models/__init__.py
+++ b/askbot/models/__init__.py
@@ -3,7 +3,6 @@ import re
import hashlib
import datetime
from django.core.urlresolvers import reverse
-from django.core.mail import EmailMessage
from askbot.search.indexer import create_fulltext_indexes
from django.db.models import signals as django_signals
from django.template import loader, Context
@@ -16,6 +15,7 @@ from django.db import models
from django.conf import settings as django_settings
from django.contrib.contenttypes.models import ContentType
from django.core import exceptions as django_exceptions
+import askbot
from askbot import exceptions as askbot_exceptions
from askbot import const
from askbot.conf import settings as askbot_settings
@@ -1408,7 +1408,7 @@ User.add_to_class(
)
#todo: move this to askbot/utils ??
-def format_instant_notification_body(
+def format_instant_notification_email(
to_user = None,
from_user = None,
post = None,
@@ -1417,6 +1417,8 @@ def format_instant_notification_body(
):
"""
returns text of the instant notification body
+ and subject line
+
that is built when post is updated
only update_types in const.RESPONSE_ACTIVITY_TYPE_MAP_FOR_TEMPLATES
are supported
@@ -1431,13 +1433,37 @@ def format_instant_notification_body(
if update_type == 'question_comment':
assert(isinstance(post, Comment))
assert(isinstance(post.content_object, Question))
+ subject_line = _(
+ 'new question comment about: "%(title)s"'
+ ) % {'title': origin_post.title}
elif update_type == 'answer_comment':
assert(isinstance(post, Comment))
assert(isinstance(post.content_object, Answer))
- elif update_type in ('answer_update', 'new_answer'):
+ subject_line = _(
+ 'new answer comment about: "%(title)s"'
+ ) % {'title': origin_post.title}
+ elif update_type == 'answer_update':
+ assert(isinstance(post, Answer))
+ subject_line = _(
+ 'answer modified for: "%(title)s"'
+ ) % {'title': origin_post.title}
+ elif update_type == 'new_answer':
assert(isinstance(post, Answer))
- elif update_type in ('question_update', 'new_question'):
+ subject_line = _(
+ 'new answer for: "%(title)s"'
+ ) % {'title': origin_post.title}
+ elif update_type == 'question_update':
assert(isinstance(post, Question))
+ subject_line = _(
+ 'question modified: "%(title)s"'
+ ) % {'title': origin_post.title}
+ elif update_type == 'new_question':
+ assert(isinstance(post, Question))
+ subject_line = _(
+ 'new question: "%(title)s"'
+ ) % {'title': origin_post.title}
+ else:
+ raise ValueError('unexpected update_type %s' % update_type)
update_data = {
'update_author_name': from_user.username,
@@ -1447,7 +1473,7 @@ def format_instant_notification_body(
'origin_post_title': origin_post.title,
'user_subscriptions_url': user_subscriptions_url,
}
- return template.render(Context(update_data))
+ return subject_line, template.render(Context(update_data))
#todo: action
def send_instant_notifications_about_activity_in_post(
@@ -1476,8 +1502,7 @@ def send_instant_notifications_about_activity_in_post(
for user in receiving_users:
- subject = _('email update message subject')
- text = format_instant_notification_body(
+ subject_line, body_text = format_instant_notification_email(
to_user = user,
from_user = update_activity.user,
post = post,
@@ -1486,22 +1511,13 @@ def send_instant_notifications_about_activity_in_post(
)
#todo: this could be packaged as an "action" - a bundle
#of executive function with the activity log recording
- msg = EmailMessage(
- subject,
- text,
- django_settings.DEFAULT_FROM_EMAIL,
- [user.email]
- )
- msg.content_subtype = 'html'
- msg.send()
- #print text
- EMAIL_UPDATE_ACTIVITY = const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT
- email_activity = Activity(
- user = user,
- content_object = post.get_origin_post(),
- activity_type = EMAIL_UPDATE_ACTIVITY
- )
- email_activity.save()
+ askbot.send_mail(
+ subject_line = subject_line,
+ body_text = body_text,
+ recipient_list = [user.email],
+ related_object = post.get_origin_post(),
+ activity_type = const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT
+ )
#todo: move to utils
diff --git a/askbot/models/question.py b/askbot/models/question.py
index 1be112e7..3ce6dfcf 100644
--- a/askbot/models/question.py
+++ b/askbot/models/question.py
@@ -297,12 +297,15 @@ class Question(content.Content, DeletableContent):
return LazyList(get_data)
+ def get_tag_names(self):
+ return self.tagnames.split(' ')
+
def get_similarity(self, other_question = None):
"""return number of tags in the other question
that overlap with the current question (self)
"""
- my_tags = set(self.tagnames.split(' '))
- others_tags = set(other_question.tagnames.split(' '))
+ my_tags = set(self.get_tag_names())
+ others_tags = set(other_question.get_tag_names())
return len(my_tags & others_tags)
def update_tags(self, tagnames, user):
diff --git a/askbot/skins/default/media/jquery-openid/jquery.openid.js b/askbot/skins/default/media/jquery-openid/jquery.openid.js
index eae7b3ea..120b034b 100755
--- a/askbot/skins/default/media/jquery-openid/jquery.openid.js
+++ b/askbot/skins/default/media/jquery-openid/jquery.openid.js
@@ -103,7 +103,7 @@ $.fn.openid = function() {
$usrfs.hide();
$idfs.hide();
$localfs.hide();
- $this.find('td:eq(0)').click();
+ //$this.find('td:eq(0)').click();
return this;
};
diff --git a/askbot/skins/default/media/jquery-openid/openid.css b/askbot/skins/default/media/jquery-openid/openid.css
index e1577c2c..27eae2c3 100755
--- a/askbot/skins/default/media/jquery-openid/openid.css
+++ b/askbot/skins/default/media/jquery-openid/openid.css
@@ -18,12 +18,13 @@ input[name=openid_username] {width:8em}
input[name=openid_identifier] {width:18em}
form.openid ul li.highlight { -moz-border-radius:4px; -webkit-border-radius:4px; background-color: #FD6}
form.openid fieldset div {
- -moz-border-radius:4px;
- -webkit-border-radius:4px;
- background: #DCDCDC;
+ /*-moz-border-radius:4px; */
+ /*-webkit-border-radius:4px; */
+ /*background: #DCDCDC;*/
padding:10px;
float:left;
}
+.openid-signin h2 {margin-top:10px;}
form.openid p {margin-bottom:4px;}
form.openid fieldset div p {padding:0px;margin:0px;}
form.openid fieldset div p.login {padding:0px;margin:0 0 10px 0;}
diff --git a/askbot/skins/default/templates/authopenid/complete.html b/askbot/skins/default/templates/authopenid/complete.html
index 62970e38..8e668ab7 100644
--- a/askbot/skins/default/templates/authopenid/complete.html
+++ b/askbot/skins/default/templates/authopenid/complete.html
@@ -5,12 +5,15 @@ views calling this template:
* django_authopenid.views.register with login_type='openid'
* django_authopenid.views.signin - with login_type='legacy'
+purpose of this template is to allow user enter his/her name
+email and sign up for email alerts at the initial registratio
+
parameters:
* provider
* login_type openid|legacy
* username (same as screen name or username in the models, and nickname in openid sreg)
-* form1 - OpenidRegisterForm
-* form2 - OpenidVerifyForm not clear what this form is supposed to do, not used for legacy
+* openid_register_form
+* openid_verify_form - not clear what this form is supposed to do, not used for legacy
* email_feeds_form forum.forms.SimpleEmailSubscribeForm
* openid_username_exists
{% endcomment %}
@@ -19,9 +22,9 @@ parameters:
{% block title %}{% spaceless %}{% trans "Connect your OpenID with this site" %}{% endspaceless %}{% endblock %}
{% block content %}
<div id="main-bar" class="headNormal">
- {% trans "Connect your OpenID with your account on this site" %}
+ {% trans "Connect your OpenID with your account on this site" %}
</div>
- <div id="completetxt" >
+ <div id="completetxt" >
<div class="message">
{% ifequal login_type 'openid' %}
{% blocktrans %}register new {{provider}} account info, see {{gravatar_faq_url}}{% endblocktrans %}
@@ -39,35 +42,35 @@ parameters:
{% endifequal %}
{% endifequal %}
</div>
- <p style="display:none">{% trans "This account already exists, please use another." %}</p>
- </div>
+ <p style="display:none">{% trans "This account already exists, please use another." %}</p>
+ </div>
- {% if form1.errors %}
+ {% if openid_register_form.errors %}
<ul class="errorlist">
- {% if form1.non_field_errors %}
- {% for error in form1.non_field_errors %}
+ {% if openid_register_form.non_field_errors %}
+ {% for error in openid_register_form.non_field_errors %}
<li>{{error}}</li>
{% endfor %}
{% endif %}
</ul>
- {% endif %}
+ {% endif %}
{% comment %}
- {% if form2.errors %}<!--form2 is dysfunctional so commented out -->
- <div class="errors">
+ {% if openid_verify_form.errors %}<!--openid_verify_form is dysfunctional so commented out -->
+ <div class="errors">
<span class="big">{% trans "Sorry, looks like we have some errors:" %}</span><br/>
<ul class="error-list">
- {% if form2.username.errors %}
- <li><span class="error">{{ form2.username.errors|join:", " }}</span></li>
- {% endif %}
- {% if form2.password.errors %}
- <li><span class="error">{{ form2.password.errors|join:", " }}</span></li>
- {% endif %}
+ {% if openid_verify_form.username.errors %}
+ <li><span class="error">{{ openid_verify_form.username.errors|join:", " }}</span></li>
+ {% endif %}
+ {% if openid_verify_form.password.errors %}
+ <li><span class="error">{{ openid_verify_form.password.errors|join:", " }}</span></li>
+ {% endif %}
</ul>
- </div>
- {% endif %}
+ </div>
+ {% endif %}
{% endcomment %}
- <div class="login">
+ <div class="login">
{% ifequal login_type 'openid' %}
<form name="fregister" action="{% url user_register %}" method="POST">
{% else %}
@@ -77,20 +80,20 @@ parameters:
<form name="fregister" action="{% url user_signin %}" method="POST">
{% endifequal %}
{% endifequal %}
- {{ form1.next }}
+ {{ openid_register_form.next }}
<div class="form-row-vertical">
<label for="id_username">{% trans "Screen name label" %}</label>
- {% if form1.username.errors %}
- <p class="error">{{ form1.username.errors|join:", " }}</p>
+ {% if openid_register_form.username.errors %}
+ <p class="error">{{ openid_register_form.username.errors|join:", " }}</p>
{% endif %}
- {{ form1.username }}
+ {{ openid_register_form.username }}
</div>
<div class="form-row-vertical margin-bottom">
<label for="id_email">{% trans "Email address label" %}</label>
- {% if form1.email.errors %}
- <p class="error">{{ form1.email.errors|join:", " }}</p>
+ {% if openid_register_form.email.errors %}
+ <p class="error">{{ openid_register_form.email.errors|join:", " }}</p>
{% endif %}
- {{ form1.email }}
+ {{ openid_register_form.email }}
</div>
<p>{% trans "receive updates motivational blurb" %}</p>
<div class='simple-subscribe-options'>
@@ -101,29 +104,29 @@ parameters:
</div>
<p class='space-above'>{% trans "Tag filter tool will be your right panel, once you log in." %}</p>
<div class="submit-row"><input type="submit" class="submit" name="bnewaccount" value="{% trans "create account" %}"/></div>
- </form>
- </div>
+ </form>
+ </div>
{% comment %}<!-- this form associates openID with an existing password-protected account, not yet functional -->
- {% if form2 %}
- <div class="login" style="display:none">
+ {% if openid_verify_form %}
+ <div class="login" style="display:none">
<form name="fverify" action="{% url user_register %}" method="POST">
- {{ form2.next }}
- <fieldset style="padding:10px">
- <legend class="big">{% trans "Existing account" %}</legend>
- <div class="form-row"><label for="id_username">{% trans "user name" %}</label><br/>{{ form2.username }}</div>
- <div class="form-row"><label for="id_passwordl">{% trans "password" %}</label><br/>{{ form2.password }}</div>
+ {{ openid_verify_form.next }}
+ <fieldset style="padding:10px">
+ <legend class="big">{% trans "Existing account" %}</legend>
+ <div class="form-row"><label for="id_username">{% trans "user name" %}</label><br/>{{ openid_verify_form.username }}</div>
+ <div class="form-row"><label for="id_passwordl">{% trans "password" %}</label><br/>{{ openid_verify_form.password }}</div>
<p><span class='big strong'>(Optional) receive updates by email</span> - only sent when there are any.</p>
<div class='simple-subscribe-options'>
{{email_feeds_form.subscribe}}
</div>
- <!--todo double check translation from chinese 确认 = "Register" -->
- <div class="submit-row">
- <input type="submit" class="submit" name="bverify" value="{% trans "Register" %}"/>
- <a href="{% url user_sendpw %}">{% trans "Forgot your password?" %}</a>
- </div>
- </fieldset>
- </form>
- </div>
+ <!--todo double check translation from chinese 确认 = "Register" -->
+ <div class="submit-row">
+ <input type="submit" class="submit" name="bverify" value="{% trans "Register" %}"/>
+ <a href="{% url user_sendpw %}">{% trans "Forgot your password?" %}</a>
+ </div>
+ </fieldset>
+ </form>
+ </div>
{% endif %}
{% endcomment %}
{% endblock %}
diff --git a/askbot/skins/default/templates/authopenid/signin.html b/askbot/skins/default/templates/authopenid/signin.html
index 25f9c452..da766667 100755
--- a/askbot/skins/default/templates/authopenid/signin.html
+++ b/askbot/skins/default/templates/authopenid/signin.html
@@ -2,175 +2,205 @@
<!-- signin.html -->
{% load i18n %}
{% load extra_tags %}
+{% load smart_if %}
{% block title %}{% spaceless %}{% trans "User login" %}{% endspaceless %}{% endblock %}
{% block forejs %}
<script type='text/javascript' src='{% media "/js/jquery.validate.pack.js" %}'></script>
- <link rel="stylesheet" type="text/css" media="screen" href="{% media "/jquery-openid/openid.css" %}"/>
- <script type="text/javascript" src="{% media "/jquery-openid/jquery.openid.js" %}"></script>
- <script type="text/javascript"> $().ready( function() { $("form.openid:eq(0)").openid(); })</script>
- <!--<script type="text/javascript">
- $().ready(function(){
- openid.init('id_openid_url');
- setupFormValidation("#openid_form", {bsignin:{required: true}});
- });
- </script>-->
+ <link rel="stylesheet" type="text/css" media="screen" href="{% media "/jquery-openid/openid.css" %}"/>
+ <script type="text/javascript" src="{% media "/jquery-openid/jquery.openid.js" %}"></script>
+ <script type="text/javascript"> $().ready( function() { $("form.openid:eq(0)").openid(); })</script>
+ <!--<script type="text/javascript">
+ $().ready(function(){
+ openid.init('id_openid_url');
+ setupFormValidation("#openid_form", {bsignin:{required: true}});
+ });
+ </script>-->
{% endblock %}
{% block content %}
-<div class="headNormal">
- {% trans "User login" %}
-</div>
- {% if msg %}
- <p class="warning">{{ msg }}</p>
- {% endif %}
- {% if answer %}
- <div class="message">
- {% blocktrans with answer.question.title as title and answer.summary as summary %}
- Your answer to {{title}} {{summary}} will be posted once you log in
- {% endblocktrans %}
- </div>
- {% endif %}
- {% if question %}
- <div class="message">
- {% blocktrans with question.title as title and question.summary as summary %}Your question
- {{title}} {{summary}} will be posted once you log in
- {% endblocktrans %}
+<h1>{{page_title}}</h1>
+ {% if answer %}
+ <div class="message">
+ {% blocktrans with answer.question.title as title and answer.summary as summary %}
+ Your answer to {{title}} {{summary}} will be posted once you log in
+ {% endblocktrans %}
+ </div>
+ {% endif %}
+ {% if question %}
+ <div class="message">
+ {% blocktrans with question.title as title and question.summary as summary %}Your question
+ {{title}} {{summary}} will be posted once you log in
+ {% endblocktrans %}
+ </div>
+ {% endif %}
+ <form id="openid_form" name="openid_form" class="openid" method="post" action="{% url user_signin %}">
+ {% if view_subtype == 'default' or view_subtype == 'email_sent' %}
+ <p>
+ {% trans "You can use your favorite service from those listed below to sign in using secure OpenID or similar technology. Your external service password always stays confidential and you don't have to rememeber or create another one." %}
+ </p>
+ {% endif %}
+ {% if view_subtype == 'add_openid' %}
+ <p>{% trans "Please add a more permanent login method by clicking one of the icons below, to avoioid logging in via email each time. All of the services listed below provide a secure sign-in method based on OpenID or similar technology." %}</p>
+ {% endif %}
+ {% if view_subtype == 'change_openid' %}
+ <p>{% trans "You are already signed in, but if you want to change the login method for the future use - just click on one of the icons below." %}</p>
+ {% endif %}
+ {% if openid_error_message %}
+ <p class="warning">{{ openid_error_message }}</p>
+ {% endif %}
+ <table>
+ {% comment %}
+ <li class="local" title="Local login">
+ <div class="logo_box local_login_box">
+ <img src="{% media "/jquery-openid/images/logo-small.gif" %}"
+ alt="your icon here" />
</div>
- {% endif %}
- <form id="openid_form" name="openid_form" class="openid" method="post" action="{% url user_signin %}">
- <div><!-- style="width:600px;float:left;margin-bottom:5px;"> -->
- {% trans "Click to sign in through any of these services." %}
- </div>
- <table>
- {% comment %}
- <li class="local" title="Local login">
- <div class="logo_box local_login_box">
- <img src="{% media "/jquery-openid/images/logo-small.gif" %}" alt="your icon here" />
- </div>
- <span></span>
- </li>
- {% endcomment %}
+ <span></span>
+ </li>
+ {% endcomment %}
<tr class="providers">
- <td class="username" title="OpenID URL">
- <div class="logo_box openid_box">
- <img src="{% media "/jquery-openid/images/openid.gif" %}" alt="icon" />
- <span>http://<strong>username</strong></span>
+ <td class="username" title="OpenID URL">
+ <div class="logo_box openid_box">
+ <img src="{% media "/jquery-openid/images/openid.gif" %}" alt="icon" />
+ <span>http://<strong>username</strong></span>
</div>
- </td>
- <td class="direct" title="Google">
- <div class="logo_box google_box">
- <img src="{% media "/jquery-openid/images/google.gif" %}" alt="icon" /><span>https://www.google.com/accounts/o8/id</span>
- </div>
- </td>
- <td class="direct" title="Yahoo">
+ </td>
+ <td class="direct" title="Google">
+ <div class="logo_box google_box">
+ <img src="{% media "/jquery-openid/images/google.gif" %}" alt="icon" />
+ <span>https://www.google.com/accounts/o8/id</span>
+ </div>
+ </td>
+ <td class="direct" title="Yahoo">
<div class="logo_box yahoo_box">
- <img src="{% media "/jquery-openid/images/yahoo.gif" %}" alt="icon" /><span>http://yahoo.com/</span>
+ <img src="{% media "/jquery-openid/images/yahoo.gif" %}" alt="icon" />
+ <span>http://yahoo.com/</span>
</div>
- </td>
- <td class="username" title="AOL screen name">
+ </td>
+ <td class="username" title="AOL screen name">
<div class="logo_box aol_box">
- <img src="{% media "/jquery-openid/images/aol.gif" %}" alt="icon" /><span>http://openid.aol.com/<strong>username</strong></span>
+ <img src="{% media "/jquery-openid/images/aol.gif" %}" alt="icon" />
+ <span>http://openid.aol.com/<strong>username</strong></span>
</div>
- </td>
+ </td>
</tr>
</table>
<table>
- <tr id="openid_small_providers" class="providers">
- <!--<li class="openid" title="OpenID">
- <div class="logo_box openid_box">
- <img src="/jquery-openid/images/openid.gif" alt="icon" />
- </div>
- <span><strong>http://{your-openid-url}</strong></span>
- </li>-->
- {% comment %}
- <li class="first_tiny_li facebook" title="Facebook Connect">
+ <tr id="openid_small_providers" class="providers">
+ {% comment %}
+ <li class="openid" title="OpenID">
+ <div class="logo_box openid_box">
+ <img src="/jquery-openid/images/openid.gif" alt="icon" />
+ </div>
+ <span><strong>http://{your-openid-url}</strong></span>
+ </li>
+ <li class="first_tiny_li facebook" title="Facebook Connect">
{% if question %}
- <fb:login-button onlogin="window.location = '{% url fb_signin_new_question %}'"></fb:login-button>
+ <fb:login-button onlogin="window.location = '{% url fb_signin_new_question %}'"></fb:login-button>
{% else %}
{% if answer %}
- <fb:login-button onlogin="window.location = '{% url fb_signin_new_answer %}'"></fb:login-button>
+ <fb:login-button onlogin="window.location = '{% url fb_signin_new_answer %}'"></fb:login-button>
{% else %}
- <fb:login-button onlogin="window.location = '{% url fb_signin %}'"></fb:login-button>
+ <fb:login-button onlogin="window.location = '{% url fb_signin %}'"></fb:login-button>
{% endif %}
{% endif %}
- </li>
- {% endcomment %}
- {% comment %}
- <li class="openid first_tiny_li" title="OpenID URL">
- <img src="{% media "/jquery-openid/images/openidico16.png" %}" alt="icon" />
- <span>http://{your-openid-url}</span>
- </li>
- {% endcomment %}
- <td class="username first_tiny_li" title="MyOpenID user name">
- <img src="{% media "/jquery-openid/images/myopenid-2.png" %}" alt="icon" />
- <span>http://<strong>username</strong>.myopenid.com/</span>
- </td>
- <td class="username" title="Flickr user name">
- <img src="{% media "/jquery-openid/images/flickr.png" %}" alt="icon" />
- <span>http://flickr.com/<strong>username</strong>/</span>
- </td>
- <td class="username" title="Technorati user name">
- <img src="{% media "/jquery-openid/images/technorati-1.png" %}" alt="icon" />
- <span>http://technorati.com/people/technorati/<strong>username</strong>/</span>
- </td>
- <td class="username" title="Wordpress blog name">
- <img src="{% media "/jquery-openid/images/wordpress.png" %}" alt="icon" />
- <span>http://<strong>username</strong>.wordpress.com</span>
- </td>
- <td class="username" title="Blogger blog name">
- <img src="{% media "/jquery-openid/images/blogger-1.png" %}" alt="icon" />
- <span>http://<strong>username</strong>.blogspot.com/</span>
- </td>
- <td class="username" title="LiveJournal blog name">
- <img src="{% media "/jquery-openid/images/livejournal-1.png" %}" alt="icon" />
- <span>http://<strong>username</strong>.livejournal.com</span>
- </td>
- <td class="username" title="ClaimID user name">
- <img src="{% media "/jquery-openid/images/claimid-0.png" %}" alt="icon" />
- <span>http://claimid.com/<strong>username</strong></span>
- </td>
- <td class="username" title="Vidoop user name">
- <img src="{% media "/jquery-openid/images/vidoop.png" %}" alt="icon" />
- <span>http://<strong>username</strong>.myvidoop.com/</span>
- </td>
- <td class="username" title="Verisign user name">
- <img src="{% media "/jquery-openid/images/verisign-2.png" %}" alt="icon" />
- <span>http://<strong>username</strong>.pip.verisignlabs.com/</span>
- </td>
- </tr>
+ </li>
+ <li class="openid first_tiny_li" title="OpenID URL">
+ <img src="{% media "/jquery-openid/images/openidico16.png" %}" alt="icon" />
+ <span>http://{your-openid-url}
+ </li>
+ {% endcomment %}
+ <td class="username first_tiny_li" title="MyOpenID user name">
+ <img src="{% media "/jquery-openid/images/myopenid-2.png" %}" alt="icon" />
+ <span>http://<strong>username</strong>.myopenid.com/</span>
+ </td>
+ <td class="username" title="Flickr user name">
+ <img src="{% media "/jquery-openid/images/flickr.png" %}" alt="icon" />
+ <span>http://flickr.com/<strong>username</strong>/</span>
+ </td>
+ <td class="username" title="Technorati user name">
+ <img src="{% media "/jquery-openid/images/technorati-1.png" %}" alt="icon" />
+ <span>http://technorati.com/people/technorati/<strong>username</strong>/</span>
+ </td>
+ <td class="username" title="Wordpress blog name">
+ <img src="{% media "/jquery-openid/images/wordpress.png" %}" alt="icon" />
+ <span>http://<strong>username</strong>.wordpress.com</span>
+ </td>
+ <td class="username" title="Blogger blog name">
+ <img src="{% media "/jquery-openid/images/blogger-1.png" %}" alt="icon" />
+ <span>http://<strong>username</strong>.blogspot.com/</span>
+ </td>
+ <td class="username" title="LiveJournal blog name">
+ <img src="{% media "/jquery-openid/images/livejournal-1.png" %}" alt="icon" />
+ <span>http://<strong>username</strong>.livejournal.com</span>
+ </td>
+ <td class="username" title="ClaimID user name">
+ <img src="{% media "/jquery-openid/images/claimid-0.png" %}" alt="icon" />
+ <span>http://claimid.com/<strong>username</strong></span>
+ </td>
+ <td class="username" title="Vidoop user name">
+ <img src="{% media "/jquery-openid/images/vidoop.png" %}" alt="icon" />
+ <span>http://<strong>username</strong>.myvidoop.com/</span>
+ </td>
+ <td class="username" title="Verisign user name">
+ <img src="{% media "/jquery-openid/images/verisign-2.png" %}" alt="icon" />
+ <span>http://<strong>username</strong>.pip.verisignlabs.com/</span>
+ </td>
+ </tr>
</table>
- {{ form2.next }}
- <fieldset>
- <p id="provider_name_slot">{% trans 'Enter your <span id="enter_your_what">Provider user name</span>' %}</p>
- <div><p><span></span>
- <input id="openid_username" type="text" name="openid_username" /><span></span>
- <input type="submit" value="Login" />
- </p></div>
- </fieldset>
- <fieldset>
- <p>{% trans 'Enter your <a class="openid_logo" href="http://openid.net">OpenID</a> web address' %}</p>
- <div><p><input id="openid_url" type="text" value="http://" name="openid_url" />
- <input id="bsignin" name="bsignin" type="submit" value="{% trans "Login" %}" /></p></div>
- </fieldset>
- {% comment %}
- <fieldset id='local_login_fs'>
- <p>{% trans 'Enter your login name and password' %}</p>
- {% if form1.errors %}
- {{form1.non_field_errors.as_ul}}
- {% endif %}
- <div><p class="login"><label for="id_username">{% trans "Login name" %}</label>
- {{form1.username}}</p>
- <p class="login"><label for="id_password">{% trans "Password" %}</label>
- {{form1.password}}</p>
- <p id="local_login_buttons">
- <input id="blogin" name="blogin" type="submit" value="{% trans "Login" %}" />
- <a href="{% url user_signup %}">{% trans "Create account" %}</a><br/>
- <a href="{% url user_sendpw %}">{% trans "Forgot your password?" %}</a>
- </p>
- </div>
- </fieldset>
- {% endcomment %}
- </form>
+ {{ openid_login_form.next }}
+ <fieldset style="display:none;">
+ <p id="provider_name_slot">{% trans 'Enter your <span id="enter_your_what">Provider user name</span>' %}</p>
+ <div><p><span></span>
+ <input id="openid_username" type="text" name="openid_username" /><span></span>
+ <input type="submit" value="{% trans "Login" %}" />
+ </p></div>
+ </fieldset>
+ <fieldset style="display:none">
+ <p>{% trans 'Enter your <a class="openid_logo" href="http://openid.net">OpenID</a> web address' %}</p>
+ <div><p><input id="openid_url" type="text" value="http://" name="openid_url" />
+ <input id="bsignin" name="bsignin" type="submit" value="{% trans "Login" %}" /></p></div>
+ </fieldset>
+ {% comment %}
+ <fieldset id='local_login_fs'>
+ <p>{% trans 'Enter your login name and password' %}</p>
+ {% if password_login_form.errors %}
+ {{password_login_form.non_field_errors.as_ul}}
+ {% endif %}
+ <div>
+ <p class="login">
+ <label for="id_username">{% trans "Login name" %}</label>
+ {{password_login_form.username}}
+ </p>
+ <p class="login">
+ <label for="id_password">{% trans "Password" %}</label>
+ {{password_login_form.password}}
+ </p>
+ <p id="local_login_buttons">
+ <input id="blogin" name="blogin" type="submit" value="{% trans "Login" %}" />
+ <a href="{% url user_signup %}">{% trans "Create account" %}</a><br/>
+ <a href="{% url user_sendpw %}">{% trans "Forgot your password?" %}</a>
+ </p>
+ </div>
+ </fieldset>
+ {% endcomment %}
+ </form>
+ {% if view_subtype == 'default' or view_subtype == 'email_sent' %}
+ <form action="{% url user_account_recover %}" method="post">
+ {% if view_subtype == 'email_sent' %}
+ <h2>{% trans "Account recovery email sent" %}</h2>
+ {% else %}
+ <h2>{% trans "Still have trouble accessing your account?" %}</h2>
+ {% endif %}
+ {% if account_recovery_message %}
+ <p>{{account_recovery_message}}</p>
+ {% else %}
+ <p>{% trans "Please, enter your email address below to recover" %}</p>
+ {% endif %}
+ {{ account_recovery_form.email }}
+ <input type="submit" value="{% trans "Recover your account via email" %}"/>
+ </form>
+ {% endif %}
{% endblock %}
{% block sidebar %}
@@ -178,16 +208,16 @@
<h3 class="subtitle">{% trans "Why use OpenID?" %}</h3>
<ul class="list-item">
<li>
- {% trans "with openid it is easier" %}
+ {% trans "with openid it is easier" %}
</li>
<li>
- {% trans "reuse openid" %}
+ {% trans "reuse openid" %}
</li>
<li>
- {% trans "openid is widely adopted" %}
+ {% trans "openid is widely adopted" %}
</li>
<li>
- {% trans "openid is supported open standard" %}
+ {% trans "openid is supported open standard" %}
</li>
</ul>
@@ -198,9 +228,9 @@
</div>
{% comment %}
<script type="text/javascript" src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php"></script>
-<script type="text/javascript"> FB.init("{{ fb_api_key }}","{% url xd_receiver %}");</script>
+<script type="text/javascript"> FB.init("{{ settings.FB_API_KEY }}","{% url xd_receiver %}");</script>
{% endcomment %}
{% endblock%}
- <script type="text/javascript"> $( function() { $("form.openid:eq(0)").openid(); })</script>
+<script type="text/javascript"> $( function() { $("form.openid:eq(0)").openid(); })</script>
<!-- end signin.html -->
diff --git a/askbot/skins/default/templates/base.html b/askbot/skins/default/templates/base.html
index 822a69ad..4a36ad25 100644
--- a/askbot/skins/default/templates/base.html
+++ b/askbot/skins/default/templates/base.html
@@ -69,7 +69,11 @@
{% block forejs %}
{% endblock %}
</head>
+ {% if page_class %}
+ <body class="{{page_class}}">
+ {% else %}
<body>
+ {% endif %}
<div class="notify" style="display:none">
{% autoescape off %}
{% if user_messages %}
diff --git a/askbot/tests/email_alert_tests.py b/askbot/tests/email_alert_tests.py
index 8b17b5aa..f0508f03 100644
--- a/askbot/tests/email_alert_tests.py
+++ b/askbot/tests/email_alert_tests.py
@@ -643,3 +643,41 @@ class InstantQAnsEmailAlertTests(EmailAlertTests):
self.setup_timestamp = datetime.datetime.now() - datetime.timedelta(1)
self.expected_results['answer_edit'] = {'message_count': 1, }
self.expected_results['q_ans_new_answer'] = {'message_count': 1, }
+
+class DelayedAlertSubjectLineTests(TestCase):
+ def test_topics_in_subject_line(self):
+ q1 = models.Question(id=1, tagnames='one two three four five')
+ q2 = models.Question(id=2, tagnames='two three four five')
+ q3 = models.Question(id=3, tagnames='three four five')
+ q4 = models.Question(id=4, tagnames='four five')
+ q5 = models.Question(id=5, tagnames='five')
+ q6 = models.Question(id=6, tagnames='six')
+ q7 = models.Question(id=7, tagnames='six')
+ q8 = models.Question(id=8, tagnames='six')
+ q9 = models.Question(id=9, tagnames='six')
+ q10 = models.Question(id=10, tagnames='six')
+ q11 = models.Question(id=11, tagnames='six')
+ q_dict = {
+ q1:'', q2:'', q3:'', q4:'', q5:'', q6:'', q7:'',
+ q8:'', q9:'', q10:'', q11:'',
+ }
+ from askbot.management.commands import send_email_alerts as cmd
+ subject = cmd.get_update_subject_line(q_dict)
+ print subject
+
+ self.assertTrue('one' not in subject)
+ self.assertTrue('two' in subject)
+ self.assertTrue('three' in subject)
+ self.assertTrue('four' in subject)
+ self.assertTrue('five' in subject)
+ self.assertTrue('six' in subject)
+ i2 = subject.index('two')
+ i3 = subject.index('three')
+ i4 = subject.index('four')
+ i5 = subject.index('five')
+ i6 = subject.index('six')
+ order = [i6, i5, i4, i3, i2]
+ self.assertEquals(
+ order,
+ sorted(order)
+ )
diff --git a/askbot/views/users.py b/askbot/views/users.py
index 9f74fbf4..49a083cc 100644
--- a/askbot/views/users.py
+++ b/askbot/views/users.py
@@ -6,10 +6,13 @@ and other views showing profile-related information.
Also this module includes the view listing all forum users.
"""
+import calendar
+import functools
+import datetime
+import logging
from django.db.models import Sum
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator, EmptyPage, InvalidPage
-from django.core import mail
from django.template.defaultfilters import slugify
from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
@@ -21,17 +24,15 @@ from django.utils.translation import ugettext as _
from django.utils.html import strip_tags
from django.utils import simplejson
from django.conf import settings as django_settings
+import askbot
from askbot.utils.html import sanitize_html
from askbot import auth
from askbot import forms
-import calendar
-import functools
-import datetime
from askbot import const
from askbot.conf import settings as askbot_settings
from askbot import models
+from askbot import exceptions
from askbot.models import signals
-import logging
question_type = ContentType.objects.get_for_model(models.Question)
answer_type = ContentType.objects.get_for_model(models.Answer)
@@ -141,6 +142,7 @@ def user_moderate(request, subject):
user_rep_changed = False
user_status_changed = False
message_sent = False
+ email_error_message = None
user_rep_form = forms.ChangeUserReputationForm()
send_message_form = forms.SendMessageForm()
@@ -159,18 +161,18 @@ def user_moderate(request, subject):
if send_message_form.is_valid():
subject_line = send_message_form.cleaned_data['subject_line']
body_text = send_message_form.cleaned_data['body_text']
- message = mail.EmailMessage(
- subject_line,
- body_text,
- django_settings.DEFAULT_FROM_EMAIL,
- [subject.email,],
- headers={'Reply-to':moderator.email}
- )
+
try:
- message.send()
+ askbot.send_mail(
+ subject_line = subject_line,
+ body_text = body_text,
+ recipient_list = [subject.email],
+ headers={'Reply-to':moderator.email},
+ raise_on_failure = True
+ )
message_sent = True
- except Exception, e:
- logging.critical(unicode(e))
+ except exceptions.EmailNotSent, e:
+ email_error_message = unicode(e)
send_message_form = forms.SendMessageForm()
else:
reputation_change_type = None
@@ -217,6 +219,7 @@ def user_moderate(request, subject):
'change_user_reputation_form': user_rep_form,
'send_message_form': send_message_form,
'message_sent': message_sent,
+ 'email_error_message': email_error_message,
'user_rep_changed': user_rep_changed,
'user_status_changed': user_status_changed
},