[Python-modules-commits] [python-social-auth] 217/322: Update django/mongoengine example (similar to default one). Refs #576

Wolfgang Borgert debacle at moszumanska.debian.org
Sat Dec 24 15:13:11 UTC 2016


This is an automated email from the git hooks/post-receive script.

debacle pushed a commit to tag v0.2.10
in repository python-social-auth.

commit da84831f62ea0468a1eb112e316fa74de8e81e04
Author: Matías Aguirre <matiasaguirre at gmail.com>
Date:   Thu Apr 2 23:55:49 2015 -0300

    Update django/mongoengine example (similar to default one). Refs #576
---
 .../django_me_example/example/app/decorators.py    |  16 +
 examples/django_me_example/example/app/mail.py     |  16 +-
 examples/django_me_example/example/app/models.py   |   7 -
 examples/django_me_example/example/app/pipeline.py |   7 +-
 .../example/app/templatetags/__init__.py           |   0
 .../example/app/templatetags/backend_utils.py      |  82 ++++
 examples/django_me_example/example/app/views.py    |  73 ++-
 examples/django_me_example/example/settings.py     |  12 +-
 .../django_me_example/example/templates/base.html  |  14 -
 .../django_me_example/example/templates/done.html  |  25 -
 .../django_me_example/example/templates/email.html |  11 -
 .../example/templates/email_signup.html            |  19 -
 .../django_me_example/example/templates/home.html  | 533 +++++++++++++++++----
 .../example/templates/username_signup.html         |  19 -
 .../example/templates/validation_sent.html         |   6 -
 examples/django_me_example/example/urls.py         |   4 +-
 examples/django_me_example/example/wsgi.py         |   2 +-
 examples/django_me_example/requirements.txt        |   2 +-
 18 files changed, 614 insertions(+), 234 deletions(-)

diff --git a/examples/django_me_example/example/app/decorators.py b/examples/django_me_example/example/app/decorators.py
new file mode 100644
index 0000000..2ba85b1
--- /dev/null
+++ b/examples/django_me_example/example/app/decorators.py
@@ -0,0 +1,16 @@
+from functools import wraps
+
+from django.template import RequestContext
+from django.shortcuts import render_to_response
+
+
+def render_to(tpl):
+    def decorator(func):
+        @wraps(func)
+        def wrapper(request, *args, **kwargs):
+            out = func(request, *args, **kwargs)
+            if isinstance(out, dict):
+                out = render_to_response(tpl, out, RequestContext(request))
+            return out
+        return wrapper
+    return decorator
diff --git a/examples/django_me_example/example/app/mail.py b/examples/django_me_example/example/app/mail.py
index 238251c..4dd59b5 100644
--- a/examples/django_me_example/example/app/mail.py
+++ b/examples/django_me_example/example/app/mail.py
@@ -3,11 +3,11 @@ from django.core.mail import send_mail
 from django.core.urlresolvers import reverse
 
 
-def send_validation(strategy, code):
-    url = reverse('social:complete', args=(strategy.backend_name,)) \
-            + '?verification_code=' + code.code
-    send_mail('Validate your account',
-              'Validate your account {0}'.format(url),
-              settings.EMAIL_FROM,
-              [code.email],
-              fail_silently=False)
+def send_validation(strategy, backend, code):
+    url = '{0}?verification_code={1}'.format(
+        reverse('social:complete', args=(backend.name,)),
+        code.code
+    )
+    url = strategy.request.build_absolute_uri(url)
+    send_mail('Validate your account', 'Validate your account {0}'.format(url),
+              settings.EMAIL_FROM, [code.email], fail_silently=False)
diff --git a/examples/django_me_example/example/app/models.py b/examples/django_me_example/example/app/models.py
index 4508722..e69de29 100644
--- a/examples/django_me_example/example/app/models.py
+++ b/examples/django_me_example/example/app/models.py
@@ -1,7 +0,0 @@
-from mongoengine.fields import ListField
-from mongoengine.django.auth import User
-
-
-class User(User):
-    """Extend Mongo Engine User model"""
-    foo = ListField(default=[])
diff --git a/examples/django_me_example/example/app/pipeline.py b/examples/django_me_example/example/app/pipeline.py
index 136f8b5..245e69c 100644
--- a/examples/django_me_example/example/app/pipeline.py
+++ b/examples/django_me_example/example/app/pipeline.py
@@ -5,10 +5,11 @@ from social.pipeline.partial import partial
 
 @partial
 def require_email(strategy, details, user=None, is_new=False, *args, **kwargs):
-    if user and user.email:
+    if kwargs.get('ajax') or user and user.email:
         return
     elif is_new and not details.get('email'):
-        if strategy.session_get('saved_email'):
-            details['email'] = strategy.session_pop('saved_email')
+        email = strategy.request_data().get('email')
+        if email:
+            details['email'] = email
         else:
             return redirect('require_email')
