diff options
Diffstat (limited to 'appengine_django/auth')
-rw-r--r-- | appengine_django/auth/__init__.py | 25 | ||||
-rw-r--r-- | appengine_django/auth/__init__.pyc | bin | 0 -> 478 bytes | |||
-rw-r--r-- | appengine_django/auth/decorators.py | 31 | ||||
-rw-r--r-- | appengine_django/auth/decorators.pyc | bin | 0 -> 1008 bytes | |||
-rw-r--r-- | appengine_django/auth/middleware.py | 36 | ||||
-rw-r--r-- | appengine_django/auth/middleware.pyc | bin | 0 -> 1428 bytes | |||
-rw-r--r-- | appengine_django/auth/models.py | 172 | ||||
-rw-r--r-- | appengine_django/auth/models.pyc | bin | 0 -> 7999 bytes | |||
-rw-r--r-- | appengine_django/auth/templatetags.py | 62 | ||||
-rw-r--r-- | appengine_django/auth/templatetags.pyc | bin | 0 -> 2124 bytes | |||
-rw-r--r-- | appengine_django/auth/tests.py | 58 |
11 files changed, 384 insertions, 0 deletions
diff --git a/appengine_django/auth/__init__.py b/appengine_django/auth/__init__.py new file mode 100644 index 0000000..d2db207 --- /dev/null +++ b/appengine_django/auth/__init__.py @@ -0,0 +1,25 @@ +# Copyright 2008 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Authentication module that mimics the behavior of Django's authentication +implementation. + +Limitations: + - all user permissions methods are not available (requires contenttypes) +""" + +from django.template import add_to_builtins + +add_to_builtins('appengine_django.auth.templatetags') diff --git a/appengine_django/auth/__init__.pyc b/appengine_django/auth/__init__.pyc Binary files differnew file mode 100644 index 0000000..4d1edc3 --- /dev/null +++ b/appengine_django/auth/__init__.pyc diff --git a/appengine_django/auth/decorators.py b/appengine_django/auth/decorators.py new file mode 100644 index 0000000..d897c24 --- /dev/null +++ b/appengine_django/auth/decorators.py @@ -0,0 +1,31 @@ +# Copyright 2008 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Decorators for the authentication framework.""" + +from django.http import HttpResponseRedirect + +from google.appengine.api import users + + +def login_required(function): + """Implementation of Django's login_required decorator. + + The login redirect URL is always set to request.path + """ + def login_required_wrapper(request, *args, **kw): + if request.user.is_authenticated(): + return function(request, *args, **kw) + return HttpResponseRedirect(users.create_login_url(request.path)) + return login_required_wrapper diff --git a/appengine_django/auth/decorators.pyc b/appengine_django/auth/decorators.pyc Binary files differnew file mode 100644 index 0000000..477c819 --- /dev/null +++ b/appengine_django/auth/decorators.pyc diff --git a/appengine_django/auth/middleware.py b/appengine_django/auth/middleware.py new file mode 100644 index 0000000..a727e47 --- /dev/null +++ b/appengine_django/auth/middleware.py @@ -0,0 +1,36 @@ +# Copyright 2008 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.contrib.auth.models import AnonymousUser + +from google.appengine.api import users + +from appengine_django.auth.models import User + + +class LazyUser(object): + def __get__(self, request, obj_type=None): + if not hasattr(request, '_cached_user'): + user = users.get_current_user() + if user: + request._cached_user = User.get_djangouser_for_user(user) + else: + request._cached_user = AnonymousUser() + return request._cached_user + + +class AuthenticationMiddleware(object): + def process_request(self, request): + request.__class__.user = LazyUser() + return None diff --git a/appengine_django/auth/middleware.pyc b/appengine_django/auth/middleware.pyc Binary files differnew file mode 100644 index 0000000..ff36de8 --- /dev/null +++ b/appengine_django/auth/middleware.pyc diff --git a/appengine_django/auth/models.py b/appengine_django/auth/models.py new file mode 100644 index 0000000..d93e240 --- /dev/null +++ b/appengine_django/auth/models.py @@ -0,0 +1,172 @@ +# Copyright 2008 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +App Engine compatible models for the Django authentication framework. +""" + +from django.core import mail +from django.core.exceptions import ImproperlyConfigured +from django.db import models +from django.utils.encoding import smart_str +import urllib + +from django.db.models.manager import EmptyManager + +from google.appengine.api import users +from google.appengine.ext import db + +from appengine_django.models import BaseModel + + +class User(BaseModel): + """A model with the same attributes and methods as a Django user model. + + The model has two additions. The first addition is a 'user' attribute which + references a App Engine user. The second is the 'get_djangouser_for_user' + classmethod that should be used to retrieve a DjangoUser instance from a App + Engine user object. + """ + user = db.UserProperty(required=True) + username = db.StringProperty(required=True) + first_name = db.StringProperty() + last_name = db.StringProperty() + email = db.EmailProperty() + password = db.StringProperty() + is_staff = db.BooleanProperty(default=False, required=True) + is_active = db.BooleanProperty(default=True, required=True) + is_superuser = db.BooleanProperty(default=False, required=True) + last_login = db.DateTimeProperty(auto_now_add=True, required=True) + date_joined = db.DateTimeProperty(auto_now_add=True, required=True) + groups = EmptyManager() + user_permissions = EmptyManager() + + def __unicode__(self): + return self.username + + def __str__(self): + return unicode(self).encode('utf-8') + + @classmethod + def get_djangouser_for_user(cls, user): + query = cls.all().filter("user =", user) + if query.count() == 0: + django_user = cls(user=user, email=user.email(), username=user.nickname()) + django_user.save() + else: + django_user = query.get() + return django_user + + def set_password(self, raw_password): + raise NotImplementedError + + def check_password(self, raw_password): + raise NotImplementedError + + def set_unusable_password(self): + raise NotImplementedError + + def has_usable_password(self): + raise NotImplementedError + + def get_group_permissions(self): + return self.user_permissions + + def get_all_permissions(self): + return self.user_permissions + + def has_perm(self, perm): + return False + + def has_perms(self, perm_list): + return False + + def has_module_perms(self, module): + return False + + def get_and_delete_messages(self): + """Gets and deletes messages for this user""" + msgs = [] + for msg in self.message_set: + msgs.append(msg) + msg.delete() + return msgs + + def is_anonymous(self): + """Always return False""" + return False + + def is_authenticated(self): + """Always return True""" + return True + + def get_absolute_url(self): + return "/users/%s/" % urllib.quote(smart_str(self.username)) + + def get_full_name(self): + full_name = u'%s %s' % (self.first_name, self.last_name) + return full_name.strip() + + def email_user(self, subject, message, from_email): + """Sends an email to this user. + + According to the App Engine email API the from_email must be the + email address of a registered administrator for the application. + """ + mail.send_mail(subject, + message, + from_email, + [self.email]) + + def get_profile(self): + """ + Returns site-specific profile for this user. Raises + SiteProfileNotAvailable if this site does not allow profiles. + + When using the App Engine authentication framework, users are created + automatically. + """ + from django.contrib.auth.models import SiteProfileNotAvailable + if not hasattr(self, '_profile_cache'): + from django.conf import settings + if not hasattr(settings, "AUTH_PROFILE_MODULE"): + raise SiteProfileNotAvailable + try: + app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.') + model = models.get_model(app_label, model_name) + self._profile_cache = model.all().filter("user =", self).get() + if not self._profile_cache: + raise model.DoesNotExist + except (ImportError, ImproperlyConfigured): + raise SiteProfileNotAvailable + return self._profile_cache + + +class Group(BaseModel): + """Group model not fully implemented yet.""" + # TODO: Implement this model, requires contenttypes + name = db.StringProperty() + permissions = EmptyManager() + + +class Message(BaseModel): + """User message model""" + user = db.ReferenceProperty(User) + message = db.TextProperty() + + +class Permission(BaseModel): + """Permission model not fully implemented yet.""" + # TODO: Implement this model, requires contenttypes + name = db.StringProperty() diff --git a/appengine_django/auth/models.pyc b/appengine_django/auth/models.pyc Binary files differnew file mode 100644 index 0000000..0a73b9c --- /dev/null +++ b/appengine_django/auth/models.pyc diff --git a/appengine_django/auth/templatetags.py b/appengine_django/auth/templatetags.py new file mode 100644 index 0000000..8237890 --- /dev/null +++ b/appengine_django/auth/templatetags.py @@ -0,0 +1,62 @@ +# Copyright 2008 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Template tags for the auth module. These are inserted into Django as "built-in" +tags so you do not need to use the load statement in your template to get +access to them. +""" + +from django.template import Library +from django.template import Node + +from google.appengine.api import users + + +class AuthLoginUrlsNode(Node): + """Template node that creates an App Engine login or logout URL. + + If create_login_url is True the App Engine's login URL is rendered into + the template, otherwise the logout URL. + """ + def __init__(self, create_login_url, redirect): + self.redirect = redirect + self.create_login_url = create_login_url + + def render(self, context): + if self.create_login_url: + return users.create_login_url(self.redirect) + else: + return users.create_logout_url(self.redirect) + + +def auth_login_urls(parser, token): + """Template tag registered as 'auth_login_url' and 'auth_logout_url' + when the module is imported. + + Both tags take an optional argument that specifies the redirect URL and + defaults to '/'. + """ + bits = list(token.split_contents()) + if len(bits) == 2: + redirect = bits[1] + else: + redirect = "/" + login = bits[0] == "auth_login_url" + return AuthLoginUrlsNode(login, redirect) + + +register = Library() +register.tag("auth_login_url", auth_login_urls) +register.tag("auth_logout_url", auth_login_urls) diff --git a/appengine_django/auth/templatetags.pyc b/appengine_django/auth/templatetags.pyc Binary files differnew file mode 100644 index 0000000..7121f59 --- /dev/null +++ b/appengine_django/auth/templatetags.pyc diff --git a/appengine_django/auth/tests.py b/appengine_django/auth/tests.py new file mode 100644 index 0000000..20aecfa --- /dev/null +++ b/appengine_django/auth/tests.py @@ -0,0 +1,58 @@ +# Copyright 2008 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +BASIC_TESTS = """ +>>> from google.appengine.api import users +>>> from models import User, AnonymousUser +>>> appengine_user = users.User("test@example.com") +>>> django_user = User.get_djangouser_for_user(appengine_user) +>>> django_user.email == appengine_user.email() +True +>>> django_user.username == appengine_user.nickname() +True +>>> django_user.user == appengine_user +True + +>>> django_user.username = 'test2' +>>> key = django_user.save() +>>> django_user.username == 'test2' +True + +>>> django_user2 = User.get_djangouser_for_user(appengine_user) +>>> django_user2 == django_user +True + +>>> django_user.is_authenticated() +True +>>> django_user.is_staff +False +>>> django_user.is_active +True + +>>> a = AnonymousUser() +>>> a.is_authenticated() +False +>>> a.is_staff +False +>>> a.is_active +False +>>> a.groups.all() +[] +>>> a.user_permissions.all() +[] + + +""" + +__test__ = {'BASIC_TESTS': BASIC_TESTS} |