summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-09-01 20:17:21 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-09-01 20:17:21 -0400
commit52d0ae5ccdd6d0953c1b3df5fca1a85672cbb6b6 (patch)
treefacafb58b5403a18748a02989ee492648c0127d9
parentd0406081233fb7784d5b006fb182e6fdc92560ba (diff)
downloadaskbot-52d0ae5ccdd6d0953c1b3df5fca1a85672cbb6b6.tar.gz
askbot-52d0ae5ccdd6d0953c1b3df5fca1a85672cbb6b6.tar.bz2
askbot-52d0ae5ccdd6d0953c1b3df5fca1a85672cbb6b6.zip
put django_authopenid under migrations, allowed multiple login methods per account, login methods may be deleted or added by users
-rw-r--r--askbot/deps/django_authopenid/migrations/0004_auto__add_field_userassociation_last_used_timestamp__add_unique_useras.py123
-rw-r--r--askbot/deps/django_authopenid/models.py6
-rw-r--r--askbot/deps/django_authopenid/urls.py29
-rw-r--r--askbot/deps/django_authopenid/views.py107
-rw-r--r--askbot/importers/stackexchange/management/commands/load_stackexchange.py1
-rw-r--r--askbot/middleware/view_log.py1
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/openid.css9
-rwxr-xr-xaskbot/skins/default/templates/authopenid/signin.html97
-rw-r--r--askbot/skins/default/templates/user_info.html9
9 files changed, 341 insertions, 41 deletions
diff --git a/askbot/deps/django_authopenid/migrations/0004_auto__add_field_userassociation_last_used_timestamp__add_unique_useras.py b/askbot/deps/django_authopenid/migrations/0004_auto__add_field_userassociation_last_used_timestamp__add_unique_useras.py
new file mode 100644
index 00000000..fb0bb9ac
--- /dev/null
+++ b/askbot/deps/django_authopenid/migrations/0004_auto__add_field_userassociation_last_used_timestamp__add_unique_useras.py
@@ -0,0 +1,123 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding field 'UserAssociation.last_used_timestamp'
+ db.add_column('django_authopenid_userassociation', 'last_used_timestamp', self.gf('django.db.models.fields.DateTimeField')(null=True), keep_default=False)
+
+ # Adding unique constraint on 'UserAssociation', fields ['provider_name', 'openid_url']
+ db.create_unique('django_authopenid_userassociation', ['provider_name', 'openid_url'])
+
+
+ def backwards(self, orm):
+
+ # Deleting field 'UserAssociation.last_used_timestamp'
+ db.delete_column('django_authopenid_userassociation', 'last_used_timestamp')
+
+ # Removing unique constraint on 'UserAssociation', fields ['provider_name', 'openid_url']
+ db.delete_unique('django_authopenid_userassociation', ['provider_name', 'openid_url'])
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'tag_filter_setting': ('django.db.models.fields.CharField', [], {'default': "'ignored'", 'max_length': '16'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'django_authopenid.association': {
+ 'Meta': {'object_name': 'Association'},
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
+ },
+ 'django_authopenid.externallogindata': {
+ 'Meta': {'object_name': 'ExternalLoginData'},
+ 'external_session_data': ('django.db.models.fields.TextField', [], {}),
+ 'external_username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'})
+ },
+ 'django_authopenid.nonce': {
+ 'Meta': {'object_name': 'Nonce'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'server_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'django_authopenid.userassociation': {
+ 'Meta': {'unique_together': "(('user', 'provider_name'), ('openid_url', 'provider_name'))", 'object_name': 'UserAssociation'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_used_timestamp': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'openid_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'provider_name': ('django.db.models.fields.CharField', [], {'default': "'unknown'", 'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'django_authopenid.userpasswordqueue': {
+ 'Meta': {'object_name': 'UserPasswordQueue'},
+ 'confirm_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'new_password': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
+ }
+ }
+
+ complete_apps = ['django_authopenid']
diff --git a/askbot/deps/django_authopenid/models.py b/askbot/deps/django_authopenid/models.py
index 90a22487..b5162064 100644
--- a/askbot/deps/django_authopenid/models.py
+++ b/askbot/deps/django_authopenid/models.py
@@ -40,9 +40,13 @@ class UserAssociation(models.Model):
#association with a Provider record
#to hold things like login badge, etc
provider_name = models.CharField(max_length=64, default='unknown')
+ last_used_timestamp = models.DateTimeField(null=True)
class Meta(object):
- unique_together = (('user','provider_name'),)
+ unique_together = (
+ ('user','provider_name'),
+ ('openid_url', 'provider_name')
+ )
def __unicode__(self):
return "Openid %s with user %s" % (self.openid_url, self.user)
diff --git a/askbot/deps/django_authopenid/urls.py b/askbot/deps/django_authopenid/urls.py
index 5357a808..cf8c0062 100644
--- a/askbot/deps/django_authopenid/urls.py
+++ b/askbot/deps/django_authopenid/urls.py
@@ -26,22 +26,27 @@ urlpatterns = patterns('askbot.deps.django_authopenid.views',
url(r'^%s$' % _('signout/'), 'signout', name='user_signout'),
url(r'^%s%s$' % (_('signin/'), _('complete/')), 'complete_signin',
name='user_complete_signin'),
- url(r'^%s$' % _('register/'), 'register', name='user_register'),
- url(r'^%s$' % _('signup/'), 'signup', name='user_signup'),
+ #url(r'^%s$' % _('register/'), 'register', name='user_register'),
+ #url(r'^%s$' % _('signup/'), 'signup', name='user_signup'),
#disable current sendpw function
- url(r'^%s$' % _('sendpw/'), 'sendpw', name='user_sendpw'),
- url(r'^%s%s$' % (_('password/'), _('confirm/')), 'confirmchangepw', name='user_confirmchangepw'),
+ #url(r'^%s$' % _('sendpw/'), 'sendpw', name='user_sendpw'),
+ #url(r'^%s%s$' % (_('password/'), _('confirm/')), 'confirmchangepw', name='user_confirmchangepw'),
# manage account settings
- url(r'^$', 'account_settings', name='user_account_settings'),
- url(r'^%s$' % _('password/'), 'changepw', name='user_changepw'),
- 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'^$', 'account_settings', name='user_account_settings'),
+ #url(r'^%s$' % _('password/'), 'changepw', name='user_changepw'),
+ #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'),
+ #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'),
+ url(
+ r'^%s$' % _('delete_login_method/'),#thid method is ajax only
+ 'delete_login_method',
+ name ='delete_login_method'
+ ),
)
#todo move these out of this file completely
diff --git a/askbot/deps/django_authopenid/views.py b/askbot/deps/django_authopenid/views.py
index 5d3ba147..4e8e5720 100644
--- a/askbot/deps/django_authopenid/views.py
+++ b/askbot/deps/django_authopenid/views.py
@@ -30,8 +30,11 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+import datetime
+from django.utils import simplejson
from django.http import HttpResponseRedirect, get_host, Http404, \
HttpResponseServerError
+from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.template import RequestContext, loader, Context
from django.conf import settings
@@ -212,8 +215,8 @@ def not_authenticated(func):
#@not_authenticated
def signin(
request,
- newquestion = False,
- newanswer = False,
+ newquestion = False,#todo: not needed
+ newanswer = False,#todo: not needed
):
"""
signin page. It manages the legacy authentification (user/password)
@@ -228,6 +231,7 @@ def signin(
on_failure = signin_failure
email_feeds_form = askbot_forms.SimpleEmailSubscribeForm()
initial_data = {'next': get_next_url(request)}
+ logging.debug('next url is %s' % get_next_url(request))
openid_login_form = forms.OpenidSigninForm(initial = initial_data)
password_login_form = forms.ClassicLoginForm(initial = initial_data)
@@ -336,11 +340,23 @@ def signin(
if openid_login_form.is_valid():
logging.debug('OpenidSigninForm is valid')
next = openid_login_form.cleaned_data['next']
+ print next
sreg_req = sreg.SRegRequest(optional=['nickname', 'email'])
+
+ if next == reverse('user_signin'):
+ #if next was explicitly set to the url of this function
+ #that means user wants to stay on this page indefinitely
+ #so we need to double-up the "next"
+ #alternatively, next parameter must be set explicitly everywhere
+ #to the url of the referer page (except the signin page)
+ url_encoded_next_url = urllib.urlencode({'next':'%s?next=%s' % (next, next)})
+ else:
+ url_encoded_next_url = urllib.urlencode({'next': next})
+
redirect_to = "%s%s?%s" % (
get_url_host(request),
reverse('user_complete_signin'),
- urllib.urlencode({'next':next})
+ url_encoded_next_url
)
return ask_openid(request,
openid_login_form.cleaned_data['openid_url'],
@@ -414,12 +430,16 @@ def show_signin_view(
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')
+ existing_login_methods = UserAssociation.objects.filter(user = request.user)
+ if len(existing_login_methods) == 0:
+ page_title = _('Please add one or more login methods.')
+ else:
+ page_title = _('If you wish, please add, remove or re-validate your login methods')
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', {
+ data = {
'page_class': 'openid-signin',
'view_subtype': view_subtype, #add_openid|default
'page_title': page_title,
@@ -430,7 +450,40 @@ def show_signin_view(
'account_recovery_form': account_recovery_form,
'openid_error_message': request.REQUEST.get('msg',''),
'account_recovery_message': account_recovery_message,
- }, context_instance=RequestContext(request))
+ }
+
+ if view_subtype == 'change_openid' and request.user.is_authenticated():
+ data['existing_login_methods'] = existing_login_methods
+
+ return render_to_response(
+ 'authopenid/signin.html',
+ data,
+ context_instance=RequestContext(request)
+ )
+
+@login_required
+def delete_login_method(request):
+ if request.is_ajax() and request.method == 'POST':
+ provider_name = request.POST['provider_name']
+ try:
+ login_method = UserAssociation.objects.get(
+ user = request.user,
+ provider_name = provider_name
+ )
+ login_method.delete()
+ return HttpResponse('', mimetype = 'application/json')
+ except UserAssociation.DoesNotExist:
+ #error response
+ message = _('Login method %(provider_name)s does not exist')
+ return HttpResponse(message, status=500, mimetype = 'application/json')
+ except UserAssociation.MultipleObjectsReturned:
+ logging.critical(
+ 'have multiple %(provider)s logins for user %(id)s'
+ ) % {'provider':provider_name, 'id': request.user.id}
+ message = _('Sorry, there was some error, we will look at it')
+ return HttpResponse(message, status=500, mimetype = 'application/json')
+ else:
+ raise Http404
def complete_signin(request):
""" in case of complete signin with openid """
@@ -454,27 +507,25 @@ def signin_success(request, identity_url, openid_response):
request.session['openid'] = openid_
try:
logging.debug('trying to get user associated with this openid...')
- rel = UserAssociation.objects.get(openid_url__exact = str(openid_))
- print 'have openid, and logged in - success'
- logging.debug('success')
- if request.user.is_authenticated() and rel.user != request.user:
+ user_assoc = UserAssociation.objects.get(openid_url__exact = str(openid_))
+ logging.debug('have openid, and logged in - success')
+ if request.user.is_authenticated() and user_assoc.user != request.user:
print 'stealing openid'
logging.critical(
'possible account theft attempt by %s,%d to %s %d' % \
(
request.user.username,
request.user.id,
- rel.user.username,
- rel.user.id
+ user_assoc.user.username,
+ user_assoc.user.id
)
)
raise Http404
else:
logging.debug('success')
except UserAssociation.DoesNotExist:
- print 'openid %s not found' % str(openid_)
+ logging.debug('openid %s not found' % str(openid_))
if request.user.is_anonymous():
- print 'registering new user, because he is anonymous'
logging.debug('failed --> try to register brand new user')
# try to register this new user
return register(request)
@@ -482,12 +533,12 @@ def signin_success(request, identity_url, openid_response):
#store openid association
provider_name = util.get_provider_name(str(openid_))
try:
- print 'recovering association via user and provider name'
+ logging.debug('recovering association via user and provider name')
user_assoc = UserAssociation.objects.get(
user = request.user,
provider_name = provider_name
)
- print 'have %s replacing with new' % user_assoc.openid_url
+ logging.debug('have %s replacing with new' % user_assoc.openid_url)
user_assoc.openid_url = str(openid_)
#association changed
except UserAssociation.DoesNotExist:
@@ -504,20 +555,32 @@ def signin_success(request, identity_url, openid_response):
logging.critical(message)
raise error
+ user_assoc.last_used_timestamp = datetime.datetime.now()
user_assoc.save()
- message = _('New login method saved. Thanks!')
+ message = _('Your %(provider)s login method saved.') % {'provider': provider_name}
request.user.message_set.create(message = message)
- print message
#set "account recovered" message
+ logging.debug('redirecting to %s' % get_next_url(request))
+ logging.debug('redirecting to %s' % get_next_url(request))
return HttpResponseRedirect(get_next_url(request))
- user_ = rel.user
- if user_.is_active:
- user_.backend = "django.contrib.auth.backends.ModelBackend"
+ except Exception, e:
+ logging.critical(unicode(e))
+
+ user_assoc.last_used_timestamp = datetime.datetime.now()
+ if user_assoc.user.is_active:
+ #this is a substitute for the "authenticate" function
+ #todo - build a recular authenticate func and backend
+ user_assoc.user.backend = "django.contrib.auth.backends.ModelBackend"
logging.debug('user is active --> attached django auth ModelBackend --> calling login')
- login(request, user_)
+ login(request, user_assoc.user)
logging.debug('success')
else:
+ msg = _( 'Sorry, your account is inactive and you '
+ 'cannot sign in - please contact the site '
+ 'administrator.')
logging.debug('user is inactive, do not log them in')
+ request.user.message_set.create(message=msg)
+
logging.debug('redirecting to %s' % get_next_url(request))
return HttpResponseRedirect(get_next_url(request))
diff --git a/askbot/importers/stackexchange/management/commands/load_stackexchange.py b/askbot/importers/stackexchange/management/commands/load_stackexchange.py
index 852500b6..53e5e029 100644
--- a/askbot/importers/stackexchange/management/commands/load_stackexchange.py
+++ b/askbot/importers/stackexchange/management/commands/load_stackexchange.py
@@ -744,6 +744,7 @@ class Command(BaseCommand):
u_openid.openid_url = se_u.open_id
u.save()
u_openid.user = u
+ u_openid.last_used_timestamp = se_u.last_login_date
u_openid.save()
except AssertionError:
print 'User %s (id=%d) does not have openid' % \
diff --git a/askbot/middleware/view_log.py b/askbot/middleware/view_log.py
index fa38f29a..cf612ad2 100644
--- a/askbot/middleware/view_log.py
+++ b/askbot/middleware/view_log.py
@@ -62,6 +62,7 @@ class ViewLogMiddleware(object):
else:
user_name = request.META['REMOTE_ADDR']
logging.debug('user %s, view %s' % (request.user.username, view_str))
+ logging.debug('next url is %s' % request.REQUEST.get('next','nothing'))
if 'view_log' in request.session:
view_log = request.session['view_log']
diff --git a/askbot/skins/default/media/jquery-openid/openid.css b/askbot/skins/default/media/jquery-openid/openid.css
index 27eae2c3..795d1ddf 100755
--- a/askbot/skins/default/media/jquery-openid/openid.css
+++ b/askbot/skins/default/media/jquery-openid/openid.css
@@ -78,3 +78,12 @@ ul.providers {
ul.providers {
display: block;
}
+
+.openid-signin th {
+ color: #555;
+ font-weight: normal;
+}
+
+.openid-signin .ab-provider-name {
+ font-weight: bold;
+}
diff --git a/askbot/skins/default/templates/authopenid/signin.html b/askbot/skins/default/templates/authopenid/signin.html
index 1bcdbb1b..e700d189 100755
--- a/askbot/skins/default/templates/authopenid/signin.html
+++ b/askbot/skins/default/templates/authopenid/signin.html
@@ -34,17 +34,21 @@
</div>
{% endif %}
<form id="openid_form" name="openid_form" class="openid" method="post" action="{% url user_signin %}">
+ <p id='ab-login-method-prompt'>
{% 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 avoid 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>
+ {% trans "Please add a more permanent login method by clicking one of the icons below, to avoid logging in via email each time. All of the services listed below provide a secure sign-in method based on OpenID or similar technology." %}
{% 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>
+ {% if existing_login_methods %}
+ {% trans "Click on one of the icons below to add a new login method or re-validate an existing one." %}
+ {% else %}
+ {% trans "You don't have a method to log in right now, please add one or more by clicking any of the icons below." %}
+ {% endif %}
{% endif %}
+ </p>
{% if openid_error_message %}
<p class="warning">{{ openid_error_message }}</p>
{% endif %}
@@ -201,6 +205,91 @@
<input type="submit" value="{% trans "Recover your account via email" %}"/>
</form>
{% endif %}
+ {% if view_subtype == 'change_openid' %}
+ {% if existing_login_methods %}
+ <h2 id='ab-show-login-methods'>
+ {% trans "Here are your current login methods" %}
+ </h2>
+ <table id='ab-existing-login-methods'>
+ <tr>
+ <th>{% trans "provider" %}</th>
+ <th>{% trans "last used" %}</th>
+ <th>{% trans "delete, if you like" %}</th>
+ </tr>
+ {% for login_method in existing_login_methods %}
+ <tr class="ab-provider-row">
+ <td class="ab-provider-name">
+ {{login_method.provider_name}}
+ </td>
+ <td>
+ {% if login_method.last_used_timestamp %}
+ {% diff_date login_method.last_used_timestamp %}
+ {% endif %}
+ </td>
+ <td>
+ <button>{% trans "delete" %}</button>
+ </td>
+ </tr>
+ {% endfor %}
+ </table>
+ <script type="text/javascript">
+ $(document).ready(
+ function(){
+ var provider_count = {{existing_login_methods|length}};
+ $('.ab-provider-row').each(
+ function(i, provider_row){
+ var provider_name = $(
+ provider_row
+ ).find(
+ '.ab-provider-name'
+ ).html().trim();
+ var remove_button = $(
+ provider_row
+ ).find('button');
+ remove_button.click(
+ function(){
+ var message = $.i18n._(
+ 'Are you sure you want to remove ' +
+ 'your {provider} login?'
+ ).replace(
+ '{provider}',
+ provider_name
+ );
+ if (confirm(message)){
+ $.ajax({
+ type: 'POST',
+ url: '{% url delete_login_method %}',
+ data: {provider_name: provider_name},
+ success: function(data, text_status, xhr){
+ $(provider_row).remove();
+ provider_count -=1;
+ if (provider_count < 0){
+ provider_count === 0;
+ }
+ if (provider_count === 0){
+ $('#ab-existing-login-methods').remove();
+ $('#ab-show-login-methods').remove();
+ $('h1').html(
+ $.i18n._("Please add one or more login methods.")
+ );
+ $('#ab-login-method-prompt').html(
+ $.i18n._("You don\'t have a method to log in right now, please add one or more by clicking any of the icons below.")
+ );
+ alert($.i18n._('You have deleted all login methods, please add at least one'));
+ }
+ },
+
+ });
+ }
+ }
+ );
+ }
+ );
+ }
+ );
+ </script>
+ {% endif %}
+ {% endif %}
{% endblock %}
{% block sidebar %}
diff --git a/askbot/skins/default/templates/user_info.html b/askbot/skins/default/templates/user_info.html
index e942ceec..4699cb18 100644
--- a/askbot/skins/default/templates/user_info.html
+++ b/askbot/skins/default/templates/user_info.html
@@ -29,9 +29,14 @@
{% if request.user|can_view_user_edit:view_user %}
<tr>
<td class="user-profile-tool-links" align="left" colspan="2">
- {% if request.user|can_view_user_edit:view_user %}
- <span class="user-edit-link"><a href="{% url users %}{{ view_user.id }}/{% trans "edit/" %}">{% trans "update profile" %}</a></span>
+ {% if request.user == view_user %}
+ <a href="{% url user_signin %}?next={% url user_signin %}">
+ {% trans "manage login methods" %}
+ </a> |
{% endif %}
+ <a href="{% url users %}{{ view_user.id }}/{% trans "edit/" %}">
+ {% trans "update profile" %}
+ </a>
</td>
</tr>
{% endif %}