diff --git a/examples/django_me_example/example/app/templatetags/__init__.py b/examples/django_me_example/example/app/templatetags/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/examples/django_me_example/example/app/templatetags/backend_utils.py b/examples/django_me_example/example/app/templatetags/backend_utils.py
new file mode 100644
index 0000000..573b6d6
--- /dev/null
+++ b/examples/django_me_example/example/app/templatetags/backend_utils.py
@@ -0,0 +1,82 @@
+import re
+
+from django import template
+
+from social.backends.oauth import OAuthAuth
+from social.apps.django_app.me.models import UserSocialAuth
+
+
+register = template.Library()
+
+name_re = re.compile(r'([^O])Auth')
+
+
+ at register.filter
+def backend_name(backend):
+    name = backend.__class__.__name__
+    name = name.replace('OAuth', ' OAuth')
+    name = name.replace('OpenId', ' OpenId')
+    name = name.replace('Sandbox', '')
+    name = name_re.sub(r'\1 Auth', name)
+    return name
+
+
+ at register.filter
+def backend_class(backend):
+    return backend.name.replace('-', ' ')
+
+
+ at register.filter
+def icon_name(name):
+    return {
+        'stackoverflow': 'stack-overflow',
+        'google-oauth': 'google',
+        'google-oauth2': 'google',
+        'google-openidconnect': 'google',
+        'yahoo-oauth': 'yahoo',
+        'facebook-app': 'facebook',
+        'email': 'envelope',
+        'vimeo': 'vimeo-square',
+        'linkedin-oauth2': 'linkedin',
+        'vk-oauth2': 'vk',
+        'live': 'windows',
+        'username': 'user',
+    }.get(name, name)
+
+
+ at register.filter
+def social_backends(backends):
+    backends = [(name, backend) for name, backend in backends.items()
+                    if name not in ['username', 'email']]
+    backends.sort(key=lambda b: b[0])
+    return [backends[n:n + 10] for n in range(0, len(backends), 10)]
+
+
+ at register.filter
+def legacy_backends(backends):
+    backends = [(name, backend) for name, backend in backends.items()
+                    if name in ['username', 'email']]
+    backends.sort(key=lambda b: b[0])
+    return backends
+
+
+ at register.filter
+def oauth_backends(backends):
+    backends = [(name, backend) for name, backend in backends.items()
+                    if issubclass(backend, OAuthAuth)]
+    backends.sort(key=lambda b: b[0])
+    return backends
+
+
+ at register.simple_tag(takes_context=True)
+def associated(context, backend):
+    user = context.get('user')
+    context['association'] = None
+    if user and user.is_authenticated():
+        try:
+            context['association'] = UserSocialAuth.objects.filter(
+                user=user, provider=backend.name
+            )[0]
+        except IndexError:
+            pass
+    return ''
diff --git a/examples/django_me_example/example/app/views.py b/examples/django_me_example/example/app/views.py
index 62eeb90..2ed6654 100644
--- a/examples/django_me_example/example/app/views.py
+++ b/examples/django_me_example/example/app/views.py
@@ -1,35 +1,74 @@
+import json
+
+from django.conf import settings
+from django.http import HttpResponse, HttpResponseBadRequest
+from django.shortcuts import redirect
 from django.contrib.auth.decorators import login_required
-from django.template import RequestContext
-from django.shortcuts import render_to_response, redirect
+from django.contrib.auth import logout as auth_logout, login
+
+from social.backends.oauth import BaseOAuth1, BaseOAuth2
+from social.backends.google import GooglePlusAuth
+from social.backends.utils import load_backends
+from social.apps.django_app.utils import psa
+
+from example.app.decorators import render_to
+
+
+def logout(request):
+    """Logs out user"""
+    auth_logout(request)
+    return redirect('/')
+
 
+def context(**extra):
+    return dict({
+        'plus_id': getattr(settings, 'SOCIAL_AUTH_GOOGLE_PLUS_KEY', None),
+        'plus_scope': ' '.join(GooglePlusAuth.DEFAULT_SCOPE),
+        'available_backends': load_backends(settings.AUTHENTICATION_BACKENDS)
+    }, **extra)
 
+
+ at render_to('home.html')
 def home(request):
     """Home view, displays login mechanism"""
     if request.user.is_authenticated():
         return redirect('done')
-    return render_to_response('home.html', {}, RequestContext(request))
+    return context()
 
 
 @login_required
+ at render_to('home.html')
 def done(request):
     """Login complete view, displays user data"""
-    return render_to_response('done.html', {'user': request.user},
-                              RequestContext(request))
-
-
-def signup_email(request):
-    return render_to_response('email_signup.html', {}, RequestContext(request))
+    return context()
 
 
+ at render_to('home.html')
 def validation_sent(request):
-    return render_to_response('validation_sent.html', {
-        'email': request.session.get('email_validation_address')
-    }, RequestContext(request))
+    return context(
+        validation_sent=True,
+        email=request.session.get('email_validation_address')
+    )
 
 
+ at render_to('home.html')
 def require_email(request):
