Revision bef3bf46
b/snf-astakos-app/astakos/im/backends.py | ||
---|---|---|
61 | 61 |
according to the INVITATIONS_ENABLED setting |
62 | 62 |
(if True returns ``astakos.im.backends.InvitationsBackend`` and if False |
63 | 63 |
returns ``astakos.im.backends.SimpleBackend``). |
64 |
|
|
64 |
|
|
65 | 65 |
If the backend cannot be located ``django.core.exceptions.ImproperlyConfigured`` |
66 | 66 |
is raised. |
67 | 67 |
""" |
... | ... | |
93 | 93 |
""" |
94 | 94 |
self.request = request |
95 | 95 |
self.invitation = get_invitation(request) |
96 |
|
|
96 |
|
|
97 | 97 |
def get_signup_form(self, provider): |
98 | 98 |
""" |
99 |
Returns the form class name
|
|
99 |
Returns the form class name |
|
100 | 100 |
""" |
101 | 101 |
invitation = self.invitation |
102 | 102 |
initial_data = self.get_signup_initial_data(provider) |
... | ... | |
104 | 104 |
main = provider.capitalize() if provider == 'local' else 'ThirdParty' |
105 | 105 |
suffix = 'UserCreationForm' |
106 | 106 |
formclass = '%s%s%s' % (prefix, main, suffix) |
107 |
return globals()[formclass](initial_data, ip=self.request.META['REMOTE_ADDR']) |
|
108 |
|
|
107 |
ip = self.request.META.get('REMOTE_ADDR', |
|
108 |
self.request.META.get('HTTP_X_REAL_IP', None)) |
|
109 |
return globals()[formclass](initial_data, ip=ip) |
|
110 |
|
|
109 | 111 |
def get_signup_initial_data(self, provider): |
110 | 112 |
""" |
111 | 113 |
Returns the necassary registration form depending the user is invited or not |
112 |
|
|
114 |
|
|
113 | 115 |
Throws Invitation.DoesNotExist in case ``code`` is not valid. |
114 | 116 |
""" |
115 | 117 |
request = self.request |
... | ... | |
128 | 130 |
if provider == request.POST.get('provider', ''): |
129 | 131 |
initial_data = request.POST |
130 | 132 |
return initial_data |
131 |
|
|
133 |
|
|
132 | 134 |
def _is_preaccepted(self, user): |
133 | 135 |
""" |
134 | 136 |
If there is a valid, not-consumed invitation code for the specific user |
... | ... | |
141 | 143 |
invitation.consume() |
142 | 144 |
return True |
143 | 145 |
return False |
144 |
|
|
146 |
|
|
145 | 147 |
@transaction.commit_manually |
146 | 148 |
def signup(self, form, admin_email_template_name='im/admin_notification.txt'): |
147 | 149 |
""" |
... | ... | |
149 | 151 |
(has a valid invitation code) the user is activated and if the request |
150 | 152 |
param ``next`` is present redirects to it. |
151 | 153 |
In any other case the method returns the action status and a message. |
152 |
|
|
154 |
|
|
153 | 155 |
The method uses commit_manually decorator in order to ensure the user |
154 | 156 |
will be created only if the procedure has been completed successfully. |
155 | 157 |
""" |
... | ... | |
170 | 172 |
except socket.error, e: |
171 | 173 |
status = messages.ERROR |
172 | 174 |
message = _(e.strerror) |
173 |
|
|
175 |
|
|
174 | 176 |
# rollback in case of error |
175 | 177 |
if status == messages.ERROR: |
176 | 178 |
transaction.rollback() |
... | ... | |
186 | 188 |
""" |
187 | 189 |
def __init__(self, request): |
188 | 190 |
self.request = request |
189 |
|
|
191 |
|
|
190 | 192 |
def get_signup_form(self, provider): |
191 | 193 |
""" |
192 | 194 |
Returns the form class name |
... | ... | |
199 | 201 |
if request.method == 'POST': |
200 | 202 |
if provider == request.POST.get('provider', ''): |
201 | 203 |
initial_data = request.POST |
202 |
return globals()[formclass](initial_data, ip=self.request.META['REMOTE_ADDR']) |
|
203 |
|
|
204 |
ip = self.request.META.get('REMOTE_ADDR', |
|
205 |
self.request.META.get('HTTP_X_REAL_IP', None)) |
|
206 |
return globals()[formclass](initial_data, ip=ip) |
|
207 |
|
|
204 | 208 |
@transaction.commit_manually |
205 | 209 |
def signup(self, form, email_template_name='im/activation_email.txt', admin_email_template_name='im/admin_notification.txt'): |
206 | 210 |
""" |
207 | 211 |
Creates an inactive user account and sends a verification email. |
208 |
|
|
212 |
|
|
209 | 213 |
The method uses commit_manually decorator in order to ensure the user |
210 | 214 |
will be created only if the procedure has been completed successfully. |
211 |
|
|
215 |
|
|
212 | 216 |
** Arguments ** |
213 |
|
|
217 |
|
|
214 | 218 |
``email_template_name`` |
215 | 219 |
A custom template for the verification email body to use. This is |
216 | 220 |
optional; if not specified, this will default to |
217 | 221 |
``im/activation_email.txt``. |
218 |
|
|
222 |
|
|
219 | 223 |
** Templates ** |
220 | 224 |
im/activation_email.txt or ``email_template_name`` keyword argument |
221 |
|
|
225 |
|
|
222 | 226 |
** Settings ** |
223 |
|
|
227 |
|
|
224 | 228 |
* DEFAULT_CONTACT_EMAIL: service support email |
225 | 229 |
* DEFAULT_FROM_EMAIL: from email |
226 | 230 |
""" |
... | ... | |
242 | 246 |
status = messages.ERROR |
243 | 247 |
name = 'strerror' |
244 | 248 |
message = getattr(e, name) if hasattr(e, name) else e |
245 |
|
|
249 |
|
|
246 | 250 |
# rollback in case of error |
247 | 251 |
if status == messages.ERROR: |
248 | 252 |
transaction.rollback() |
b/snf-astakos-app/astakos/im/target/twitter.py | ||
---|---|---|
1 | 1 |
# Copyright 2011-2012 GRNET S.A. All rights reserved. |
2 |
#
|
|
2 |
# |
|
3 | 3 |
# Redistribution and use in source and binary forms, with or |
4 | 4 |
# without modification, are permitted provided that the following |
5 | 5 |
# conditions are met: |
6 |
#
|
|
6 |
# |
|
7 | 7 |
# 1. Redistributions of source code must retain the above |
8 | 8 |
# copyright notice, this list of conditions and the following |
9 | 9 |
# disclaimer. |
10 |
#
|
|
10 |
# |
|
11 | 11 |
# 2. Redistributions in binary form must reproduce the above |
12 | 12 |
# copyright notice, this list of conditions and the following |
13 | 13 |
# disclaimer in the documentation and/or other materials |
14 | 14 |
# provided with the distribution. |
15 |
#
|
|
15 |
# |
|
16 | 16 |
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
17 | 17 |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | 18 |
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
... | ... | |
25 | 25 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
26 | 26 |
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
27 | 27 |
# POSSIBILITY OF SUCH DAMAGE. |
28 |
#
|
|
28 |
# |
|
29 | 29 |
# The views and conclusions contained in the software and |
30 | 30 |
# documentation are those of the authors and should not be |
31 | 31 |
# interpreted as representing official policies, either expressed |
... | ... | |
49 | 49 |
from astakos.im.settings import TWITTER_KEY, TWITTER_SECRET, INVITATIONS_ENABLED, IM_MODULES |
50 | 50 |
|
51 | 51 |
# It's probably a good idea to put your consumer's OAuth token and |
52 |
# OAuth secret into your project's settings.
|
|
52 |
# OAuth secret into your project's settings. |
|
53 | 53 |
consumer = oauth.Consumer(TWITTER_KEY, TWITTER_SECRET) |
54 | 54 |
client = oauth.Client(consumer) |
55 | 55 |
|
... | ... | |
72 | 72 |
request_token = dict(urlparse.parse_qsl(content)) |
73 | 73 |
if request.GET.get('next'): |
74 | 74 |
request_token['next'] = request.GET['next'] |
75 |
|
|
75 |
|
|
76 | 76 |
# Step 2. Store the request token in a session for later use. |
77 | 77 |
response = HttpResponse() |
78 | 78 |
request.session['Twitter-Request-Token'] = value=json.dumps(request_token) |
79 |
|
|
79 |
|
|
80 | 80 |
# Step 3. Redirect the user to the authentication URL. |
81 | 81 |
url = "%s?oauth_token=%s" % (authenticate_url, request_token['oauth_token']) |
82 | 82 |
response['Location'] = url |
83 | 83 |
response.status_code = 302 |
84 |
|
|
84 |
|
|
85 | 85 |
return response |
86 | 86 |
|
87 | 87 |
@requires_anonymous |
... | ... | |
91 | 91 |
if not data: |
92 | 92 |
raise Exception("Request token cookie not found.") |
93 | 93 |
del request.session['Twitter-Request-Token'] |
94 |
|
|
94 |
|
|
95 | 95 |
request_token = json.loads(data) |
96 | 96 |
if not hasattr(request_token, '__getitem__'): |
97 | 97 |
raise BadRequest('Invalid data formating') |
... | ... | |
101 | 101 |
except: |
102 | 102 |
raise BadRequest('Invalid request token cookie formatting') |
103 | 103 |
client = oauth.Client(consumer, token) |
104 |
|
|
104 |
|
|
105 | 105 |
# Step 2. Request the authorized access token from Twitter. |
106 | 106 |
resp, content = client.request(access_token_url, "GET") |
107 | 107 |
if resp['status'] != '200': |
108 | 108 |
raise Exception("Invalid response from Twitter.") |
109 |
|
|
109 |
|
|
110 | 110 |
""" |
111 | 111 |
This is what you'll get back from Twitter. Note that it includes the |
112 | 112 |
user's user_id and screen_name. |
113 | 113 |
{ |
114 | 114 |
'oauth_token_secret': 'IcJXPiJh8be3BjDWW50uCY31chyhsMHEhqJVsphC3M', |
115 |
'user_id': '120889797',
|
|
115 |
'user_id': '120889797', |
|
116 | 116 |
'oauth_token': '120889797-H5zNnM3qE0iFoTTpNEHIz3noL9FKzXiOxwtnyVOD', |
117 | 117 |
'screen_name': 'heyismysiteup' |
118 | 118 |
} |
119 | 119 |
""" |
120 | 120 |
access_token = dict(urlparse.parse_qsl(content)) |
121 |
|
|
121 |
|
|
122 | 122 |
# Step 3. Lookup the user or create them if they don't exist. |
123 |
|
|
123 |
|
|
124 | 124 |
# When creating the user I just use their screen_name@twitter.com |
125 | 125 |
# for their email and the oauth_token_secret for their password. |
126 |
# These two things will likely never be used. Alternatively, you
|
|
127 |
# can prompt them for their email here. Either way, the password
|
|
126 |
# These two things will likely never be used. Alternatively, you |
|
127 |
# can prompt them for their email here. Either way, the password |
|
128 | 128 |
# should never be used. |
129 | 129 |
screen_name = access_token['screen_name'] |
130 | 130 |
next = request_token.get('next') |
131 |
|
|
131 |
|
|
132 | 132 |
# check first if user with that email is registered |
133 | 133 |
# and if not create one |
134 | 134 |
user = None |
135 | 135 |
email = request.session.pop('email') |
136 |
|
|
136 |
|
|
137 | 137 |
if email: # signup mode |
138 |
if not reserved_screen_name(screen_name):
|
|
138 |
if not reserved_screen_name(screen_name): |
|
139 | 139 |
try: |
140 | 140 |
user = AstakosUser.objects.get(email = email) |
141 | 141 |
except AstakosUser.DoesNotExist, e: |
... | ... | |
166 | 166 |
return prepare_response(request, user, next) |
167 | 167 |
elif user and not user.is_active: |
168 | 168 |
messages.add_message(request, messages.ERROR, 'Inactive account: %s' % user.email) |
169 |
ip = request.META.get('REMOTE_ADDR', |
|
170 |
request.META.get('HTTP_X_REAL_IP', None)) |
|
169 | 171 |
return render_response(login_template, |
170 |
form = LocalUserCreationForm(ip=request.META['REMOTE_ADDR']),
|
|
172 |
form = LocalUserCreationForm(ip=ip),
|
|
171 | 173 |
context_instance=get_context(request, extra_context)) |
172 | 174 |
|
173 | 175 |
def reserved_screen_name(screen_name): |
... | ... | |
178 | 180 |
except AstakosUser.DoesNotExist, e: |
179 | 181 |
return False |
180 | 182 |
|
181 |
def create_user(request, form, backend=None, post_data={}, next = None, on_failure='im/signup.html', on_success='im/signup_complete.html', extra_context={}):
|
|
183 |
def create_user(request, form, backend=None, post_data={}, next = None, on_failure='im/signup.html', on_success='im/signup_complete.html', extra_context={}): |
|
182 | 184 |
""" |
183 | 185 |
Create a user. |
184 |
|
|
186 |
|
|
185 | 187 |
The user activation will be delegated to the backend specified by the ``backend`` keyword argument |
186 | 188 |
if present, otherwise to the ``astakos.im.backends.InvitationBackend`` |
187 | 189 |
if settings.ASTAKOS_INVITATIONS_ENABLED is True or ``astakos.im.backends.SimpleBackend`` if not |
188 | 190 |
(see backends); |
189 |
|
|
191 |
|
|
190 | 192 |
Upon successful user creation if ``next`` url parameter is present the user is redirected there |
191 | 193 |
otherwise renders the ``on_success`` template (if exists) or im/signup_complete.html. |
192 |
|
|
194 |
|
|
193 | 195 |
On unsuccessful creation, renders the ``on_failure`` template (if exists) or im/signup.html with an error message. |
194 |
|
|
196 |
|
|
195 | 197 |
**Arguments** |
196 |
|
|
198 |
|
|
197 | 199 |
``on_failure`` |
198 | 200 |
A custom template to render in case of failure. This is optional; |
199 | 201 |
if not specified, this will default to ``im/signup.html``. |
200 |
|
|
202 |
|
|
201 | 203 |
``on_success`` |
202 | 204 |
A custom template to render in case of success. This is optional; |
203 | 205 |
if not specified, this will default to ``im/signup_complete.html``. |
204 |
|
|
206 |
|
|
205 | 207 |
``extra_context`` |
206 | 208 |
An dictionary of variables to add to the template context. |
207 |
|
|
209 |
|
|
208 | 210 |
**Template:** |
209 |
|
|
211 |
|
|
210 | 212 |
im/signup.html or ``on_failure`` keyword argument. |
211 | 213 |
im/signup_complete.html or ``on_success`` keyword argument. |
212 | 214 |
""" |
... | ... | |
230 | 232 |
messages.add_message(request, messages.ERROR, e) |
231 | 233 |
for provider in IM_MODULES: |
232 | 234 |
extra_context['%s_form' % provider] = backend.get_signup_form(provider) |
235 |
ip = request.META.get('REMOTE_ADDR', |
|
236 |
request.META.get('HTTP_X_REAL_IP', None)) |
|
233 | 237 |
return render_response(on_failure, |
234 |
form = LocalUserCreationForm(ip=request.META['REMOTE_ADDR']), |
|
235 |
context_instance=get_context(request, extra_context)) |
|
238 |
form = LocalUserCreationForm(ip=ip), |
|
239 |
context_instance=get_context(request, extra_context)) |
Also available in: Unified diff