Skip to content
This repository has been archived by the owner on Oct 15, 2021. It is now read-only.

Allow social auth users to choose usernames #115

Open
wants to merge 3 commits into
base: devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion transifex/settings/52-socialauth.conf
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,16 @@ SOCIAL_AUTH_ASSOCIATE_BY_MAIL = True
from txcommon.template import slugify
SOCIAL_AUTH_USERNAME_FIXER = lambda u: slugify(u).replace('-', '.')

SOCIAL_AUTH_CREATE_USERS = False
SOCIAL_AUTH_RAISE_EXCEPTIONS = False
SOCIAL_AUTH_PIPELINE_RESUME_ENTRY = 'social_auth.backends.pipeline.misc.save_status_to_session'

# Register our custom user creation function
SOCIAL_AUTH_PIPELINE = (
'social_auth.backends.pipeline.social.social_auth_user',
'social_auth.backends.pipeline.associate.associate_by_email',
'transifex.txcommon.user.get_username',
'social_auth.backends.pipeline.misc.save_status_to_session',
'transifex.txcommon.user.redirect_to_get_username_form',
'transifex.txcommon.user.create_user',
'social_auth.backends.pipeline.social.associate_user',
'social_auth.backends.pipeline.social.load_extra_data',
Expand Down
19 changes: 19 additions & 0 deletions transifex/templates/txcommon/get_username.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{% extends "base-sample.html" %}
{% load i18n %}
{% block title %}{% trans "Registration" %}{% endblock %}

{% block content_title %}{% trans "User Registration" %}{% endblock %}

{% block content_main %}
<form action="" method="post">{% csrf_token %}
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.username.errors }}
<label for="id_username">Username:</label>
{{ form.username }}
</div>
<input type="submit" value="Submit" />
</form>
{% endblock %}

{% block content_footer %}{% endblock %}
18 changes: 18 additions & 0 deletions transifex/txcommon/forms.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from django import forms
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _

from contact_form.forms import ContactForm
from tagging.forms import TagField
from tagging_autocomplete.widgets import TagAutocomplete
from userena.forms import EditProfileForm as UserenaEditProfileForm,\
AuthenticationForm
from userena.utils import get_profile_model
from social_auth.backends.pipeline import USERNAME_MAX_LENGTH


class EditProfileForm(UserenaEditProfileForm):
Expand Down Expand Up @@ -42,3 +45,18 @@ class TxAuthenticationForm(AuthenticationForm):
def __init__(self, *args, **kwargs):
super(TxAuthenticationForm, self).__init__(*args, **kwargs)
self.fields['remember_me'].initial = True

class GetUsernameForm(forms.Form):
username = forms.CharField(max_length=USERNAME_MAX_LENGTH, widget=forms.TextInput())

def __init__(self, *args, **kwargs):
super(GetUsernameForm, self).__init__(*args, **kwargs)

def clean_username(self):
data = self.cleaned_data
try:
User.objects.get(username = data['username'])
except User.DoesNotExist:
return data['username']
raise forms.ValidationError(_('This username is already taken.'))

70 changes: 18 additions & 52 deletions transifex/txcommon/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
from uuid import uuid4
from django.conf import settings
from django.contrib.auth.models import User
from django.shortcuts import render_to_response
from django.template import RequestContext

from userena.models import UserenaSignup
from social_auth.backends.pipeline import USERNAME, USERNAME_MAX_LENGTH, \
warn_setting

from transifex.txcommon.forms import GetUsernameForm

class CreateUserFromSocial(object):
"""Create local users from a social auth mechanism.
Expand Down Expand Up @@ -42,57 +44,21 @@ def __call__(self, *args, **kwargs):

create_user = CreateUserFromSocial()


class GetUsername(object):
"""Choose a username for socially authenticated users.

This is a wrapper around social_auth.backends.pipeline.user.get_username.
def redirect_to_get_username_form(request, user=None, username=None, *args, **kwargs):
""" Redirect user to from to enter desired username
"""
template_name = 'txcommon/get_username.html'
if user:
return {'username': user.username}

def __call__(self, details, user=None, *args, **kwargs):
"""Get a new username.

We check for existing usernames in a case-insensitive way.
"""
if user:
return {'username': user.username}

warn_setting('SOCIAL_AUTH_FORCE_RANDOM_USERNAME', 'get_username')
warn_setting('SOCIAL_AUTH_DEFAULT_USERNAME', 'get_username')
warn_setting('SOCIAL_AUTH_UUID_LENGTH', 'get_username')
warn_setting('SOCIAL_AUTH_USERNAME_FIXER', 'get_username')

if getattr(settings, 'SOCIAL_AUTH_FORCE_RANDOM_USERNAME', False):
username = uuid4().get_hex()
elif details.get(USERNAME):
username = details[USERNAME]
elif settings.hasattr('SOCIAL_AUTH_DEFAULT_USERNAME'):
username = settings.SOCIAL_AUTH_DEFAULT_USERNAME
if callable(username):
username = username()
else:
username = uuid4().get_hex()

uuid_lenght = getattr(settings, 'SOCIAL_AUTH_UUID_LENGTH', 16)
username_fixer = getattr(settings, 'SOCIAL_AUTH_USERNAME_FIXER',
lambda u: u)

short_username = username[:USERNAME_MAX_LENGTH - uuid_lenght]
final_username = None

while True:
final_username = username_fixer(username)[:USERNAME_MAX_LENGTH]
if request.method == 'POST':
form = GetUsernameForm(request.POST)
if form.is_valid():
return {'username': form.cleaned_data['username']}
else:
form = GetUsernameForm({'username': username})

try:
User.objects.get(username__iexact=final_username)
except User.DoesNotExist:
break
else:
# User with same username already exists, generate a unique
# username for current user using username as base but adding
# a unique hash at the end. Original username is cut to avoid
# the field max_length.
username = short_username + uuid4().get_hex()[:uuid_lenght]
return {'username': final_username}
return render_to_response(template_name, {
'form': form
}, context_instance=RequestContext(request))

get_username = GetUsername()