From: Matías Aguirre Date: Mon, 9 Jul 2012 04:47:37 +0000 (-0300) Subject: Merge branch 'estebistec' X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=ce08404741beab7ccfc2e1ae671d59beb74c2c08;p=django-social-auth.git Merge branch 'estebistec' Conflicts: README.rst doc/contributions.rst social_auth/models.py --- ce08404741beab7ccfc2e1ae671d59beb74c2c08 diff --cc README.rst index 292b1b6,be4f2ed..9abd274 --- a/README.rst +++ b/README.rst @@@ -1343,10 -1289,10 +1363,14 @@@ Attributions to whom deserves - Evernote support +- fmoga_ (Florian Moga) + + - Mixcloud support + + - estebistec_ (Steven Cummings) + + - Overrideable models feature + Copyrights ---------- @@@ -1452,7 -1398,6 +1476,10 @@@ Base work is copyrighted by .. _Odnoklassniki OAuth: http://dev.odnoklassniki.ru/wiki/display/ok/The+OAuth+2.0+Protocol .. _authentication for VKontakte applications: http://www.ikrvss.ru/2011/11/08/django-social-auh-and-vkontakte-application/ .. _Facebook Canvas Application Authentication: http://www.ikrvss.ru/2011/09/22/django-social-auth-and-facebook-canvas-applications/ +.. _Mixcloud OAuth2: http://www.mixcloud.com/developers/documentation/#authorization +.. _Mixcloud API: http://www.mixcloud.com/developers/documentation +.. _Mixcloud Developers: http://www.mixcloud.com/developers +.. _fmoga: https://github.com/fmoga + .. _MongoEngine: http://mongoengine.org + .. _MongoEngine Django integration: http://mongoengine-odm.readthedocs.org/en/latest/django.html + .. _estebistec: https://github.com/estebistec diff --cc doc/contributions.rst index 97df20f,bfba6e4..ae1cb09 --- a/doc/contributions.rst +++ b/doc/contributions.rst @@@ -61,9 -46,8 +61,11 @@@ niQo_ (Nicolas Quiénot hassek_ (Tomas Henriquez) * Evernote support +fmoga_ (Florian Moga) + * Mixcloud support + + estebistec_ (Steven Cummings) + * Overrideable models feature .. _caioariede: https://github.com/caioariede .. _krvss: https://github.com/krvss @@@ -80,7 -64,4 +82,8 @@@ .. _python-oauth2: https://github.com/simplegeo/python-oauth2 .. _niQo: https://github.com/niQo .. _hassek: https://github.com/hassek +.. _fmoga: https://github.com/fmoga +.. _revolunet: https://github.com/revolunet +.. _r4vi: https://github.com/r4vi +.. _danielgtaylor: https://github.com/danielgtaylor + .. _estebistec: https://github.com/estebistec diff --cc social_auth/backends/__init__.py index 0171118,5acc43b..fbf59eb --- a/social_auth/backends/__init__.py +++ b/social_auth/backends/__init__.py @@@ -24,9 -24,9 +23,10 @@@ from django.contrib.auth.backends impor from django.utils import simplejson from django.utils.importlib import import_module + from social_auth.models import UserSocialAuth from social_auth.utils import setting, log, model_to_ctype, ctype_to_model, \ - clean_partial_pipeline + clean_partial_pipeline, url_add_parameters, \ + get_random_string, constant_time_compare from social_auth.store import DjangoOpenIDStore from social_auth.backends.exceptions import StopPipeline, AuthException, \ AuthFailed, AuthCanceled, \ diff --cc social_auth/db/base.py index 0000000,333d3f9..64885b6 mode 000000,100644..100644 --- a/social_auth/db/base.py +++ b/social_auth/db/base.py @@@ -1,0 -1,160 +1,173 @@@ + """Models mixins for Social Auth""" + import base64 -from datetime import datetime ++import time ++from datetime import datetime, timedelta + + from django.utils.timezone import utc + + from openid.association import Association as OIDAssociation + + from social_auth.utils import setting + + + class UserSocialAuthMixin(object): + User = None + user = '' + provider = '' + + def __unicode__(self): + """Return associated user unicode representation""" + return u'%s - %s' % (unicode(self.user), self.provider.title()) + + @property + def tokens(self): + """Return access_token stored in extra_data or None""" + # Make import here to avoid recursive imports :-/ + from social_auth.backends import get_backends + backend = get_backends().get(self.provider) + if backend: + return backend.AUTH_BACKEND.tokens(self) + else: + return {} + + def expiration_datetime(self): - """Return saved session expiration seconds if any. Is returned in - the form of timezone-aware datetime. None is returned if there's no - value stored or it's malformed. ++ """Return provider session live seconds. Returns a timedelta ready to ++ use with session.set_expiry(). ++ ++ If provider returns a timestamp instead of session seconds to live, the ++ timedelta is inferred from current time (using UTC timezone). None is ++ returned if there's no value stored or it's invalid. + """ - if self.extra_data: - name = setting('SOCIAL_AUTH_EXPIRATION', 'expires') ++ name = setting('SOCIAL_AUTH_EXPIRATION', 'expires') ++ if self.extra_data and name in self.extra_data: + try: - return datetime.utcfromtimestamp(self.extra_data.get(name))\ - .replace(tzinfo=utc) ++ expires = int(self.extra_data.get(name)) + except (ValueError, TypeError): - pass - return None ++ return None ++ ++ now = datetime.now() ++ now_timestamp = time.mktime(now.timetuple()) ++ ++ # Detect if expires is a timestamp ++ if expires > now_timestamp: # expires is a datetime ++ return datetime.utcfromtimestamp(expires) \ ++ .replace(tzinfo=utc) - \ ++ now.replace(tzinfo=utc) ++ else: # expires is a timedelta ++ return timedelta(seconds=expires) + + @classmethod + def username_max_length(cls): + raise NotImplementedError('Implement in subclass') + + @classmethod + def simple_user_exists(cls, *args, **kwargs): + """ + Return True/False if a User instance exists with the given arguments. + Arguments are directly passed to filter() manager method. + """ + return cls.User.objects.filter(*args, **kwargs).count() > 0 + + @classmethod + def create_user(cls, *args, **kwargs): + return cls.User.objects.create(*args, **kwargs) + + @classmethod + def get_user(cls, pk): + try: + return cls.User.objects.get(pk=pk) + except cls.User.DoesNotExist: + return None + + @classmethod + def get_user_by_email(cls, email): + return cls.User.objects.get(email=email) + + @classmethod + def resolve_user_or_id(cls, user_or_id): + if isinstance(user_or_id, cls.User): + return user_or_id + return cls.User.objects.get(pk=user_or_id) + + @classmethod + def get_social_auth(cls, provider, uid): + try: + return cls.objects.get(provider=provider, uid=uid) + except cls.DoesNotExist: + return None + + @classmethod + def get_social_auth_for_user(cls, user): + return user.social_auth.all() + + @classmethod + def create_social_auth(cls, user, uid, provider): + return cls.objects.create(user=user, uid=uid, provider=provider) + + @classmethod + def store_association(cls, server_url, association): + from social_auth.models import Association + args = {'server_url': server_url, 'handle': association.handle} + try: + assoc = Association.objects.get(**args) + except Association.DoesNotExist: + assoc = Association(**args) + assoc.secret = base64.encodestring(association.secret) + assoc.issued = association.issued + assoc.lifetime = association.lifetime + assoc.assoc_type = association.assoc_type + assoc.save() + + @classmethod + def get_oid_associations(cls, server_url, handle=None): + from social_auth.models import Association + args = {'server_url': server_url} + if handle is not None: + args['handle'] = handle + + return sorted([ + (assoc.id, + OIDAssociation(assoc.handle, + base64.decodestring(assoc.secret), + assoc.issued, + assoc.lifetime, + assoc.assoc_type)) + for assoc in Association.objects.filter(**args) + ], key=lambda x: x[1].issued, reverse=True) + + @classmethod + def delete_associations(cls, ids_to_delete): + from social_auth.models import Association + Association.objects.filter(pk__in=ids_to_delete).delete() + + @classmethod + def use_nonce(cls, server_url, timestamp, salt): + from social_auth.models import Nonce + return Nonce.objects.get_or_create(server_url=server_url, + timestamp=timestamp, + salt=salt)[1] + + + class NonceMixin(object): + """One use numbers""" + server_url = '' + timestamp = 0 + salt = '' + + def __unicode__(self): + """Unicode representation""" + return self.server_url + + + class AssociationMixin(object): + """OpenId account association""" + server_url = '' + handle = '' + secret = '' + issued = 0 + lifetime = 0 + assoc_type = '' + + def __unicode__(self): + """Unicode representation""" + return '%s %s' % (self.handle, self.issued)