-    if request.method == 'POST':
-        request.session['saved_email'] = request.POST.get('email')
-        backend = request.session['partial_pipeline']['backend']
-        return redirect('social:complete', backend=backend)
-    return render_to_response('email.html', RequestContext(request))
+    backend = request.session['partial_pipeline']['backend']
+    return context(email_required=True, backend=backend)
+
+
+ at psa('social:complete')
+def ajax_auth(request, backend):
+    if isinstance(request.backend, BaseOAuth1):
+        token = {
+            'oauth_token': request.REQUEST.get('access_token'),
+            'oauth_token_secret': request.REQUEST.get('access_token_secret'),
+        }
+    elif isinstance(request.backend, BaseOAuth2):
+        token = request.REQUEST.get('access_token')
+    else:
+        raise HttpResponseBadRequest('Wrong backend type')
+    user = request.backend.do_auth(token, ajax=True)
+    login(request, user)
+    data = {'id': user.id, 'username': user.username}
+    return HttpResponse(json.dumps(data), mimetype='application/json')
diff --git a/examples/django_me_example/example/settings.py b/examples/django_me_example/example/settings.py
index 9c2a157..82fd114 100644
--- a/examples/django_me_example/example/settings.py
+++ b/examples/django_me_example/example/settings.py
@@ -19,8 +19,7 @@ MANAGERS = ADMINS
 
 DATABASES = {
     'default': {
-        'ENGINE': 'django.db.backends.sqlite3',
-        'NAME': 'test.db'
+        'ENGINE': 'django.db.backends.dummy',
     }
 }
 
@@ -119,11 +118,13 @@ TEMPLATE_CONTEXT_PROCESSORS = (
     'social.apps.django_app.context_processors.backends',
 )
 
+AUTH_USER_MODEL = 'mongo_auth.MongoUser'
+MONGOENGINE_USER_DOCUMENT = 'mongoengine.django.auth.User'
 SESSION_ENGINE = 'mongoengine.django.sessions'
+SESSION_SERIALIZER = 'mongoengine.django.sessions.BSONSerializer'
 mongoengine.connect('psa', host='mongodb://localhost/psa')
