[snowy] add support for linking multiple OpenID accounts to one User



commit 8b3633f9111527c1c3077f129ab081ec79b1a292
Author: Natan Yellin <aantny gmail com>
Date:   Tue Dec 14 02:43:00 2010 +0200

    add support for linking multiple OpenID accounts to one User

 accounts/forms.py                            |   12 ++++++++++
 accounts/templates/accounts/preferences.html |   22 ++++++++++++++++++
 accounts/views.py                            |   31 ++++++++++++++++++++++++-
 3 files changed, 63 insertions(+), 2 deletions(-)
---
diff --git a/accounts/forms.py b/accounts/forms.py
index 426d574..79f86a3 100644
--- a/accounts/forms.py
+++ b/accounts/forms.py
@@ -16,6 +16,7 @@
 #
 
 from django.contrib.auth.models import User
+from django.forms import ModelChoiceField
 from registration.forms import RegistrationFormUniqueEmail
 from django.utils.translation import ugettext_lazy as _
 from recaptcha_django import ReCaptchaField
@@ -97,3 +98,14 @@ class EmailChangeForm(forms.ModelForm):
         model = User
         fields = ('email', )
 
+class UserOpenIDChoiceField(ModelChoiceField):
+    """Custom ModelChoiceField to display UserOpenIDs by UserOpenID.display_id"""
+    def label_from_instance(self, obj):
+        return obj.display_id
+
+class RemoveUserOpenIDForm(forms.Form):
+    def __init__(self, *args, **kwargs):
+        open_ids = kwargs.pop('open_ids')
+        super(RemoveUserOpenIDForm, self).__init__(*args, **kwargs)
+
+        self.fields['openid'] = UserOpenIDChoiceField(open_ids, required=True, label=_('Delete OpenID account'))
diff --git a/accounts/templates/accounts/preferences.html b/accounts/templates/accounts/preferences.html
index 1a674a2..7a322a6 100644
--- a/accounts/templates/accounts/preferences.html
+++ b/accounts/templates/accounts/preferences.html
@@ -72,5 +72,27 @@
     <input type="hidden" name="i18n_form" value="1" />
 </form>
 
+<h3>{% trans "OpenID Accounts" %}</h3>
+<form method="POST">
+    <table class="input-form">
+        <tr>
+            <th>
+                <a href="{% url openid-login %}">{% trans "Add OpenID account" %}</a>
+            </th>
+            <td></td>
+        </tr>
+    {{ openid_form.as_table }}
+        <tfoot>
+            <tr>
+                <th></th>
+                <td>
+                    <input type="submit" value="{% trans "Delete" %}"/>
+                </td>
+            </tr>
+        </tfoot>
+    </table>
+    <input type="hidden" name="openid_form" value="1" />
+</form>
+
 {#<h3>{% trans "Registered Applications" %}</h3>#}
 {% endblock %}
diff --git a/accounts/views.py b/accounts/views.py
index 36f7181..9a50abf 100644
--- a/accounts/views.py
+++ b/accounts/views.py
@@ -17,6 +17,7 @@
 
 from django.utils.translation import ugettext_lazy as _
 
+from django.contrib.auth import get_backends
 from django.contrib.auth.forms import UserChangeForm, PasswordChangeForm
 from django.contrib.auth.models import User
 from django.contrib.auth import authenticate, login, REDIRECT_FIELD_NAME
@@ -31,9 +32,11 @@ from django.template import RequestContext
 from django.conf import settings
 
 from snowy.accounts.models import UserProfile
-from snowy.accounts.forms import InternationalizationForm, OpenIDRegistrationFormUniqueUser, EmailChangeForm
+from snowy.accounts.forms import InternationalizationForm, OpenIDRegistrationFormUniqueUser, EmailChangeForm, RemoveUserOpenIDForm
 
 from django_openid_auth import auth
+from django_openid_auth.auth import OpenIDBackend
+from django_openid_auth.models import UserOpenID
 import django_openid_auth.views
 
 def openid_registration(request, template_name='registration/registration_form.html'):
@@ -44,6 +47,17 @@ def openid_registration(request, template_name='registration/registration_form.h
     except KeyError:
         return HttpResponseNotAllowed(_(u'No openid_response object for this session!'))
 
+    # If the user is already logged on, then link this new UserOpenID to their User
+    if request.user.is_authenticated():
+        for backend in get_backends():
+            if type(backend) == OpenIDBackend:
+                backend.associate_openid(request.user, openid_response)
+
+        # Clear the openid_response from the session so it can't be used to create another account
+        del request.session['openid_response']
+
+        return HttpResponseRedirect(reverse('preferences'))
+
     try:
         attributes = auth._extract_user_details(openid_response)
         registration_form.fields['username'].initial = attributes['nickname']
@@ -115,6 +129,7 @@ def render_openid_failure(request, message, status=403, **kwargs):
 def accounts_preferences(request, template_name='accounts/preferences.html'):
     user = request.user
     profile = user.get_profile()
+    open_ids = UserOpenID.objects.filter(user=user)
 
     if 'password_form' in request.POST:
         password_form = PasswordChangeForm(user, data=request.POST)
@@ -138,8 +153,20 @@ def accounts_preferences(request, template_name='accounts/preferences.html'):
     else:
         i18n_form = InternationalizationForm(instance=profile)
 
+    if 'openid_form' in request.POST:
+        openid_form = RemoveUserOpenIDForm(request.POST, open_ids=open_ids)
+        if openid_form.is_valid():
+            if len(open_ids) == 1 and not user.has_usable_password():
+                openid_form.errors['openid'] = [_('Cannot delete the last OpenID account')]
+            else:
+                openid_form.cleaned_data['openid'].delete()
+    else:
+        openid_form = RemoveUserOpenIDForm(open_ids=open_ids)
+
     return render_to_response(template_name,
                               {'user': user, 'i18n_form': i18n_form,
                                'password_form': password_form,
-                               'email_form' : email_form},
+                               'email_form' : email_form,
+                               'open_ids' : open_ids,
+                               'openid_form' : openid_form},
                               context_instance=RequestContext(request))



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]