Statistics
| Branch: | Tag: | Revision:

root / astakos / im / target / twitter.py @ a196eb7e

History | View | Annotate | Download (7.5 kB)

1
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2
# 
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
# 
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
# 
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
# 
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
# 
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
# This is based on the docs at: https://github.com/simplegeo/python-oauth2
35

    
36
import oauth2 as oauth
37
import urlparse
38
import  traceback
39

    
40
from django.conf import settings
41
from django.http import HttpResponse
42
from django.utils import simplejson as json
43
from django.contrib.auth import authenticate
44
from django.contrib import messages
45
from django.shortcuts import redirect
46

    
47
from astakos.im.target.util import prepare_response, requires_anonymous
48
from astakos.im.util import get_or_create_user, get_context
49
from astakos.im.models import AstakosUser, Invitation
50
from astakos.im.views import render_response, create_user
51
from astakos.im.backends import get_backend
52
from astakos.im.forms import LocalUserCreationForm, ThirdPartyUserCreationForm
53
from astakos.im.faults import BadRequest
54

    
55
# It's probably a good idea to put your consumer's OAuth token and
56
# OAuth secret into your project's settings. 
57
consumer = oauth.Consumer(settings.TWITTER_KEY, settings.TWITTER_SECRET)
58
client = oauth.Client(consumer)
59

    
60
request_token_url = 'http://twitter.com/oauth/request_token'
61
access_token_url = 'http://twitter.com/oauth/access_token'
62

    
63
# This is the slightly different URL used to authenticate/authorize.
64
authenticate_url = 'http://twitter.com/oauth/authenticate'
65

    
66
@requires_anonymous
67
def login(request, template_name='signup.html', extra_context={}):
68
    # store invitation code and email
69
    request.session['email'] = request.GET.get('email')
70
    request.session['invitation_code'] = request.GET.get('code')
71

    
72
    # Step 1. Get a request token from Twitter.
73
    resp, content = client.request(request_token_url, "GET")
74
    if resp['status'] != '200':
75
        raise Exception("Invalid response from Twitter.")
76
    request_token = dict(urlparse.parse_qsl(content))
77
    if request.GET.get('next'):
78
        request_token['next'] = request.GET['next']
79
    
80
    # Step 2. Store the request token in a session for later use.
81
    response = HttpResponse()
82
    request.session['Twitter-Request-Token'] = value=json.dumps(request_token)
83
    
84
    # Step 3. Redirect the user to the authentication URL.
85
    url = "%s?oauth_token=%s" % (authenticate_url, request_token['oauth_token'])
86
    response['Location'] = url
87
    response.status_code = 302
88
    
89
    return response
90

    
91
@requires_anonymous
92
def authenticated(request, backend=None, template_name='login.html', extra_context={}):
93
    # Step 1. Use the request token in the session to build a new client.
94
    data = request.session.get('Twitter-Request-Token')
95
    if not data:
96
        raise Exception("Request token cookie not found.")
97
    del request.session['Twitter-Request-Token']
98
    
99
    request_token = json.loads(data)
100
    if not hasattr(request_token, '__getitem__'):
101
        raise BadRequest('Invalid data formating')
102
    try:
103
        token = oauth.Token(request_token['oauth_token'],
104
                            request_token['oauth_token_secret'])
105
    except:
106
        raise BadRequest('Invalid request token cookie formatting')
107
    client = oauth.Client(consumer, token)
108
    
109
    # Step 2. Request the authorized access token from Twitter.
110
    resp, content = client.request(access_token_url, "GET")
111
    if resp['status'] != '200':
112
        raise Exception("Invalid response from Twitter.")
113
    
114
    """
115
    This is what you'll get back from Twitter. Note that it includes the
116
    user's user_id and screen_name.
117
    {
118
        'oauth_token_secret': 'IcJXPiJh8be3BjDWW50uCY31chyhsMHEhqJVsphC3M',
119
        'user_id': '120889797', 
120
        'oauth_token': '120889797-H5zNnM3qE0iFoTTpNEHIz3noL9FKzXiOxwtnyVOD',
121
        'screen_name': 'heyismysiteup'
122
    }
123
    """
124
    access_token = dict(urlparse.parse_qsl(content))
125
    
126
    # Step 3. Lookup the user or create them if they don't exist.
127
    
128
    # When creating the user I just use their screen_name@twitter.com
129
    # for their email and the oauth_token_secret for their password.
130
    # These two things will likely never be used. Alternatively, you 
131
    # can prompt them for their email here. Either way, the password 
132
    # should never be used.
133
    screen_name = access_token['screen_name']
134
    next = request_token.get('next')
135
    
136
    # check first if user with that email is registered
137
    # and if not create one
138
    user = None
139
    email = request.session.pop('email')
140
    
141
    # signup mode
142
    if email:
143
        if not reserved_screen_name(screen_name): 
144
            try:
145
                user = AstakosUser.objects.get(email = email)
146
            except AstakosUser.DoesNotExist, e:
147
                # register a new user
148
                post_data = {'provider':'Twitter', 'affiliation':'twitter',
149
                                'third_party_identifier':screen_name}
150
                form = ThirdPartyUserCreationForm({'email':email})
151
                return create_user(request, form, backend, post_data, next, template_name, extra_context)
152
        else:
153
            status = messages.ERROR
154
            message = '%s@twitter is already registered' % screen_name
155
            messages.add_message(request, messages.ERROR, message)
156
    else:
157
        # login mode
158
        try:
159
            user = AstakosUser.objects.get(third_party_identifier = screen_name,
160
                                           provider = 'Twitter')
161
        except AstakosUser.DoesNotExist:
162
            messages.add_message(request, messages.ERROR, 'Not registered user')
163
        if user and user.is_active:
164
            #in order to login the user we must call authenticate first
165
            user = authenticate(email=user.email, auth_token=user.auth_token)
166
            return prepare_response(request, user, next)
167
        elif user and not user.is_active:
168
            messages.add_message(request, messages.ERROR, 'Inactive account: %s' % user.email)
169
    return render_response(template_name,
170
                   form = LocalUserCreationForm(),
171
                   context_instance=get_context(request, extra_context))
172

    
173
def reserved_screen_name(screen_name):
174
    try:
175
        AstakosUser.objects.get(provider='Twitter',
176
                                third_party_identifier=screen_name)
177
        return True
178
    except AstakosUser.DoesNotExist, e:
179
        return False