-MONGOENGINE_USER_DOCUMENT = 'example.app.models.User'
-SOCIAL_AUTH_USER_MODEL = 'example.app.models.User'
-
+# MONGOENGINE_USER_DOCUMENT = 'example.app.models.User'
+# SOCIAL_AUTH_USER_MODEL = 'example.app.models.User'
 
 AUTHENTICATION_BACKENDS = (
     'social.backends.open_id.OpenIdAuth',
@@ -181,6 +182,7 @@ AUTHENTICATION_BACKENDS = (
     'social.backends.email.EmailAuth',
     'social.backends.username.UsernameAuth',
     'social.backends.wunderlist.WunderlistOAuth2',
+    'mongoengine.django.auth.MongoEngineBackend',
     'django.contrib.auth.backends.ModelBackend',
 )
 
diff --git a/examples/django_me_example/example/templates/base.html b/examples/django_me_example/example/templates/base.html
deleted file mode 100644
index 86db504..0000000
--- a/examples/django_me_example/example/templates/base.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <title>Social</title>
-    <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet" media="screen">
-  </head>
-  <body>
-    {% block content %}{% endblock %}
-    {% block scripts %}{% endblock %}
-
-    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
-    <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/js/bootstrap.min.js" type="text/javascript"></script>
-  </body>
-</html>
diff --git a/examples/django_me_example/example/templates/done.html b/examples/django_me_example/example/templates/done.html
deleted file mode 100644
index b248082..0000000
--- a/examples/django_me_example/example/templates/done.html
+++ /dev/null
@@ -1,25 +0,0 @@
-{% extends "base.html" %}
-{% load url from future %}
-
-{% block content %}
-<p>You are logged in as {{ user.username }}!</p>
-
-<p>Associated:</p>
-{% for assoc in backends.associated %}
-  <div>
-    <strong>{{ assoc.provider }}</strong>
-    <form action="{% url 'social:disconnect_individual' assoc.provider assoc.id %}" method="post">{% csrf_token %}
-      <button>Disconnect</button>
-    </form>
-  </div>
-{% endfor %}
-
-<p>Associate:</p>
-<ul>
-  {% for name in backends.not_associated %}
-    <li>
-      <a href="{% url 'social:begin' name %}">{{ name }}</a>
-    </li>
-  {% endfor %}
-</ul>
-{% endblock %}
diff --git a/examples/django_me_example/example/templates/email.html b/examples/django_me_example/example/templates/email.html
deleted file mode 100644
index 0bf012b..0000000
--- a/examples/django_me_example/example/templates/email.html
+++ /dev/null
@@ -1,11 +0,0 @@
-{% extends "base.html" %}
-{% load url from future %}
-
-{% block content %}
-<form action="" method="post">
-  {% csrf_token %}
-  <label for="email">Email address:</label>
-  <input id="email" type="email" name="email" value="" />
-  <button>Save</button>
-</form>
-{% endblock %}
diff --git a/examples/django_me_example/example/templates/email_signup.html b/examples/django_me_example/example/templates/email_signup.html
deleted file mode 100644
index bb5a6ff..0000000
--- a/examples/django_me_example/example/templates/email_signup.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{% extends "base.html" %}
-{% load url from future %}
-
-{% block content %}
-<form action="{% url 'social:complete' "email" %}" method="post">
-  {% csrf_token %}
-  <label for="email">Email address:</label>
-  <input id="email" type="email" name="email" value="" />
-
-  <label for="password">Password:</label>
-  <input id="password" type="password" name="password" value="" />
-
-  <label for="fullname">Full name:</label>
-  <input id="fullname" type="text" name="fullname" value="" />
-
-  <br />
-  <button>Signup</button>
-</form>
-{% endblock %}
diff --git a/examples/django_me_example/example/templates/home.html b/examples/django_me_example/example/templates/home.html
index 5184b12..3a51c59 100644
--- a/examples/django_me_example/example/templates/home.html
+++ b/examples/django_me_example/example/templates/home.html
@@ -1,101 +1,440 @@
-{% extends "base.html" %}
-{% load url from future %}
-
-{% block content %}
-<a href="{% url 'social:begin' "google-oauth2" %}">Google OAuth2</a> <br />
-<a href="{% url 'social:begin' "google-oauth" %}">Google OAuth</a> <br />
-<a href="{% url 'social:begin' "google" %}">Google OpenId</a> <br />
-<a href="{% url 'social:begin' "twitter" %}">Twitter OAuth</a> <br />
-<a href="{% url 'social:begin' "yahoo" %}">Yahoo OpenId</a> <br />
-<a href="{% url 'social:begin' "yahoo-oauth" %}">Yahoo OAuth</a> <br />
-<a href="{% url 'social:begin' "stripe" %}">Stripe OAuth2</a> <br />
-<a href="{% url 'social:begin' "strava" %}">Strava OAuth2</a> <br />
-<a href="{% url 'social:begin' "facebook" %}">Facebook OAuth2</a> <br />
-<a href="{% url 'social:begin' "facebook-app" %}">Facebook App</a> <br />
-<a href="{% url 'social:begin' "angel" %}">Angel OAuth2</a> <br />
-<a href="{% url 'social:begin' "behance" %}">Behance OAuth2</a> <br />
-<a href="{% url 'social:begin' "bitbucket" %}">Bitbucket OAuth</a> <br />
-<a href="{% url 'social:begin' "box" %}">Box.net OAuth2</a> <br />
-<a href="{% url 'social:begin' "linkedin" %}">LinkedIn OAuth</a> <br />
-<a href="{% url 'social:begin' "github" %}">Github OAuth2</a> <br />
-<a href="{% url 'social:begin' "foursquare" %}">Foursquare OAuth2</a> <br />
-<a href="{% url 'social:begin' "instagram" %}">Instagram OAuth2</a> <br />
-<a href="{% url 'social:begin' "live" %}">Live OAuth2</a> <br />
-<a href="{% url 'social:begin' "vk-oauth2" %}">VK.com OAuth2</a> <br />
-<a href="{% url 'social:begin' "dailymotion" %}">Dailymotion OAuth2</a> <br />
-<a href="{% url 'social:begin' "disqus" %}">Disqus OAuth2</a> <br />
-<a href="{% url 'social:begin' "dropbox" %}">Dropbox OAuth</a> <br />
-<a href="{% url 'social:begin' "evernote-sandbox" %}">Evernote OAuth (sandbox mode)</a> <br />
-<a href="{% url 'social:begin' "fitbit" %}">Fitbit OAuth</a> <br />
-<a href="{% url 'social:begin' "flickr" %}">Flickr OAuth</a> <br />
-<a href="{% url 'social:begin' "soundcloud" %}">Soundcloud OAuth2</a> <br />
-<a href="{% url 'social:begin' "thisismyjam" %}">ThisIsMyJam OAuth1</a> <br />
-<a href="{% url 'social:begin' "stocktwits" %}">Stocktwits OAuth2</a> <br />
-<a href="{% url 'social:begin' "tripit" %}">Tripit OAuth</a> <br />
-<a href="{% url 'social:begin' "clef" %}">Clef OAuth</a> <br />
-<a href="{% url 'social:begin' "twilio" %}">Twilio</a> <br />
-<a href="{% url 'social:begin' "xing" %}">Xing OAuth</a> <br />
-<a href="{% url 'social:begin' "yandex-oauth2" %}">Yandex OAuth2</a> <br />
-<a href="{% url 'social:begin' "douban-oauth2" %}">Douban OAuth2</a> <br />
-<a href="{% url 'social:begin' "mineid" %}">MineID OAuth2</a> <br />
-<a href="{% url 'social:begin' "mixcloud" %}">Mixcloud OAuth2</a> <br />
-<a href="{% url 'social:begin' "rdio-oauth2" %}">Rdio OAuth2</a> <br />
-<a href="{% url 'social:begin' "rdio-oauth1" %}">Rdio OAuth1</a> <br />
-<a href="{% url 'social:begin' "yammer" %}">Yammer OAuth2</a> <br />
-<a href="{% url 'social:begin' "stackoverflow" %}">Stackoverflow OAuth2</a> <br />
-<a href="{% url 'social:begin' "readability" %}">Readability OAuth1</a> <br />
-<a href="{% url 'social:begin' "skyrock" %}">Skyrock OAuth1</a> <br />
-<a href="{% url 'social:begin' "tumblr" %}">Tumblr OAuth1</a> <br />
-<a href="{% url 'social:begin' "reddit" %}">Reddit OAuth2</a> <br />
-<a href="{% url 'social:begin' "podio" %}">Podio OAuth2</a> <br />
-<a href="{% url 'social:begin' "amazon" %}">Amazon OAuth2</a> <br />
-<a href="{% url 'social:begin' "steam" %}">Steam OpenId</a> <br />
-<a href="{% url 'social:begin' "email" %}">Email Auth</a> <br />
-<a href="{% url 'social:begin' "username" %}">Username Auth</a> <br />
-
-<form action="{% url 'social:begin' "openid" %}" method="post">{% csrf_token %}
-  <div>
-    <label for="openid_identifier">OpenId provider</label>
-    <input id="openid_identifier" type="text" value="" name="openid_identifier" />
-    <input type="submit" value="Login" />
-  </div>
-</form>
-
-<form action="{% url 'social:begin' "livejournal" %}" method="post">{% csrf_token %}
-  <div>
-    <label for="openid_lj_identifier">LiveJournal ID</label>
-    <input id="openid_lj_identifier" type="text" value="" name="openid_lj_user" />
-    <input type="submit" value="Login" />
-  </div>
-</form>
-
-<form method="post" action="{% url 'social:complete' "persona" %}">
-  <input type="hidden" name="assertion" value="" />
-  <a rel="nofollow" id="persona" href="#">Persona</a>
-</form>
-{% endblock %}
-
-{% block scripts %}
-<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript"></script>
-<script src="https://login.persona.org/include.js" type="text/javascript"></script>
-<script type="text/javascript">
-$(function () {
-    $('#persona').on('click', function (e) {
-        e.preventDefault();
-        var self = $(this);
-
-        navigator.id.get(function (assertion) {
+{% load backend_utils %}
+<!doctype html>
+<html>
+  <head>
+    <title>Python Social Auth</title>
+    <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
+    <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css" rel="stylesheet">
+    <link href="//netdna.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet">
+    <style>
+      h1 { padding: 0 30px; }
+      .col-md-2 { width: 18.6667%; }
+      .buttons { display: block; table-layout: fixed; border-radius: 7px; border: 1px solid #ccc;
+                 margin: 20px; background: #eee; padding: 30px; }
+      .buttons > div a { margin: 5px 10px; }
+      .buttons > div:not(:first-child) { margin-top: 10px; border-top: 1px solid #ccc;
+                                         padding-top: 10px; text-align: center; }
+      .user-details { text-align: center; font-size: 16px; font-weight: bold; }
+      .disconnect-form { padding: 0; margin: 0px 10px; }
+      .disconnect-form > a { display: block; margin: 5px 0 !important; }
+    </style>
+  </head>
+  <body>
+    <h1>Python Social Auth</h1>
+
+    <div class="buttons">
+      {% if user.is_authenticated %}
+        <div class="user-details">
+          You are logged in as <code>{{ user.username }}</code>!
+        </div>
+      {% endif %}
+
+      <div class="social">
+        {% for sublist in available_backends|social_backends %}
+          <div class="row">
+            {% for name, backend in sublist %}
+              {% associated backend %}
+              {% if association %}
+                <form class="disconnect-form col-md-2" action="{% url "social:disconnect_individual" backend=association.provider association_id=association.id %}" method="post">{% csrf_token %}
+                  <a class="btn btn-danger" name="{{ backend|backend_class }}" href="#">
+                    <i class="fa fa-{{ name|icon_name }}"></i>
+                    Disconnect {{ backend|backend_name }}
+                  </a>
+                </form>
+              {% else %}
+                <a class="col-md-2 btn btn-default" name="{{ backend|backend_class }}" href="{% url "social:begin" backend=name %}">
+                  <i class="fa fa-{{ name|icon_name }}"></i>
+                  {{ backend|backend_name }}
+                </a>
+              {% endif %}
+            {% endfor %}
+          </div>
+        {% endfor %}
+      </div>
+
+      <div class="legacy">
+        {% for name, backend in available_backends|legacy_backends %}
+          {% associated backend %}
+          {% if association %}
+            <form class="disconnect-form" action="{% url "social:disconnect_individual" backend=association.provider association_id=association.id %}" method="post">{% csrf_token %}
+              <a class="btn btn-danger" name="{{ backend|backend_class }}" href="#">
+                <i class="fa fa-{{ name|icon_name }}"></i>
+                Disconnect {{ backend|backend_name }}
+              </a>
+            </form>
+          {% else %}
+            <a class="btn btn-default" name="{{ backend|backend_class }}" href="{% url "social:begin" backend=name %}">
+              <i class="fa fa-{{ name|icon_name }}"></i>
+              {{ backend|backend_name }}
+            </a>
+          {% endif %}
+        {% endfor %}
+
+        <a class="btn btn-info" name="ajax-login" href="#">
+          <i class="fa fa-refresh"></i>
+          Ajax
+        </a>
+      </div>
+
+      <div>
+        <a class="btn btn-primary" href="/logout/">
+          <i class="fa fa-sign-out"></i>
+          Logout
+        </a>
+      </div>
+    </div>
+
+    <div id="username-modal" class="modal fade">
+      <form action="{% url "social:complete" "username" %}" method="post" role="form">{% csrf_token %}
+        <div class="modal-dialog">
+          <div class="modal-content">
+            <div class="modal-header">
+              <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+              <h4 class="modal-title">Email Authentication</h4>
+            </div>
+
+            <div class="modal-body">
+              <div class="form-group">
+                <label class="control-label" for="username">Username:</label>
+                <input class="form-control" id="username" type="text" name="username" value="" />
+              </div>
+
+              <div class="form-group">
+                <label class="control-label" for="password">Password:</label>
+                <input class="form-control" id="password" type="password" name="password" value="" />
+              </div>
+
+              <div class="form-group">
+                <label class="control-label" for="fullname">Full name:</label>
+                <input class="form-control" id="fullname" type="text" name="fullname" value="" />
+              </div>
+            </div>
+
+            <div class="modal-footer">
+              <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+              <button type="button" class="btn btn-primary">Login</button>
+            </div>
+          </div>
+        </div>
+      </form>
+    </div>
+
+    <div id="email-modal" class="modal fade">
+      <form action="{% url "social:complete" "email" %}" method="post" role="form">{% csrf_token %}
+        <div class="modal-dialog">
+          <div class="modal-content">
+            <div class="modal-header">
+              <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+              <h4 class="modal-title">Email Authentication</h4>
+            </div>
+
+            <div class="modal-body">
+              <div class="form-group">
+                <label class="control-label" for="email">Email address:</label>
+                <input class="form-control" id="email" type="email" name="email" value="" />
+              </div>
+
+              <div class="form-group">
+                <label class="control-label" for="password">Password:</label>
+                <input class="form-control" id="password" type="password" name="password" value="" />
+              </div>
+
+              <div class="form-group">
+                <label class="control-label" for="fullname">Full name:</label>
+                <input class="form-control" id="fullname" type="text" name="fullname" value="" />
+              </div>
+            </div>
+
+            <div class="modal-footer">
+              <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+              <button type="button" class="btn btn-primary">Login</button>
+            </div>
+          </div>
+        </div>
+      </form>
+    </div>
+
+    <div id="livejournal-modal" class="modal fade">
+      <form action="{% url "social:begin" "livejournal" %}" method="post" role="form">{% csrf_token %}
+        <div class="modal-dialog">
+          <div class="modal-content">
+            <div class="modal-header">
+              <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+              <h4 class="modal-title">LiveJournal OpenId Authentication</h4>
+            </div>
+
+            <div class="modal-body">
+              <div class="form-group">
+                <label class="control-label" for="openid_lj_identifier">LiveJournal ID:</label>
+                <input class="form-control" id="openid_lj_identifier" type="text" value="" name="openid_lj_user" />
+              </div>
+            </div>
+
+            <div class="modal-footer">
+              <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+              <button type="button" class="btn btn-primary">Login</button>
+            </div>
+          </div>
+        </div>
+      </form>
+    </div>
+
+    <div id="openid-modal" class="modal fade">
+      <form action="{% url "social:begin" backend="openid" %}" method="post" role="form">{% csrf_token %}
+        <div class="modal-dialog">
+          <div class="modal-content">
+            <div class="modal-header">
+              <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+              <h4 class="modal-title">Generic OpenId Authentication</h4>
+            </div>
+
+            <div class="modal-body">
+              <div class="form-group">
+                <label class="control-label" for="openid_identifier">OpenId Provider:</label>
+                <input class="form-control" id="openid_identifier" type="text" value="" name="openid_identifier" />
+              </div>
+            </div>
+
+            <div class="modal-footer">
+              <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+              <button type="button" class="btn btn-primary">Login</button>
+            </div>
+          </div>
+        </div>
+      </form>
+    </div>
+
+    <div id="ajax-login-modal" class="modal fade">
+      <div class="modal-dialog">
+        <div class="modal-content">
+          <div class="modal-header">
+            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+            <h4 class="modal-title">Ajax Authentication by AccessToken</h4>
+          </div>
+
+          <div class="modal-body">
+            <form action="#" method="post" class="form-horizontal" role="form">{% csrf_token %}
+              <div class="form-group">
+                <label class="control-label" for="backend">Backend:</label>
+                <select class="form-control" name="backend">
+                  <option value=""></option>
+                  {% for name, backend in available_backends|oauth_backends %}
+                    <option value="{{ name }}">{{ backend|backend_name }}</option>
+                  {% endfor %}
+                </select>
+              </div>
+
+              <div class="form-group">
+                <label class="control-label" for="access_token">Access token:</label>
+                <input class="form-control" id="access_token" name="access_token" type="text" value="" placeholder="OAuth1 or OAuth2 access token">
+              </div>
+
+              <div class="form-group">
+                <label class="control-label" for="access_token_secret">Access token secret:</label>
+                <input class="form-control" id="access_token_secret" name="access_token_secret" type="text" value="" placeholder="OAuth1 access token secret">
+              </div>
+            </form>
+
+            <div class="login-result" style="display: none;">
+              <p><strong>User Id:</strong><span class="user-id"></span></p>
+              <p><strong>Username:</strong><span class="user-username"></span></p>
+              <p>This page will be reloaded in 10s and the user should be logged in.</p>
+            </div>
+          </div>
+
+          <div class="modal-footer">
+            <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+            <button type="button" class="btn btn-primary">Login</button>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div id="persona-modal" class="modal fade">
+      <form action="{% url "social:complete" backend="persona" %}" method="post">{% csrf_token %}
+        <div class="modal-dialog">
+          <div class="modal-content">
+            <div class="modal-header">
+              <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+              <h4 class="modal-title">Mozilla Persona Authentication</h4>
+            </div>
+
+            <div class="modal-body">
+              <p>Login with Mozilla Persona by clicking the <code>Login</code> button below.</p>
+              <input type="hidden" name="assertion" value="" />
+            </div>
+
+            <div class="modal-footer">
+              <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+              <button type="button" class="btn btn-primary">Login</button>
+            </div>
+          </div>
+        </div>
+      </form>
+    </div>
+
+    {% if backend %}
+      <div id="email-required-modal" class="modal fade">
+        <form action="{% url "social:complete" backend=backend %}" method="post" role="form">{% csrf_token %}
+          <div class="modal-dialog">
+            <div class="modal-content">
+              <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+                <h4 class="modal-title">Email required</h4>
+              </div>
+
+              <div class="modal-body">
+                <p>An email address is required.</p>
+                <div class="form-group">
+                  <label class="control-label" for="email">Email address:</label>
+                  <input class="form-control" id="email" type="email" name="email" value="" />
+                </div>
+              </div>
+
+              <div class="modal-footer">
+                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                <button type="button" class="btn btn-primary">Continue</button>
+              </div>
+            </div>
+          </div>
+        </form>
+      </div>
+    {% endif %}
+
+    <div id="validation-sent-modal" class="modal fade">
+      <div class="modal-dialog">
+        <div class="modal-content">
+          <div class="modal-header">
+            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+            <h4 class="modal-title">Email Validation Sent</h4>
+          </div>
+
+          <div class="modal-body">
+            <p>An email validation was sent{% if email %} to <code>{{ email }}</code>{% endif %}.</p>
+            <p>Click the link sent to finish the authentication process.</p>
+          </div>
+
+          <div class="modal-footer">
+            <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    {% if plus_id %}
+    <form id="google-plus" method="post" action="{% url "social:complete" backend="google-plus" %}">{% csrf_token %}
+      <input id="at" type="hidden" name="access_token" value="" />
+      <input id="code" type="hidden" name="code" value="" />
+
+      <div id="signinButton">
+        <span class="g-signin" data-scope="{{ plus_scope }}"
+                               data-clientid="{{ plus_id }}"
+                               data-redirecturi="postmessage"
+                               data-accesstype="offline"
+                               data-cookiepolicy="single_host_origin"
+                               data-callback="signInCallback">
+        </span>
+      </div>
+    </form>
+    {% endif %}
+
+    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+    <script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
+    <script src="https://plus.google.com/js/client:plusone.js?onload=start" type="text/javascript"></script>
+    <script src="https://login.persona.org/include.js" type="text/javascript"></script>
+
+    <script type="text/javascript">
+      var signInCallback = function (result) {
+          if (result['error']) {
+            alert('An error happened:', result['error']);
+          } else {
+            $('#code').attr('value', result['code']);
+            $('#at').attr('value', result['access_token']);
+            $('#google-plus').submit();
+          }
+      };
+
+      var modalDialog = function (modalId, modalLinkName, submitHandler) {
+        var $modal;
+
+        $modal = $(modalId).modal({show: false});
+
+        $modal.on('click', '.btn-primary', submitHandler || function (event) {
+          event.preventDefault();
+          $modal.find('form').submit();
+        });
+
+        if (modalLinkName) {
+          $('a[name="' + modalLinkName + '"]').on('click', function (event) {
+            event.preventDefault();
+            $modal.modal('toggle');
+          });
+        }
+
+        return $modal;
+      };
+
+      $(function () {
+        var $validationModal, $emailRequired;
+
+        modalDialog('#livejournal-modal', 'livejournal');
+        modalDialog('#openid-modal', 'openid');
+        modalDialog('#email-modal', 'email');
+        modalDialog('#username-modal', 'username');
+        $validationModal = modalDialog('#validation-sent-modal');
+        $emailRequired = modalDialog('#email-required-modal');
+
+        modalDialog('#ajax-login-modal', 'ajax-login', function (event) {
+          var $backend, $accessToken, $accessTokenSecret, $fields, $result;
+          event.preventDefault();
+
+          $modal = $(this).closest('.modal');
+          $form = $modal.find('form');
+          $backend = $modal.find('[name="backend"]');
+          $accessToken = $modal.find('[name="access_token"]');
+          $accessTokenSecret = $modal.find('[name="access_token_secret"]');
+          $result = $modal.find('.login-result');
+
+          $.get('/ajax-auth/' + $backend.val() + '/', {
+            access_token: $accessToken.val(),
+            access_token_secret: $accessTokenSecret.val(),
+          }, function (data, xhr, response) {
+            $result.find('.user-id').html(data.id);
+            $result.find('.user-username').html(data.username);
+            $form.hide();
+            $result.show();
+            setTimeout(function () { window.location = '/'; }, 10000);
+          }, 'json')
+        });
+
+        modalDialog('#persona-modal', 'persona', function (event) {
+          var $form;
+          event.preventDefault();
+
+          $form = $(this).closest('form');
+          navigator.id.get(function (assertion) {
             if (assertion) {
-                self.parent('form')
-                        .find('input[type=hidden]')
-                        .attr('value', assertion)
-                        .end()
-                    .submit();
+              $form.find('[name="assertion"]').val(assertion)
+              $form.submit();
             } else {
-                alert('Some error occurred');
+              alert('An error occurred while getting your assertion, try again.');
             }
+          });
         });
-    });
-});
-</script>
-{% endblock %}
+
+        $('.disconnect-form').on('click', 'a.btn', function (event) {
+          event.preventDefault();
+          $(event.target).closest('form').submit();
+        });
+
+        {% if validation_sent %}
+          $validationModal.modal('show');
+        {% endif %}
+
+        {% if email_required %}
+          $emailRequired.modal('show');
+        {% endif %}
+      });
+    </script>
+  </body>
+</html>
diff --git a/examples/django_me_example/example/templates/username_signup.html b/examples/django_me_example/example/templates/username_signup.html
deleted file mode 100644
index 343d30c..0000000
--- a/examples/django_me_example/example/templates/username_signup.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{% extends "base.html" %}
-{% load url from future %}
-
-{% block content %}
-<form action="{% url 'social:complete' "username" %}" method="post">
-  {% csrf_token %}
-  <label for="username">Username:</label>
-  <input id="username" type="text" name="username" value="" />
-
-  <label for="password">Password:</label>
-  <input id="password" type="password" name="password" value="" />
-
-  <label for="fullname">Full name:</label>
-  <input id="fullname" type="text" name="fullname" value="" />
-
-  <br />
-  <button>Signup</button>
-</form>
-{% endblock %}
diff --git a/examples/django_me_example/example/templates/validation_sent.html b/examples/django_me_example/example/templates/validation_sent.html
deleted file mode 100644
index 6614e3e..0000000
--- a/examples/django_me_example/example/templates/validation_sent.html
+++ /dev/null
@@ -1,6 +0,0 @@
-{% extends "base.html" %}
-{% load url from future %}
-
-{% block content %}
-A email validation was sent to {{ email }}.
-{% endblock %}
diff --git a/examples/django_me_example/example/urls.py b/examples/django_me_example/example/urls.py
index 9821119..354ab4a 100644
--- a/examples/django_me_example/example/urls.py
+++ b/examples/django_me_example/example/urls.py
@@ -7,10 +7,12 @@ admin.autodiscover()
 urlpatterns = patterns('',
     url(r'^$', 'example.app.views.home'),
     url(r'^admin/', include(admin.site.urls)),
-    url(r'^signup-email/', 'example.app.views.signup_email'),
     url(r'^email-sent/', 'example.app.views.validation_sent'),
     url(r'^login/$', 'example.app.views.home'),
+    url(r'^logout/$', 'example.app.views.logout'),
     url(r'^done/$', 'example.app.views.done', name='done'),
+    url(r'^ajax-auth/(?P<backend>[^/]+)/$', 'example.app.views.ajax_auth',
+        name='ajax-auth'),
     url(r'^email/$', 'example.app.views.require_email', name='require_email'),
     url(r'', include('social.apps.django_app.urls', namespace='social'))
 )
diff --git a/examples/django_me_example/example/wsgi.py b/examples/django_me_example/example/wsgi.py
index 9b42e63..4b3fb45 100644
--- a/examples/django_me_example/example/wsgi.py
+++ b/examples/django_me_example/example/wsgi.py
@@ -1,5 +1,5 @@
 """
-WSGI config for example project.
+WSGI config for dj project.
 
 This module contains the WSGI application used by Django's development server
 and any production WSGI deployments. It should expose a module-level variable
diff --git a/examples/django_me_example/requirements.txt b/examples/django_me_example/requirements.txt
index 37f1c1a..1a339e9 100644
--- a/examples/django_me_example/requirements.txt
+++ b/examples/django_me_example/requirements.txt
@@ -1,3 +1,3 @@
-django>=1.4
+django>=1.4,<1.8
 mongoengine>=0.8.6
 python-social-auth

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-social-auth.git



More information about the Python-modules-commits mailing list