3 # Copyright 2007 Google Inc.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
22 """Python datastore class User to be used as a datastore data type.
25 User: object representing a user. A user could be a Google Accounts user
27 Error: base exception type
28 UserNotFoundError: UserService exception
29 RedirectTooLongError: UserService exception
30 NotAllowedError: UserService exception
45 from google
.appengine
.api
import apiproxy_stub_map
46 from google
.appengine
.api
import user_service_pb
47 from google
.appengine
.runtime
import apiproxy_errors
50 class Error(Exception):
51 """Base User error type."""
54 class UserNotFoundError(Error
):
55 """Raised by User.__init__() when there's no email argument and no user is
59 class RedirectTooLongError(Error
):
60 """Raised by UserService calls if the generated redirect URL was too long.
64 class NotAllowedError(Error
):
65 """Raised by UserService calls if the requested redirect URL is not allowed.
72 We provide the email address, nickname, and id for a user.
74 A nickname is a human-readable string which uniquely identifies a Google
75 user, akin to a username. It will be an email address for some users, but
78 A user could be a Google Accounts user or a federated login user.
80 federated_identity and federated_provider are only avaliable for
89 __federated_identity
= None
90 __federated_provider
= None
92 def __init__(self
, email
=None, _auth_domain
=None,
93 _user_id
=None, federated_identity
=None, federated_provider
=None,
98 email: An optional string of the user's email address. It defaults to
99 the current user's email address.
100 federated_identity: federated identity of user. It defaults to the current
101 user's federated identity.
102 federated_provider: federated provider url of user.
105 UserNotFoundError: Raised if the user is not logged in and both email
106 and federated identity are empty.
115 if _auth_domain
is None:
116 _auth_domain
= os
.environ
.get('AUTH_DOMAIN')
119 if email
is None and federated_identity
is None:
120 email
= os
.environ
.get('USER_EMAIL', email
)
121 _user_id
= os
.environ
.get('USER_ID', _user_id
)
122 federated_identity
= os
.environ
.get('FEDERATED_IDENTITY',
124 federated_provider
= os
.environ
.get('FEDERATED_PROVIDER',
134 if not email
and not federated_identity
and _strict_mode
:
137 raise UserNotFoundError
140 self
.__federated
_identity
= federated_identity
141 self
.__federated
_provider
= federated_provider
142 self
.__auth
_domain
= _auth_domain
143 self
.__user
_id
= _user_id
or None
147 """Return this user's nickname.
149 The nickname will be a unique, human readable identifier for this user
150 with respect to this application. It will be an email address for some
151 users, part of the email address for some users, and the federated identity
152 for federated users who have not asserted an email address.
154 if (self
.__email
and self
.__auth
_domain
and
155 self
.__email
.endswith('@' + self
.__auth
_domain
)):
156 suffix_len
= len(self
.__auth
_domain
) + 1
157 return self
.__email
[:-suffix_len
]
158 elif self
.__federated
_identity
:
159 return self
.__federated
_identity
164 """Return this user's email address."""
168 """Return either a permanent unique identifying string or None.
170 If the email address was set explicity, this will return None.
172 return self
.__user
_id
174 def auth_domain(self
):
175 """Return this user's auth domain.
177 This method is internal and should not be used by client applications.
179 return self
.__auth
_domain
181 def federated_identity(self
):
182 """Return this user's federated identity, None if not a federated user."""
183 return self
.__federated
_identity
185 def federated_provider(self
):
186 """Return this user's federated provider, None if not a federated user."""
187 return self
.__federated
_provider
189 def __unicode__(self
):
190 return unicode(self
.nickname())
193 return str(self
.nickname())
198 values
.append("email='%s'" % self
.__email
)
199 if self
.__federated
_identity
:
200 values
.append("federated_identity='%s'" % self
.__federated
_identity
)
202 values
.append("_user_id='%s'" % self
.__user
_id
)
203 return 'users.User(%s)' % ','.join(values
)
206 if self
.__federated
_identity
:
207 return hash((self
.__federated
_identity
, self
.__auth
_domain
))
209 return hash((self
.__email
, self
.__auth
_domain
))
211 def __cmp__(self
, other
):
212 if not isinstance(other
, User
):
213 return NotImplemented
214 if self
.__federated
_identity
:
215 return cmp((self
.__federated
_identity
, self
.__auth
_domain
),
216 (other
.__federated
_identity
, other
.__auth
_domain
))
218 return cmp((self
.__email
, self
.__auth
_domain
),
219 (other
.__email
, other
.__auth
_domain
))
222 def create_login_url(dest_url
=None, _auth_domain
=None,
223 federated_identity
=None):
224 """Computes the login URL for redirection.
227 dest_url: String that is the desired final destination URL for the user
228 once login is complete. If 'dest_url' does not have a host
229 specified, we will use the host from the current request.
230 federated_identity: federated_identity is used to trigger OpenId Login
231 flow, an empty value will trigger Google OpenID Login
235 Login URL as a string. If federated_identity is set, this will be
236 a federated login using the specified identity. If not, this
237 will use Google Accounts.
239 req
= user_service_pb
.CreateLoginURLRequest()
240 resp
= user_service_pb
.CreateLoginURLResponse()
242 req
.set_destination_url(dest_url
)
244 req
.set_destination_url('')
246 req
.set_auth_domain(_auth_domain
)
247 if federated_identity
:
248 req
.set_federated_identity(federated_identity
)
251 apiproxy_stub_map
.MakeSyncCall('user', 'CreateLoginURL', req
, resp
)
252 except apiproxy_errors
.ApplicationError
, e
:
253 if (e
.application_error
==
254 user_service_pb
.UserServiceError
.REDIRECT_URL_TOO_LONG
):
255 raise RedirectTooLongError
256 elif (e
.application_error
==
257 user_service_pb
.UserServiceError
.NOT_ALLOWED
):
258 raise NotAllowedError
261 return resp
.login_url()
264 CreateLoginURL
= create_login_url
267 def create_logout_url(dest_url
, _auth_domain
=None):
268 """Computes the logout URL for this request and specified destination URL,
269 for both federated login App and Google Accounts App.
272 dest_url: String that is the desired final destination URL for the user
273 once logout is complete. If 'dest_url' does not have a host
274 specified, we will use the host from the current request.
277 Logout URL as a string
279 req
= user_service_pb
.CreateLogoutURLRequest()
280 resp
= user_service_pb
.CreateLogoutURLResponse()
281 req
.set_destination_url(dest_url
)
283 req
.set_auth_domain(_auth_domain
)
286 apiproxy_stub_map
.MakeSyncCall('user', 'CreateLogoutURL', req
, resp
)
287 except apiproxy_errors
.ApplicationError
, e
:
288 if (e
.application_error
==
289 user_service_pb
.UserServiceError
.REDIRECT_URL_TOO_LONG
):
290 raise RedirectTooLongError
293 return resp
.logout_url()
296 CreateLogoutURL
= create_logout_url
299 def get_current_user():
302 except UserNotFoundError
:
306 GetCurrentUser
= get_current_user
309 def is_current_user_admin():
310 """Return true if the user making this request is an admin for this
311 application, false otherwise.
313 We specifically make this a separate function, and not a member function of
314 the User class, because admin status is not persisted in the datastore. It
315 only exists for the user making this request right now.
317 return (os
.environ
.get('USER_IS_ADMIN', '0')) == '1'
320 IsCurrentUserAdmin
= is_current_user_admin