-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added social auth... #405
base: develop
Are you sure you want to change the base?
Added social auth... #405
Changes from 6 commits
27b9ba6
6f3e3a5
877e8e6
975919e
154a93f
7a62df1
07e736b
de224fd
f60101e
6a71cc2
8dc9189
9cd4dd7
234cd85
2358b76
d83e4d8
f941e4d
69a839b
2ad75db
7d4b614
eefeeaf
95000c8
61f7512
a68a8d7
4074506
6fc8016
abeb563
05ef643
fb1ee77
ac18294
ee71430
9a5c366
650f643
9c3c79b
66cd83e
1441faf
6749cd0
3faba06
f0b76ea
841760f
44d074e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from social_auth.middleware import SocialAuthExceptionMiddleware | ||
from django.conf import settings | ||
|
||
|
||
class OpenBudgetsSocialAuthExceptionMiddleware(SocialAuthExceptionMiddleware): | ||
def get_redirect_uri(self, request, exception): | ||
return settings.LOGIN_URL |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from social_auth.exceptions import SocialAuthBaseException | ||
from django.utils.translation import ugettext | ||
|
||
|
||
class NonIdenticalEmailAddress(SocialAuthBaseException): | ||
def __unicode__(self): | ||
return ugettext(u'Identical email error: %(message)s' % {'message': | ||
self.message}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should prabably be: return _(u'Identical email error: %s') % self.message So that the string formatting is done after the translation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @yprez is correct, however, it's still better to keep the named params form:
this helps a lot later in the translation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ydaniv agreed, we should always use named params, and actually, in the codebase we mostly use the newer python string formatting, which I definitely prefer: '{msg}'.format(msg=self.message) At least - it needs to be lazy. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agreed.
Is best imo. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. This form of formating is also best IMO
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, will path this up and update the PR, as well as other improvements. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist | ||
from django.utils.translation import ugettext | ||
from social_auth.models import UserSocialAuth | ||
from .models import Account | ||
from social_auth.exceptions import AuthException | ||
from social_exceptions import NonIdenticalEmailAddress | ||
|
||
|
||
def associate_by_email(details, user=None, *args, **kwargs): | ||
"""Return user entry with same email address as one returned on details.""" | ||
email = details.get('email', None) | ||
|
||
if user and user.email == email: | ||
return None | ||
elif not email or (user and user.email != email): | ||
msg = ugettext('Social email address and account email ' + | ||
'address must be idnetical') | ||
raise NonIdenticalEmailAddress(msg) | ||
if email: | ||
# Try to associate accounts registered with the same email address, | ||
# only if it's a single object. AuthException is raised if multiple | ||
# objects are returned. | ||
try: | ||
return {'user': UserSocialAuth.get_user_by_email(email=email)} | ||
except MultipleObjectsReturned: | ||
raise AuthException(kwargs['backend'], 'Not unique email address.') | ||
except ObjectDoesNotExist: | ||
pass | ||
|
||
|
||
def create_user(backend, details, response, uid, username, user=None, *args, | ||
**kwargs): | ||
"""Create user. Depends on get_username pipeline.""" | ||
if user: | ||
return {'user': user} | ||
if not username: | ||
return None | ||
|
||
# Avoid hitting field max length | ||
email = details.get('email') | ||
original_email = None | ||
if email and UserSocialAuth.email_max_length() < len(email): | ||
original_email = email | ||
email = '' | ||
first_name = details.get('first_name') or 'John' | ||
last_name = details.get('last_name') or 'Doe' | ||
password = Account.objects.make_random_password() | ||
|
||
return { | ||
'user': UserSocialAuth.create_user(username=username, email=email, | ||
first_name=first_name, | ||
last_name=last_name, | ||
password=password), | ||
'original_email': original_email, | ||
'is_new': True | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,7 +30,19 @@ | |
</div> | ||
</div> | ||
|
||
|
||
<div class="social-accounts"> | ||
{% for provider,account in social_auth.items %} | ||
{% if account and provider %} | ||
<div class="account"> | ||
<form method="POST" action="{% url "socialauth_disconnect_individual" provider account.id %}" | ||
class="social-revoke-form"> | ||
{% csrf_token %} | ||
<input type="submit" class="social-revoke-control" value="-"> {{ provider }} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @BeOleg There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The idea is to have a Same thing can be achieved by placing Wanted to enhance the design of this entire thing, but frankly could not figure out which less file applies to this section :( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't worry abut UI behaviour, until we do new UI work with Ran. |
||
</form> | ||
</div> | ||
{% endif %} | ||
{% endfor %} | ||
</div> | ||
|
||
|
||
|
||
|
@@ -42,7 +54,7 @@ | |
|
||
{% block content %} | ||
<div id="filter"> | ||
<select> | ||
<select>socialauth_disconnect | ||
<option>{% trans 'Show everything' %}</option> | ||
<option>{% trans 'Item comments' %}</option> | ||
<option>{% trans 'Vizualization states' %}</option> | ||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -27,6 +27,7 @@ | |||
CustomRegistrationForm, CustomAuthenticationForm, CustomPasswordChangeForm,\ | ||||
CustomPasswordResetForm | ||||
from openbudgets.commons.mixins.views import UserDataObjectMixin, JSONResponseMixin | ||||
from django.contrib.messages import get_messages | ||||
|
||||
|
||||
class AccountDetailView(LoginRequiredMixin, UserDataObjectMixin, DetailView): | ||||
|
@@ -153,7 +154,6 @@ def account_login(request, template_name='registration/login.html', | |||
redirect_field_name=REDIRECT_FIELD_NAME, | ||||
authentication_form=CustomAuthenticationForm, | ||||
current_app=None, extra_context=None): | ||||
|
||||
redirect_to = request.REQUEST.get(redirect_field_name, '') | ||||
|
||||
if request.method == "POST": | ||||
|
@@ -206,6 +206,7 @@ def account_login(request, template_name='registration/login.html', | |||
redirect_field_name: redirect_to, | ||||
'site': current_site, | ||||
'site_name': current_site.name, | ||||
'messages': get_messages(request), | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not use the
|
||||
} | ||||
|
||||
if extra_context is not None: | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
import os | ||
|
||
|
||
DEBUG = True | ||
|
||
TEMPLATE_DEBUG = DEBUG | ||
|
@@ -103,6 +102,7 @@ | |
'django.middleware.clickjacking.XFrameOptionsMiddleware', | ||
'corsheaders.middleware.CorsMiddleware', | ||
'django.middleware.cache.FetchFromCacheMiddleware', | ||
'openbudgets.apps.accounts.middleware.OpenBudgetsSocialAuthExceptionMiddleware', | ||
) | ||
|
||
INSTALLED_APPS = ( | ||
|
@@ -143,8 +143,45 @@ | |
'openbudgets.apps.transport', | ||
'openbudgets.apps.api', | ||
'openbudgets.commons', | ||
'social_auth', | ||
) | ||
|
||
AUTHENTICATION_BACKENDS = ( | ||
'social_auth.backends.facebook.FacebookBackend', | ||
'social_auth.backends.twitter.TwitterBackend', | ||
'social_auth.backends.google.GoogleBackend', | ||
'social_auth.backends.google.GoogleOAuth2Backend', | ||
'django.contrib.auth.backends.ModelBackend', | ||
) | ||
|
||
SOCIAL_AUTH_PIPELINE = ( | ||
'social_auth.backends.pipeline.social.social_auth_user', | ||
'openbudgets.apps.accounts.social_pipeline.associate_by_email', # only difference from default | ||
'social_auth.backends.pipeline.user.get_username', | ||
# 'social_auth.backends.pipeline.user.create_user', | ||
'openbudgets.apps.accounts.social_pipeline.create_user',#custom pipeline | ||
'social_auth.backends.pipeline.social.associate_user', | ||
'social_auth.backends.pipeline.social.load_extra_data', | ||
'social_auth.backends.pipeline.user.update_user_details' | ||
|
||
) | ||
|
||
try: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand why you wrap all of these in a try/except. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ydaniv asked me to catch an import error there, in case some developers On Fri, Mar 7, 2014 at 8:08 AM, Paul Walsh [email protected] wrote:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, shouldn't this stuff be in the said file then, and not here at all? Seeing as it all strictly depends on that file? Which file are you referring to? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if it these are project's defaults and it makes sense to have them here then they should be left here, if not then they can be removed and we only need import |
||
from . import social_config | ||
FACEBOOK_APP_ID=social_config.social_config_vars.get('FACEBOOK_APP_ID') or None | ||
FACEBOOK_API_SECRET=social_config.social_config_vars.get('FACEBOOK_API_SECRET') or None | ||
TWITTER_CONSUMER_KEY=social_config.social_config_vars.get('TWITTER_CONSUMER_KEY') or None | ||
TWITTER_CONSUMER_SECRET=social_config.social_config_vars.get('GOOGLE_CONSUMER_SECRET') or None | ||
FACEBOOK_EXTENDED_PERMISSIONS = ['email'] | ||
SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL = True | ||
SOCIAL_AUTH_FORCE_POST_DISCONNECT = True | ||
SOCIAL_AUTH_REDIRECT_IS_HTTPS = False #? | ||
SOCIAL_AUTH_CREATE_USERS= True | ||
SOCIAL_AUTH_FORCE_RANDOM_USERNAME=False | ||
SOCIAL_AUTH_PROTECTED_USER_FIELDS = ['email', 'first_name', 'last_name'] | ||
except ImportError: | ||
pass | ||
|
||
TEMPLATE_CONTEXT_PROCESSORS = ( | ||
'django.contrib.auth.context_processors.auth', | ||
'django.core.context_processors.debug', | ||
|
@@ -157,6 +194,7 @@ | |
'openbudgets.commons.context_processors.site', | ||
'openbudgets.commons.context_processors.forms', | ||
'openbudgets.commons.context_processors.openbudgets', | ||
'social_auth.context_processors.social_auth_by_name_backends', | ||
) | ||
|
||
LOGGING = { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
social_config_vars = {} | ||
social_config_vars['FACEBOOK_APP_ID']='393614634107619'#local | ||
social_config_vars['FACEBOOK_API_SECRET']='67745d338966c0049543cd82b4601d49' | ||
social_config_vars['TWITTER_CONSUMER_KEY']='v8v3kladozPuOmKdRF3aTw' | ||
social_config_vars['TWITTER_CONSUMER_SECRET']='makIoMXdTmw6SI8DKsuqRH9ozESgKxXPuxEoMTyaZs' | ||
social_config_vars['GOOGLE_CONSUMER_KEY']='318602050989.apps.googleusercontent.com'#redirects to openmuni.org.il | ||
social_config_vars['GOOGLE_CONSUMER_SECRET']='F6enSvoTvkm9-4_NwsOCWYr7' | ||
|
||
#staging | ||
#social_config_vars['FACEBOOK_APP_ID']='' | ||
#social_config_vars['FACEBOOK_API_SECRET']='' | ||
|
||
# social_config_vars['TWITTER_CONSUMER_KEY']='' | ||
# social_config_vars['TWITTER_CONSUMER_SECRET']='' | ||
# social_config_vars['GOOGLE_CONSUMER_KEY']='' | ||
# social_config_vars['GOOGLE_CONSUMER_SECRET']='' | ||
|
||
#prod | ||
#social_config_vars['FACEBOOK_APP_ID']='' | ||
#social_config_vars['FACEBOOK_API_SECRET']='' | ||
|
||
# social_config_vars['TWITTER_CONSUMER_KEY']='' | ||
# social_config_vars['TWITTER_CONSUMER_SECRET']='' | ||
# social_config_vars['GOOGLE_CONSUMER_KEY']='' | ||
# social_config_vars['GOOGLE_CONSUMER_SECRET']='' |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,5 +57,7 @@ | |
|
||
url(r'^', | ||
include('openbudgets.apps.pages.urls')), | ||
url(r'', | ||
include('social_auth.urls')), | ||
|
||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,64 @@ | ||
django==1.5.5 | ||
Django==1.5.5 | ||
Fabric==1.8.1 | ||
Jinja2==2.7.2 | ||
MarkupSafe==0.18 | ||
Pillow==2.3.0 | ||
Pygments==1.6 | ||
Quilt==0.1-alpha | ||
South==0.8.4 | ||
Sphinx==1.2.1 | ||
amqp==1.4.2 | ||
anyjson==0.3.3 | ||
argparse==1.2.1 | ||
billiard==3.3.0.14 | ||
celery==3.1.8 | ||
ckanclient==0.10 | ||
coverage==3.7.1 | ||
cuisine==0.6.5 | ||
django-autoslug==1.7.2 | ||
django-braces==1.3.1 | ||
django-celery==3.1.1 | ||
django-cors-headers==0.12 | ||
django-debug-toolbar==1.0.1 | ||
django-grappelli==2.4.8 | ||
django-gravatar2==1.1.3 | ||
django-modeltranslation==0.7.3 | ||
django-oauth-toolkit==0.6.0 | ||
django-pdb==0.3.2 | ||
django-redis-cache==0.10.2 | ||
django-registration==0.9b1 | ||
django-social-auth==0.7.28 | ||
django-subdomains==2.0.4 | ||
django-taggit==0.11.2 | ||
django-uuidfield==0.4.0 | ||
djangorestframework==2.3.9 | ||
gunicorn | ||
psycopg2 | ||
south | ||
dock==0.1.1 | ||
docutils==0.11 | ||
ecdsa==0.10 | ||
factory-boy==2.3.1 | ||
gdata==2.0.18 | ||
grappelli-modeltranslation==0.1.2 | ||
gunicorn==18.0 | ||
hiredis==0.1.2 | ||
httplib2==0.8 | ||
ipdb==0.8 | ||
ipython==1.1.0 | ||
jsonfield==0.9.20 | ||
kombu==3.0.11 | ||
mock==1.0.1 | ||
oauth2==1.5.211 | ||
oauthlib==0.6.1 | ||
paramiko==1.12.1 | ||
psycopg2==2.5.2 | ||
pycrypto==2.6.1 | ||
pystache==0.5.3 | ||
python-openid==2.2.5 | ||
python-quilt==0.2 | ||
pytz==2013b | ||
tablib | ||
celery | ||
factory-boy | ||
coverage | ||
redis | ||
hiredis | ||
pillow | ||
sphinx | ||
raven | ||
gdata | ||
ckanclient | ||
jsonfield | ||
pystache | ||
mock | ||
django-celery | ||
django-oauth-toolkit | ||
django-redis-cache | ||
django-autoslug | ||
django-pdb | ||
django-gravatar2 | ||
django-taggit | ||
django-debug-toolbar | ||
django-braces | ||
django-modeltranslation | ||
django-grappelli==2.4.8 | ||
django-cors-headers | ||
django-subdomains | ||
grappelli-modeltranslation | ||
git+https://github.com/dcramer/django-uuidfield.git#egg=uuidfield | ||
git+https://github.com/mozilla/unicode-slugify | ||
|
||
# upstream still doesn't fully support custom user model | ||
hg+https://bitbucket.org/prjts/django-registration | ||
|
||
# temp, while working | ||
git+https://github.com/pwalsh/quilt#egg=quilt | ||
git+https://github.com/pwalsh/dock#egg=dock | ||
raven==4.0.4 | ||
redis==2.9.1 | ||
six==1.3.0 | ||
sqlparse==0.1.10 | ||
tablib==0.9.11 | ||
unicode-slugify==0.1.1 | ||
wsgiref==0.1.2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that using
ugettextlazy
here will be better. and importas _
for make the code cleaner...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yprez, I'm not sure we need a lazy gettext here. The lazy form is usually needed when you call
_(...)
in runtime when evaluating a class' attribute that's not wrapped in a callable, e.g. a model's field.Here the text is wrapped in a function, so I don't see a reason for making it lazy.
Don't you agree?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose there is no functional difference in this case.
Personally I always use lazy gettext, so the function returns a lazy object, unless it's problematic. Seems cleaner to evaluate the gettext on rendering than on function call.
Maybe it's just my personal preference, I haven't given it much thought until now...