allauth folder added
This commit is contained in:
parent
efa48df80b
commit
6bfa53f1dc
0
itf/allauth/__init__.py
Normal file
0
itf/allauth/__init__.py
Normal file
0
itf/allauth/account/__init__.py
Normal file
0
itf/allauth/account/__init__.py
Normal file
8
itf/allauth/account/admin.py
Normal file
8
itf/allauth/account/admin.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# from models import PasswordReset
|
||||
#
|
||||
# class PasswordResetAdmin(admin.ModelAdmin):
|
||||
# list_display = ["user", "temp_key", "timestamp", "reset"]
|
||||
#
|
||||
# admin.site.register(PasswordReset, PasswordResetAdmin)
|
57
itf/allauth/account/app_settings.py
Normal file
57
itf/allauth/account/app_settings.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
import warnings
|
||||
from django.conf import settings
|
||||
|
||||
class AuthenticationMethod:
|
||||
USERNAME = 'username'
|
||||
EMAIL = 'email'
|
||||
USERNAME_EMAIL = 'username_email'
|
||||
|
||||
# The user is required to hand over an e-mail address when signing up
|
||||
EMAIL_REQUIRED = getattr(settings, "ACCOUNT_EMAIL_REQUIRED", False)
|
||||
|
||||
# After signing up, keep the user account inactive until the email
|
||||
# address is verified
|
||||
EMAIL_VERIFICATION = getattr(settings, "ACCOUNT_EMAIL_VERIFICATION", False)
|
||||
|
||||
# Login by email address, not username
|
||||
if hasattr(settings, "ACCOUNT_EMAIL_AUTHENTICATION"):
|
||||
warnings.warn("ACCOUNT_EMAIL_AUTHENTICATION is deprecated, use ACCOUNT_AUTHENTICATION_METHOD",
|
||||
DeprecationWarning)
|
||||
if getattr(settings, "ACCOUNT_EMAIL_AUTHENTICATION"):
|
||||
AUTHENTICATION_METHOD = AuthenticationMethod.EMAIL
|
||||
else:
|
||||
AUTHENTICATION_METHOD = AuthenticationMethod.USERNAME
|
||||
else:
|
||||
AUTHENTICATION_METHOD = getattr(settings, "ACCOUNT_AUTHENTICATION_METHOD",
|
||||
AuthenticationMethod.USERNAME)
|
||||
|
||||
# Enforce uniqueness of e-mail addresses
|
||||
UNIQUE_EMAIL = getattr(settings, "ACCOUNT_UNIQUE_EMAIL", True)
|
||||
|
||||
# Signup password verification
|
||||
SIGNUP_PASSWORD_VERIFICATION = getattr(settings,
|
||||
"ACCOUNT_SIGNUP_PASSWORD_VERIFICATION",
|
||||
True)
|
||||
|
||||
# Minimum Password Length
|
||||
PASSWORD_MIN_LENGTH = getattr(settings, "ACCOUNT_PASSWORD_MIN_LENGTH", 6)
|
||||
|
||||
# Subject-line prefix to use for email messages sent
|
||||
EMAIL_SUBJECT_PREFIX = getattr(settings, "ACCOUNT_EMAIL_SUBJECT_PREFIX", None)
|
||||
|
||||
# Signup form
|
||||
SIGNUP_FORM_CLASS = getattr(settings, "ACCOUNT_SIGNUP_FORM_CLASS", None)
|
||||
|
||||
# The user is required to enter a username when signing up
|
||||
USERNAME_REQUIRED = getattr(settings, "ACCOUNT_USERNAME_REQUIRED", True)
|
||||
|
||||
# render_value parameter as passed to PasswordInput fields
|
||||
PASSWORD_INPUT_RENDER_VALUE = getattr(settings,
|
||||
"ACCOUNT_PASSWORD_INPUT_RENDER_VALUE",
|
||||
False)
|
||||
|
||||
# If login is by email, email must be required
|
||||
assert (not AUTHENTICATION_METHOD==AuthenticationMethod.EMAIL) or EMAIL_REQUIRED
|
||||
# If login includes email, login must be unique
|
||||
assert (AUTHENTICATION_METHOD==AuthenticationMethod.USERNAME) or UNIQUE_EMAIL
|
||||
assert (not EMAIL_VERIFICATION) or EMAIL_REQUIRED
|
40
itf/allauth/account/auth_backends.py
Normal file
40
itf/allauth/account/auth_backends.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
from django.contrib.auth.backends import ModelBackend
|
||||
from django.contrib.auth.models import User
|
||||
from django.db.models import Q
|
||||
|
||||
from app_settings import AuthenticationMethod
|
||||
import app_settings
|
||||
|
||||
class AuthenticationBackend(ModelBackend):
|
||||
|
||||
def authenticate(self, **credentials):
|
||||
ret = None
|
||||
if app_settings.AUTHENTICATION_METHOD == AuthenticationMethod.EMAIL:
|
||||
ret = self._authenticate_by_email(**credentials)
|
||||
elif app_settings.AUTHENTICATION_METHOD \
|
||||
== AuthenticationMethod.USERNAME_EMAIL:
|
||||
ret = self._authenticate_by_email(**credentials)
|
||||
if not ret:
|
||||
ret = self._authenticate_by_username(**credentials)
|
||||
else:
|
||||
ret = self._authenticate_by_username(**credentials)
|
||||
return ret
|
||||
|
||||
def _authenticate_by_username(self, **credentials):
|
||||
return super(AuthenticationBackend, self).authenticate(**credentials)
|
||||
|
||||
def _authenticate_by_email(self, **credentials):
|
||||
# Even though allauth will pass along `email`, other apps may
|
||||
# not respect this setting. For example, when using
|
||||
# django-tastypie basic authentication, the login is always
|
||||
# passed as `username`. So let's place nice with other apps
|
||||
# and use username as fallback
|
||||
email = credentials.get('email', credentials.get('username'))
|
||||
if email:
|
||||
users = User.objects.filter(Q(email__iexact=email)
|
||||
| Q(emailaddress__email__iexact
|
||||
=email))
|
||||
for user in users:
|
||||
if user.check_password(credentials["password"]):
|
||||
return user
|
||||
return None
|
6
itf/allauth/account/context_processors.py
Normal file
6
itf/allauth/account/context_processors.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from django.conf import settings
|
||||
|
||||
def account(request):
|
||||
return {
|
||||
"CONTACT_EMAIL": getattr(settings, "CONTACT_EMAIL", "support@example.com")
|
||||
}
|
38
itf/allauth/account/decorators.py
Normal file
38
itf/allauth/account/decorators.py
Normal file
|
@ -0,0 +1,38 @@
|
|||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||
from django.shortcuts import render
|
||||
|
||||
from emailconfirmation.models import EmailAddress
|
||||
|
||||
from utils import send_email_confirmation
|
||||
|
||||
|
||||
def verified_email_required(function=None,
|
||||
login_url=None,
|
||||
redirect_field_name=REDIRECT_FIELD_NAME):
|
||||
"""
|
||||
Even when email verification is not mandatory during signup, there
|
||||
may be circumstances during which you really want to prevent
|
||||
unverified users to proceed. This decorator ensures the user is
|
||||
authenticated and has a verified email address. If the former is
|
||||
not the case then the behavior is identical to that of the
|
||||
standard `login_required` decorator. If the latter does not hold,
|
||||
email verification mails are automatically resend and the user is
|
||||
presented with a page informing him he needs to verify his email
|
||||
address.
|
||||
"""
|
||||
def decorator(view_func):
|
||||
@login_required(redirect_field_name=redirect_field_name,
|
||||
login_url=login_url)
|
||||
def _wrapped_view(request, *args, **kwargs):
|
||||
if not EmailAddress.objects.filter(user=request.user,
|
||||
verified=True).exists():
|
||||
send_email_confirmation(request.user, request)
|
||||
return render(request,
|
||||
'account/verified_email_required.html')
|
||||
return view_func(request, *args, **kwargs)
|
||||
return _wrapped_view
|
||||
|
||||
if function:
|
||||
return decorator(function)
|
||||
return decorator
|
479
itf/allauth/account/forms.py
Normal file
479
itf/allauth/account/forms.py
Normal file
|
@ -0,0 +1,479 @@
|
|||
import base64
|
||||
import re
|
||||
import uuid
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.core.mail import send_mail
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core import exceptions
|
||||
from django.db.models import Q
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.translation import ugettext_lazy as _, ugettext
|
||||
from django.utils.http import int_to_base36
|
||||
from django.utils.importlib import import_module
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import authenticate
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.tokens import default_token_generator
|
||||
from django.contrib.sites.models import Site
|
||||
|
||||
from emailconfirmation.models import EmailAddress
|
||||
|
||||
# from models import PasswordReset
|
||||
from utils import perform_login, send_email_confirmation, format_email_subject
|
||||
from allauth.utils import email_address_exists
|
||||
from app_settings import AuthenticationMethod
|
||||
|
||||
import app_settings
|
||||
|
||||
alnum_re = re.compile(r"^\w+$")
|
||||
|
||||
|
||||
class PasswordField(forms.CharField):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
render_value = kwargs.pop('render_value',
|
||||
app_settings.PASSWORD_INPUT_RENDER_VALUE)
|
||||
kwargs['widget'] = forms.PasswordInput(render_value=render_value)
|
||||
super(PasswordField, self).__init__(*args, **kwargs)
|
||||
|
||||
class SetPasswordField(PasswordField):
|
||||
|
||||
def clean(self, value):
|
||||
value = super(SetPasswordField, self).clean(value)
|
||||
min_length = app_settings.PASSWORD_MIN_LENGTH
|
||||
if len(value) < min_length:
|
||||
raise forms.ValidationError(_("Password must be a minimum of {0} "
|
||||
"characters.").format(min_length))
|
||||
return value
|
||||
|
||||
class LoginForm(forms.Form):
|
||||
|
||||
password = PasswordField(
|
||||
label = _("Password"))
|
||||
remember = forms.BooleanField(
|
||||
label = _("Remember Me"),
|
||||
# help_text = _("If checked you will stay logged in for 3 weeks"),
|
||||
required = False
|
||||
)
|
||||
|
||||
user = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(LoginForm, self).__init__(*args, **kwargs)
|
||||
if app_settings.AUTHENTICATION_METHOD == AuthenticationMethod.EMAIL:
|
||||
login_widget = forms.TextInput(attrs={'placeholder':
|
||||
_('E-mail address') })
|
||||
login_field = forms.EmailField(label=_("E-mail"),
|
||||
widget=login_widget)
|
||||
elif app_settings.AUTHENTICATION_METHOD \
|
||||
== AuthenticationMethod.USERNAME:
|
||||
login_widget = forms.TextInput(attrs={'placeholder':
|
||||
_('Username') })
|
||||
login_field = forms.CharField(label=_("Username"),
|
||||
widget=login_widget,
|
||||
max_length=30)
|
||||
else:
|
||||
assert app_settings.AUTHENTICATION_METHOD \
|
||||
== AuthenticationMethod.USERNAME_EMAIL
|
||||
login_widget = forms.TextInput(attrs={'placeholder':
|
||||
_('Username or e-mail') })
|
||||
login_field = forms.CharField(label=ugettext("Login"),
|
||||
widget=login_widget)
|
||||
self.fields["login"] = login_field
|
||||
self.fields.keyOrder = ["login", "password", "remember"]
|
||||
|
||||
def user_credentials(self):
|
||||
"""
|
||||
Provides the credentials required to authenticate the user for
|
||||
login.
|
||||
"""
|
||||
credentials = {}
|
||||
login = self.cleaned_data["login"]
|
||||
if app_settings.AUTHENTICATION_METHOD == AuthenticationMethod.EMAIL:
|
||||
credentials["email"] = login
|
||||
elif (app_settings.AUTHENTICATION_METHOD
|
||||
== AuthenticationMethod.USERNAME):
|
||||
credentials["username"] = login
|
||||
else:
|
||||
if "@" in login and "." in login:
|
||||
credentials["email"] = login
|
||||
else:
|
||||
credentials["username"] = login
|
||||
credentials["password"] = self.cleaned_data["password"]
|
||||
return credentials
|
||||
|
||||
def clean(self):
|
||||
if self._errors:
|
||||
return
|
||||
user = authenticate(**self.user_credentials())
|
||||
if user:
|
||||
if user.is_active:
|
||||
self.user = user
|
||||
else:
|
||||
raise forms.ValidationError(_("This account is currently"
|
||||
" inactive."))
|
||||
else:
|
||||
if app_settings.AUTHENTICATION_METHOD == AuthenticationMethod.EMAIL:
|
||||
error = _("The e-mail address and/or password you specified"
|
||||
" are not correct.")
|
||||
elif app_settings.AUTHENTICATION_METHOD \
|
||||
== AuthenticationMethod.USERNAME:
|
||||
error = _("The username and/or password you specified are"
|
||||
" not correct.")
|
||||
else:
|
||||
error = _("The login and/or password you specified are not"
|
||||
" correct.")
|
||||
raise forms.ValidationError(error)
|
||||
return self.cleaned_data
|
||||
|
||||
def login(self, request, redirect_url=None):
|
||||
ret = perform_login(request, self.user, redirect_url=redirect_url)
|
||||
if self.cleaned_data["remember"]:
|
||||
request.session.set_expiry(60 * 60 * 24 * 7 * 3)
|
||||
else:
|
||||
request.session.set_expiry(0)
|
||||
return ret
|
||||
|
||||
|
||||
|
||||
class _DummyCustomSignupForm(forms.Form):
|
||||
def save(self, user):
|
||||
pass
|
||||
|
||||
def _base_signup_form_class():
|
||||
if not app_settings.SIGNUP_FORM_CLASS:
|
||||
return _DummyCustomSignupForm
|
||||
try:
|
||||
fc_module, fc_classname = app_settings.SIGNUP_FORM_CLASS.rsplit('.', 1)
|
||||
except ValueError:
|
||||
raise exceptions.ImproperlyConfigured('%s does not point to a form'
|
||||
' class'
|
||||
% app_settings.SIGNUP_FORM_CLASS)
|
||||
try:
|
||||
mod = import_module(fc_module)
|
||||
except ImportError, e:
|
||||
raise exceptions.ImproperlyConfigured('Error importing form class %s:'
|
||||
' "%s"' % (fc_module, e))
|
||||
try:
|
||||
fc_class = getattr(mod, fc_classname)
|
||||
except AttributeError:
|
||||
raise exceptions.ImproperlyConfigured('Module "%s" does not define a'
|
||||
' "%s" class' % (fc_module,
|
||||
fc_classname))
|
||||
if not hasattr(fc_class, 'save'):
|
||||
raise exceptions.ImproperlyConfigured('The custom signup form must'
|
||||
' implement a "save" method')
|
||||
return fc_class
|
||||
|
||||
|
||||
class BaseSignupForm(_base_signup_form_class()):
|
||||
username = forms.CharField(
|
||||
label = _("Username"),
|
||||
max_length = 30,
|
||||
widget = forms.TextInput()
|
||||
)
|
||||
email = forms.EmailField(widget=forms.TextInput())
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(BaseSignupForm, self).__init__(*args, **kwargs)
|
||||
if (app_settings.EMAIL_REQUIRED or
|
||||
app_settings.EMAIL_VERIFICATION or
|
||||
app_settings.AUTHENTICATION_METHOD == AuthenticationMethod.EMAIL):
|
||||
self.fields["email"].label = ugettext("E-mail")
|
||||
self.fields["email"].required = True
|
||||
else:
|
||||
self.fields["email"].label = ugettext("E-mail (optional)")
|
||||
self.fields["email"].required = False
|
||||
if not app_settings.USERNAME_REQUIRED:
|
||||
del self.fields["username"]
|
||||
|
||||
def random_username(self):
|
||||
return base64.urlsafe_b64encode(uuid.uuid4().bytes).strip('=')
|
||||
|
||||
def clean_username(self):
|
||||
value = self.cleaned_data["username"]
|
||||
if not alnum_re.search(value):
|
||||
raise forms.ValidationError(_("Usernames can only contain "
|
||||
"letters, numbers and underscores."))
|
||||
try:
|
||||
User.objects.get(username__iexact=value)
|
||||
except User.DoesNotExist:
|
||||
return value
|
||||
raise forms.ValidationError(_("This username is already taken. Please "
|
||||
"choose another."))
|
||||
|
||||
def clean_email(self):
|
||||
value = self.cleaned_data["email"]
|
||||
if app_settings.UNIQUE_EMAIL:
|
||||
if value and email_address_exists(value):
|
||||
raise forms.ValidationError \
|
||||
(_("A user is registered with this e-mail address."))
|
||||
return value
|
||||
|
||||
def create_user(self, commit=True):
|
||||
user = User()
|
||||
# data collected by providers, if any, is passed as `initial`
|
||||
# signup form data. This may contain fields such as
|
||||
# `first_name`, whereas these may not have field counterparts
|
||||
# in the form itself. So let's pick these up here...
|
||||
data = self.initial
|
||||
user.last_name = data.get('last_name', '')
|
||||
user.first_name = data.get('first_name', '')
|
||||
if app_settings.USERNAME_REQUIRED:
|
||||
user.username = self.cleaned_data["username"]
|
||||
else:
|
||||
while True:
|
||||
user.username = self.random_username()
|
||||
try:
|
||||
User.objects.get(username=user.username)
|
||||
except User.DoesNotExist:
|
||||
break
|
||||
user.email = self.cleaned_data["email"].strip().lower()
|
||||
user.set_unusable_password()
|
||||
if commit:
|
||||
user.save()
|
||||
return user
|
||||
|
||||
|
||||
class SignupForm(BaseSignupForm):
|
||||
|
||||
password1 = SetPasswordField(label=_("Password"))
|
||||
password2 = PasswordField(label=_("Password (again)"))
|
||||
confirmation_key = forms.CharField(
|
||||
max_length = 40,
|
||||
required = False,
|
||||
widget = forms.HiddenInput())
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SignupForm, self).__init__(*args, **kwargs)
|
||||
current_order =self.fields.keyOrder
|
||||
preferred_order = self.fields.keyOrder = ["username",
|
||||
"password1",
|
||||
"password2",
|
||||
"email"]
|
||||
if not app_settings.USERNAME_REQUIRED:
|
||||
preferred_order = self.fields.keyOrder = ["email",
|
||||
"password1",
|
||||
"password2"]
|
||||
# Make sure custom fields are put below main signup fields
|
||||
self.fields.keyOrder = preferred_order + [ f for f in current_order if not f in preferred_order ]
|
||||
if not app_settings.SIGNUP_PASSWORD_VERIFICATION:
|
||||
del self.fields["password2"]
|
||||
|
||||
def clean(self):
|
||||
super(SignupForm, self).clean()
|
||||
if app_settings.SIGNUP_PASSWORD_VERIFICATION \
|
||||
and "password1" in self.cleaned_data \
|
||||
and "password2" in self.cleaned_data:
|
||||
if self.cleaned_data["password1"] != self.cleaned_data["password2"]:
|
||||
raise forms.ValidationError(_("You must type the same password each time."))
|
||||
return self.cleaned_data
|
||||
|
||||
def create_user(self, commit=True):
|
||||
user = super(SignupForm, self).create_user(commit=False)
|
||||
password = self.cleaned_data.get("password1")
|
||||
if password:
|
||||
user.set_password(password)
|
||||
if commit:
|
||||
user.save()
|
||||
return user
|
||||
|
||||
def save(self, request=None):
|
||||
# don't assume a username is available. it is a common removal if
|
||||
# site developer wants to use e-mail authentication.
|
||||
email = self.cleaned_data["email"]
|
||||
|
||||
if self.cleaned_data.get("confirmation_key"):
|
||||
from friends.models import JoinInvitation # @@@ temporary fix for issue 93
|
||||
try:
|
||||
join_invitation = JoinInvitation.objects.get(confirmation_key=self.cleaned_data["confirmation_key"])
|
||||
confirmed = True
|
||||
except JoinInvitation.DoesNotExist:
|
||||
confirmed = False
|
||||
else:
|
||||
confirmed = False
|
||||
|
||||
new_user = self.create_user()
|
||||
super(SignupForm, self).save(new_user, request)
|
||||
|
||||
# @@@ clean up some of the repetition below -- DRY!
|
||||
if confirmed:
|
||||
if email == join_invitation.contact.email:
|
||||
join_invitation.accept(new_user) # should go before creation of EmailAddress below
|
||||
if request:
|
||||
messages.add_message(request, messages.INFO,
|
||||
ugettext(u"Your e-mail address has already been verified")
|
||||
)
|
||||
# already verified so can just create
|
||||
EmailAddress(user=new_user, email=email, verified=True, primary=True).save()
|
||||
else:
|
||||
join_invitation.accept(new_user) # should go before creation of EmailAddress below
|
||||
if email:
|
||||
if request:
|
||||
messages.add_message(request, messages.INFO,
|
||||
ugettext(u"Confirmation e-mail sent to %(email)s") % {
|
||||
"email": email,
|
||||
}
|
||||
)
|
||||
EmailAddress.objects.add_email(new_user, email)
|
||||
else:
|
||||
send_email_confirmation(new_user, request=request)
|
||||
|
||||
self.after_signup(new_user)
|
||||
|
||||
return new_user
|
||||
|
||||
def after_signup(self, user, **kwargs):
|
||||
"""
|
||||
An extension point for subclasses.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class UserForm(forms.Form):
|
||||
|
||||
def __init__(self, user=None, *args, **kwargs):
|
||||
self.user = user
|
||||
super(UserForm, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class AddEmailForm(UserForm):
|
||||
|
||||
email = forms.EmailField(
|
||||
label = _("E-mail"),
|
||||
required = True,
|
||||
widget = forms.TextInput(attrs={"size": "30"})
|
||||
)
|
||||
|
||||
def clean_email(self):
|
||||
value = self.cleaned_data["email"]
|
||||
errors = {
|
||||
"this_account": _("This e-mail address already associated with this account."),
|
||||
"different_account": _("This e-mail address already associated with another account."),
|
||||
}
|
||||
emails = EmailAddress.objects.filter(email__iexact=value)
|
||||
if emails.filter(user=self.user).exists():
|
||||
raise forms.ValidationError(errors["this_account"])
|
||||
if app_settings.UNIQUE_EMAIL:
|
||||
if emails.exclude(user=self.user).exists():
|
||||
raise forms.ValidationError(errors["different_account"])
|
||||
return value
|
||||
|
||||
def save(self):
|
||||
return EmailAddress.objects.add_email(self.user, self.cleaned_data["email"])
|
||||
|
||||
|
||||
class ChangePasswordForm(UserForm):
|
||||
|
||||
oldpassword = PasswordField(label=_("Current Password"))
|
||||
password1 = SetPasswordField(label=_("New Password"))
|
||||
password2 = PasswordField(label=_("New Password (again)"))
|
||||
|
||||
def clean_oldpassword(self):
|
||||
if not self.user.check_password(self.cleaned_data.get("oldpassword")):
|
||||
raise forms.ValidationError(_("Please type your current password."))
|
||||
return self.cleaned_data["oldpassword"]
|
||||
|
||||
def clean_password2(self):
|
||||
if "password1" in self.cleaned_data and "password2" in self.cleaned_data:
|
||||
if self.cleaned_data["password1"] != self.cleaned_data["password2"]:
|
||||
raise forms.ValidationError(_("You must type the same password each time."))
|
||||
return self.cleaned_data["password2"]
|
||||
|
||||
def save(self):
|
||||
self.user.set_password(self.cleaned_data["password1"])
|
||||
self.user.save()
|
||||
|
||||
|
||||
class SetPasswordForm(UserForm):
|
||||
|
||||
password1 = SetPasswordField(label=_("Password"))
|
||||
password2 = PasswordField(label=_("Password (again)"))
|
||||
|
||||
def clean_password2(self):
|
||||
if "password1" in self.cleaned_data and "password2" in self.cleaned_data:
|
||||
if self.cleaned_data["password1"] != self.cleaned_data["password2"]:
|
||||
raise forms.ValidationError(_("You must type the same password each time."))
|
||||
return self.cleaned_data["password2"]
|
||||
|
||||
def save(self):
|
||||
self.user.set_password(self.cleaned_data["password1"])
|
||||
self.user.save()
|
||||
|
||||
|
||||
class ResetPasswordForm(forms.Form):
|
||||
|
||||
email = forms.EmailField(
|
||||
label = _("E-mail"),
|
||||
required = True,
|
||||
widget = forms.TextInput(attrs={"size":"30"})
|
||||
)
|
||||
|
||||
def clean_email(self):
|
||||
email = self.cleaned_data["email"]
|
||||
self.users = User.objects.filter(Q(email__iexact=email)
|
||||
| Q(emailaddress__email__iexact=email)).distinct()
|
||||
if not self.users.exists():
|
||||
raise forms.ValidationError(_("The e-mail address is not assigned to any user account"))
|
||||
return self.cleaned_data["email"]
|
||||
|
||||
def save(self, **kwargs):
|
||||
|
||||
email = self.cleaned_data["email"]
|
||||
token_generator = kwargs.get("token_generator", default_token_generator)
|
||||
|
||||
for user in self.users:
|
||||
|
||||
temp_key = token_generator.make_token(user)
|
||||
|
||||
# save it to the password reset model
|
||||
# password_reset = PasswordReset(user=user, temp_key=temp_key)
|
||||
# password_reset.save()
|
||||
|
||||
current_site = Site.objects.get_current()
|
||||
|
||||
# send the password reset email
|
||||
subject = format_email_subject(_("Password Reset E-mail"))
|
||||
path = reverse("account_reset_password_from_key",
|
||||
kwargs=dict(uidb36=int_to_base36(user.id),
|
||||
key=temp_key))
|
||||
url = 'http://%s%s' % (current_site.domain,
|
||||
path)
|
||||
message = render_to_string \
|
||||
("account/password_reset_key_message.txt",
|
||||
{ "site": current_site,
|
||||
"user": user,
|
||||
"password_reset_url": url })
|
||||
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [email])
|
||||
return self.cleaned_data["email"]
|
||||
|
||||
|
||||
class ResetPasswordKeyForm(forms.Form):
|
||||
|
||||
password1 = SetPasswordField(label=_("New Password"))
|
||||
password2 = PasswordField(label=_("New Password (again)"))
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.user = kwargs.pop("user", None)
|
||||
self.temp_key = kwargs.pop("temp_key", None)
|
||||
super(ResetPasswordKeyForm, self).__init__(*args, **kwargs)
|
||||
|
||||
# FIXME: Inspecting other fields -> should be put in def clean(self) ?
|
||||
def clean_password2(self):
|
||||
if "password1" in self.cleaned_data and "password2" in self.cleaned_data:
|
||||
if self.cleaned_data["password1"] != self.cleaned_data["password2"]:
|
||||
raise forms.ValidationError(_("You must type the same password each time."))
|
||||
return self.cleaned_data["password2"]
|
||||
|
||||
def save(self):
|
||||
# set the new user password
|
||||
user = self.user
|
||||
user.set_password(self.cleaned_data["password1"])
|
||||
user.save()
|
||||
# mark password reset object as reset
|
||||
# PasswordReset.objects.filter(temp_key=self.temp_key).update(reset=True)
|
||||
|
||||
|
11
itf/allauth/account/models.py
Normal file
11
itf/allauth/account/models.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
from emailconfirmation.models import EmailConfirmation
|
||||
from emailconfirmation.signals import email_confirmed
|
||||
|
||||
|
||||
def mark_user_active(sender, instance=None, **kwargs):
|
||||
user = kwargs.get("email_address").user
|
||||
user.is_active = True
|
||||
user.save()
|
||||
|
||||
|
||||
email_confirmed.connect(mark_user_active, sender=EmailConfirmation)
|
4
itf/allauth/account/signals.py
Normal file
4
itf/allauth/account/signals.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
import django.dispatch
|
||||
|
||||
|
||||
user_logged_in = django.dispatch.Signal(providing_args=["request", "user"])
|
1
itf/allauth/account/templatetags/__init__.py
Normal file
1
itf/allauth/account/templatetags/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
|
47
itf/allauth/account/templatetags/account_tags.py
Normal file
47
itf/allauth/account/templatetags/account_tags.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
from django import template
|
||||
|
||||
from allauth.account.utils import user_display
|
||||
|
||||
register = template.Library()
|
||||
|
||||
class UserDisplayNode(template.Node):
|
||||
|
||||
def __init__(self, user, as_var=None):
|
||||
self.user_var = template.Variable(user)
|
||||
self.as_var = as_var
|
||||
|
||||
def render(self, context):
|
||||
user = self.user_var.resolve(context)
|
||||
|
||||
display = user_display(user)
|
||||
|
||||
if self.as_var:
|
||||
context[self.as_var] = display
|
||||
return ""
|
||||
return display
|
||||
|
||||
|
||||
@register.tag(name="user_display")
|
||||
def do_user_display(parser, token):
|
||||
"""
|
||||
Example usage::
|
||||
|
||||
{% user_display user %}
|
||||
|
||||
or if you need to use in a {% blocktrans %}::
|
||||
|
||||
{% user_display user as user_display %}
|
||||
{% blocktrans %}{{ user_display }} has sent you a gift.{% endblocktrans %}
|
||||
|
||||
"""
|
||||
bits = token.split_contents()
|
||||
if len(bits) == 2:
|
||||
user = bits[1]
|
||||
as_var = None
|
||||
elif len(bits) == 4:
|
||||
user = bits[1]
|
||||
as_var = bits[3]
|
||||
else:
|
||||
raise template.TemplateSyntaxError("'%s' takes either two or four arguments" % bits[0])
|
||||
|
||||
return UserDisplayNode(user, as_var)
|
98
itf/allauth/account/tests.py
Normal file
98
itf/allauth/account/tests.py
Normal file
|
@ -0,0 +1,98 @@
|
|||
from datetime import timedelta
|
||||
try:
|
||||
from django.utils.timezone import now
|
||||
except ImportError:
|
||||
from datetime import datetime
|
||||
now = datetime.now
|
||||
|
||||
from django.test import TestCase
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test.client import Client
|
||||
from django.core import mail
|
||||
from django.contrib.sites.models import Site
|
||||
|
||||
from emailconfirmation.models import EmailAddress, EmailConfirmation
|
||||
|
||||
from app_settings import AuthenticationMethod
|
||||
import app_settings
|
||||
|
||||
class AccountTests(TestCase):
|
||||
def setUp(self):
|
||||
self.OLD_EMAIL_VERIFICATION = app_settings.EMAIL_VERIFICATION
|
||||
self.OLD_AUTHENTICATION_METHOD = app_settings.AUTHENTICATION_METHOD
|
||||
self.OLD_SIGNUP_FORM_CLASS = app_settings.SIGNUP_FORM_CLASS
|
||||
self.OLD_USERNAME_REQUIRED = app_settings.USERNAME_REQUIRED
|
||||
app_settings.EMAIL_VERIFICATION = True
|
||||
app_settings.AUTHENTICATION_METHOD = AuthenticationMethod.USERNAME
|
||||
app_settings.SIGNUP_FORM_CLASS = None
|
||||
app_settings.USERNAME_REQUIRED = True
|
||||
|
||||
if 'allauth.socialaccount' in settings.INSTALLED_APPS:
|
||||
# Otherwise ImproperlyConfigured exceptions may occur
|
||||
from ..socialaccount.models import SocialApp
|
||||
SocialApp.objects.create(name='testfb',
|
||||
provider='facebook',
|
||||
site=Site.objects.get_current())
|
||||
|
||||
def test_email_verification_mandatory(self):
|
||||
c = Client()
|
||||
# Signup
|
||||
resp = c.post(reverse('account_signup'),
|
||||
{ 'username': 'johndoe',
|
||||
'email': 'john@doe.com',
|
||||
'password1': 'johndoe',
|
||||
'password2': 'johndoe' })
|
||||
self.assertEquals(resp.status_code, 200)
|
||||
self.assertEquals(mail.outbox[0].to, ['john@doe.com'])
|
||||
self.assertEquals(len(mail.outbox), 1)
|
||||
self.assertTemplateUsed(resp,
|
||||
'account/verification_sent.html')
|
||||
# Attempt to login, unverified
|
||||
for attempt in [1, 2]:
|
||||
resp = c.post(reverse('account_login'),
|
||||
{ 'login': 'johndoe',
|
||||
'password': 'johndoe'})
|
||||
# is_active is controlled by the admin to manually disable
|
||||
# users. I don't want this flag to flip automatically whenever
|
||||
# users verify their email adresses.
|
||||
self.assertTrue(User.objects.filter(username='johndoe',
|
||||
is_active=True).exists())
|
||||
self.assertTemplateUsed(resp,
|
||||
'account/verification_sent.html')
|
||||
self.assertEquals(len(mail.outbox), attempt)
|
||||
# Wait for cooldown
|
||||
EmailConfirmation.objects.update(sent=now()
|
||||
- timedelta(days=1))
|
||||
# Verify, and re-attempt to login.
|
||||
EmailAddress.objects.filter(user__username='johndoe') \
|
||||
.update(verified=True)
|
||||
resp = c.post(reverse('account_login'),
|
||||
{ 'login': 'johndoe',
|
||||
'password': 'johndoe'})
|
||||
self.assertEquals(resp['location'],
|
||||
'http://testserver'+settings.LOGIN_REDIRECT_URL)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def x_test_email_escaping(self):
|
||||
"""
|
||||
Test is only valid if emailconfirmation is listed after
|
||||
allauth in INSTALLED_APPS
|
||||
"""
|
||||
site = Site.objects.get_current()
|
||||
site.name = '<enc&"test>'
|
||||
site.save()
|
||||
u = User.objects.create(username='test',
|
||||
email='foo@bar.com')
|
||||
EmailAddress.objects.add_email(u, u.email)
|
||||
|
||||
def tearDown(self):
|
||||
app_settings.EMAIL_VERIFICATION = self.OLD_EMAIL_VERIFICATION
|
||||
app_settings.AUTHENTICATION_METHOD = self.OLD_AUTHENTICATION_METHOD
|
||||
app_settings.SIGNUP_FORM_CLASS = self.OLD_SIGNUP_FORM_CLASS
|
||||
app_settings.USERNAME_REQUIRED = self.OLD_USERNAME_REQUIRED
|
||||
|
24
itf/allauth/account/urls.py
Normal file
24
itf/allauth/account/urls.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
from django.conf.urls.defaults import patterns, url
|
||||
|
||||
import views
|
||||
|
||||
urlpatterns = patterns("",
|
||||
url(r"^email/$", views.email, name="account_email"),
|
||||
url(r"^signup/$", views.signup, name="account_signup"),
|
||||
url(r"^login/$", views.login, name="account_login"),
|
||||
url(r"^password/change/$", views.password_change, name="account_change_password"),
|
||||
url(r"^password/set/$", views.password_set, name="account_set_password"),
|
||||
# url(r"^password_delete/$", views.password_delete, name="acct_passwd_delete"),
|
||||
# url(r"^password_delete/done/$", "django.views.generic.simple.direct_to_template", {
|
||||
# "template": "account/password_delete_done.html",
|
||||
# }, name="acct_passwd_delete_done"),
|
||||
url(r"^logout/$", views.logout, name="account_logout"),
|
||||
|
||||
url(r"^confirm_email/(\w+)/$", "emailconfirmation.views.confirm_email", name="account_confirm_email"),
|
||||
|
||||
# password reset
|
||||
url(r"^password/reset/$", views.password_reset, name="account_reset_password"),
|
||||
url(r"^password/reset/done/$", views.password_reset_done, name="account_reset_password_done"),
|
||||
url(r"^password/reset/key/(?P<uidb36>[0-9A-Za-z]+)-(?P<key>.+)/$", views.password_reset_from_key, name="account_reset_password_from_key"),
|
||||
|
||||
)
|
162
itf/allauth/account/utils.py
Normal file
162
itf/allauth/account/utils.py
Normal file
|
@ -0,0 +1,162 @@
|
|||
from datetime import timedelta
|
||||
try:
|
||||
from django.utils.timezone import now
|
||||
except ImportError:
|
||||
from datetime import datetime
|
||||
now = datetime.now
|
||||
|
||||
from django.contrib import messages
|
||||
from django.shortcuts import render
|
||||
from django.contrib.sites.models import Site
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.contrib.auth import login
|
||||
from django.utils.translation import ugettext_lazy as _, ugettext
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
from emailconfirmation.models import EmailAddress, EmailConfirmation
|
||||
|
||||
from allauth.utils import import_callable
|
||||
|
||||
from signals import user_logged_in
|
||||
|
||||
import app_settings
|
||||
|
||||
|
||||
LOGIN_REDIRECT_URLNAME = getattr(settings, "LOGIN_REDIRECT_URLNAME", "")
|
||||
|
||||
|
||||
def get_default_redirect(request, redirect_field_name="next",
|
||||
login_redirect_urlname=LOGIN_REDIRECT_URLNAME, session_key_value="redirect_to"):
|
||||
"""
|
||||
Returns the URL to be used in login procedures by looking at different
|
||||
values in the following order:
|
||||
|
||||
- a REQUEST value, GET or POST, named "next" by default.
|
||||
- LOGIN_REDIRECT_URL - the URL in the setting
|
||||
- LOGIN_REDIRECT_URLNAME - the name of a URLconf entry in the settings
|
||||
"""
|
||||
if login_redirect_urlname:
|
||||
default_redirect_to = reverse(login_redirect_urlname)
|
||||
else:
|
||||
default_redirect_to = settings.LOGIN_REDIRECT_URL
|
||||
redirect_to = request.REQUEST.get(redirect_field_name)
|
||||
if not redirect_to:
|
||||
# try the session if available
|
||||
if hasattr(request, "session"):
|
||||
redirect_to = request.session.get(session_key_value)
|
||||
# light security check -- make sure redirect_to isn't garabage.
|
||||
if not redirect_to or "://" in redirect_to or " " in redirect_to:
|
||||
redirect_to = default_redirect_to
|
||||
return redirect_to
|
||||
|
||||
|
||||
|
||||
_user_display_callable = None
|
||||
|
||||
def user_display(user):
|
||||
global _user_display_callable
|
||||
if not _user_display_callable:
|
||||
f = getattr(settings, "ACCOUNT_USER_DISPLAY",
|
||||
lambda user: user.username)
|
||||
_user_display_callable = import_callable(f)
|
||||
return _user_display_callable(user)
|
||||
|
||||
|
||||
# def has_openid(request):
|
||||
# """
|
||||
# Given a HttpRequest determine whether the OpenID on it is associated thus
|
||||
# allowing caller to know whether OpenID is good to depend on.
|
||||
# """
|
||||
# from django_openid.models import UserOpenidAssociation
|
||||
# for association in UserOpenidAssociation.objects.filter(user=request.user):
|
||||
# if association.openid == unicode(request.openid):
|
||||
# return True
|
||||
# return False
|
||||
|
||||
|
||||
def perform_login(request, user, redirect_url=None):
|
||||
# not is_active: social users are redirected to a template
|
||||
# local users are stopped due to form validation checking is_active
|
||||
assert user.is_active
|
||||
if (app_settings.EMAIL_VERIFICATION
|
||||
and not EmailAddress.objects.filter(user=user,
|
||||
verified=True).exists()):
|
||||
send_email_confirmation(user, request=request)
|
||||
return render(request,
|
||||
"account/verification_sent.html",
|
||||
{ "email": user.email })
|
||||
# HACK: This may not be nice. The proper Django way is to use an
|
||||
# authentication backend, but I fail to see any added benefit
|
||||
# whereas I do see the downsides (having to bother the integrator
|
||||
# to set up authentication backends in settings.py
|
||||
if not hasattr(user, 'backend'):
|
||||
user.backend = "django.contrib.auth.backends.ModelBackend"
|
||||
user_logged_in.send(sender=user.__class__, request=request, user=user)
|
||||
login(request, user)
|
||||
messages.add_message(request, messages.SUCCESS,
|
||||
ugettext("Successfully signed in as %(user)s.") % { "user": user_display(user) } )
|
||||
|
||||
if not redirect_url:
|
||||
redirect_url = get_default_redirect(request)
|
||||
return HttpResponseRedirect(redirect_url)
|
||||
|
||||
|
||||
def complete_signup(request, user, success_url):
|
||||
return perform_login(request, user, redirect_url=success_url)
|
||||
|
||||
|
||||
def send_email_confirmation(user, request=None):
|
||||
"""
|
||||
E-mail verification mails are sent:
|
||||
a) Explicitly: when a user signs up
|
||||
b) Implicitly: when a user attempts to log in using an unverified
|
||||
e-mail while EMAIL_VERIFICATION is mandatory.
|
||||
|
||||
Especially in case of b), we want to limit the number of mails
|
||||
sent (consider a user retrying a few times), which is why there is
|
||||
a cooldown period before sending a new mail.
|
||||
"""
|
||||
COOLDOWN_PERIOD = timedelta(minutes=3)
|
||||
email = user.email
|
||||
if email:
|
||||
try:
|
||||
email_address = EmailAddress.objects.get(user=user,
|
||||
email__iexact=email)
|
||||
email_confirmation_sent = EmailConfirmation.objects \
|
||||
.filter(sent__gt=now() - COOLDOWN_PERIOD,
|
||||
email_address=email_address) \
|
||||
.exists()
|
||||
if not email_confirmation_sent:
|
||||
EmailConfirmation.objects.send_confirmation(email_address)
|
||||
except EmailAddress.DoesNotExist:
|
||||
EmailAddress.objects.add_email(user, user.email)
|
||||
email_confirmation_sent = False
|
||||
if request and not email_confirmation_sent:
|
||||
messages.info(request,
|
||||
_(u"Confirmation e-mail sent to %(email)s") % {"email": email}
|
||||
)
|
||||
|
||||
def format_email_subject(subject):
|
||||
prefix = app_settings.EMAIL_SUBJECT_PREFIX
|
||||
if prefix is None:
|
||||
site = Site.objects.get_current()
|
||||
prefix = "[{name}] ".format(name=site.name)
|
||||
return prefix + unicode(subject)
|
||||
|
||||
|
||||
def sync_user_email_addresses(user):
|
||||
"""
|
||||
Keep user.email in sync with user.emailadress_set.
|
||||
|
||||
Under some circumstances the user.email may not have ended up as
|
||||
an EmailAddress record, e.g. in the case of manually created admin
|
||||
users.
|
||||
"""
|
||||
if user.email and not EmailAddress.objects.filter(user=user,
|
||||
email=user.email).exists():
|
||||
EmailAddress.objects.create(user=user,
|
||||
email=user.email,
|
||||
primary=False,
|
||||
verified=False)
|
||||
|
250
itf/allauth/account/views.py
Normal file
250
itf/allauth/account/views.py
Normal file
|
@ -0,0 +1,250 @@
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.contrib.sites.models import Site
|
||||
from django.http import HttpResponseRedirect, Http404
|
||||
from django.shortcuts import render_to_response, get_object_or_404
|
||||
from django.template import RequestContext
|
||||
from django.utils.http import base36_to_int
|
||||
from django.utils.translation import ugettext
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.tokens import default_token_generator
|
||||
from emailconfirmation.models import EmailAddress, EmailConfirmation
|
||||
|
||||
from allauth.utils import passthrough_login_redirect_url
|
||||
|
||||
from utils import get_default_redirect, complete_signup
|
||||
from forms import AddEmailForm, ChangePasswordForm
|
||||
from forms import LoginForm, ResetPasswordKeyForm
|
||||
from forms import ResetPasswordForm, SetPasswordForm, SignupForm
|
||||
from utils import sync_user_email_addresses
|
||||
|
||||
def login(request, **kwargs):
|
||||
form_class = kwargs.pop("form_class", LoginForm)
|
||||
template_name = kwargs.pop("template_name", "account/login.html")
|
||||
success_url = kwargs.pop("success_url", None)
|
||||
url_required = kwargs.pop("url_required", False)
|
||||
extra_context = kwargs.pop("extra_context", {})
|
||||
redirect_field_name = kwargs.pop("redirect_field_name", "next")
|
||||
|
||||
if extra_context is None:
|
||||
extra_context = {}
|
||||
if success_url is None:
|
||||
success_url = get_default_redirect(request, redirect_field_name)
|
||||
|
||||
if request.method == "POST" and not url_required:
|
||||
form = form_class(request.POST)
|
||||
if form.is_valid():
|
||||
return form.login(request, redirect_url=success_url)
|
||||
else:
|
||||
form = form_class()
|
||||
|
||||
ctx = {
|
||||
"form": form,
|
||||
"signup_url": passthrough_login_redirect_url(request,
|
||||
reverse("account_signup")),
|
||||
"site": Site.objects.get_current(),
|
||||
"url_required": url_required,
|
||||
"redirect_field_name": redirect_field_name,
|
||||
"redirect_field_value": request.REQUEST.get(redirect_field_name),
|
||||
}
|
||||
ctx.update(extra_context)
|
||||
return render_to_response(template_name, RequestContext(request, ctx))
|
||||
|
||||
|
||||
def signup(request, **kwargs):
|
||||
form_class = kwargs.pop("form_class", SignupForm)
|
||||
template_name = kwargs.pop("template_name", "account/signup.html")
|
||||
redirect_field_name = kwargs.pop("redirect_field_name", "next")
|
||||
success_url = kwargs.pop("success_url", None)
|
||||
|
||||
if success_url is None:
|
||||
success_url = get_default_redirect(request, redirect_field_name)
|
||||
|
||||
if request.method == "POST":
|
||||
form = form_class(request.POST)
|
||||
if form.is_valid():
|
||||
user = form.save(request=request)
|
||||
return complete_signup(request, user, success_url)
|
||||
|
||||
else:
|
||||
form = form_class()
|
||||
ctx = {"form": form,
|
||||
"login_url": passthrough_login_redirect_url(request,
|
||||
reverse("account_login")),
|
||||
"redirect_field_name": redirect_field_name,
|
||||
"redirect_field_value": request.REQUEST.get(redirect_field_name) }
|
||||
return render_to_response(template_name, RequestContext(request, ctx))
|
||||
|
||||
|
||||
@login_required
|
||||
def email(request, **kwargs):
|
||||
form_class = kwargs.pop("form_class", AddEmailForm)
|
||||
template_name = kwargs.pop("template_name", "account/email.html")
|
||||
sync_user_email_addresses(request.user)
|
||||
if request.method == "POST" and request.user.is_authenticated():
|
||||
if request.POST.has_key("action_add"):
|
||||
add_email_form = form_class(request.user, request.POST)
|
||||
if add_email_form.is_valid():
|
||||
add_email_form.save()
|
||||
messages.add_message(request, messages.INFO,
|
||||
ugettext(u"Confirmation e-mail sent to %(email)s") % {
|
||||
"email": add_email_form.cleaned_data["email"]
|
||||
}
|
||||
)
|
||||
add_email_form = form_class() # @@@
|
||||
else:
|
||||
add_email_form = form_class()
|
||||
if request.POST.get("email"):
|
||||
if request.POST.has_key("action_send"):
|
||||
email = request.POST["email"]
|
||||
try:
|
||||
email_address = EmailAddress.objects.get(
|
||||
user=request.user,
|
||||
email=email,
|
||||
)
|
||||
messages.add_message(request, messages.INFO,
|
||||
ugettext("Confirmation e-mail sent to %(email)s") % {
|
||||
"email": email,
|
||||
}
|
||||
)
|
||||
EmailConfirmation.objects.send_confirmation(email_address)
|
||||
except EmailAddress.DoesNotExist:
|
||||
pass
|
||||
elif request.POST.has_key("action_remove"):
|
||||
email = request.POST["email"]
|
||||
try:
|
||||
email_address = EmailAddress.objects.get(
|
||||
user=request.user,
|
||||
email=email
|
||||
)
|
||||
email_address.delete()
|
||||
messages.add_message(request, messages.SUCCESS,
|
||||
ugettext("Removed e-mail address %(email)s") % {
|
||||
"email": email,
|
||||
}
|
||||
)
|
||||
except EmailAddress.DoesNotExist:
|
||||
pass
|
||||
elif request.POST.has_key("action_primary"):
|
||||
email = request.POST["email"]
|
||||
email_address = EmailAddress.objects.get(
|
||||
user=request.user,
|
||||
email=email,
|
||||
)
|
||||
email_address.set_as_primary()
|
||||
messages.add_message(request, messages.SUCCESS,
|
||||
ugettext("Primary e-mail address set"))
|
||||
else:
|
||||
add_email_form = form_class()
|
||||
ctx = { "add_email_form": add_email_form }
|
||||
return render_to_response(template_name, RequestContext(request, ctx))
|
||||
|
||||
|
||||
@login_required
|
||||
def password_change(request, **kwargs):
|
||||
|
||||
form_class = kwargs.pop("form_class", ChangePasswordForm)
|
||||
template_name = kwargs.pop("template_name", "account/password_change.html")
|
||||
|
||||
if not request.user.has_usable_password():
|
||||
return HttpResponseRedirect(reverse(password_set))
|
||||
|
||||
if request.method == "POST":
|
||||
password_change_form = form_class(request.user, request.POST)
|
||||
if password_change_form.is_valid():
|
||||
password_change_form.save()
|
||||
messages.add_message(request, messages.SUCCESS,
|
||||
ugettext(u"Password successfully changed.")
|
||||
)
|
||||
password_change_form = form_class(request.user)
|
||||
else:
|
||||
password_change_form = form_class(request.user)
|
||||
ctx = { "password_change_form": password_change_form }
|
||||
return render_to_response(template_name, RequestContext(request, ctx))
|
||||
|
||||
|
||||
@login_required
|
||||
def password_set(request, **kwargs):
|
||||
|
||||
form_class = kwargs.pop("form_class", SetPasswordForm)
|
||||
template_name = kwargs.pop("template_name", "account/password_set.html")
|
||||
|
||||
if request.user.has_usable_password():
|
||||
return HttpResponseRedirect(reverse(password_change))
|
||||
|
||||
if request.method == "POST":
|
||||
password_set_form = form_class(request.user, request.POST)
|
||||
if password_set_form.is_valid():
|
||||
password_set_form.save()
|
||||
messages.add_message(request, messages.SUCCESS,
|
||||
ugettext(u"Password successfully set.")
|
||||
)
|
||||
return HttpResponseRedirect(reverse(password_change))
|
||||
else:
|
||||
password_set_form = form_class(request.user)
|
||||
ctx = { "password_set_form": password_set_form }
|
||||
return render_to_response(template_name, RequestContext(request, ctx))
|
||||
|
||||
|
||||
def password_reset(request, **kwargs):
|
||||
|
||||
form_class = kwargs.pop("form_class", ResetPasswordForm)
|
||||
template_name = kwargs.pop("template_name", "account/password_reset.html")
|
||||
|
||||
if request.method == "POST":
|
||||
password_reset_form = form_class(request.POST)
|
||||
if password_reset_form.is_valid():
|
||||
password_reset_form.save()
|
||||
return HttpResponseRedirect(reverse(password_reset_done))
|
||||
else:
|
||||
password_reset_form = form_class()
|
||||
|
||||
return render_to_response(template_name, RequestContext(request, { "password_reset_form": password_reset_form, }))
|
||||
|
||||
|
||||
def password_reset_done(request, **kwargs):
|
||||
|
||||
return render_to_response(kwargs.pop("template_name", "account/password_reset_done.html"), RequestContext(request, {}))
|
||||
|
||||
|
||||
def password_reset_from_key(request, uidb36, key, **kwargs):
|
||||
|
||||
form_class = kwargs.get("form_class", ResetPasswordKeyForm)
|
||||
template_name = kwargs.get("template_name", "account/password_reset_from_key.html")
|
||||
token_generator = kwargs.get("token_generator", default_token_generator)
|
||||
|
||||
# pull out user
|
||||
try:
|
||||
uid_int = base36_to_int(uidb36)
|
||||
except ValueError:
|
||||
raise Http404
|
||||
|
||||
user = get_object_or_404(User, id=uid_int)
|
||||
|
||||
if token_generator.check_token(user, key):
|
||||
if request.method == "POST":
|
||||
password_reset_key_form = form_class(request.POST, user=user, temp_key=key)
|
||||
if password_reset_key_form.is_valid():
|
||||
password_reset_key_form.save()
|
||||
messages.add_message(request, messages.SUCCESS,
|
||||
ugettext(u"Password successfully changed.")
|
||||
)
|
||||
password_reset_key_form = None
|
||||
else:
|
||||
password_reset_key_form = form_class()
|
||||
ctx = { "form": password_reset_key_form, }
|
||||
else:
|
||||
ctx = { "token_fail": True, }
|
||||
|
||||
return render_to_response(template_name, RequestContext(request, ctx))
|
||||
|
||||
|
||||
def logout(request, **kwargs):
|
||||
messages.add_message(request, messages.SUCCESS,
|
||||
ugettext("You have signed out.")
|
||||
)
|
||||
kwargs['template_name'] = kwargs.pop('template_name', 'account/logout.html')
|
||||
from django.contrib.auth.views import logout as _logout
|
||||
return _logout(request, **kwargs)
|
10
itf/allauth/app_settings.py
Normal file
10
itf/allauth/app_settings.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
from django.conf import settings
|
||||
|
||||
SOCIALACCOUNT_ENABLED = 'allauth.socialaccount' in settings.INSTALLED_APPS
|
||||
|
||||
if SOCIALACCOUNT_ENABLED:
|
||||
assert 'allauth.socialaccount.context_processors.socialaccount' \
|
||||
in settings.TEMPLATE_CONTEXT_PROCESSORS
|
||||
|
||||
LOGIN_REDIRECT_URL = getattr(settings, 'LOGIN_REDIRECT_URL', '/')
|
||||
|
BIN
itf/allauth/locale/nl/LC_MESSAGES/django.mo
Normal file
BIN
itf/allauth/locale/nl/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
689
itf/allauth/locale/nl/LC_MESSAGES/django.po
Normal file
689
itf/allauth/locale/nl/LC_MESSAGES/django.po
Normal file
|
@ -0,0 +1,689 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2012-06-22 23:00+0200\n"
|
||||
"PO-Revision-Date: 2012-06-22 23:04+0200\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: account/forms.py:48
|
||||
msgid "Password must be a minimum of {0} characters."
|
||||
msgstr "Het wachtwoord moet minimaal {0} tekens bevatten."
|
||||
|
||||
#: account/forms.py:55 account/forms.py:243 account/forms.py:393
|
||||
msgid "Password"
|
||||
msgstr "Wachtwoord"
|
||||
|
||||
#: account/forms.py:57
|
||||
msgid "Remember Me"
|
||||
msgstr "Onthouden"
|
||||
|
||||
#: account/forms.py:68
|
||||
msgid "E-mail address"
|
||||
msgstr "E-mail adres"
|
||||
|
||||
#: account/forms.py:69 account/forms.py:185 account/forms.py:346
|
||||
#: account/forms.py:410
|
||||
msgid "E-mail"
|
||||
msgstr "E-mail"
|
||||
|
||||
#: account/forms.py:74 account/forms.py:75 account/forms.py:174
|
||||
msgid "Username"
|
||||
msgstr "Gebruikersnaam"
|
||||
|
||||
#: account/forms.py:82
|
||||
msgid "Username or e-mail"
|
||||
msgstr "Gebruikersnaam of e-mail"
|
||||
|
||||
#: account/forms.py:83
|
||||
msgid "Login"
|
||||
msgstr "Inloggen"
|
||||
|
||||
#: account/forms.py:116
|
||||
msgid "This account is currently inactive."
|
||||
msgstr "Dit account is niet actief"
|
||||
|
||||
#: account/forms.py:120
|
||||
msgid "The e-mail address and/or password you specified are not correct."
|
||||
msgstr "Je e-mail adres en wachtwoord komen niet overeen."
|
||||
|
||||
#: account/forms.py:124
|
||||
msgid "The username and/or password you specified are not correct."
|
||||
msgstr "Je gebruikersnaam en wachtwoord komen niet overeen."
|
||||
|
||||
#: account/forms.py:127
|
||||
msgid "The login and/or password you specified are not correct."
|
||||
msgstr "Je login en wachtwoord komen niet overeen."
|
||||
|
||||
#: account/forms.py:188
|
||||
msgid "E-mail (optional)"
|
||||
msgstr "E-mail (optioneel)"
|
||||
|
||||
#: account/forms.py:199
|
||||
msgid "Usernames can only contain letters, numbers and underscores."
|
||||
msgstr ""
|
||||
"Gebruikersnamen mogen alleen letters, cijfers en liggende streepjes (_) "
|
||||
"bevatten."
|
||||
|
||||
#: account/forms.py:205
|
||||
msgid "This username is already taken. Please choose another."
|
||||
msgstr "Deze gebruikersnaam is al in gebruik. Kies a.u.b. een andere naam."
|
||||
|
||||
#: account/forms.py:213
|
||||
msgid "A user is registered with this e-mail address."
|
||||
msgstr "Er is al een gebruiker geregistreerd met dit e-mail adres."
|
||||
|
||||
#: account/forms.py:244 account/forms.py:394
|
||||
msgid "Password (again)"
|
||||
msgstr "Wachtwoord (bevestigen)"
|
||||
|
||||
#: account/forms.py:272 account/forms.py:383 account/forms.py:399
|
||||
#: account/forms.py:468
|
||||
msgid "You must type the same password each time."
|
||||
msgstr "Je moet hetzelfde wachtwoord twee keer intoetsen."
|
||||
|
||||
#: account/forms.py:308
|
||||
msgid "Your e-mail address has already been verified"
|
||||
msgstr "Je e-mail adres is al geverifieerd"
|
||||
|
||||
#: account/forms.py:317 account/utils.py:135 account/views.py:93
|
||||
#: account/views.py:109
|
||||
#, python-format
|
||||
msgid "Confirmation e-mail sent to %(email)s"
|
||||
msgstr "Bevestigings e-mail verzonden aan %(email)s"
|
||||
|
||||
#: account/forms.py:354
|
||||
msgid "This e-mail address already associated with this account."
|
||||
msgstr "Dit e-mail adres is al geassocieerd met dit account."
|
||||
|
||||
#: account/forms.py:355
|
||||
msgid "This e-mail address already associated with another account."
|
||||
msgstr "Dit e-mail adres is al geassocieerd met een ander account."
|
||||
|
||||
#: account/forms.py:371
|
||||
msgid "Current Password"
|
||||
msgstr "Huidig wachtwoord"
|
||||
|
||||
#: account/forms.py:372 account/forms.py:456
|
||||
msgid "New Password"
|
||||
msgstr "Nieuw wachtwoord"
|
||||
|
||||
#: account/forms.py:373 account/forms.py:457
|
||||
msgid "New Password (again)"
|
||||
msgstr "Nieuw wachtwoord (bevestigen)"
|
||||
|
||||
#: account/forms.py:377
|
||||
msgid "Please type your current password."
|
||||
msgstr "Geef je huidige wachtwoord op."
|
||||
|
||||
#: account/forms.py:420
|
||||
msgid "The e-mail address is not assigned to any user account"
|
||||
msgstr "Dit e-mail adres is niet bij ons bekend"
|
||||
|
||||
#: account/forms.py:439
|
||||
msgid "Password Reset E-mail"
|
||||
msgstr "Nieuw wachtwoord"
|
||||
|
||||
#: account/utils.py:96
|
||||
#, python-format
|
||||
msgid "Successfully signed in as %(user)s."
|
||||
msgstr "Je bent nu ingelogd als %(user)s."
|
||||
|
||||
#: account/views.py:125
|
||||
#, python-format
|
||||
msgid "Removed e-mail address %(email)s"
|
||||
msgstr "E-mail adres %(email)s verwijderd"
|
||||
|
||||
#: account/views.py:139
|
||||
msgid "Primary e-mail address set"
|
||||
msgstr "Primair e-mail adres ingesteld"
|
||||
|
||||
#: account/views.py:160 account/views.py:233
|
||||
msgid "Password successfully changed."
|
||||
msgstr "Wachtwoord wijziging geslaagd."
|
||||
|
||||
#: account/views.py:183
|
||||
msgid "Password successfully set."
|
||||
msgstr "Je wachtwoord is gewijzigd."
|
||||
|
||||
#: account/views.py:247 templates/account/logout.html:10
|
||||
msgid "You have signed out."
|
||||
msgstr "Je bent afgemeld."
|
||||
|
||||
#: socialaccount/forms.py:34
|
||||
msgid "Your local account has no password setup."
|
||||
msgstr "Je account heeft geen wachtwoord ingesteld."
|
||||
|
||||
#: socialaccount/forms.py:38
|
||||
msgid "Your local account has no verified e-mail address."
|
||||
msgstr "Je account heeft geen geverifieerd e-mail adres."
|
||||
|
||||
#: socialaccount/helpers.py:108
|
||||
msgid "The social account has been connected to your existing account"
|
||||
msgstr "Het externe account is gekoppeld aan je bestaande account"
|
||||
|
||||
#: socialaccount/views.py:58
|
||||
msgid "The social account has been disconnected"
|
||||
msgstr "Het externe account is ontkoppeld"
|
||||
|
||||
#: socialaccount/providers/oauth/client.py:79
|
||||
#, python-format
|
||||
msgid "Invalid response while obtaining request token from \"%s\"."
|
||||
msgstr ""
|
||||
"Ongeldig antwoord ontvangen tijdens het ophalen van een verzoeksleutel van "
|
||||
"\"%s\"."
|
||||
|
||||
#: socialaccount/providers/oauth/client.py:102
|
||||
#, python-format
|
||||
msgid "Invalid response while obtaining access token from \"%s\"."
|
||||
msgstr ""
|
||||
"Ongeldig antwoord ontvangen tijdens het ophalen van een toegangssleutel van "
|
||||
"\"%s\"."
|
||||
|
||||
#: socialaccount/providers/oauth/client.py:115
|
||||
#, python-format
|
||||
msgid "No request token saved for \"%s\"."
|
||||
msgstr "Geen verzoeksleutel opgeslagen voor \"%s\"."
|
||||
|
||||
#: socialaccount/providers/oauth/client.py:163
|
||||
#, python-format
|
||||
msgid "No access token saved for \"%s\"."
|
||||
msgstr "Geen toegangssleutel opgeslagen voor \"%s\"."
|
||||
|
||||
#: socialaccount/providers/oauth/client.py:183
|
||||
#, python-format
|
||||
msgid "No access to private resources at \"%s\"."
|
||||
msgstr "Geen toegang tot prive data bij \"%s\"."
|
||||
|
||||
#: templates/account/email.html:5
|
||||
msgid "Account"
|
||||
msgstr "Account"
|
||||
|
||||
#: templates/account/email.html:8
|
||||
msgid "E-mail Addresses"
|
||||
msgstr "E-mail adressen"
|
||||
|
||||
#: templates/account/email.html:10
|
||||
msgid "The following e-mail addresses are associated to your account:"
|
||||
msgstr "De volgende e-mail adressen zijn gekoppeld aan jouw account:"
|
||||
|
||||
#: templates/account/email.html:24
|
||||
msgid "Verified"
|
||||
msgstr "Geverifieerd"
|
||||
|
||||
#: templates/account/email.html:26
|
||||
msgid "Unverified"
|
||||
msgstr "Ongeverifieerd"
|
||||
|
||||
#: templates/account/email.html:28
|
||||
msgid "Primary"
|
||||
msgstr "Primair"
|
||||
|
||||
#: templates/account/email.html:34
|
||||
msgid "Make Primary"
|
||||
msgstr "Maak primair"
|
||||
|
||||
#: templates/account/email.html:35
|
||||
msgid "Re-send Verification"
|
||||
msgstr "Stuur verificatie e-mail opnieuw"
|
||||
|
||||
#: templates/account/email.html:36
|
||||
msgid "Remove"
|
||||
msgstr "Verwijder"
|
||||
|
||||
#: templates/account/email.html:43
|
||||
msgid "Warning:"
|
||||
msgstr "Waarschuwing:"
|
||||
|
||||
#: templates/account/email.html:43
|
||||
msgid ""
|
||||
"You currently do not have any e-mail address set up. You should really add "
|
||||
"an e-mail address so you can receive notifications, reset your password, etc."
|
||||
msgstr ""
|
||||
"Het is raadzaam een e-mail adres toe te voegen zodat je notificaties kunt "
|
||||
"ontvangen, je wachtwoord opnieuw kunt instellen, enz."
|
||||
|
||||
#: templates/account/email.html:48
|
||||
msgid "Add E-mail Address"
|
||||
msgstr "Voeg e-mail adres toe"
|
||||
|
||||
#: templates/account/email.html:53
|
||||
msgid "Add E-mail"
|
||||
msgstr "E-mail toevoegen"
|
||||
|
||||
#: templates/account/email.html:63
|
||||
msgid "Do you really want to remove the selected e-mail address?"
|
||||
msgstr "Wil je het geselecteerde e-mail adres echt verwijderen?"
|
||||
|
||||
#: templates/account/login.html:6 templates/account/login.html.py:11
|
||||
#: templates/account/login.html:43
|
||||
msgid "Sign In"
|
||||
msgstr "Aanmelden"
|
||||
|
||||
#: templates/account/login.html:16
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Please sign in with one\n"
|
||||
"of your existing third party accounts. Or, <a \n"
|
||||
"href=\"%(signup_url)s\">sign up</a> for a %(site_name)s account and sign in\n"
|
||||
"below:"
|
||||
msgstr ""
|
||||
"Meld je aan met een van je bestaande externe accounts. Of, <a \n"
|
||||
"href=\"%(signup_url)s\">registreer</a> voor een %(site_name)s account en "
|
||||
"meld je hiermee aan:"
|
||||
|
||||
#: templates/account/login.html:27
|
||||
msgid "or"
|
||||
msgstr "of"
|
||||
|
||||
#: templates/account/login.html:42
|
||||
msgid "Forgot Password?"
|
||||
msgstr "Wachtwoord vergeten?"
|
||||
|
||||
#: templates/account/logout.html:5 templates/account/logout.html.py:8
|
||||
msgid "Signed Out"
|
||||
msgstr "Afgemeld"
|
||||
|
||||
#: templates/account/password_change.html:4
|
||||
#: templates/account/password_change.html:7
|
||||
#: templates/account/password_change.html:12
|
||||
#: templates/account/password_reset_from_key.html:4
|
||||
#: templates/account/password_reset_from_key.html:7
|
||||
msgid "Change Password"
|
||||
msgstr "Wachtwoord wijzigen"
|
||||
|
||||
#: templates/account/password_delete.html:5
|
||||
#: templates/account/password_delete.html:8
|
||||
msgid "Delete Password"
|
||||
msgstr "Wis wachtwoord"
|
||||
|
||||
#: templates/account/password_delete.html:9
|
||||
msgid ""
|
||||
"You may delete your password since you are currently logged in using OpenID."
|
||||
msgstr "Je kunt je wachtwoord wissen omdat je via OpenID bent ingelogd."
|
||||
|
||||
#: templates/account/password_delete.html:12
|
||||
msgid "delete my password"
|
||||
msgstr "Wis mijn wachtwoord"
|
||||
|
||||
#: templates/account/password_delete_done.html:5
|
||||
#: templates/account/password_delete_done.html:8
|
||||
msgid "Password Deleted"
|
||||
msgstr "Wachtwoord gewist"
|
||||
|
||||
#: templates/account/password_delete_done.html:9
|
||||
msgid "Your password has been deleted."
|
||||
msgstr "Je wachtwoord is gewist."
|
||||
|
||||
#: templates/account/password_reset.html:6
|
||||
#: templates/account/password_reset.html:10
|
||||
#: templates/account/password_reset_done.html:6
|
||||
#: templates/account/password_reset_done.html:9
|
||||
msgid "Password Reset"
|
||||
msgstr "Nieuw wachtwoord"
|
||||
|
||||
#: templates/account/password_reset.html:15
|
||||
msgid ""
|
||||
"Forgotten your password? Enter your e-mail address below, and we'll send you "
|
||||
"an e-mail allowing you to reset it."
|
||||
msgstr ""
|
||||
"Wachtwoord vergeten? Vul je e-mail adres in en we sturen je een e-mail "
|
||||
"waarmee je een nieuw wachtwoord kunt instellen."
|
||||
|
||||
#: templates/account/password_reset.html:20
|
||||
msgid "Reset My Password"
|
||||
msgstr "Herstel mijn wachtwoord"
|
||||
|
||||
#: templates/account/password_reset.html:23
|
||||
#, python-format
|
||||
msgid ""
|
||||
"If you have any trouble resetting your password, contact us at <a href="
|
||||
"\"mailto:%(CONTACT_EMAIL)s\">%(CONTACT_EMAIL)s</a>."
|
||||
msgstr ""
|
||||
"Als je problemen hebt je wachtwoord opnieuw in te stellen, neem dan contact "
|
||||
"op met <a href=\"mailto:%(CONTACT_EMAIL)s\">%(CONTACT_EMAIL)s</a>."
|
||||
|
||||
#: templates/account/password_reset_done.html:15
|
||||
#, python-format
|
||||
msgid ""
|
||||
"We have sent you an e-mail. If you do not receive it within a few minutes, "
|
||||
"contact us at <a href=\"mailto:%(CONTACT_EMAIL)s\">%(CONTACT_EMAIL)s</a>."
|
||||
msgstr ""
|
||||
"We hebben je een e-mail verstuurd. Als je deze niet binnen enkele minuten "
|
||||
"ontvangen hebt, neem dan contact op met <a href=\"mailto:%(CONTACT_EMAIL)s\">"
|
||||
"%(CONTACT_EMAIL)s</a>."
|
||||
|
||||
#: templates/account/password_reset_from_key.html:7
|
||||
msgid "Bad Token"
|
||||
msgstr "Ongeldige sleutel"
|
||||
|
||||
#: templates/account/password_reset_from_key.html:11
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The password reset link was invalid, possibly because it has already been "
|
||||
"used. Please request a <a href=\"%(passwd_reset_url)s\">new password reset</"
|
||||
"a>."
|
||||
msgstr ""
|
||||
"De link om je wachtwoord opnieuw in te stellen is niet geldig. Mogelijk is "
|
||||
"deze al een keer gebruikt. <a href=\"%(passwd_reset_url)s\">Herstel je "
|
||||
"wachtwoord</a> opnieuw."
|
||||
|
||||
#: templates/account/password_reset_from_key.html:17
|
||||
msgid "change password"
|
||||
msgstr "Wachtwoord wijzigen"
|
||||
|
||||
#: templates/account/password_reset_from_key.html:20
|
||||
msgid "Your password is now changed."
|
||||
msgstr "Je wachtwoord is gewijzigd."
|
||||
|
||||
#: templates/account/password_reset_key_message.txt:1
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You're receiving this e-mail because you or someone else has requested a "
|
||||
"password for your user account at %(site_domain)s.\n"
|
||||
"It can be safely ignored if you did not request a password reset. Click the "
|
||||
"link below to reset your password.\n"
|
||||
"\n"
|
||||
"%(password_reset_url)s\n"
|
||||
"\n"
|
||||
"In case you forgot, your username is %(username)s.\n"
|
||||
"\n"
|
||||
"Thanks for using our site!\n"
|
||||
msgstr ""
|
||||
"Je ontvangt deze mail omdat er een verzoek is ingelegd om het wachtwoord "
|
||||
"behorende bij je %(site_domain)s account opnieuw in te stellen. Je kunt deze "
|
||||
"gerust mail negeren als je dit niet zelf gedaan hebt. Anders, klik op de "
|
||||
"volgende link om je wachtwoord opnieuw in te stellen.\n"
|
||||
"\n"
|
||||
"%(password_reset_url)s\n"
|
||||
"\n"
|
||||
"Deze link hoort bij je account met gebruikersnaam %(username)s.\n"
|
||||
"\n"
|
||||
"Bedankt voor het gebruik van onze site!\n"
|
||||
|
||||
#: templates/account/password_set.html:5 templates/account/password_set.html:8
|
||||
#: templates/account/password_set.html:13
|
||||
msgid "Set Password"
|
||||
msgstr "Zet wachtwoord"
|
||||
|
||||
#: templates/account/signup.html:5 templates/socialaccount/signup.html:5
|
||||
msgid "Signup"
|
||||
msgstr "Registreren"
|
||||
|
||||
#: templates/account/signup.html:8 templates/account/signup.html.py:21
|
||||
#: templates/socialaccount/signup.html:8
|
||||
#: templates/socialaccount/signup.html:19
|
||||
msgid "Sign Up"
|
||||
msgstr "Registreren"
|
||||
|
||||
#: templates/account/signup.html:13
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Already have an account? Then please <a href=\"%(login_url)s\">sign in</a>."
|
||||
msgstr "Heb je al een account? <a href=\"%(login_url)s\">Meld je dan aan</a>."
|
||||
|
||||
#: templates/account/verification_sent.html:5
|
||||
#: templates/account/verification_sent.html:8
|
||||
#: templates/account/verified_email_required.html:5
|
||||
#: templates/account/verified_email_required.html:8
|
||||
msgid "Verify Your E-mail Address"
|
||||
msgstr "Verifieer je e-mail adres"
|
||||
|
||||
#: templates/account/verification_sent.html:10
|
||||
#, python-format
|
||||
msgid ""
|
||||
"We have sent you an e-mail to <b>%(email)s</b> for verification. Follow the "
|
||||
"link provided to finalize the signup process. If you do not receive it "
|
||||
"within a few minutes, contact us at <a href=\"mailto:%(CONTACT_EMAIL)s\">"
|
||||
"%(CONTACT_EMAIL)s</a>."
|
||||
msgstr ""
|
||||
"We hebben een e-mail verstuurd aan <b>%(email)s</b> ter verificatie. Volg de "
|
||||
"link in deze mail om je registratie af te sluiten. Als je de e-mail niet "
|
||||
"binnen enkele minuten ontvangt, neem dan contact op met <a href=\"mailto:"
|
||||
"%(CONTACT_EMAIL)s\">%(CONTACT_EMAIL)s</a>."
|
||||
|
||||
#: templates/account/verified_email_required.html:12
|
||||
msgid ""
|
||||
"This part of the site requires us to verify that\n"
|
||||
"you are who you claim to be. For this purpose, we require that you\n"
|
||||
"verify ownership of your e-mail address. "
|
||||
msgstr ""
|
||||
"Voor dit gedeelte van de site is het nodig dat we je identiteit\n"
|
||||
"verifiëren. Via een verificatie e-mail kunnen we controleren dat je\n"
|
||||
"daadwerkelijk toegang hebt tot het opgegeven e-mail adres."
|
||||
|
||||
#: templates/account/verified_email_required.html:16
|
||||
#, python-format
|
||||
msgid ""
|
||||
"We have sent an e-mail to you for\n"
|
||||
"verification. Please click on the link inside this\n"
|
||||
"e-mail. If you do not receive it within a few minutes, contact us\n"
|
||||
"at <a href=\"mailto:%(CONTACT_EMAIL)s\">%(CONTACT_EMAIL)s</a>. \n"
|
||||
msgstr ""
|
||||
"Volg de link in de verificatie e-mail om de controle af te ronden. Als je de\n"
|
||||
"e-mail niet binnen enkele minuten ontvangt, neem dan contact op met <a\n"
|
||||
"href=\"mailto:%(CONTACT_EMAIL)s\">%(CONTACT_EMAIL)s</a>. \n"
|
||||
|
||||
#: templates/account/verified_email_required.html:22
|
||||
#, python-format
|
||||
msgid ""
|
||||
"<strong>Note:</strong> you can still <a href=\"%(email_url)s\">change your e-"
|
||||
"mail address</a>."
|
||||
msgstr "<strong>Merk op:</strong> je kunt altijd <a href=\"%(email_url)s\">je e-mail adres wijzigen</a>."
|
||||
|
||||
#: templates/account/snippets/already_logged_in.html:5
|
||||
msgid "Note"
|
||||
msgstr "Notitie"
|
||||
|
||||
#: templates/account/snippets/already_logged_in.html:5
|
||||
#, python-format
|
||||
msgid "you are already logged in as %(user_display)s."
|
||||
msgstr "je bent al ingelogd als %(user_display)s."
|
||||
|
||||
#: templates/emailconfirmation/confirm_email.html:6
|
||||
#: templates/emailconfirmation/confirm_email.html:12
|
||||
msgid "E-mail Address Confirmation"
|
||||
msgstr "E-mail adres bevestiging"
|
||||
|
||||
#: templates/emailconfirmation/confirm_email.html:16
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You have confirmed that <a href=\"mailto:%(email)s\">%(email)s</a> is an e-"
|
||||
"mail address for user %(user_display)s."
|
||||
msgstr ""
|
||||
"Je hebt bevestigd dat <a href=\"mailto:%(email)s\">%(email)s</a> een e-mail "
|
||||
"adres is voor gebruiker %(user_display)s."
|
||||
|
||||
#: templates/emailconfirmation/confirm_email.html:18
|
||||
msgid "Invalid confirmation key."
|
||||
msgstr "Ongeldige bevestigingssleutel."
|
||||
|
||||
#: templates/emailconfirmation/email_confirmation_message.txt:1
|
||||
#, python-format
|
||||
msgid ""
|
||||
"User %(user_display)s at %(site_name)s has given this as an email address.\n"
|
||||
"\n"
|
||||
"To confirm this is correct, go to %(activate_url)s\n"
|
||||
msgstr ""
|
||||
"Gebruiker %(user_display)s van %(site_name)s heeft dit als e-mail adres "
|
||||
"opgegeven.\n"
|
||||
"\n"
|
||||
"Bezoek de volgende link en bevestig dat dit correct is: %(activate_url)s\n"
|
||||
|
||||
#: templates/emailconfirmation/email_confirmation_subject.txt:1
|
||||
msgid "Confirm E-mail Address"
|
||||
msgstr "Bevestig e-mail adres"
|
||||
|
||||
#: templates/openid/login.html:9
|
||||
msgid "OpenID Sign In"
|
||||
msgstr "Aanmelden via OpenID"
|
||||
|
||||
#: templates/socialaccount/account_inactive.html:5
|
||||
#: templates/socialaccount/account_inactive.html:8
|
||||
msgid "Account Inactive"
|
||||
msgstr "Account inactief"
|
||||
|
||||
#: templates/socialaccount/account_inactive.html:10
|
||||
msgid "This account is inactive."
|
||||
msgstr "Dit account is niet actief"
|
||||
|
||||
#: templates/socialaccount/authentication_error.html:5
|
||||
#: templates/socialaccount/authentication_error.html:8
|
||||
msgid "Social Network Login Failure"
|
||||
msgstr "Aanmelden Mislukt"
|
||||
|
||||
#: templates/socialaccount/authentication_error.html:10
|
||||
msgid ""
|
||||
"An error occured while attempting to login via your social network account."
|
||||
msgstr ""
|
||||
"Er is een fout opgetreden toen we je wilde inloggen via je externe account."
|
||||
|
||||
#: templates/socialaccount/connections.html:5
|
||||
#: templates/socialaccount/connections.html:8
|
||||
msgid "Account Connections"
|
||||
msgstr "Account Connecties"
|
||||
|
||||
#: templates/socialaccount/connections.html:11
|
||||
msgid ""
|
||||
"You can sign in to your account using any of the following third party "
|
||||
"accounts:"
|
||||
msgstr "Je kunt jezelf aanmelden met een van de volgende externe accounts:"
|
||||
|
||||
#: templates/socialaccount/connections.html:46
|
||||
msgid "Add a 3rd Party Account"
|
||||
msgstr "Voeg een extern account toe"
|
||||
|
||||
#: templates/socialaccount/login_cancelled.html:5
|
||||
#: templates/socialaccount/login_cancelled.html:9
|
||||
msgid "Login Cancelled"
|
||||
msgstr "Aanmelden geannuleerd"
|
||||
|
||||
#: templates/socialaccount/login_cancelled.html:13
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You decided to cancel logging in to our site using one of your exisiting "
|
||||
"accounts. If this was a mistake, please proceed to <a href=\"%(login_url)s"
|
||||
"\">sign in</a>."
|
||||
msgstr ""
|
||||
"Je hebt het aanmelden via een extern account geannuleerd. Als dit een "
|
||||
"vergissing was, <a href=\"%(login_url)s\">meld je dan opnieuw aan</a>."
|
||||
|
||||
#: templates/socialaccount/signup.html:10
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You are about to use your %(provider_name)s account to login to \n"
|
||||
"%(site_name)s. As a final step, please complete the following form:"
|
||||
msgstr ""
|
||||
"Om bij %(site_name)s in te kunnen loggen via %(provider_name)s hebben we de "
|
||||
"volgende gegevens nodig:"
|
||||
|
||||
#~ msgid "OpenID"
|
||||
#~ msgstr "OpenID"
|
||||
|
||||
#~ msgid "Already have an account?"
|
||||
#~ msgstr "Heb je al een account?"
|
||||
|
||||
#~ msgid "Sign in"
|
||||
#~ msgstr "Aanmelden"
|
||||
|
||||
#~ msgid "Language"
|
||||
#~ msgstr "Taal"
|
||||
|
||||
#~ msgid "Pinax can be used in your preferred language."
|
||||
#~ msgstr "Deze site kan in jouw voorkeurstaal gebruikt worden."
|
||||
|
||||
#~ msgid "Change my language"
|
||||
#~ msgstr "Verander mijn taal"
|
||||
|
||||
#~ msgid "Timezone"
|
||||
#~ msgstr "Tijdzone"
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid ""
|
||||
#~ "You're receiving this e-mail because you requested a password reset\n"
|
||||
#~ "for your user account at Pinax.\n"
|
||||
#~ "\n"
|
||||
#~ "Your new password is: %(new_password)s\n"
|
||||
#~ "\n"
|
||||
#~ "Your username, in case you've forgotten: %(username)s\n"
|
||||
#~ "\n"
|
||||
#~ "You should log in as soon as possible and change your password.\n"
|
||||
#~ "\n"
|
||||
#~ "Thanks for using our site!\n"
|
||||
#~ msgstr ""
|
||||
#~ "Je ontvangt deze mail omdat er een verzoek is ingelegd om het wachtwoord\n"
|
||||
#~ "behorende bij je %(site_name)s account opnieuw in te stellen.\n"
|
||||
#~ "\n"
|
||||
#~ "Je nieuwe wachtwoord is: %(new_password)s\n"
|
||||
#~ "\n"
|
||||
#~ "Je gebruikersnaam, voor het geval je die vergeten bent, is: %(username)s\n"
|
||||
#~ "\n"
|
||||
#~ "Je moet zo snel mogelijk inloggen en bovenstaand wachtwoord veranderen.\n"
|
||||
#~ "\n"
|
||||
#~ "Bedankt voor het gebruik van onze site!\n"
|
||||
|
||||
#~ msgid "If checked you will stay logged in for 3 weeks"
|
||||
#~ msgstr "Bij 'Onthouden' blijf je ingelogd gedurende 3 weken"
|
||||
|
||||
#~ msgid "Timezone successfully updated."
|
||||
#~ msgstr "Tijdzone gewijzigd."
|
||||
|
||||
#~ msgid "Language successfully updated."
|
||||
#~ msgstr "Taal gewijzigd."
|
||||
|
||||
#~ msgid "E-Mail Addresses"
|
||||
#~ msgstr "E-mail adressen"
|
||||
|
||||
#~ msgid "None"
|
||||
#~ msgstr "Geen"
|
||||
|
||||
#~ msgid "add"
|
||||
#~ msgstr "Voeg toe"
|
||||
|
||||
#~ msgid "Log In"
|
||||
#~ msgstr "Inloggen"
|
||||
|
||||
#~ msgid "Log in"
|
||||
#~ msgstr "Inloggen"
|
||||
|
||||
#~ msgid "Logout"
|
||||
#~ msgstr "Afmelden"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "When you receive the new password, you should <a href=\"%(login_url)s"
|
||||
#~ "\">log in</a> and change it as soon as possible."
|
||||
#~ msgstr ""
|
||||
#~ "Zodra je het nieuwe wachtwoord ontvangen hebt moet je zo snel mogelijk <a "
|
||||
#~ "href=\"%(login_url)s\">inloggen</a> en het wachtwoord wijzigen."
|
||||
|
||||
#~ msgid "You are already logged in."
|
||||
#~ msgstr "Je bent al ingelogd."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "By clicking \"Sign Up\", you are indicating that you have read and agree "
|
||||
#~ "to the <a href=\"%(terms_url)s\">Terms of Use</a> and <a href="
|
||||
#~ "\"%(privacy_url)s\">Privacy Policy</a>."
|
||||
#~ msgstr ""
|
||||
#~ "Door te registreren geef je aan dat je de <a href=\"%(terms_url)s"
|
||||
#~ "\">gebruiksvoorwaarden</a> en de <a href=\"%(privacy_url)s\">privacy "
|
||||
#~ "policy</a> gelezen hebt en ermee akkoord gaat."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "If you have any trouble creating your account, contact us at <a href="
|
||||
#~ "\"mailto:%(contact_email)s\">%(contact_email)s</a>."
|
||||
#~ msgstr ""
|
||||
#~ "Als je problemen hebt om een account aan te maken, neem dan contact op "
|
||||
#~ "met <a href=\"mailto:%(contact_email)s\">%(contact_email)s</a>."
|
||||
|
||||
#~ msgid "Log in »"
|
||||
#~ msgstr "Inloggen"
|
0
itf/allauth/models.py
Normal file
0
itf/allauth/models.py
Normal file
0
itf/allauth/socialaccount/__init__.py
Normal file
0
itf/allauth/socialaccount/__init__.py
Normal file
21
itf/allauth/socialaccount/admin.py
Normal file
21
itf/allauth/socialaccount/admin.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from models import SocialApp, SocialAccount, SocialToken
|
||||
|
||||
|
||||
class SocialAppAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'provider', 'site')
|
||||
|
||||
|
||||
class SocialAccountAdmin(admin.ModelAdmin):
|
||||
raw_id_fields = ('user',)
|
||||
list_display = ('user', 'uid', 'provider')
|
||||
|
||||
|
||||
class SocialTokenAdmin(admin.ModelAdmin):
|
||||
raw_id_fields = ('app', 'account',)
|
||||
list_display = ('app', 'account', 'token')
|
||||
|
||||
admin.site.register(SocialApp, SocialAppAdmin)
|
||||
admin.site.register(SocialToken, SocialTokenAdmin)
|
||||
admin.site.register(SocialAccount, SocialAccountAdmin)
|
21
itf/allauth/socialaccount/app_settings.py
Normal file
21
itf/allauth/socialaccount/app_settings.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
from django.conf import settings
|
||||
|
||||
from allauth.account import app_settings as account_settings
|
||||
|
||||
# Request e-mail address from 3rd party account provider? E.g. OpenID AX
|
||||
QUERY_EMAIL = getattr(settings, "SOCIALACCOUNT_QUERY_EMAIL",
|
||||
account_settings.EMAIL_REQUIRED)
|
||||
|
||||
# Attempt to bypass the signup form by using fields (e.g. username,
|
||||
# email) retrieved from the social account provider. If a conflict
|
||||
# arises due to a duplicate e-mail signup form will still kick in.
|
||||
AUTO_SIGNUP = getattr(settings, "SOCIALACCOUNT_AUTO_SIGNUP", True)
|
||||
|
||||
# Enable support for django-avatar. When enabled, the profile image of
|
||||
# the user is copied locally into django-avatar at signup.
|
||||
AVATAR_SUPPORT = getattr(settings, "SOCIALACCOUNT_AVATAR_SUPPORT",
|
||||
'avatar' in settings.INSTALLED_APPS)
|
||||
|
||||
|
||||
# Provider specific settings
|
||||
PROVIDERS = getattr(settings, "SOCIALACCOUNT_PROVIDERS", {})
|
5
itf/allauth/socialaccount/context_processors.py
Normal file
5
itf/allauth/socialaccount/context_processors.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
import providers
|
||||
|
||||
def socialaccount(request):
|
||||
ctx = { 'providers': providers.registry.get_list() }
|
||||
return dict(socialaccount=ctx)
|
60
itf/allauth/socialaccount/fields.py
Normal file
60
itf/allauth/socialaccount/fields.py
Normal file
|
@ -0,0 +1,60 @@
|
|||
# Courtesy of django-social-auth
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.utils import simplejson
|
||||
from django.utils.encoding import smart_unicode
|
||||
|
||||
|
||||
class JSONField(models.TextField):
|
||||
"""Simple JSON field that stores python structures as JSON strings
|
||||
on database.
|
||||
"""
|
||||
__metaclass__ = models.SubfieldBase
|
||||
|
||||
def to_python(self, value):
|
||||
"""
|
||||
Convert the input JSON value into python structures, raises
|
||||
django.core.exceptions.ValidationError if the data can't be converted.
|
||||
"""
|
||||
if self.blank and not value:
|
||||
return None
|
||||
if isinstance(value, basestring):
|
||||
try:
|
||||
return simplejson.loads(value)
|
||||
except Exception, e:
|
||||
raise ValidationError(str(e))
|
||||
else:
|
||||
return value
|
||||
|
||||
def validate(self, value, model_instance):
|
||||
"""Check value is a valid JSON string, raise ValidationError on
|
||||
error."""
|
||||
if isinstance(value, basestring):
|
||||
super(JSONField, self).validate(value, model_instance)
|
||||
try:
|
||||
simplejson.loads(value)
|
||||
except Exception, e:
|
||||
raise ValidationError(str(e))
|
||||
|
||||
def get_prep_value(self, value):
|
||||
"""Convert value to JSON string before save"""
|
||||
try:
|
||||
return simplejson.dumps(value)
|
||||
except Exception, e:
|
||||
raise ValidationError(str(e))
|
||||
|
||||
def value_to_string(self, obj):
|
||||
"""Return value from object converted to string properly"""
|
||||
return smart_unicode(self.get_prep_value(self._get_val_from_obj(obj)))
|
||||
|
||||
def value_from_object(self, obj):
|
||||
"""Return value dumped to string."""
|
||||
return self.get_prep_value(self._get_val_from_obj(obj))
|
||||
|
||||
|
||||
try:
|
||||
from south.modelsinspector import add_introspection_rules
|
||||
add_introspection_rules([], ["^allauth\.socialaccount\.fields\.JSONField"])
|
||||
except:
|
||||
pass
|
55
itf/allauth/socialaccount/forms.py
Normal file
55
itf/allauth/socialaccount/forms.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from django import forms
|
||||
|
||||
from emailconfirmation.models import EmailAddress
|
||||
from models import SocialAccount
|
||||
from allauth.account.forms import BaseSignupForm
|
||||
from allauth.account.utils import send_email_confirmation
|
||||
|
||||
|
||||
class SignupForm(BaseSignupForm):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.sociallogin = kwargs.pop('sociallogin')
|
||||
user = self.sociallogin.account.user
|
||||
initial = { 'email': user.email or '',
|
||||
'username': user.username or '',
|
||||
'first_name': user.first_name or '',
|
||||
'last_name': user.last_name or '' }
|
||||
kwargs['initial'] = initial
|
||||
super(SignupForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def save(self, request=None):
|
||||
new_user = self.create_user()
|
||||
self.sociallogin.account.user = new_user
|
||||
self.sociallogin.save()
|
||||
super(SignupForm, self).save(new_user)
|
||||
# Confirmation last (save may alter first_name etc -- used in mail)
|
||||
send_email_confirmation(new_user, request=request)
|
||||
return new_user
|
||||
|
||||
|
||||
class DisconnectForm(forms.Form):
|
||||
account = forms.ModelChoiceField(queryset=SocialAccount.objects.none(),
|
||||
widget=forms.RadioSelect,
|
||||
required=True)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.user = kwargs.pop('user')
|
||||
self.accounts = SocialAccount.objects.filter(user=self.user)
|
||||
super(DisconnectForm, self).__init__(*args, **kwargs)
|
||||
self.fields['account'].queryset = self.accounts
|
||||
|
||||
def clean(self):
|
||||
if len(self.accounts) == 1:
|
||||
# No usable password would render the local account unusable
|
||||
if not self.user.has_usable_password():
|
||||
raise forms.ValidationError(_("Your local account has no password setup."))
|
||||
# No email address, no password reset
|
||||
if EmailAddress.objects.filter(user=self.user,
|
||||
verified=True).count() == 0:
|
||||
raise forms.ValidationError(_("Your local account has no verified e-mail address."))
|
||||
return self.cleaned_data
|
||||
|
||||
def save(self):
|
||||
self.cleaned_data['account'].delete()
|
179
itf/allauth/socialaccount/helpers.py
Normal file
179
itf/allauth/socialaccount/helpers.py
Normal file
|
@ -0,0 +1,179 @@
|
|||
from django.contrib import messages
|
||||
from django.shortcuts import render_to_response
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.template import RequestContext
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.template.defaultfilters import slugify
|
||||
|
||||
from allauth.utils import get_login_redirect_url, \
|
||||
generate_unique_username, email_address_exists
|
||||
from allauth.account.utils import send_email_confirmation, \
|
||||
perform_login, complete_signup
|
||||
from allauth.account import app_settings as account_settings
|
||||
|
||||
import app_settings
|
||||
|
||||
def _process_signup(request, sociallogin):
|
||||
# If email is specified, check for duplicate and if so, no auto signup.
|
||||
auto_signup = app_settings.AUTO_SIGNUP
|
||||
email = sociallogin.account.user.email
|
||||
if auto_signup:
|
||||
# Let's check if auto_signup is really possible...
|
||||
if email:
|
||||
if account_settings.UNIQUE_EMAIL:
|
||||
if email_address_exists(email):
|
||||
# Oops, another user already has this address. We
|
||||
# cannot simply connect this social account to the
|
||||
# existing user. Reason is that the email adress may
|
||||
# not be verified, meaning, the user may be a hacker
|
||||
# that has added your email address to his account in
|
||||
# the hope that you fall in his trap. We cannot check
|
||||
# on 'email_address.verified' either, because
|
||||
# 'email_address' is not guaranteed to be verified.
|
||||
auto_signup = False
|
||||
# FIXME: We redirect to signup form -- user will
|
||||
# see email address conflict only after posting
|
||||
# whereas we detected it here already.
|
||||
elif account_settings.EMAIL_REQUIRED:
|
||||
# Nope, email is required and we don't have it yet...
|
||||
auto_signup = False
|
||||
if not auto_signup:
|
||||
request.session['socialaccount_sociallogin'] = sociallogin
|
||||
url = reverse('socialaccount_signup')
|
||||
ret = HttpResponseRedirect(url)
|
||||
else:
|
||||
# FIXME: There is some duplication of logic inhere
|
||||
# (create user, send email, in active etc..)
|
||||
u = sociallogin.account.user
|
||||
u.username = generate_unique_username(u.username
|
||||
or email
|
||||
or 'user')
|
||||
u.last_name = (u.last_name or '') \
|
||||
[0:User._meta.get_field('last_name').max_length]
|
||||
u.first_name = (u.first_name or '') \
|
||||
[0:User._meta.get_field('first_name').max_length]
|
||||
u.email = email or ''
|
||||
u.set_unusable_password()
|
||||
sociallogin.save()
|
||||
send_email_confirmation(u, request=request)
|
||||
ret = complete_social_signup(request, sociallogin)
|
||||
return ret
|
||||
|
||||
|
||||
def _login_social_account(request, sociallogin):
|
||||
user = sociallogin.account.user
|
||||
if not user.is_active:
|
||||
ret = render_to_response(
|
||||
'socialaccount/account_inactive.html',
|
||||
{},
|
||||
context_instance=RequestContext(request))
|
||||
else:
|
||||
ret = perform_login(request, user,
|
||||
redirect_url=sociallogin.get_redirect_url())
|
||||
return ret
|
||||
|
||||
|
||||
def render_authentication_error(request, extra_context={}):
|
||||
return render_to_response(
|
||||
"socialaccount/authentication_error.html",
|
||||
extra_context, context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def complete_social_login(request, sociallogin):
|
||||
assert not sociallogin.is_existing
|
||||
sociallogin.lookup()
|
||||
if request.user.is_authenticated():
|
||||
if sociallogin.is_existing:
|
||||
# Existing social account, existing user
|
||||
if sociallogin.account.user != request.user:
|
||||
# Social account of other user. Simply logging in may
|
||||
# not be correct in the case that the user was
|
||||
# attempting to hook up another social account to his
|
||||
# existing user account. For now, this scenario is not
|
||||
# supported. Issue is that one cannot simply remove
|
||||
# the social account from the other user, as that may
|
||||
# render the account unusable.
|
||||
pass
|
||||
ret = _login_social_account(request, sociallogin)
|
||||
else:
|
||||
# New social account
|
||||
sociallogin.account.user = request.user
|
||||
sociallogin.save()
|
||||
default_next = reverse('socialaccount_connections')
|
||||
next = sociallogin.get_redirect_url(fallback=default_next)
|
||||
messages.add_message(request, messages.INFO,
|
||||
_('The social account has been connected'
|
||||
' to your existing account'))
|
||||
return HttpResponseRedirect(next)
|
||||
else:
|
||||
if sociallogin.is_existing:
|
||||
# Login existing user
|
||||
ret = _login_social_account(request, sociallogin)
|
||||
else:
|
||||
# New social user
|
||||
ret = _process_signup(request, sociallogin)
|
||||
return ret
|
||||
|
||||
|
||||
def _name_from_url(url):
|
||||
"""
|
||||
>>> _name_from_url('http://google.com/dir/file.ext')
|
||||
u'file.ext'
|
||||
>>> _name_from_url('http://google.com/dir/')
|
||||
u'dir'
|
||||
>>> _name_from_url('http://google.com/dir')
|
||||
u'dir'
|
||||
>>> _name_from_url('http://google.com/dir/..')
|
||||
u'dir'
|
||||
>>> _name_from_url('http://google.com/dir/../')
|
||||
u'dir'
|
||||
>>> _name_from_url('http://google.com')
|
||||
u'google.com'
|
||||
>>> _name_from_url('http://google.com/dir/subdir/file..ext')
|
||||
u'file.ext'
|
||||
"""
|
||||
from urlparse import urlparse
|
||||
|
||||
p = urlparse(url)
|
||||
for base in (p.path.split('/')[-1],
|
||||
p.path,
|
||||
p.netloc):
|
||||
name = ".".join(filter(lambda s: s,
|
||||
map(slugify, base.split("."))))
|
||||
if name:
|
||||
return name
|
||||
|
||||
|
||||
def _copy_avatar(request, user, account):
|
||||
import urllib2
|
||||
from django.core.files.base import ContentFile
|
||||
from avatar.models import Avatar
|
||||
url = account.get_avatar_url()
|
||||
if url:
|
||||
ava = Avatar(user=user)
|
||||
ava.primary = Avatar.objects.filter(user=user).count() == 0
|
||||
try:
|
||||
content = urllib2.urlopen(url).read()
|
||||
name = _name_from_url(url)
|
||||
ava.avatar.save(name, ContentFile(content))
|
||||
except IOError:
|
||||
# Let's nog make a big deal out of this...
|
||||
pass
|
||||
|
||||
|
||||
def complete_social_signup(request, sociallogin):
|
||||
if app_settings.AVATAR_SUPPORT:
|
||||
_copy_avatar(request, sociallogin.account.user, sociallogin.account)
|
||||
return complete_signup(request,
|
||||
sociallogin.account.user,
|
||||
sociallogin.get_redirect_url())
|
||||
|
||||
|
||||
# TODO: Factor out callable importing functionality
|
||||
# See: account.utils.user_display
|
||||
def import_path(path):
|
||||
modname, _, attr = path.rpartition('.')
|
||||
m = __import__(modname, fromlist=[attr])
|
||||
return getattr(m, attr)
|
73
itf/allauth/socialaccount/migrations/0001_initial.py
Normal file
73
itf/allauth/socialaccount/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,73 @@
|
|||
# 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 model 'SocialAccount'
|
||||
db.create_table('socialaccount_socialaccount', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
|
||||
('last_login', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
|
||||
('date_joined', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
|
||||
))
|
||||
db.send_create_signal('socialaccount', ['SocialAccount'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting model 'SocialAccount'
|
||||
db.delete_table('socialaccount_socialaccount')
|
||||
|
||||
|
||||
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']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", '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'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", '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'})
|
||||
},
|
||||
'socialaccount.socialaccount': {
|
||||
'Meta': {'object_name': 'SocialAccount'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['socialaccount']
|
150
itf/allauth/socialaccount/migrations/0002_genericmodels.py
Normal file
150
itf/allauth/socialaccount/migrations/0002_genericmodels.py
Normal file
|
@ -0,0 +1,150 @@
|
|||
# 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 model 'SocialToken'
|
||||
db.create_table('socialaccount_socialtoken', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('app', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['socialaccount.SocialApp'])),
|
||||
('account', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['socialaccount.SocialAccount'])),
|
||||
('token', self.gf('django.db.models.fields.CharField')(max_length=200)),
|
||||
('token_secret', self.gf('django.db.models.fields.CharField')(max_length=200, blank=True)),
|
||||
))
|
||||
db.send_create_signal('socialaccount', ['SocialToken'])
|
||||
|
||||
# Adding unique constraint on 'SocialToken', fields ['app', 'account']
|
||||
db.create_unique('socialaccount_socialtoken', ['app_id', 'account_id'])
|
||||
|
||||
# Adding model 'SocialApp'
|
||||
db.create_table('socialaccount_socialapp', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('site', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['sites.Site'])),
|
||||
('provider', self.gf('django.db.models.fields.CharField')(max_length=30)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=40)),
|
||||
('key', self.gf('django.db.models.fields.CharField')(max_length=100)),
|
||||
('secret', self.gf('django.db.models.fields.CharField')(max_length=100)),
|
||||
))
|
||||
db.send_create_signal('socialaccount', ['SocialApp'])
|
||||
|
||||
# Adding field 'SocialAccount.provider'
|
||||
db.add_column('socialaccount_socialaccount', 'provider', self.gf('django.db.models.fields.CharField')(default='', max_length=30, blank=True), keep_default=False)
|
||||
|
||||
# Adding field 'SocialAccount.uid'
|
||||
db.add_column('socialaccount_socialaccount', 'uid', self.gf('django.db.models.fields.CharField')(default='', max_length=255, blank=True), keep_default=False)
|
||||
|
||||
# Adding field 'SocialAccount.extra_data'
|
||||
db.add_column('socialaccount_socialaccount', 'extra_data', self.gf('allauth.socialaccount.fields.JSONField')(default='{}'), keep_default=False)
|
||||
|
||||
# Changing field 'SocialAccount.last_login'
|
||||
db.alter_column('socialaccount_socialaccount', 'last_login', self.gf('django.db.models.fields.DateTimeField')(auto_now=True))
|
||||
|
||||
# Changing field 'SocialAccount.date_joined'
|
||||
db.alter_column('socialaccount_socialaccount', 'date_joined', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True))
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Removing unique constraint on 'SocialToken', fields ['app', 'account']
|
||||
db.delete_unique('socialaccount_socialtoken', ['app_id', 'account_id'])
|
||||
|
||||
# Deleting model 'SocialToken'
|
||||
db.delete_table('socialaccount_socialtoken')
|
||||
|
||||
# Deleting model 'SocialApp'
|
||||
db.delete_table('socialaccount_socialapp')
|
||||
|
||||
# Deleting field 'SocialAccount.provider'
|
||||
db.delete_column('socialaccount_socialaccount', 'provider')
|
||||
|
||||
# Deleting field 'SocialAccount.uid'
|
||||
db.delete_column('socialaccount_socialaccount', 'uid')
|
||||
|
||||
# Deleting field 'SocialAccount.extra_data'
|
||||
db.delete_column('socialaccount_socialaccount', 'extra_data')
|
||||
|
||||
# Changing field 'SocialAccount.last_login'
|
||||
db.alter_column('socialaccount_socialaccount', 'last_login', self.gf('django.db.models.fields.DateTimeField')())
|
||||
|
||||
# Changing field 'SocialAccount.date_joined'
|
||||
db.alter_column('socialaccount_socialaccount', 'date_joined', self.gf('django.db.models.fields.DateTimeField')())
|
||||
|
||||
|
||||
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']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", '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'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", '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'})
|
||||
},
|
||||
'sites.site': {
|
||||
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
|
||||
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'socialaccount.socialaccount': {
|
||||
'Meta': {'object_name': 'SocialAccount'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'extra_data': ('allauth.socialaccount.fields.JSONField', [], {'default': "'{}'"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'provider': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'uid': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
},
|
||||
'socialaccount.socialapp': {
|
||||
'Meta': {'object_name': 'SocialApp'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'key': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
|
||||
'provider': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
|
||||
'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"})
|
||||
},
|
||||
'socialaccount.socialtoken': {
|
||||
'Meta': {'unique_together': "(('app', 'account'),)", 'object_name': 'SocialToken'},
|
||||
'account': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['socialaccount.SocialAccount']"}),
|
||||
'app': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['socialaccount.SocialApp']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'token': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
|
||||
'token_secret': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['socialaccount']
|
|
@ -0,0 +1,96 @@
|
|||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
depends_on = (('facebook', '0003_tosocialaccount'),
|
||||
('twitter', '0003_tosocialaccount'),
|
||||
('openid', '0002_tosocialaccount'))
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Adding unique constraint on 'SocialAccount', fields ['uid', 'provider']
|
||||
db.create_unique('socialaccount_socialaccount', ['uid', 'provider'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Removing unique constraint on 'SocialAccount', fields ['uid', 'provider']
|
||||
db.delete_unique('socialaccount_socialaccount', ['uid', 'provider'])
|
||||
|
||||
|
||||
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']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", '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'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", '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'})
|
||||
},
|
||||
'sites.site': {
|
||||
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
|
||||
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'socialaccount.socialaccount': {
|
||||
'Meta': {'unique_together': "(('provider', 'uid'),)", 'object_name': 'SocialAccount'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'extra_data': ('allauth.socialaccount.fields.JSONField', [], {'default': "'{}'"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'provider': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
|
||||
'uid': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
},
|
||||
'socialaccount.socialapp': {
|
||||
'Meta': {'object_name': 'SocialApp'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'key': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
|
||||
'provider': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
|
||||
'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"})
|
||||
},
|
||||
'socialaccount.socialtoken': {
|
||||
'Meta': {'unique_together': "(('app', 'account'),)", 'object_name': 'SocialToken'},
|
||||
'account': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['socialaccount.SocialAccount']"}),
|
||||
'app': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['socialaccount.SocialApp']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'token': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
|
||||
'token_secret': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['socialaccount']
|
0
itf/allauth/socialaccount/migrations/__init__.py
Normal file
0
itf/allauth/socialaccount/migrations/__init__.py
Normal file
197
itf/allauth/socialaccount/models.py
Normal file
197
itf/allauth/socialaccount/models.py
Normal file
|
@ -0,0 +1,197 @@
|
|||
from django.db import models
|
||||
from django.contrib.auth import authenticate
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.sites.models import Site
|
||||
from django.utils import simplejson
|
||||
|
||||
import allauth.app_settings
|
||||
from allauth.utils import get_login_redirect_url
|
||||
|
||||
import providers
|
||||
from fields import JSONField
|
||||
|
||||
|
||||
class SocialAppManager(models.Manager):
|
||||
def get_current(self, provider):
|
||||
site = Site.objects.get_current()
|
||||
return self.get(site=site,
|
||||
provider=provider)
|
||||
|
||||
|
||||
class SocialApp(models.Model):
|
||||
objects = SocialAppManager()
|
||||
|
||||
site = models.ForeignKey(Site)
|
||||
provider = models.CharField(max_length=30,
|
||||
choices=providers.registry.as_choices())
|
||||
name = models.CharField(max_length=40)
|
||||
key = models.CharField(max_length=100,
|
||||
help_text='App ID, or consumer key')
|
||||
secret = models.CharField(max_length=100,
|
||||
help_text='API secret, or consumer secret')
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class SocialAccount(models.Model):
|
||||
user = models.ForeignKey(User)
|
||||
provider = models.CharField(max_length=30,
|
||||
choices=providers.registry.as_choices())
|
||||
# Just in case you're wondering if an OpenID identity URL is going
|
||||
# to fit in a 'uid':
|
||||
#
|
||||
# Ideally, URLField(max_length=1024, unique=True) would be used
|
||||
# for identity. However, MySQL has a max_length limitation of 255
|
||||
# for URLField. How about models.TextField(unique=True) then?
|
||||
# Well, that won't work either for MySQL due to another bug[1]. So
|
||||
# the only way out would be to drop the unique constraint, or
|
||||
# switch to shorter identity URLs. Opted for the latter, as [2]
|
||||
# suggests that identity URLs are supposed to be short anyway, at
|
||||
# least for the old spec.
|
||||
#
|
||||
# [1] http://code.djangoproject.com/ticket/2495.
|
||||
# [2] http://openid.net/specs/openid-authentication-1_1.html#limits
|
||||
|
||||
uid = models.CharField(max_length=255)
|
||||
last_login = models.DateTimeField(auto_now=True)
|
||||
date_joined = models.DateTimeField(auto_now_add=True)
|
||||
extra_data = JSONField(default='{}')
|
||||
|
||||
class Meta:
|
||||
unique_together = ('provider', 'uid')
|
||||
|
||||
def authenticate(self):
|
||||
return authenticate(account=self)
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.user)
|
||||
|
||||
def get_profile_url(self):
|
||||
return self.get_provider_account().get_profile_url()
|
||||
|
||||
def get_avatar_url(self):
|
||||
return self.get_provider_account().get_avatar_url()
|
||||
|
||||
def get_provider(self):
|
||||
return providers.registry.by_id(self.provider)
|
||||
|
||||
def get_provider_account(self):
|
||||
return self.get_provider().wrap_account(self)
|
||||
|
||||
|
||||
class SocialToken(models.Model):
|
||||
app = models.ForeignKey(SocialApp)
|
||||
account = models.ForeignKey(SocialAccount)
|
||||
token = models.CharField(max_length=200)
|
||||
token_secret = models.CharField(max_length=200, blank=True)
|
||||
|
||||
class Meta:
|
||||
unique_together = ('app', 'account')
|
||||
|
||||
def __unicode__(self):
|
||||
return self.token
|
||||
|
||||
|
||||
class SocialLogin(object):
|
||||
"""
|
||||
Represents a social user that is in the process of being logged
|
||||
in. This consists of the following information:
|
||||
|
||||
`account` (`SocialAccount` instance): The social account being
|
||||
logged in. Providers are not responsible for checking whether or
|
||||
not an account already exists or not. Therefore, a provider
|
||||
typically creates a new (unsaved) `SocialAccount` instance. The
|
||||
`User` instance pointed to by the account (`account.user`) may be
|
||||
prefilled by the provider for use as a starting point later on
|
||||
during the signup process.
|
||||
|
||||
`token` (`SocialToken` instance): An optional access token token
|
||||
that results from performing a successful authentication
|
||||
handshake.
|
||||
|
||||
`state` (`dict`): The state to be preserved during the
|
||||
authentication handshake. Note that this state may end up in the
|
||||
url (e.g. OAuth2 `state` parameter) -- do not put any secrets in
|
||||
there. It currently only contains the url to redirect to after
|
||||
login.
|
||||
"""
|
||||
|
||||
def __init__(self, account, token=None):
|
||||
if token:
|
||||
assert token.account is None or token.account == account
|
||||
token.account = account
|
||||
self.token = token
|
||||
self.account = account
|
||||
self.state = {}
|
||||
|
||||
def save(self):
|
||||
user = self.account.user
|
||||
user.save()
|
||||
self.account.user = user
|
||||
self.account.save()
|
||||
if self.token:
|
||||
self.token.account = self.account
|
||||
self.token.save()
|
||||
|
||||
@property
|
||||
def is_existing(self):
|
||||
"""
|
||||
Account is temporary, not yet backed by a database record.
|
||||
"""
|
||||
return self.account.pk
|
||||
|
||||
def lookup(self):
|
||||
"""
|
||||
Lookup existing account, if any.
|
||||
"""
|
||||
assert not self.is_existing
|
||||
try:
|
||||
a = SocialAccount.objects.get(provider=self.account.provider,
|
||||
uid=self.account.uid)
|
||||
# Update account
|
||||
a.extra_data = self.account.extra_data
|
||||
self.account = a
|
||||
a.save()
|
||||
# Update token
|
||||
if self.token:
|
||||
assert not self.token.pk
|
||||
try:
|
||||
t = SocialToken.objects.get(account=self.account,
|
||||
app=self.token.app)
|
||||
t.token = self.token.token
|
||||
t.token_secret = self.token.token_secret
|
||||
t.save()
|
||||
self.token = t
|
||||
except SocialToken.DoesNotExist:
|
||||
self.token.account = a
|
||||
self.token.save()
|
||||
except SocialAccount.DoesNotExist:
|
||||
pass
|
||||
|
||||
def get_redirect_url(self,
|
||||
fallback=allauth.app_settings.LOGIN_REDIRECT_URL):
|
||||
url = self.state.get('next') or fallback
|
||||
return url
|
||||
|
||||
@classmethod
|
||||
def state_from_request(cls, request):
|
||||
state = {}
|
||||
next = get_login_redirect_url(request, fallback=None)
|
||||
if next:
|
||||
state['next'] = next
|
||||
return state
|
||||
|
||||
@classmethod
|
||||
def marshall_state(cls, request):
|
||||
state = cls.state_from_request(request)
|
||||
return simplejson.dumps(state)
|
||||
|
||||
@classmethod
|
||||
def unmarshall_state(cls, state_string):
|
||||
if state_string:
|
||||
state = simplejson.loads(state_string)
|
||||
else:
|
||||
state = {}
|
||||
return state
|
||||
|
||||
|
36
itf/allauth/socialaccount/providers/__init__.py
Normal file
36
itf/allauth/socialaccount/providers/__init__.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
from django.conf import settings
|
||||
from django.utils import importlib
|
||||
|
||||
class ProviderRegistry(object):
|
||||
def __init__(self):
|
||||
self.provider_map = {}
|
||||
self.loaded = False
|
||||
|
||||
def get_list(self):
|
||||
self.load()
|
||||
return self.provider_map.values()
|
||||
|
||||
def register(self, cls):
|
||||
self.load()
|
||||
self.provider_map[cls.id] = cls()
|
||||
|
||||
def by_id(self, id):
|
||||
self.load()
|
||||
return self.provider_map[id]
|
||||
|
||||
def as_choices(self):
|
||||
self.load()
|
||||
for provider in self.get_list():
|
||||
yield (provider.id, provider.name)
|
||||
|
||||
def load(self):
|
||||
if not self.loaded:
|
||||
for app in settings.INSTALLED_APPS:
|
||||
provider_module = app + '.provider'
|
||||
try:
|
||||
importlib.import_module(provider_module)
|
||||
except ImportError:
|
||||
pass
|
||||
self.loaded = True
|
||||
|
||||
registry = ProviderRegistry()
|
52
itf/allauth/socialaccount/providers/base.py
Normal file
52
itf/allauth/socialaccount/providers/base.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
from allauth.socialaccount import app_settings
|
||||
from allauth.socialaccount.models import SocialApp
|
||||
|
||||
class Provider(object):
|
||||
def get_login_url(self, request, next=None, **kwargs):
|
||||
"""
|
||||
Builds the URL to redirect to when initiating a login for this
|
||||
provider.
|
||||
"""
|
||||
raise NotImplementedError, "get_login_url() for " + self.name
|
||||
|
||||
def get_app(self, request):
|
||||
return SocialApp.objects.get_current(self.id)
|
||||
|
||||
def media_js(self, request):
|
||||
"""
|
||||
Some providers may require extra scripts (e.g. a Facebook connect)
|
||||
"""
|
||||
return ''
|
||||
|
||||
def wrap_account(self, social_account):
|
||||
return self.account_class(social_account)
|
||||
|
||||
def get_settings(self):
|
||||
return app_settings.PROVIDERS.get(self.id, {})
|
||||
|
||||
class ProviderAccount(object):
|
||||
def __init__(self, social_account):
|
||||
self.account = social_account
|
||||
|
||||
def get_profile_url(self):
|
||||
return None
|
||||
|
||||
def get_avatar_url(self):
|
||||
return None
|
||||
|
||||
def get_brand(self):
|
||||
"""
|
||||
Returns a dict containing an id and name identifying the
|
||||
brand. Useful when displaying logos next to accounts in
|
||||
templates.
|
||||
|
||||
For most providers, these are identical to the provider. For
|
||||
OpenID however, the brand can derived from the OpenID identity
|
||||
url.
|
||||
"""
|
||||
provider = self.account.get_provider()
|
||||
return dict(id=provider.id,
|
||||
name=provider.name)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.get_brand()['name']
|
|
@ -0,0 +1,850 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<locales>
|
||||
<locale>
|
||||
<englishName>Afrikaans</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>af_ZA</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Arabic</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>ar_AR</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Azerbaijani</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>az_AZ</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Belarusian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>be_BY</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Bulgarian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>bg_BG</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Bengali</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>bn_IN</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Bosnian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>bs_BA</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Catalan</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>ca_ES</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Czech</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>cs_CZ</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Welsh</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>cy_GB</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Danish</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>da_DK</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>German</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>de_DE</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Greek</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>el_GR</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>English (UK)</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>en_GB</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>English (Pirate)</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>en_PI</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>English (Upside Down)</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>en_UD</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>English (US)</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>en_US</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Esperanto</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>eo_EO</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Spanish (Spain)</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>es_ES</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Spanish</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>es_LA</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Estonian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>et_EE</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Basque</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>eu_ES</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Persian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>fa_IR</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Leet Speak</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>fb_LT</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Finnish</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>fi_FI</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Faroese</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>fo_FO</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>French (Canada)</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>fr_CA</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>French (France)</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>fr_FR</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Frisian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>fy_NL</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Irish</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>ga_IE</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Galician</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>gl_ES</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Hebrew</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>he_IL</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Hindi</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>hi_IN</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Croatian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>hr_HR</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Hungarian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>hu_HU</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Armenian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>hy_AM</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Indonesian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>id_ID</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Icelandic</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>is_IS</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Italian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>it_IT</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Japanese</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>ja_JP</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Georgian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>ka_GE</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Khmer</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>km_KH</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Korean</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>ko_KR</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Kurdish</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>ku_TR</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Latin</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>la_VA</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Lithuanian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>lt_LT</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Latvian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>lv_LV</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Macedonian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>mk_MK</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Malayalam</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>ml_IN</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Malay</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>ms_MY</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Norwegian (bokmal)</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>nb_NO</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Nepali</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>ne_NP</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Dutch</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>nl_NL</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Norwegian (nynorsk)</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>nn_NO</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Punjabi</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>pa_IN</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Polish</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>pl_PL</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Pashto</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>ps_AF</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Portuguese (Brazil)</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>pt_BR</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Portuguese (Portugal)</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>pt_PT</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Romanian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>ro_RO</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Russian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>ru_RU</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Slovak</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>sk_SK</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Slovenian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>sl_SI</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Albanian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>sq_AL</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Serbian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>sr_RS</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Swedish</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>sv_SE</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Swahili</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>sw_KE</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Tamil</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>ta_IN</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Telugu</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>te_IN</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Thai</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>th_TH</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Filipino</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>tl_PH</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Turkish</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>tr_TR</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Ukrainian</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>uk_UA</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Vietnamese</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>vi_VN</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Simplified Chinese (China)</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>zh_CN</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Traditional Chinese (Hong Kong)</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>zh_HK</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
<locale>
|
||||
<englishName>Traditional Chinese (Taiwan)</englishName>
|
||||
<codes>
|
||||
<code>
|
||||
<standard>
|
||||
<name>FB</name>
|
||||
<representation>zh_TW</representation>
|
||||
</standard>
|
||||
</code>
|
||||
</codes>
|
||||
</locale>
|
||||
</locales>
|
5
itf/allauth/socialaccount/providers/facebook/forms.py
Normal file
5
itf/allauth/socialaccount/providers/facebook/forms.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django import forms
|
||||
|
||||
|
||||
class FacebookConnectForm(forms.Form):
|
||||
access_token = forms.CharField(required=True)
|
70
itf/allauth/socialaccount/providers/facebook/locale.py
Normal file
70
itf/allauth/socialaccount/providers/facebook/locale.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
# Default locale mapping for the Facebook JS SDK
|
||||
# The list of supported locales is at
|
||||
# https://www.facebook.com/translations/FacebookLocales.xml
|
||||
import os
|
||||
|
||||
from django.utils.translation import get_language, to_locale
|
||||
|
||||
|
||||
def _build_locale_table(filename_or_file):
|
||||
"""
|
||||
Parses the FacebookLocales.xml file and builds a dict relating every
|
||||
available language ('en, 'es, 'zh', ...) with a list of available regions
|
||||
for that language ('en' -> 'US', 'EN') and an (arbitrary) default region.
|
||||
"""
|
||||
# Require the XML parser module only if we want the default mapping
|
||||
from xml.dom.minidom import parse
|
||||
|
||||
dom = parse(filename_or_file)
|
||||
|
||||
reps = dom.getElementsByTagName('representation')
|
||||
locs = map(lambda r: r.childNodes[0].data, reps)
|
||||
|
||||
locale_map = {}
|
||||
for loc in locs:
|
||||
lang, _, reg = loc.partition('_')
|
||||
lang_map = locale_map.setdefault(lang, {'regs': [], 'default': reg})
|
||||
lang_map['regs'].append(reg)
|
||||
|
||||
# Default region overrides (arbitrary)
|
||||
locale_map['en']['default'] = 'US'
|
||||
# Special case: Use es_ES for Spain and es_LA for everything else
|
||||
locale_map['es']['default'] = 'LA'
|
||||
locale_map['zh']['default'] = 'CN'
|
||||
locale_map['fr']['default'] = 'FR'
|
||||
locale_map['pt']['default'] = 'PT'
|
||||
|
||||
return locale_map
|
||||
|
||||
|
||||
def get_default_locale_callable():
|
||||
"""
|
||||
Wrapper function so that the default mapping is only built when needed
|
||||
"""
|
||||
exec_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
xml_path = os.path.join(exec_dir, 'data', 'FacebookLocales.xml')
|
||||
|
||||
fb_locales = _build_locale_table(xml_path)
|
||||
|
||||
def default_locale(request):
|
||||
"""
|
||||
Guess an appropiate FB locale based on the active Django locale.
|
||||
If the active locale is available, it is returned. Otherwise,
|
||||
it tries to return another locale with the same language. If there
|
||||
isn't one avaible, 'en_US' is returned.
|
||||
"""
|
||||
locale = to_locale(get_language())
|
||||
lang, _, reg = locale.partition('_')
|
||||
|
||||
lang_map = fb_locales.get(lang)
|
||||
if lang_map is not None:
|
||||
if reg in lang_map['regs']:
|
||||
chosen = lang + '_' + reg
|
||||
else:
|
||||
chosen = lang + '_' + lang_map['default']
|
||||
else:
|
||||
chosen = 'en_US'
|
||||
|
||||
return chosen
|
||||
|
||||
return default_locale
|
|
@ -0,0 +1,110 @@
|
|||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
depends_on = (('socialaccount', '0001_initial'),)
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Adding model 'FacebookApp'
|
||||
db.create_table('facebook_facebookapp', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('site', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['sites.Site'])),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=40)),
|
||||
('application_id', self.gf('django.db.models.fields.CharField')(max_length=80)),
|
||||
('api_key', self.gf('django.db.models.fields.CharField')(max_length=80)),
|
||||
('application_secret', self.gf('django.db.models.fields.CharField')(max_length=80)),
|
||||
))
|
||||
db.send_create_signal('facebook', ['FacebookApp'])
|
||||
|
||||
# Adding model 'FacebookAccount'
|
||||
db.create_table('facebook_facebookaccount', (
|
||||
('socialaccount_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['socialaccount.SocialAccount'], unique=True, primary_key=True)),
|
||||
('social_id', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
('link', self.gf('django.db.models.fields.URLField')(max_length=200)),
|
||||
))
|
||||
db.send_create_signal('facebook', ['FacebookAccount'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting model 'FacebookApp'
|
||||
db.delete_table('facebook_facebookapp')
|
||||
|
||||
# Deleting model 'FacebookAccount'
|
||||
db.delete_table('facebook_facebookaccount')
|
||||
|
||||
|
||||
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']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", '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'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", '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'})
|
||||
},
|
||||
'facebook.facebookaccount': {
|
||||
'Meta': {'object_name': 'FacebookAccount', '_ormbases': ['socialaccount.SocialAccount']},
|
||||
'link': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'social_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
|
||||
'socialaccount_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['socialaccount.SocialAccount']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'facebook.facebookapp': {
|
||||
'Meta': {'object_name': 'FacebookApp'},
|
||||
'api_key': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'application_id': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'application_secret': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
|
||||
'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"})
|
||||
},
|
||||
'sites.site': {
|
||||
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
|
||||
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'socialaccount.socialaccount': {
|
||||
'Meta': {'object_name': 'SocialAccount'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['facebook']
|
|
@ -0,0 +1,108 @@
|
|||
# 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 model 'FacebookAccessToken'
|
||||
db.create_table('facebook_facebookaccesstoken', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('app', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['facebook.FacebookApp'])),
|
||||
('account', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['facebook.FacebookAccount'])),
|
||||
('access_token', self.gf('django.db.models.fields.CharField')(max_length=200)),
|
||||
))
|
||||
db.send_create_signal('facebook', ['FacebookAccessToken'])
|
||||
|
||||
# Adding unique constraint on 'FacebookAccessToken', fields ['app', 'account']
|
||||
db.create_unique('facebook_facebookaccesstoken', ['app_id', 'account_id'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Removing unique constraint on 'FacebookAccessToken', fields ['app', 'account']
|
||||
db.delete_unique('facebook_facebookaccesstoken', ['app_id', 'account_id'])
|
||||
|
||||
# Deleting model 'FacebookAccessToken'
|
||||
db.delete_table('facebook_facebookaccesstoken')
|
||||
|
||||
|
||||
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']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", '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'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", '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'})
|
||||
},
|
||||
'facebook.facebookaccesstoken': {
|
||||
'Meta': {'unique_together': "(('app', 'account'),)", 'object_name': 'FacebookAccessToken'},
|
||||
'access_token': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
|
||||
'account': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['facebook.FacebookAccount']"}),
|
||||
'app': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['facebook.FacebookApp']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'facebook.facebookaccount': {
|
||||
'Meta': {'object_name': 'FacebookAccount', '_ormbases': ['socialaccount.SocialAccount']},
|
||||
'link': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'social_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
|
||||
'socialaccount_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['socialaccount.SocialAccount']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'facebook.facebookapp': {
|
||||
'Meta': {'object_name': 'FacebookApp'},
|
||||
'api_key': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'application_id': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'application_secret': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
|
||||
'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"})
|
||||
},
|
||||
'sites.site': {
|
||||
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
|
||||
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'socialaccount.socialaccount': {
|
||||
'Meta': {'object_name': 'SocialAccount'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['facebook']
|
|
@ -0,0 +1,142 @@
|
|||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import DataMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(DataMigration):
|
||||
|
||||
depends_on = (('socialaccount', '0002_genericmodels'),)
|
||||
|
||||
def forwards(self, orm):
|
||||
# Migrate FB apps
|
||||
app_id_to_sapp = {}
|
||||
for app in orm.FacebookApp.objects.all():
|
||||
sapp = orm['socialaccount.SocialApp'].objects \
|
||||
.create(site=app.site,
|
||||
provider='facebook',
|
||||
name=app.name,
|
||||
key=app.application_id,
|
||||
secret=app.application_secret)
|
||||
app_id_to_sapp[app.id] = sapp
|
||||
# Migrate FB accounts
|
||||
acc_id_to_sacc = {}
|
||||
for acc in orm.FacebookAccount.objects.all():
|
||||
sacc = acc.socialaccount_ptr
|
||||
sacc.uid = acc.social_id
|
||||
sacc.extra_data = { 'link': acc.link,
|
||||
'name': acc.name }
|
||||
sacc.provider = 'facebook'
|
||||
sacc.save()
|
||||
acc_id_to_sacc[acc.id] = sacc
|
||||
# Migrate tokens
|
||||
for token in orm.FacebookAccessToken.objects.all():
|
||||
sapp = app_id_to_sapp[token.app.id]
|
||||
sacc = acc_id_to_sacc[token.account.id]
|
||||
orm['socialaccount.SocialToken'].objects \
|
||||
.create(app=sapp,
|
||||
account=sacc,
|
||||
token=token.access_token,
|
||||
token_secret='')
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
"Write your backwards methods here."
|
||||
|
||||
|
||||
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']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", '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'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", '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'})
|
||||
},
|
||||
'facebook.facebookaccesstoken': {
|
||||
'Meta': {'unique_together': "(('app', 'account'),)", 'object_name': 'FacebookAccessToken'},
|
||||
'access_token': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
|
||||
'account': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['facebook.FacebookAccount']"}),
|
||||
'app': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['facebook.FacebookApp']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'facebook.facebookaccount': {
|
||||
'Meta': {'object_name': 'FacebookAccount', '_ormbases': ['socialaccount.SocialAccount']},
|
||||
'link': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'social_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
|
||||
'socialaccount_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['socialaccount.SocialAccount']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'facebook.facebookapp': {
|
||||
'Meta': {'object_name': 'FacebookApp'},
|
||||
'api_key': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'application_id': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'application_secret': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
|
||||
'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"})
|
||||
},
|
||||
'sites.site': {
|
||||
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
|
||||
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'socialaccount.socialaccount': {
|
||||
'Meta': {'object_name': 'SocialAccount'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'extra_data': ('allauth.socialaccount.fields.JSONField', [], {'default': "'{}'"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'provider': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'uid': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
},
|
||||
'socialaccount.socialapp': {
|
||||
'Meta': {'object_name': 'SocialApp'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'key': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
|
||||
'provider': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
|
||||
'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"})
|
||||
},
|
||||
'socialaccount.socialtoken': {
|
||||
'Meta': {'unique_together': "(('app', 'account'),)", 'object_name': 'SocialToken'},
|
||||
'account': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['socialaccount.SocialAccount']"}),
|
||||
'app': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['socialaccount.SocialApp']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'token': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
|
||||
'token_secret': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['socialaccount', 'facebook']
|
|
@ -0,0 +1,63 @@
|
|||
# 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):
|
||||
|
||||
# Removing unique constraint on 'FacebookAccessToken', fields ['app', 'account']
|
||||
db.delete_unique('facebook_facebookaccesstoken', ['app_id', 'account_id'])
|
||||
|
||||
# Deleting model 'FacebookApp'
|
||||
db.delete_table('facebook_facebookapp')
|
||||
|
||||
# Deleting model 'FacebookAccessToken'
|
||||
db.delete_table('facebook_facebookaccesstoken')
|
||||
|
||||
# Deleting model 'FacebookAccount'
|
||||
db.delete_table('facebook_facebookaccount')
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Adding model 'FacebookApp'
|
||||
db.create_table('facebook_facebookapp', (
|
||||
('application_id', self.gf('django.db.models.fields.CharField')(max_length=80)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=40)),
|
||||
('site', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['sites.Site'])),
|
||||
('api_key', self.gf('django.db.models.fields.CharField')(max_length=80)),
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('application_secret', self.gf('django.db.models.fields.CharField')(max_length=80)),
|
||||
))
|
||||
db.send_create_signal('facebook', ['FacebookApp'])
|
||||
|
||||
# Adding model 'FacebookAccessToken'
|
||||
db.create_table('facebook_facebookaccesstoken', (
|
||||
('access_token', self.gf('django.db.models.fields.CharField')(max_length=200)),
|
||||
('account', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['facebook.FacebookAccount'])),
|
||||
('app', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['facebook.FacebookApp'])),
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
))
|
||||
db.send_create_signal('facebook', ['FacebookAccessToken'])
|
||||
|
||||
# Adding unique constraint on 'FacebookAccessToken', fields ['app', 'account']
|
||||
db.create_unique('facebook_facebookaccesstoken', ['app_id', 'account_id'])
|
||||
|
||||
# Adding model 'FacebookAccount'
|
||||
db.create_table('facebook_facebookaccount', (
|
||||
('socialaccount_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['socialaccount.SocialAccount'], unique=True, primary_key=True)),
|
||||
('social_id', self.gf('django.db.models.fields.CharField')(max_length=255, unique=True)),
|
||||
('link', self.gf('django.db.models.fields.URLField')(max_length=200)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
))
|
||||
db.send_create_signal('facebook', ['FacebookAccount'])
|
||||
|
||||
|
||||
models = {
|
||||
|
||||
}
|
||||
|
||||
complete_apps = ['facebook']
|
3
itf/allauth/socialaccount/providers/facebook/models.py
Normal file
3
itf/allauth/socialaccount/providers/facebook/models.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
92
itf/allauth/socialaccount/providers/facebook/provider.py
Normal file
92
itf/allauth/socialaccount/providers/facebook/provider.py
Normal file
|
@ -0,0 +1,92 @@
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.template.loader import render_to_string
|
||||
from django.template import RequestContext
|
||||
|
||||
from allauth.utils import import_callable
|
||||
from allauth.socialaccount import providers
|
||||
from allauth.socialaccount.providers.base import ProviderAccount
|
||||
from allauth.socialaccount.providers.oauth2.provider import OAuth2Provider
|
||||
from allauth.socialaccount.app_settings import QUERY_EMAIL
|
||||
from allauth.socialaccount.models import SocialApp
|
||||
from allauth.socialaccount.helpers import import_path
|
||||
|
||||
from locale import get_default_locale_callable
|
||||
|
||||
|
||||
class FacebookAccount(ProviderAccount):
|
||||
def get_profile_url(self):
|
||||
return self.account.extra_data.get('link')
|
||||
|
||||
def get_avatar_url(self):
|
||||
uid = self.account.uid
|
||||
return 'http://graph.facebook.com/%s/picture?type=large' % uid
|
||||
|
||||
def __unicode__(self):
|
||||
dflt = super(FacebookAccount, self).__unicode__()
|
||||
return self.account.extra_data.get('name', dflt)
|
||||
|
||||
|
||||
class FacebookProvider(OAuth2Provider):
|
||||
id = 'facebook'
|
||||
name = 'Facebook'
|
||||
package = 'allauth.socialaccount.providers.facebook'
|
||||
account_class = FacebookAccount
|
||||
|
||||
def __init__(self):
|
||||
self._locale_callable_cache = None
|
||||
super(FacebookProvider, self).__init__()
|
||||
|
||||
def get_method(self):
|
||||
return self.get_settings().get('METHOD', 'oauth2')
|
||||
|
||||
def get_login_url(self, request, **kwargs):
|
||||
method = kwargs.get('method', self.get_method())
|
||||
if method == 'js_sdk':
|
||||
next = "'%s'" % (kwargs.get('next') or '')
|
||||
ret = "javascript:FB_login(%s)" % next
|
||||
else:
|
||||
assert method == 'oauth2'
|
||||
ret = super(FacebookProvider, self).get_login_url(request,
|
||||
**kwargs)
|
||||
return ret
|
||||
|
||||
def _get_locale_callable(self):
|
||||
settings = self.get_settings()
|
||||
f = settings.get('LOCALE_FUNC')
|
||||
if f:
|
||||
f = import_callable(f)
|
||||
else:
|
||||
f = get_default_locale_callable()
|
||||
return f
|
||||
|
||||
def get_locale_for_request(self, request):
|
||||
if not self._locale_callable_cache:
|
||||
self._locale_callable_cache = self._get_locale_callable()
|
||||
return self._locale_callable_cache(request)
|
||||
|
||||
def get_default_scope(self):
|
||||
scope = []
|
||||
if QUERY_EMAIL:
|
||||
scope.append('email')
|
||||
return scope
|
||||
|
||||
def media_js(self, request):
|
||||
perms = ','.join(self.get_scope())
|
||||
locale = self.get_locale_for_request(request)
|
||||
try:
|
||||
app = self.get_app(request)
|
||||
except SocialApp.DoesNotExist:
|
||||
raise ImproperlyConfigured("No Facebook app configured: please"
|
||||
" add a SocialApp using the Django"
|
||||
" admin")
|
||||
ctx = {'facebook_app': app,
|
||||
'facebook_channel_url':
|
||||
request.build_absolute_uri(reverse('facebook_channel')),
|
||||
'facebook_perms': perms,
|
||||
'facebook_jssdk_locale': locale}
|
||||
return render_to_string('facebook/fbconnect.html',
|
||||
ctx,
|
||||
RequestContext(request))
|
||||
|
||||
providers.registry.register(FacebookProvider)
|
|
@ -0,0 +1 @@
|
|||
<script src="//connect.facebook.net/{{facebook_jssdk_locale}}/all.js"></script>
|
|
@ -0,0 +1,46 @@
|
|||
{% load url from future %}
|
||||
<div id="fb-root"></div>
|
||||
<script>
|
||||
window.FB_login = function() {};
|
||||
window.fbAsyncInit = function() {
|
||||
FB.init({
|
||||
appId : '{{facebook_app.key}}',
|
||||
channelUrl : '{{facebook_channel_url}}',
|
||||
status : true,
|
||||
cookie : true,
|
||||
oauth : true,
|
||||
xfbml : true
|
||||
});
|
||||
window.FB_login = function(nextUrl) {
|
||||
FB.login(function(response) {
|
||||
if (response.authResponse) {
|
||||
document.getElementById("_fb_access_token").value = response.authResponse.accessToken;
|
||||
document.getElementById("_fb_expires_in").value = response.authResponse.expiresIn;
|
||||
document.getElementById("_fb_next_url").value = nextUrl || '';
|
||||
document.getElementById("_fb_login").submit();
|
||||
} else {
|
||||
var next;
|
||||
if (response && response.status && response.status == "notConnected") {
|
||||
next = '{% url 'socialaccount_login_cancelled' %}';
|
||||
} else {
|
||||
next = '{% url 'socialaccount_login_error' %}';
|
||||
}
|
||||
window.location.href = next;
|
||||
}
|
||||
}, {scope: '{{facebook_perms}}' });
|
||||
}
|
||||
};
|
||||
(function(d){
|
||||
var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
|
||||
js = d.createElement('script'); js.id = id; js.async = true;
|
||||
js.src = "//connect.facebook.net/{{facebook_jssdk_locale}}/all.js";
|
||||
d.getElementsByTagName('head')[0].appendChild(js);
|
||||
}(document));
|
||||
</script>
|
||||
|
||||
<form id="_fb_login" method="post" action="{% url 'facebook_login_by_token' %}">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="next" value="" id="_fb_next_url"/>
|
||||
<input type="hidden" name="access_token" id="_fb_access_token"/>
|
||||
<input type="hidden" name="expires_in" id="_fb_expires_in"/>
|
||||
</form>
|
14
itf/allauth/socialaccount/providers/facebook/urls.py
Normal file
14
itf/allauth/socialaccount/providers/facebook/urls.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
from django.conf.urls.defaults import patterns, url
|
||||
|
||||
from allauth.socialaccount.providers.oauth2.urls import default_urlpatterns
|
||||
|
||||
from provider import FacebookProvider
|
||||
import views
|
||||
|
||||
urlpatterns = default_urlpatterns(FacebookProvider)
|
||||
|
||||
urlpatterns += patterns('',
|
||||
url('^facebook/login/token/$', views.login_by_token,
|
||||
name="facebook_login_by_token"),
|
||||
url('^facebook/channel/$', views.channel, name='facebook_channel'),
|
||||
)
|
83
itf/allauth/socialaccount/providers/facebook/views.py
Normal file
83
itf/allauth/socialaccount/providers/facebook/views.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
from django.utils.cache import patch_response_headers
|
||||
from django.contrib.auth.models import User
|
||||
from django.shortcuts import render
|
||||
|
||||
from allauth.socialaccount.models import SocialAccount, SocialLogin, SocialToken
|
||||
from allauth.socialaccount.helpers import complete_social_login
|
||||
from allauth.socialaccount.helpers import render_authentication_error
|
||||
from allauth.socialaccount import providers
|
||||
from allauth.socialaccount.providers.oauth2.views import (OAuth2Adapter,
|
||||
OAuth2LoginView,
|
||||
OAuth2CallbackView)
|
||||
from allauth.socialaccount import requests
|
||||
|
||||
from forms import FacebookConnectForm
|
||||
from provider import FacebookProvider
|
||||
|
||||
from allauth.utils import valid_email_or_none
|
||||
|
||||
def fb_complete_login(app, token):
|
||||
resp = requests.get('https://graph.facebook.com/me',
|
||||
params={ 'access_token': token.token })
|
||||
extra_data = resp.json
|
||||
email = valid_email_or_none(extra_data.get('email'))
|
||||
uid = extra_data['id']
|
||||
user = User(email=email)
|
||||
# some facebook accounts don't have this data
|
||||
for k in ['username', 'first_name', 'last_name']:
|
||||
v = extra_data.get(k)
|
||||
if v:
|
||||
setattr(user, k, v)
|
||||
account = SocialAccount(uid=uid,
|
||||
provider=FacebookProvider.id,
|
||||
extra_data=extra_data,
|
||||
user=user)
|
||||
return SocialLogin(account)
|
||||
|
||||
|
||||
class FacebookOAuth2Adapter(OAuth2Adapter):
|
||||
provider_id = FacebookProvider.id
|
||||
|
||||
authorize_url = 'https://www.facebook.com/dialog/oauth'
|
||||
access_token_url = 'https://graph.facebook.com/oauth/access_token'
|
||||
|
||||
def complete_login(self, request, app, access_token):
|
||||
return fb_complete_login(app, access_token)
|
||||
|
||||
|
||||
oauth2_login = OAuth2LoginView.adapter_view(FacebookOAuth2Adapter)
|
||||
oauth2_callback = OAuth2CallbackView.adapter_view(FacebookOAuth2Adapter)
|
||||
|
||||
|
||||
def login_by_token(request):
|
||||
ret = None
|
||||
if request.method == 'POST':
|
||||
form = FacebookConnectForm(request.POST)
|
||||
if form.is_valid():
|
||||
try:
|
||||
app = providers.registry.by_id(FacebookProvider.id) \
|
||||
.get_app(request)
|
||||
access_token = form.cleaned_data['access_token']
|
||||
token = SocialToken(app=app,
|
||||
token=access_token)
|
||||
login = fb_complete_login(app, token)
|
||||
login.token = token
|
||||
login.state = SocialLogin.state_from_request(request)
|
||||
ret = complete_social_login(request, login)
|
||||
except:
|
||||
# FIXME: Catch only what is needed
|
||||
pass
|
||||
if not ret:
|
||||
ret = render_authentication_error(request)
|
||||
return ret
|
||||
|
||||
|
||||
def channel(request):
|
||||
provider = providers.registry.by_id(FacebookProvider.id)
|
||||
locale = provider.get_locale_for_request(request)
|
||||
response = render(request, 'facebook/channel.html',
|
||||
{'facebook_jssdk_locale': locale})
|
||||
cache_expire = 60 * 60 * 24 * 365
|
||||
patch_response_headers(response, cache_expire)
|
||||
response['Pragma'] = 'Public'
|
||||
return response
|
3
itf/allauth/socialaccount/providers/github/models.py
Normal file
3
itf/allauth/socialaccount/providers/github/models.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
24
itf/allauth/socialaccount/providers/github/provider.py
Normal file
24
itf/allauth/socialaccount/providers/github/provider.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
from allauth.socialaccount import providers
|
||||
from allauth.socialaccount.providers.base import ProviderAccount
|
||||
from allauth.socialaccount.providers.oauth2.provider import OAuth2Provider
|
||||
|
||||
|
||||
class GitHubAccount(ProviderAccount):
|
||||
def get_profile_url(self):
|
||||
return self.account.extra_data.get('html_url')
|
||||
|
||||
def get_avatar_url(self):
|
||||
return self.account.extra_data.get('avatar_url')
|
||||
|
||||
def __unicode__(self):
|
||||
dflt = super(GitHubAccount, self).__unicode__()
|
||||
return self.account.extra_data.get('name', dflt)
|
||||
|
||||
|
||||
class GitHubProvider(OAuth2Provider):
|
||||
id = 'github'
|
||||
name = 'GitHub'
|
||||
package = 'allauth.socialaccount.providers.github'
|
||||
account_class = GitHubAccount
|
||||
|
||||
providers.registry.register(GitHubProvider)
|
5
itf/allauth/socialaccount/providers/github/urls.py
Normal file
5
itf/allauth/socialaccount/providers/github/urls.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from allauth.socialaccount.providers.oauth2.urls import default_urlpatterns
|
||||
from provider import GitHubProvider
|
||||
|
||||
urlpatterns = default_urlpatterns(GitHubProvider)
|
||||
|
35
itf/allauth/socialaccount/providers/github/views.py
Normal file
35
itf/allauth/socialaccount/providers/github/views.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
from django.contrib.auth.models import User
|
||||
|
||||
from allauth.socialaccount.providers.oauth2.views import (OAuth2Adapter,
|
||||
OAuth2LoginView,
|
||||
OAuth2CallbackView)
|
||||
from allauth.socialaccount import requests
|
||||
|
||||
from allauth.socialaccount.models import SocialAccount, SocialLogin
|
||||
|
||||
from provider import GitHubProvider
|
||||
|
||||
class GitHubOAuth2Adapter(OAuth2Adapter):
|
||||
provider_id = GitHubProvider.id
|
||||
access_token_url = 'https://github.com/login/oauth/access_token'
|
||||
authorize_url = 'https://github.com/login/oauth/authorize'
|
||||
profile_url = 'https://api.github.com/user'
|
||||
|
||||
def complete_login(self, request, app, token):
|
||||
resp = requests.get(self.profile_url,
|
||||
params={ 'access_token': token.token })
|
||||
extra_data = resp.json
|
||||
uid = str(extra_data['id'])
|
||||
user = User(username=extra_data.get('login', ''),
|
||||
email=extra_data.get('email', ''),
|
||||
first_name=extra_data.get('name', ''))
|
||||
account = SocialAccount(user=user,
|
||||
uid=uid,
|
||||
extra_data=extra_data,
|
||||
provider=self.provider_id)
|
||||
return SocialLogin(account)
|
||||
|
||||
|
||||
oauth2_login = OAuth2LoginView.adapter_view(GitHubOAuth2Adapter)
|
||||
oauth2_callback = OAuth2CallbackView.adapter_view(GitHubOAuth2Adapter)
|
||||
|
3
itf/allauth/socialaccount/providers/google/models.py
Normal file
3
itf/allauth/socialaccount/providers/google/models.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
35
itf/allauth/socialaccount/providers/google/provider.py
Normal file
35
itf/allauth/socialaccount/providers/google/provider.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
from allauth.socialaccount import providers
|
||||
from allauth.socialaccount.providers.base import ProviderAccount
|
||||
from allauth.socialaccount.providers.oauth2.provider import OAuth2Provider
|
||||
from allauth.socialaccount.app_settings import QUERY_EMAIL
|
||||
|
||||
class Scope:
|
||||
USERINFO_PROFILE = 'https://www.googleapis.com/auth/userinfo.profile'
|
||||
USERINFO_EMAIL = 'https://www.googleapis.com/auth/userinfo.email'
|
||||
|
||||
|
||||
class GoogleAccount(ProviderAccount):
|
||||
def get_profile_url(self):
|
||||
return self.account.extra_data.get('link')
|
||||
|
||||
def get_avatar_url(self):
|
||||
return self.account.extra_data.get('picture')
|
||||
|
||||
def __unicode__(self):
|
||||
dflt = super(GoogleAccount, self).__unicode__()
|
||||
return self.account.extra_data.get('name', dflt)
|
||||
|
||||
|
||||
class GoogleProvider(OAuth2Provider):
|
||||
id = 'google'
|
||||
name = 'Google'
|
||||
package = 'allauth.socialaccount.providers.google'
|
||||
account_class = GoogleAccount
|
||||
|
||||
def get_default_scope(self):
|
||||
scope = [Scope.USERINFO_PROFILE]
|
||||
if QUERY_EMAIL:
|
||||
scope.append(Scope.USERINFO_EMAIL)
|
||||
return scope
|
||||
|
||||
providers.registry.register(GoogleProvider)
|
4
itf/allauth/socialaccount/providers/google/urls.py
Normal file
4
itf/allauth/socialaccount/providers/google/urls.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from allauth.socialaccount.providers.oauth2.urls import default_urlpatterns
|
||||
from provider import GoogleProvider
|
||||
|
||||
urlpatterns = default_urlpatterns(GoogleProvider)
|
46
itf/allauth/socialaccount/providers/google/views.py
Normal file
46
itf/allauth/socialaccount/providers/google/views.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
from django.contrib.auth.models import User
|
||||
|
||||
from allauth.socialaccount.providers.oauth2.views import (OAuth2Adapter,
|
||||
OAuth2LoginView,
|
||||
OAuth2CallbackView)
|
||||
|
||||
from allauth.socialaccount import requests
|
||||
from allauth.socialaccount.models import SocialLogin, SocialAccount
|
||||
|
||||
from provider import GoogleProvider
|
||||
|
||||
class GoogleOAuth2Adapter(OAuth2Adapter):
|
||||
provider_id = GoogleProvider.id
|
||||
access_token_url = 'https://accounts.google.com/o/oauth2/token'
|
||||
authorize_url = 'https://accounts.google.com/o/oauth2/auth'
|
||||
profile_url = 'https://www.googleapis.com/oauth2/v1/userinfo'
|
||||
|
||||
def complete_login(self, request, app, token):
|
||||
resp = requests.get(self.profile_url,
|
||||
{ 'access_token': token.token,
|
||||
'alt': 'json' })
|
||||
extra_data = resp.json
|
||||
# extra_data is something of the form:
|
||||
#
|
||||
# {u'family_name': u'Penners', u'name': u'Raymond Penners',
|
||||
# u'picture': u'https://lh5.googleusercontent.com/-GOFYGBVOdBQ/AAAAAAAAAAI/AAAAAAAAAGM/WzRfPkv4xbo/photo.jpg',
|
||||
# u'locale': u'nl', u'gender': u'male',
|
||||
# u'email': u'raymond.penners@gmail.com',
|
||||
# u'link': u'https://plus.google.com/108204268033311374519',
|
||||
# u'given_name': u'Raymond', u'id': u'108204268033311374519',
|
||||
# u'verified_email': True}
|
||||
#
|
||||
# TODO: We could use verified_email to bypass allauth email verification
|
||||
uid = str(extra_data['id'])
|
||||
user = User(email=extra_data.get('email', ''),
|
||||
last_name=extra_data['family_name'],
|
||||
first_name=extra_data['given_name'])
|
||||
account = SocialAccount(extra_data=extra_data,
|
||||
uid=uid,
|
||||
provider=self.provider_id,
|
||||
user=user)
|
||||
return SocialLogin(account)
|
||||
|
||||
oauth2_login = OAuth2LoginView.adapter_view(GoogleOAuth2Adapter)
|
||||
oauth2_callback = OAuth2CallbackView.adapter_view(GoogleOAuth2Adapter)
|
||||
|
3
itf/allauth/socialaccount/providers/linkedin/models.py
Normal file
3
itf/allauth/socialaccount/providers/linkedin/models.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
15
itf/allauth/socialaccount/providers/linkedin/provider.py
Normal file
15
itf/allauth/socialaccount/providers/linkedin/provider.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
from allauth.socialaccount import providers
|
||||
from allauth.socialaccount.providers.base import ProviderAccount
|
||||
from allauth.socialaccount.providers.oauth.provider import OAuthProvider
|
||||
|
||||
class LinkedInAccount(ProviderAccount):
|
||||
pass
|
||||
|
||||
|
||||
class LinkedInProvider(OAuthProvider):
|
||||
id = 'linkedin'
|
||||
name = 'LinkedIn'
|
||||
package = 'allauth.socialaccount.providers.linkedin'
|
||||
account_class = LinkedInAccount
|
||||
|
||||
providers.registry.register(LinkedInProvider)
|
4
itf/allauth/socialaccount/providers/linkedin/urls.py
Normal file
4
itf/allauth/socialaccount/providers/linkedin/urls.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from allauth.socialaccount.providers.oauth.urls import default_urlpatterns
|
||||
from provider import LinkedInProvider
|
||||
|
||||
urlpatterns = default_urlpatterns(LinkedInProvider)
|
68
itf/allauth/socialaccount/providers/linkedin/views.py
Normal file
68
itf/allauth/socialaccount/providers/linkedin/views.py
Normal file
|
@ -0,0 +1,68 @@
|
|||
from xml.etree import ElementTree
|
||||
from xml.parsers.expat import ExpatError
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from allauth.socialaccount.providers.oauth.client import OAuth
|
||||
from allauth.socialaccount.providers.oauth.views import (OAuthAdapter,
|
||||
OAuthLoginView,
|
||||
OAuthCallbackView)
|
||||
from allauth.socialaccount.models import SocialAccount, SocialLogin
|
||||
|
||||
from provider import LinkedInProvider
|
||||
|
||||
|
||||
class LinkedInAPI(OAuth):
|
||||
url = 'https://api.linkedin.com/v1/people/~'
|
||||
fields = ['id', 'first-name', 'last-name']
|
||||
|
||||
def get_user_info(self):
|
||||
url = self.url + ':(%s)' % ','.join(self.fields)
|
||||
raw_xml = self.query(url)
|
||||
try:
|
||||
return self.to_dict(ElementTree.fromstring(raw_xml))
|
||||
except (ExpatError, KeyError, IndexError):
|
||||
return None
|
||||
|
||||
def to_dict(self, xml):
|
||||
"""
|
||||
Convert XML structure to dict recursively, repeated keys
|
||||
entries are returned as in list containers.
|
||||
"""
|
||||
children = xml.getchildren()
|
||||
if not children:
|
||||
return xml.text
|
||||
else:
|
||||
out = {}
|
||||
for node in xml.getchildren():
|
||||
if node.tag in out:
|
||||
if not isinstance(out[node.tag], list):
|
||||
out[node.tag] = [out[node.tag]]
|
||||
out[node.tag].append(self.to_dict(node))
|
||||
else:
|
||||
out[node.tag] = self.to_dict(node)
|
||||
return out
|
||||
|
||||
|
||||
class LinkedInOAuthAdapter(OAuthAdapter):
|
||||
provider_id = LinkedInProvider.id
|
||||
request_token_url = 'https://api.linkedin.com/uas/oauth/requestToken'
|
||||
access_token_url = 'https://api.linkedin.com/uas/oauth/accessToken'
|
||||
authorize_url = 'https://www.linkedin.com/uas/oauth/authenticate'
|
||||
|
||||
def complete_login(self, request, app, token):
|
||||
client = LinkedInAPI(request, app.key, app.secret,
|
||||
self.request_token_url)
|
||||
extra_data = client.get_user_info()
|
||||
uid = extra_data['id']
|
||||
user = User(first_name=extra_data.get('first-name', ''),
|
||||
last_name=extra_data.get('last-name', ''))
|
||||
account = SocialAccount(user=user,
|
||||
provider=self.provider_id,
|
||||
extra_data=extra_data,
|
||||
uid=uid)
|
||||
return SocialLogin(account)
|
||||
|
||||
oauth_login = OAuthLoginView.adapter_view(LinkedInOAuthAdapter)
|
||||
oauth_callback = OAuthCallbackView.adapter_view(LinkedInOAuthAdapter)
|
||||
|
185
itf/allauth/socialaccount/providers/oauth/client.py
Normal file
185
itf/allauth/socialaccount/providers/oauth/client.py
Normal file
|
@ -0,0 +1,185 @@
|
|||
"""
|
||||
Parts derived from socialregistration and authorized by: alen, pinda
|
||||
Inspired by:
|
||||
http://github.com/leah/python-oauth/blob/master/oauth/example/client.py
|
||||
http://github.com/facebook/tornado/blob/master/tornado/auth.py
|
||||
"""
|
||||
|
||||
import urllib
|
||||
import urllib2
|
||||
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
# parse_qsl was moved from the cgi namespace to urlparse in Python2.6.
|
||||
# this allows backwards compatibility
|
||||
try:
|
||||
from urlparse import parse_qsl
|
||||
except ImportError:
|
||||
from cgi import parse_qsl
|
||||
|
||||
import oauth2 as oauth
|
||||
|
||||
|
||||
def get_token_prefix(url):
|
||||
"""
|
||||
Returns a prefix for the token to store in the session so we can hold
|
||||
more than one single oauth provider's access key in the session.
|
||||
|
||||
Example:
|
||||
|
||||
The request token url ``http://twitter.com/oauth/request_token``
|
||||
returns ``twitter.com``
|
||||
|
||||
"""
|
||||
return urllib2.urlparse.urlparse(url).netloc
|
||||
|
||||
|
||||
class OAuthError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class OAuthClient(object):
|
||||
|
||||
def __init__(self, request, consumer_key, consumer_secret, request_token_url,
|
||||
access_token_url, authorization_url, callback_url, parameters=None):
|
||||
|
||||
self.request = request
|
||||
|
||||
self.request_token_url = request_token_url
|
||||
self.access_token_url = access_token_url
|
||||
self.authorization_url = authorization_url
|
||||
|
||||
self.consumer_key = consumer_key
|
||||
self.consumer_secret = consumer_secret
|
||||
|
||||
self.consumer = oauth.Consumer(consumer_key, consumer_secret)
|
||||
self.client = oauth.Client(self.consumer)
|
||||
|
||||
self.signature_method = oauth.SignatureMethod_HMAC_SHA1()
|
||||
|
||||
self.parameters = parameters
|
||||
|
||||
self.callback_url = callback_url
|
||||
|
||||
self.errors = []
|
||||
self.request_token = None
|
||||
self.access_token = None
|
||||
|
||||
def _get_request_token(self):
|
||||
"""
|
||||
Obtain a temporary request token to authorize an access token and to
|
||||
sign the request to obtain the access token
|
||||
"""
|
||||
if self.request_token is None:
|
||||
rt_url = self.request_token_url + '?' + urllib.urlencode({'oauth_callback': self.request.build_absolute_uri(self.callback_url)})
|
||||
response, content = self.client.request(rt_url, "GET")
|
||||
if response['status'] != '200':
|
||||
raise OAuthError(
|
||||
_('Invalid response while obtaining request token from "%s".') % get_token_prefix(self.request_token_url))
|
||||
self.request_token = dict(parse_qsl(content))
|
||||
self.request.session['oauth_%s_request_token' % get_token_prefix(self.request_token_url)] = self.request_token
|
||||
return self.request_token
|
||||
|
||||
def get_access_token(self):
|
||||
"""
|
||||
Obtain the access token to access private resources at the API endpoint.
|
||||
"""
|
||||
if self.access_token is None:
|
||||
request_token = self._get_rt_from_session()
|
||||
token = oauth.Token(request_token['oauth_token'], request_token['oauth_token_secret'])
|
||||
self.client = oauth.Client(self.consumer, token)
|
||||
at_url = self.access_token_url
|
||||
|
||||
# Passing along oauth_verifier is required according to:
|
||||
# http://groups.google.com/group/twitter-development-talk/browse_frm/thread/472500cfe9e7cdb9#
|
||||
# Though, the custom oauth_callback seems to work without it?
|
||||
if self.request.REQUEST.has_key('oauth_verifier'):
|
||||
at_url = at_url + '?' + urllib.urlencode({'oauth_verifier': self.request.REQUEST['oauth_verifier']})
|
||||
response, content = self.client.request(at_url, "GET")
|
||||
if response['status'] != '200':
|
||||
raise OAuthError(
|
||||
_('Invalid response while obtaining access token from "%s".') % get_token_prefix(self.request_token_url))
|
||||
self.access_token = dict(parse_qsl(content))
|
||||
|
||||
self.request.session['oauth_%s_access_token' % get_token_prefix(self.request_token_url)] = self.access_token
|
||||
return self.access_token
|
||||
|
||||
def _get_rt_from_session(self):
|
||||
"""
|
||||
Returns the request token cached in the session by ``_get_request_token``
|
||||
"""
|
||||
try:
|
||||
return self.request.session['oauth_%s_request_token' % get_token_prefix(self.request_token_url)]
|
||||
except KeyError:
|
||||
raise OAuthError(_('No request token saved for "%s".') % get_token_prefix(self.request_token_url))
|
||||
|
||||
def _get_authorization_url(self):
|
||||
request_token = self._get_request_token()
|
||||
return '%s?oauth_token=%s&oauth_callback=%s' % (self.authorization_url,
|
||||
request_token['oauth_token'], self.request.build_absolute_uri(self.callback_url))
|
||||
|
||||
def is_valid(self):
|
||||
try:
|
||||
self._get_rt_from_session()
|
||||
self.get_access_token()
|
||||
except OAuthError, e:
|
||||
self.errors.append(e.args[0])
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_redirect(self):
|
||||
"""
|
||||
Returns a ``HttpResponseRedirect`` object to redirect the user to the
|
||||
URL the OAuth provider handles authorization.
|
||||
"""
|
||||
return HttpResponseRedirect(self._get_authorization_url())
|
||||
|
||||
|
||||
class OAuth(object):
|
||||
"""
|
||||
Base class to perform oauth signed requests from access keys saved in a user's
|
||||
session.
|
||||
See the ``OAuthTwitter`` class below for an example.
|
||||
"""
|
||||
|
||||
def __init__(self, request, consumer_key, secret_key, request_token_url):
|
||||
self.request = request
|
||||
|
||||
self.consumer_key = consumer_key
|
||||
self.secret_key = secret_key
|
||||
self.consumer = oauth.Consumer(consumer_key, secret_key)
|
||||
|
||||
self.request_token_url = request_token_url
|
||||
|
||||
def _get_at_from_session(self):
|
||||
"""
|
||||
Get the saved access token for private resources from the session.
|
||||
"""
|
||||
try:
|
||||
return self.request.session['oauth_%s_access_token' % get_token_prefix(self.request_token_url)]
|
||||
except KeyError:
|
||||
raise OAuthError(
|
||||
_('No access token saved for "%s".') % get_token_prefix(self.request_token_url))
|
||||
|
||||
def query(self, url, method="GET", params=dict(), headers=dict()):
|
||||
"""
|
||||
Request a API endpoint at ``url`` with ``params`` being either the
|
||||
POST or GET data.
|
||||
"""
|
||||
access_token = self._get_at_from_session()
|
||||
|
||||
token = oauth.Token(access_token['oauth_token'], access_token['oauth_token_secret'])
|
||||
|
||||
client = oauth.Client(self.consumer, token)
|
||||
|
||||
body = urllib.urlencode(params)
|
||||
|
||||
response, content = client.request(url, method=method, headers=headers,
|
||||
body=body)
|
||||
|
||||
if response['status'] != '200':
|
||||
raise OAuthError(
|
||||
_('No access to private resources at "%s".') % get_token_prefix(self.request_token_url))
|
||||
|
||||
return content
|
3
itf/allauth/socialaccount/providers/oauth/models.py
Normal file
3
itf/allauth/socialaccount/providers/oauth/models.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
13
itf/allauth/socialaccount/providers/oauth/provider.py
Normal file
13
itf/allauth/socialaccount/providers/oauth/provider.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.utils.http import urlencode
|
||||
|
||||
from allauth.socialaccount.providers.base import Provider
|
||||
|
||||
class OAuthProvider(Provider):
|
||||
def get_login_url(self, request, **kwargs):
|
||||
url = reverse(self.id + "_login")
|
||||
if kwargs:
|
||||
url = url + '?' + urlencode(kwargs)
|
||||
return url
|
||||
|
||||
|
12
itf/allauth/socialaccount/providers/oauth/urls.py
Normal file
12
itf/allauth/socialaccount/providers/oauth/urls.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
from django.conf.urls.defaults import patterns, url, include
|
||||
|
||||
|
||||
def default_urlpatterns(provider):
|
||||
|
||||
urlpatterns = patterns(provider.package + '.views',
|
||||
url('^login/$', 'oauth_login',
|
||||
name=provider.id + "_login"),
|
||||
url('^login/callback/$', 'oauth_callback',
|
||||
name=provider.id + "_callback"))
|
||||
|
||||
return patterns('', url('^' + provider.id + '/', include(urlpatterns)))
|
84
itf/allauth/socialaccount/providers/oauth/views.py
Normal file
84
itf/allauth/socialaccount/providers/oauth/views.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.utils.http import urlencode
|
||||
|
||||
from allauth.socialaccount.helpers import render_authentication_error
|
||||
from allauth.socialaccount.providers.oauth.client import (OAuthClient,
|
||||
OAuthError)
|
||||
from allauth.socialaccount.helpers import complete_social_login
|
||||
from allauth.socialaccount import providers
|
||||
from allauth.socialaccount.models import SocialToken, SocialLogin
|
||||
|
||||
class OAuthAdapter(object):
|
||||
|
||||
def complete_login(self, request, app):
|
||||
"""
|
||||
Returns a SocialLogin instance
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_provider(self):
|
||||
return providers.registry.by_id(self.provider_id)
|
||||
|
||||
|
||||
class OAuthView(object):
|
||||
@classmethod
|
||||
def adapter_view(cls, adapter):
|
||||
def view(request, *args, **kwargs):
|
||||
self = cls()
|
||||
self.request = request
|
||||
self.adapter = adapter()
|
||||
return self.dispatch(request, *args, **kwargs)
|
||||
return view
|
||||
|
||||
def _get_client(self, request, callback_url):
|
||||
app = self.adapter.get_provider().get_app(request)
|
||||
client = OAuthClient(request, app.key, app.secret,
|
||||
self.adapter.request_token_url,
|
||||
self.adapter.access_token_url,
|
||||
self.adapter.authorize_url,
|
||||
callback_url)
|
||||
return client
|
||||
|
||||
|
||||
class OAuthLoginView(OAuthView):
|
||||
def dispatch(self, request):
|
||||
callback_url = reverse(self.adapter.provider_id + "_callback")
|
||||
# TODO: Can't this be moved as query param into callback?
|
||||
# Tried but failed somehow, needs further study...
|
||||
request.session['oauth_login_state'] \
|
||||
= SocialLogin.marshall_state(request)
|
||||
client = self._get_client(request, callback_url)
|
||||
try:
|
||||
return client.get_redirect()
|
||||
except OAuthError:
|
||||
return render_authentication_error(request)
|
||||
|
||||
|
||||
class OAuthCallbackView(OAuthView):
|
||||
def dispatch(self, request):
|
||||
"""
|
||||
View to handle final steps of OAuth based authentication where the user
|
||||
gets redirected back to from the service provider
|
||||
"""
|
||||
login_done_url = reverse(self.adapter.provider_id + "_callback")
|
||||
client = self._get_client(request, login_done_url)
|
||||
if not client.is_valid():
|
||||
if request.GET.has_key('denied'):
|
||||
return HttpResponseRedirect(reverse('socialaccount_login_cancelled'))
|
||||
extra_context = dict(oauth_client=client)
|
||||
return render_authentication_error(request, extra_context)
|
||||
app = self.adapter.get_provider().get_app(request)
|
||||
try:
|
||||
access_token = client.get_access_token()
|
||||
token = SocialToken(app=app,
|
||||
token=access_token['oauth_token'],
|
||||
token_secret=access_token['oauth_token_secret'])
|
||||
login = self.adapter.complete_login(request, app, token)
|
||||
token.account = login.account
|
||||
login.token = token
|
||||
login.state = SocialLogin.unmarshall_state \
|
||||
(request.session.pop('oauth_login_state', None))
|
||||
return complete_social_login(request, login)
|
||||
except OAuthError:
|
||||
return render_authentication_error(request)
|
58
itf/allauth/socialaccount/providers/oauth2/client.py
Normal file
58
itf/allauth/socialaccount/providers/oauth2/client.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
import urllib
|
||||
import urlparse
|
||||
|
||||
from allauth.socialaccount import requests
|
||||
|
||||
class OAuth2Error(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class OAuth2Client(object):
|
||||
|
||||
def __init__(self, request, consumer_key, consumer_secret,
|
||||
authorization_url,
|
||||
access_token_url,
|
||||
callback_url,
|
||||
scope):
|
||||
self.request = request
|
||||
self.authorization_url = authorization_url
|
||||
self.access_token_url = access_token_url
|
||||
self.callback_url = callback_url
|
||||
self.consumer_key = consumer_key
|
||||
self.consumer_secret = consumer_secret
|
||||
self.scope = ' '.join(scope)
|
||||
self.state = None
|
||||
|
||||
def get_redirect_url(self):
|
||||
params = {
|
||||
'client_id': self.consumer_key,
|
||||
'redirect_uri': self.callback_url,
|
||||
'scope': self.scope,
|
||||
'response_type': 'code'
|
||||
}
|
||||
if self.state:
|
||||
params['state'] = self.state
|
||||
return '%s?%s' % (self.authorization_url, urllib.urlencode(params))
|
||||
|
||||
def get_access_token(self, code):
|
||||
params = {'client_id': self.consumer_key,
|
||||
'redirect_uri': self.callback_url,
|
||||
'grant_type': 'authorization_code',
|
||||
'client_secret': self.consumer_secret,
|
||||
'scope': self.scope,
|
||||
'code': code}
|
||||
url = self.access_token_url
|
||||
# TODO: Proper exception handling
|
||||
resp = requests.post(url, params)
|
||||
access_token = None
|
||||
if resp.status_code == 200:
|
||||
if resp.headers['content-type'] == 'application/json':
|
||||
data = resp.json
|
||||
else:
|
||||
data = dict(urlparse.parse_qsl(resp.content))
|
||||
access_token = data.get('access_token')
|
||||
if not access_token:
|
||||
raise OAuth2Error('Error retrieving access token: %s'
|
||||
% resp.content)
|
||||
|
||||
return access_token
|
3
itf/allauth/socialaccount/providers/oauth2/models.py
Normal file
3
itf/allauth/socialaccount/providers/oauth2/models.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
23
itf/allauth/socialaccount/providers/oauth2/provider.py
Normal file
23
itf/allauth/socialaccount/providers/oauth2/provider.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.utils.http import urlencode
|
||||
|
||||
from allauth.socialaccount.providers.base import Provider
|
||||
|
||||
class OAuth2Provider(Provider):
|
||||
def get_login_url(self, request, **kwargs):
|
||||
url = reverse(self.id + "_login")
|
||||
if kwargs:
|
||||
url = url + '?' + urlencode(kwargs)
|
||||
return url
|
||||
|
||||
def get_scope(self):
|
||||
settings = self.get_settings()
|
||||
scope = settings.get('SCOPE')
|
||||
if scope is None:
|
||||
scope = self.get_default_scope()
|
||||
return scope
|
||||
|
||||
def get_default_scope(self):
|
||||
return []
|
||||
|
||||
|
11
itf/allauth/socialaccount/providers/oauth2/urls.py
Normal file
11
itf/allauth/socialaccount/providers/oauth2/urls.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
from django.conf.urls.defaults import patterns, url, include
|
||||
|
||||
|
||||
def default_urlpatterns(provider):
|
||||
urlpatterns = patterns(provider.package + '.views',
|
||||
url('^login/$', 'oauth2_login',
|
||||
name=provider.id + "_login"),
|
||||
url('^login/callback/$', 'oauth2_callback',
|
||||
name=provider.id + "_callback"))
|
||||
|
||||
return patterns('', url('^' + provider.id + '/', include(urlpatterns)))
|
76
itf/allauth/socialaccount/providers/oauth2/views.py
Normal file
76
itf/allauth/socialaccount/providers/oauth2/views.py
Normal file
|
@ -0,0 +1,76 @@
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
from allauth.socialaccount.helpers import render_authentication_error
|
||||
from allauth.socialaccount import providers
|
||||
from allauth.socialaccount.providers.oauth2.client import (OAuth2Client,
|
||||
OAuth2Error)
|
||||
from allauth.socialaccount.helpers import complete_social_login
|
||||
from allauth.socialaccount.models import SocialToken, SocialLogin
|
||||
|
||||
|
||||
class OAuth2Adapter(object):
|
||||
|
||||
def get_provider(self):
|
||||
return providers.registry.by_id(self.provider_id)
|
||||
|
||||
def complete_login(self, request, app, access_token):
|
||||
"""
|
||||
Returns a SocialLogin instance
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
class OAuth2View(object):
|
||||
@classmethod
|
||||
def adapter_view(cls, adapter):
|
||||
def view(request, *args, **kwargs):
|
||||
self = cls()
|
||||
self.request = request
|
||||
self.adapter = adapter()
|
||||
return self.dispatch(request, *args, **kwargs)
|
||||
return view
|
||||
|
||||
def get_client(self, request, app):
|
||||
callback_url = reverse(self.adapter.provider_id + "_callback")
|
||||
callback_url = request.build_absolute_uri(callback_url)
|
||||
client = OAuth2Client(self.request, app.key, app.secret,
|
||||
self.adapter.authorize_url,
|
||||
self.adapter.access_token_url,
|
||||
callback_url,
|
||||
self.adapter.get_provider().get_scope())
|
||||
return client
|
||||
|
||||
|
||||
class OAuth2LoginView(OAuth2View):
|
||||
def dispatch(self, request):
|
||||
app = self.adapter.get_provider().get_app(self.request)
|
||||
client = self.get_client(request, app)
|
||||
client.state = SocialLogin.marshall_state(request)
|
||||
try:
|
||||
return HttpResponseRedirect(client.get_redirect_url())
|
||||
except OAuth2Error:
|
||||
return render_authentication_error(request)
|
||||
|
||||
|
||||
class OAuth2CallbackView(OAuth2View):
|
||||
def dispatch(self, request):
|
||||
if 'error' in request.GET or not 'code' in request.GET:
|
||||
# TODO: Distinguish cancel from error
|
||||
return render_authentication_error(request)
|
||||
app = self.adapter.get_provider().get_app(self.request)
|
||||
client = self.get_client(request, app)
|
||||
try:
|
||||
access_token = client.get_access_token(request.GET['code'])
|
||||
token = SocialToken(app=app,
|
||||
token=access_token)
|
||||
login = self.adapter.complete_login(request,
|
||||
app,
|
||||
token)
|
||||
token.account = login.account
|
||||
login.token = token
|
||||
login.state = SocialLogin.unmarshall_state(request.REQUEST
|
||||
.get('state'))
|
||||
return complete_social_login(request, login)
|
||||
except OAuth2Error:
|
||||
return render_authentication_error(request)
|
||||
|
13
itf/allauth/socialaccount/providers/openid/admin.py
Normal file
13
itf/allauth/socialaccount/providers/openid/admin.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from models import OpenIDStore, OpenIDNonce
|
||||
|
||||
|
||||
class OpenIDStoreAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
||||
class OpenIDNonceAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
||||
admin.site.register(OpenIDStore, OpenIDStoreAdmin)
|
||||
admin.site.register(OpenIDNonce, OpenIDNonceAdmin)
|
7
itf/allauth/socialaccount/providers/openid/forms.py
Normal file
7
itf/allauth/socialaccount/providers/openid/forms.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
from django import forms
|
||||
|
||||
|
||||
class LoginForm(forms.Form):
|
||||
openid = forms.URLField(label=('OpenID'),
|
||||
help_text='Get an <a href="http://openid.net/get-an-openid/">OpenID</a>')
|
|
@ -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):
|
||||
depends_on = (('socialaccount', '0001_initial'),)
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Adding model 'OpenIDAccount'
|
||||
db.create_table('openid_openidaccount', (
|
||||
('socialaccount_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['socialaccount.SocialAccount'], unique=True, primary_key=True)),
|
||||
('identity', self.gf('django.db.models.fields.URLField')(unique=True, max_length=255)),
|
||||
))
|
||||
db.send_create_signal('openid', ['OpenIDAccount'])
|
||||
|
||||
# Adding model 'OpenIDStore'
|
||||
db.create_table('openid_openidstore', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('server_url', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
('handle', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
('secret', self.gf('django.db.models.fields.TextField')()),
|
||||
('issued', self.gf('django.db.models.fields.IntegerField')()),
|
||||
('lifetime', self.gf('django.db.models.fields.IntegerField')()),
|
||||
('assoc_type', self.gf('django.db.models.fields.TextField')()),
|
||||
))
|
||||
db.send_create_signal('openid', ['OpenIDStore'])
|
||||
|
||||
# Adding model 'OpenIDNonce'
|
||||
db.create_table('openid_openidnonce', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('server_url', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
('timestamp', self.gf('django.db.models.fields.IntegerField')()),
|
||||
('salt', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
('date_created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
|
||||
))
|
||||
db.send_create_signal('openid', ['OpenIDNonce'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting model 'OpenIDAccount'
|
||||
db.delete_table('openid_openidaccount')
|
||||
|
||||
# Deleting model 'OpenIDStore'
|
||||
db.delete_table('openid_openidstore')
|
||||
|
||||
# Deleting model 'OpenIDNonce'
|
||||
db.delete_table('openid_openidnonce')
|
||||
|
||||
|
||||
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']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", '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'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", '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'})
|
||||
},
|
||||
'openid.openidaccount': {
|
||||
'Meta': {'object_name': 'OpenIDAccount', '_ormbases': ['socialaccount.SocialAccount']},
|
||||
'identity': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '255'}),
|
||||
'socialaccount_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['socialaccount.SocialAccount']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'openid.openidnonce': {
|
||||
'Meta': {'object_name': 'OpenIDNonce'},
|
||||
'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'salt': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'server_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'timestamp': ('django.db.models.fields.IntegerField', [], {})
|
||||
},
|
||||
'openid.openidstore': {
|
||||
'Meta': {'object_name': 'OpenIDStore'},
|
||||
'assoc_type': ('django.db.models.fields.TextField', [], {}),
|
||||
'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', [], {}),
|
||||
'server_url': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
},
|
||||
'socialaccount.socialaccount': {
|
||||
'Meta': {'object_name': 'SocialAccount'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['openid']
|
|
@ -0,0 +1,118 @@
|
|||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import DataMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(DataMigration):
|
||||
|
||||
depends_on = (('socialaccount', '0002_genericmodels'),)
|
||||
|
||||
def forwards(self, orm):
|
||||
for acc in orm.OpenIDAccount.objects.all():
|
||||
sacc = acc.socialaccount_ptr
|
||||
sacc.uid = acc.identity
|
||||
sacc.provider = 'openid'
|
||||
sacc.save()
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
"Write your backwards methods here."
|
||||
|
||||
|
||||
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']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", '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'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", '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'})
|
||||
},
|
||||
'openid.openidaccount': {
|
||||
'Meta': {'object_name': 'OpenIDAccount', '_ormbases': ['socialaccount.SocialAccount']},
|
||||
'identity': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '255'}),
|
||||
'socialaccount_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['socialaccount.SocialAccount']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'openid.openidnonce': {
|
||||
'Meta': {'object_name': 'OpenIDNonce'},
|
||||
'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'salt': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'server_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'timestamp': ('django.db.models.fields.IntegerField', [], {})
|
||||
},
|
||||
'openid.openidstore': {
|
||||
'Meta': {'object_name': 'OpenIDStore'},
|
||||
'assoc_type': ('django.db.models.fields.TextField', [], {}),
|
||||
'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', [], {}),
|
||||
'server_url': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
},
|
||||
'sites.site': {
|
||||
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
|
||||
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'socialaccount.socialaccount': {
|
||||
'Meta': {'object_name': 'SocialAccount'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'extra_data': ('allauth.socialaccount.fields.JSONField', [], {'default': "'{}'"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'provider': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'uid': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
},
|
||||
'socialaccount.socialapp': {
|
||||
'Meta': {'object_name': 'SocialApp'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'key': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
|
||||
'provider': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
|
||||
'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"})
|
||||
},
|
||||
'socialaccount.socialtoken': {
|
||||
'Meta': {'unique_together': "(('app', 'account'),)", 'object_name': 'SocialToken'},
|
||||
'account': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['socialaccount.SocialAccount']"}),
|
||||
'app': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['socialaccount.SocialApp']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'token': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
|
||||
'token_secret': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['socialaccount', 'openid']
|
|
@ -0,0 +1,46 @@
|
|||
# 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):
|
||||
|
||||
# Deleting model 'OpenIDAccount'
|
||||
db.delete_table('openid_openidaccount')
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Adding model 'OpenIDAccount'
|
||||
db.create_table('openid_openidaccount', (
|
||||
('socialaccount_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['socialaccount.SocialAccount'], unique=True, primary_key=True)),
|
||||
('identity', self.gf('django.db.models.fields.URLField')(max_length=255, unique=True)),
|
||||
))
|
||||
db.send_create_signal('openid', ['OpenIDAccount'])
|
||||
|
||||
|
||||
models = {
|
||||
'openid.openidnonce': {
|
||||
'Meta': {'object_name': 'OpenIDNonce'},
|
||||
'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'salt': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'server_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'timestamp': ('django.db.models.fields.IntegerField', [], {})
|
||||
},
|
||||
'openid.openidstore': {
|
||||
'Meta': {'object_name': 'OpenIDStore'},
|
||||
'assoc_type': ('django.db.models.fields.TextField', [], {}),
|
||||
'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', [], {}),
|
||||
'server_url': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['openid']
|
22
itf/allauth/socialaccount/providers/openid/models.py
Normal file
22
itf/allauth/socialaccount/providers/openid/models.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
from django.db import models
|
||||
|
||||
class OpenIDStore(models.Model):
|
||||
server_url = models.CharField(max_length=255)
|
||||
handle = models.CharField(max_length=255)
|
||||
secret = models.TextField()
|
||||
issued = models.IntegerField()
|
||||
lifetime = models.IntegerField()
|
||||
assoc_type = models.TextField()
|
||||
|
||||
def __unicode__(self):
|
||||
return self.server_url
|
||||
|
||||
|
||||
class OpenIDNonce(models.Model):
|
||||
server_url = models.CharField(max_length=255)
|
||||
timestamp = models.IntegerField()
|
||||
salt = models.CharField(max_length=255)
|
||||
date_created = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.server_url
|
58
itf/allauth/socialaccount/providers/openid/provider.py
Normal file
58
itf/allauth/socialaccount/providers/openid/provider.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
from urlparse import urlparse
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.http import urlencode
|
||||
|
||||
from allauth.socialaccount import providers
|
||||
from allauth.socialaccount.providers.base import Provider, ProviderAccount
|
||||
|
||||
class OpenIDAccount(ProviderAccount):
|
||||
def get_brand(self):
|
||||
ret = super(OpenIDAccount, self).get_brand()
|
||||
domain = urlparse(self.account.uid).netloc
|
||||
# FIXME: Instead of hardcoding, derive this from the domains
|
||||
# listed in the openid endpoints setting.
|
||||
provider_map = {'yahoo': dict(id='yahoo',
|
||||
name='Yahoo'),
|
||||
'hyves': dict(id='hyves',
|
||||
name='Hyves'),
|
||||
'google': dict(id='google',
|
||||
name='Google')}
|
||||
for d, p in provider_map.iteritems():
|
||||
if domain.lower().find(d) >= 0:
|
||||
ret = p
|
||||
break
|
||||
return ret
|
||||
|
||||
def __unicode__(self):
|
||||
return self.account.uid
|
||||
|
||||
|
||||
class OpenIDProvider(Provider):
|
||||
id = 'openid'
|
||||
name = 'OpenID'
|
||||
package = 'allauth.socialaccount.providers.openid'
|
||||
account_class = OpenIDAccount
|
||||
|
||||
def get_login_url(self, request, next=None, openid=None):
|
||||
url = reverse('openid_login')
|
||||
query = {}
|
||||
if openid:
|
||||
query['openid'] = openid
|
||||
if next:
|
||||
query['next'] = next
|
||||
if query:
|
||||
url += '?' + urlencode(query)
|
||||
return url
|
||||
|
||||
def get_brands(self):
|
||||
# These defaults are a bit too arbitrary...
|
||||
default_servers = [dict(id='yahoo',
|
||||
name='Yahoo',
|
||||
openid_url='http://me.yahoo.com'),
|
||||
dict(id='hyves',
|
||||
name='Hyves',
|
||||
openid_url='http://hyves.nl')]
|
||||
return self.get_settings().get('SERVERS', default_servers)
|
||||
|
||||
|
||||
providers.registry.register(OpenIDProvider)
|
16
itf/allauth/socialaccount/providers/openid/tests.py
Normal file
16
itf/allauth/socialaccount/providers/openid/tests.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
from django.test import TestCase
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
import views
|
||||
|
||||
|
||||
class OpenIDTests(TestCase):
|
||||
|
||||
def test_discovery_failure(self):
|
||||
"""
|
||||
This used to generate a server 500:
|
||||
DiscoveryFailure: No usable OpenID services found for http://www.google.com/
|
||||
"""
|
||||
resp = self.client.post(reverse(views.login),
|
||||
dict(openid='http://www.google.com'))
|
||||
self.assertTrue(resp.context['form'].errors.has_key('openid'))
|
8
itf/allauth/socialaccount/providers/openid/urls.py
Normal file
8
itf/allauth/socialaccount/providers/openid/urls.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from django.conf.urls.defaults import patterns, url
|
||||
|
||||
import views
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url('^openid/login/$', views.login, name="openid_login"),
|
||||
url('^openid/callback/$', views.callback),
|
||||
)
|
76
itf/allauth/socialaccount/providers/openid/utils.py
Normal file
76
itf/allauth/socialaccount/providers/openid/utils.py
Normal file
|
@ -0,0 +1,76 @@
|
|||
import base64
|
||||
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
from openid.store.interface import OpenIDStore as OIDStore
|
||||
from openid.association import Association as OIDAssociation
|
||||
|
||||
from models import OpenIDStore, OpenIDNonce
|
||||
|
||||
|
||||
class DBOpenIDStore(OIDStore):
|
||||
max_nonce_age = 6 * 60 * 60
|
||||
|
||||
def storeAssociation(self, server_url, assoc=None):
|
||||
stored_assoc = OpenIDStore.objects.create(
|
||||
server_url=server_url,
|
||||
handle=assoc.handle,
|
||||
secret=base64.encodestring(assoc.secret),
|
||||
issued=assoc.issued,
|
||||
lifetime=assoc.lifetime,
|
||||
assoc_type=assoc.assoc_type
|
||||
)
|
||||
|
||||
def getAssociation(self, server_url, handle=None):
|
||||
stored_assocs = OpenIDStore.objects.filter(
|
||||
server_url=server_url
|
||||
)
|
||||
if handle:
|
||||
stored_assocs = stored_assocs.filter(handle=handle)
|
||||
|
||||
stored_assocs.order_by('-issued')
|
||||
|
||||
if stored_assocs.count() == 0:
|
||||
return None
|
||||
|
||||
return_val = None
|
||||
|
||||
for stored_assoc in stored_assocs:
|
||||
assoc = OIDAssociation(
|
||||
stored_assoc.handle, base64.decodestring(stored_assoc.secret),
|
||||
stored_assoc.issued, stored_assoc.lifetime, stored_assoc.assoc_type
|
||||
)
|
||||
|
||||
if assoc.getExpiresIn() == 0:
|
||||
stored_assoc.delete()
|
||||
else:
|
||||
if return_val is None:
|
||||
return_val = assoc
|
||||
|
||||
return return_val
|
||||
|
||||
def removeAssociation(self, server_url, handle):
|
||||
stored_assocs = OpenIDStore.objects.filter(
|
||||
server_url=server_url
|
||||
)
|
||||
if handle:
|
||||
stored_assocs = stored_assocs.filter(handle=handle)
|
||||
|
||||
stored_assocs.delete()
|
||||
|
||||
def useNonce(self, server_url, timestamp, salt):
|
||||
try:
|
||||
nonce = OpenIDNonce.objects.get(
|
||||
server_url=server_url,
|
||||
timestamp=timestamp,
|
||||
salt=salt
|
||||
)
|
||||
except OpenIDNonce.DoesNotExist:
|
||||
nonce = OpenIDNonce.objects.create(
|
||||
server_url=server_url,
|
||||
timestamp=timestamp,
|
||||
salt=salt
|
||||
)
|
||||
return True
|
||||
|
||||
return False
|
109
itf/allauth/socialaccount/providers/openid/views.py
Normal file
109
itf/allauth/socialaccount/providers/openid/views.py
Normal file
|
@ -0,0 +1,109 @@
|
|||
from django.contrib.auth.models import User
|
||||
from django.utils.http import urlencode
|
||||
from django.shortcuts import render_to_response
|
||||
from django.template import RequestContext
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from openid.consumer.discover import DiscoveryFailure
|
||||
from openid.consumer import consumer
|
||||
from openid.extensions.sreg import SRegRequest, SRegResponse
|
||||
from openid.extensions.ax import FetchRequest, FetchResponse, AttrInfo
|
||||
|
||||
from allauth.socialaccount.app_settings import QUERY_EMAIL
|
||||
from allauth.socialaccount.models import SocialAccount, SocialLogin
|
||||
from allauth.socialaccount.helpers import render_authentication_error
|
||||
from allauth.socialaccount.helpers import complete_social_login
|
||||
from allauth.utils import valid_email_or_none
|
||||
|
||||
from utils import DBOpenIDStore
|
||||
from forms import LoginForm
|
||||
from provider import OpenIDProvider
|
||||
|
||||
class AXAttribute:
|
||||
CONTACT_EMAIL = 'http://axschema.org/contact/email'
|
||||
|
||||
|
||||
class SRegField:
|
||||
EMAIL = 'email'
|
||||
|
||||
|
||||
def _openid_consumer(request):
|
||||
store = DBOpenIDStore()
|
||||
client = consumer.Consumer(request.session, store)
|
||||
return client
|
||||
|
||||
|
||||
def login(request):
|
||||
if request.GET.has_key('openid') or request.method == 'POST':
|
||||
form = LoginForm(request.REQUEST)
|
||||
if form.is_valid():
|
||||
client = _openid_consumer(request)
|
||||
try:
|
||||
auth_request = client.begin(form.cleaned_data['openid'])
|
||||
if QUERY_EMAIL:
|
||||
sreg = SRegRequest()
|
||||
sreg.requestField(field_name=SRegField.EMAIL, required=True)
|
||||
auth_request.addExtension(sreg)
|
||||
ax = FetchRequest()
|
||||
ax.add(AttrInfo(AXAttribute.CONTACT_EMAIL,
|
||||
required=True))
|
||||
auth_request.addExtension(ax)
|
||||
callback_url = reverse(callback)
|
||||
state = SocialLogin.marshall_state(request)
|
||||
callback_url = callback_url + '?' + urlencode(dict(state=state))
|
||||
redirect_url = auth_request.redirectURL(
|
||||
request.build_absolute_uri('/'),
|
||||
request.build_absolute_uri(callback_url))
|
||||
return HttpResponseRedirect(redirect_url)
|
||||
except DiscoveryFailure, e:
|
||||
if request.method == 'POST':
|
||||
form._errors["openid"] = form.error_class([e])
|
||||
else:
|
||||
return render_authentication_error(request)
|
||||
else:
|
||||
form = LoginForm()
|
||||
d = dict(form=form)
|
||||
return render_to_response('openid/login.html',
|
||||
d, context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def _get_email_from_response(response):
|
||||
email = None
|
||||
sreg = SRegResponse.fromSuccessResponse(response)
|
||||
if sreg:
|
||||
email = valid_email_or_none(sreg.get(SRegField.EMAIL))
|
||||
if not email:
|
||||
ax = FetchResponse.fromSuccessResponse(response)
|
||||
if ax:
|
||||
try:
|
||||
values = ax.get(AXAttribute.CONTACT_EMAIL)
|
||||
if values:
|
||||
email = valid_email_or_none(values[0])
|
||||
except KeyError:
|
||||
pass
|
||||
return email
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def callback(request):
|
||||
client = _openid_consumer(request)
|
||||
response = client.complete(
|
||||
dict(request.REQUEST.items()),
|
||||
request.build_absolute_uri(request.path))
|
||||
if response.status == consumer.SUCCESS:
|
||||
user = User(email=_get_email_from_response(response))
|
||||
account = SocialAccount(uid=response.identity_url,
|
||||
provider=OpenIDProvider.id,
|
||||
user=user,
|
||||
extra_data={})
|
||||
login = SocialLogin(account)
|
||||
login.state = SocialLogin.unmarshall_state(request.REQUEST.get('state'))
|
||||
ret = complete_social_login(request, login)
|
||||
elif response.status == consumer.CANCEL:
|
||||
ret = HttpResponseRedirect(reverse('socialaccount_login_cancelled'))
|
||||
else:
|
||||
ret = render_authentication_error(request)
|
||||
return ret
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
depends_on = (('socialaccount', '0001_initial'),)
|
||||
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Adding model 'TwitterApp'
|
||||
db.create_table('twitter_twitterapp', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('site', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['sites.Site'])),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=40)),
|
||||
('consumer_key', self.gf('django.db.models.fields.CharField')(max_length=80)),
|
||||
('consumer_secret', self.gf('django.db.models.fields.CharField')(max_length=80)),
|
||||
('request_token_url', self.gf('django.db.models.fields.URLField')(max_length=200)),
|
||||
('access_token_url', self.gf('django.db.models.fields.URLField')(max_length=200)),
|
||||
('authorize_url', self.gf('django.db.models.fields.URLField')(max_length=200)),
|
||||
))
|
||||
db.send_create_signal('twitter', ['TwitterApp'])
|
||||
|
||||
# Adding model 'TwitterAccount'
|
||||
db.create_table('twitter_twitteraccount', (
|
||||
('socialaccount_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['socialaccount.SocialAccount'], unique=True, primary_key=True)),
|
||||
('social_id', self.gf('django.db.models.fields.PositiveIntegerField')(unique=True)),
|
||||
('username', self.gf('django.db.models.fields.CharField')(max_length=15)),
|
||||
('profile_image_url', self.gf('django.db.models.fields.URLField')(max_length=200)),
|
||||
))
|
||||
db.send_create_signal('twitter', ['TwitterAccount'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting model 'TwitterApp'
|
||||
db.delete_table('twitter_twitterapp')
|
||||
|
||||
# Deleting model 'TwitterAccount'
|
||||
db.delete_table('twitter_twitteraccount')
|
||||
|
||||
|
||||
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']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", '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'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", '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'})
|
||||
},
|
||||
'sites.site': {
|
||||
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
|
||||
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'socialaccount.socialaccount': {
|
||||
'Meta': {'object_name': 'SocialAccount'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
},
|
||||
'twitter.twitteraccount': {
|
||||
'Meta': {'object_name': 'TwitterAccount', '_ormbases': ['socialaccount.SocialAccount']},
|
||||
'profile_image_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
|
||||
'social_id': ('django.db.models.fields.PositiveIntegerField', [], {'unique': 'True'}),
|
||||
'socialaccount_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['socialaccount.SocialAccount']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'max_length': '15'})
|
||||
},
|
||||
'twitter.twitterapp': {
|
||||
'Meta': {'object_name': 'TwitterApp'},
|
||||
'access_token_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
|
||||
'authorize_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
|
||||
'consumer_key': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'consumer_secret': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
|
||||
'request_token_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
|
||||
'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['twitter']
|
|
@ -0,0 +1,91 @@
|
|||
# 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):
|
||||
|
||||
# Changing field 'TwitterAccount.social_id'
|
||||
db.alter_column('twitter_twitteraccount', 'social_id', self.gf('django.db.models.fields.BigIntegerField')(unique=True))
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Changing field 'TwitterAccount.social_id'
|
||||
db.alter_column('twitter_twitteraccount', 'social_id', self.gf('django.db.models.fields.PositiveIntegerField')(unique=True))
|
||||
|
||||
|
||||
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']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", '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'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", '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'})
|
||||
},
|
||||
'sites.site': {
|
||||
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
|
||||
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'socialaccount.socialaccount': {
|
||||
'Meta': {'object_name': 'SocialAccount'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
},
|
||||
'twitter.twitteraccount': {
|
||||
'Meta': {'object_name': 'TwitterAccount', '_ormbases': ['socialaccount.SocialAccount']},
|
||||
'profile_image_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
|
||||
'social_id': ('django.db.models.fields.BigIntegerField', [], {'unique': 'True'}),
|
||||
'socialaccount_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['socialaccount.SocialAccount']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'max_length': '15'})
|
||||
},
|
||||
'twitter.twitterapp': {
|
||||
'Meta': {'object_name': 'TwitterApp'},
|
||||
'access_token_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
|
||||
'authorize_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
|
||||
'consumer_key': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'consumer_secret': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
|
||||
'request_token_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
|
||||
'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['twitter']
|
|
@ -0,0 +1,128 @@
|
|||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import DataMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(DataMigration):
|
||||
|
||||
depends_on = (('socialaccount', '0002_genericmodels'),)
|
||||
|
||||
def forwards(self, orm):
|
||||
# Migrate apps
|
||||
app_id_to_sapp = {}
|
||||
for app in orm.TwitterApp.objects.all():
|
||||
sapp = orm['socialaccount.SocialApp'].objects \
|
||||
.create(site=app.site,
|
||||
provider='twitter',
|
||||
name=app.name,
|
||||
key=app.consumer_key,
|
||||
secret=app.consumer_secret)
|
||||
app_id_to_sapp[app.id] = sapp
|
||||
# Migrate accounts
|
||||
acc_id_to_sacc = {}
|
||||
for acc in orm.TwitterAccount.objects.all():
|
||||
sacc = acc.socialaccount_ptr
|
||||
sacc.uid = str(acc.social_id)
|
||||
sacc.extra_data = { 'screen_name': acc.username,
|
||||
'profile_image_url': acc.profile_image_url }
|
||||
sacc.provider = 'twitter'
|
||||
sacc.save()
|
||||
acc_id_to_sacc[acc.id] = sacc
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
"Write your backwards methods here."
|
||||
|
||||
|
||||
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']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", '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'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", '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'})
|
||||
},
|
||||
'sites.site': {
|
||||
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
|
||||
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'socialaccount.socialaccount': {
|
||||
'Meta': {'object_name': 'SocialAccount'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'extra_data': ('allauth.socialaccount.fields.JSONField', [], {'default': "'{}'"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'provider': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'uid': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
},
|
||||
'socialaccount.socialapp': {
|
||||
'Meta': {'object_name': 'SocialApp'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'key': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
|
||||
'provider': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
|
||||
'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"})
|
||||
},
|
||||
'socialaccount.socialtoken': {
|
||||
'Meta': {'unique_together': "(('app', 'account'),)", 'object_name': 'SocialToken'},
|
||||
'account': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['socialaccount.SocialAccount']"}),
|
||||
'app': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['socialaccount.SocialApp']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'token': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
|
||||
'token_secret': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'})
|
||||
},
|
||||
'twitter.twitteraccount': {
|
||||
'Meta': {'object_name': 'TwitterAccount', '_ormbases': ['socialaccount.SocialAccount']},
|
||||
'profile_image_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
|
||||
'social_id': ('django.db.models.fields.BigIntegerField', [], {'unique': 'True'}),
|
||||
'socialaccount_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['socialaccount.SocialAccount']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'max_length': '15'})
|
||||
},
|
||||
'twitter.twitterapp': {
|
||||
'Meta': {'object_name': 'TwitterApp'},
|
||||
'access_token_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
|
||||
'authorize_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
|
||||
'consumer_key': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'consumer_secret': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
|
||||
'request_token_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
|
||||
'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['socialaccount', 'twitter']
|
|
@ -0,0 +1,47 @@
|
|||
# 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):
|
||||
|
||||
# Deleting model 'TwitterAccount'
|
||||
db.delete_table('twitter_twitteraccount')
|
||||
|
||||
# Deleting model 'TwitterApp'
|
||||
db.delete_table('twitter_twitterapp')
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Adding model 'TwitterAccount'
|
||||
db.create_table('twitter_twitteraccount', (
|
||||
('username', self.gf('django.db.models.fields.CharField')(max_length=15)),
|
||||
('social_id', self.gf('django.db.models.fields.BigIntegerField')(unique=True)),
|
||||
('socialaccount_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['socialaccount.SocialAccount'], unique=True, primary_key=True)),
|
||||
('profile_image_url', self.gf('django.db.models.fields.URLField')(max_length=200)),
|
||||
))
|
||||
db.send_create_signal('twitter', ['TwitterAccount'])
|
||||
|
||||
# Adding model 'TwitterApp'
|
||||
db.create_table('twitter_twitterapp', (
|
||||
('consumer_secret', self.gf('django.db.models.fields.CharField')(max_length=80)),
|
||||
('request_token_url', self.gf('django.db.models.fields.URLField')(max_length=200)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=40)),
|
||||
('authorize_url', self.gf('django.db.models.fields.URLField')(max_length=200)),
|
||||
('consumer_key', self.gf('django.db.models.fields.CharField')(max_length=80)),
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('access_token_url', self.gf('django.db.models.fields.URLField')(max_length=200)),
|
||||
('site', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['sites.Site'])),
|
||||
))
|
||||
db.send_create_signal('twitter', ['TwitterApp'])
|
||||
|
||||
|
||||
models = {
|
||||
|
||||
}
|
||||
|
||||
complete_apps = ['twitter']
|
3
itf/allauth/socialaccount/providers/twitter/models.py
Normal file
3
itf/allauth/socialaccount/providers/twitter/models.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
46
itf/allauth/socialaccount/providers/twitter/provider.py
Normal file
46
itf/allauth/socialaccount/providers/twitter/provider.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.utils.http import urlencode
|
||||
|
||||
from allauth.socialaccount import providers
|
||||
from allauth.socialaccount.providers.base import Provider, ProviderAccount
|
||||
|
||||
|
||||
class TwitterAccount(ProviderAccount):
|
||||
def get_screen_name(self):
|
||||
return self.account.extra_data.get('screen_name')
|
||||
|
||||
def get_profile_url(self):
|
||||
ret = None
|
||||
screen_name = self.get_screen_name()
|
||||
if screen_name:
|
||||
ret = 'http://twitter.com/' + screen_name
|
||||
return ret
|
||||
|
||||
def get_avatar_url(self):
|
||||
ret = None
|
||||
profile_image_url = self.account.extra_data.get('profile_image_url')
|
||||
if profile_image_url:
|
||||
# Hmm, hack to get our hands on the large image. Not
|
||||
# really documented, but seems to work.
|
||||
ret = profile_image_url.replace('_normal', '')
|
||||
return ret
|
||||
|
||||
def __unicode__(self):
|
||||
screen_name = self.get_screen_name()
|
||||
return screen_name or super(TwitterAccount, self).__unicode__()
|
||||
|
||||
|
||||
class TwitterProvider(Provider):
|
||||
id = 'twitter'
|
||||
name = 'Twitter'
|
||||
package = 'allauth.socialaccount.providers.twitter'
|
||||
account_class = TwitterAccount
|
||||
|
||||
def get_login_url(self, request, **kwargs):
|
||||
url = reverse('twitter_login')
|
||||
if kwargs:
|
||||
url = url + '?' + urlencode(kwargs)
|
||||
return url
|
||||
|
||||
|
||||
providers.registry.register(TwitterProvider)
|
4
itf/allauth/socialaccount/providers/twitter/urls.py
Normal file
4
itf/allauth/socialaccount/providers/twitter/urls.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from allauth.socialaccount.providers.oauth.urls import default_urlpatterns
|
||||
from provider import TwitterProvider
|
||||
|
||||
urlpatterns = default_urlpatterns(TwitterProvider)
|
47
itf/allauth/socialaccount/providers/twitter/views.py
Normal file
47
itf/allauth/socialaccount/providers/twitter/views.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
from django.utils import simplejson
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from allauth.socialaccount.providers.oauth.client import OAuth
|
||||
from allauth.socialaccount.providers.oauth.views import (OAuthAdapter,
|
||||
OAuthLoginView,
|
||||
OAuthCallbackView)
|
||||
from allauth.socialaccount.models import SocialLogin, SocialAccount
|
||||
|
||||
from provider import TwitterProvider
|
||||
|
||||
|
||||
class TwitterAPI(OAuth):
|
||||
"""
|
||||
Verifying twitter credentials
|
||||
"""
|
||||
url = 'https://twitter.com/account/verify_credentials.json'
|
||||
|
||||
def get_user_info(self):
|
||||
user = simplejson.loads(self.query(self.url))
|
||||
return user
|
||||
|
||||
|
||||
class TwitterOAuthAdapter(OAuthAdapter):
|
||||
provider_id = TwitterProvider.id
|
||||
request_token_url = 'https://api.twitter.com/oauth/request_token'
|
||||
access_token_url = 'https://api.twitter.com/oauth/access_token'
|
||||
# Issue #42 -- this one authenticates over and over again...
|
||||
# authorize_url = 'https://api.twitter.com/oauth/authorize'
|
||||
authorize_url = 'https://api.twitter.com/oauth/authenticate'
|
||||
|
||||
def complete_login(self, request, app, token):
|
||||
client = TwitterAPI(request, app.key, app.secret,
|
||||
self.request_token_url)
|
||||
extra_data = client.get_user_info()
|
||||
uid = extra_data['id']
|
||||
user = User(username=extra_data['screen_name'])
|
||||
account = SocialAccount(user=user,
|
||||
uid=uid,
|
||||
provider=TwitterProvider.id,
|
||||
extra_data=extra_data)
|
||||
return SocialLogin(account)
|
||||
|
||||
|
||||
oauth_login = OAuthLoginView.adapter_view(TwitterOAuthAdapter)
|
||||
oauth_callback = OAuthCallbackView.adapter_view(TwitterOAuthAdapter)
|
||||
|
57
itf/allauth/socialaccount/requests.py
Normal file
57
itf/allauth/socialaccount/requests.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
import urllib
|
||||
import httplib2
|
||||
|
||||
class Response(object):
|
||||
def __init__(self, status_code, content, headers={}):
|
||||
self.status_code = status_code
|
||||
self.content = content
|
||||
self.headers = headers
|
||||
|
||||
@classmethod
|
||||
def from_httplib(cls, resp, content):
|
||||
return Response(resp.status,
|
||||
content,
|
||||
headers=dict(resp.iteritems()))
|
||||
|
||||
|
||||
@property
|
||||
def json(self):
|
||||
import json
|
||||
return json.loads(self.content)
|
||||
|
||||
_mocked_responses = []
|
||||
|
||||
def mock_next_request(resp):
|
||||
global _mocked_responses
|
||||
_mocked_responses.append(resp)
|
||||
|
||||
def _mockable_request(f):
|
||||
def new_f(*args, **kwargs):
|
||||
global _mocked_responses
|
||||
if _mocked_responses:
|
||||
return _mocked_responses.pop(0)
|
||||
return f(*args, **kwargs)
|
||||
return new_f
|
||||
|
||||
@_mockable_request
|
||||
def get(url, params={}):
|
||||
global _mocked_responses
|
||||
if _mocked_responses:
|
||||
return _mocked_responses.pop(0)
|
||||
client = httplib2.Http()
|
||||
query = urllib.urlencode(params)
|
||||
if query:
|
||||
url += '?' + query
|
||||
resp, content = client.request(url, 'GET')
|
||||
return Response.from_httplib(resp, content)
|
||||
|
||||
@_mockable_request
|
||||
def post(url, params):
|
||||
client = httplib2.Http()
|
||||
headers = { 'content-type': 'application/x-www-form-urlencoded' }
|
||||
resp, content = client.request(url, 'POST',
|
||||
body=urllib.urlencode(params),
|
||||
headers=headers)
|
||||
return Response.from_httplib(resp, content)
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user