Skip to content
Snippets Groups Projects
Commit 74a8b3ee authored by Ben Adida's avatar Ben Adida
Browse files

added a few missing components

parent 060f7dab
No related branches found
No related tags found
No related merge requests found
Showing
with 1365 additions and 0 deletions
[submodule "helios"]
path = helios
url = git@github.com:benadida/helios-django-app.git
[submodule "auth"]
path = auth
url = git@github.com:benadida/auth-django-app.git
This diff is collapsed.
# 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')
# 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
# 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
# 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()
# 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)
# 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}
from appengine_django.models import BaseModel
from google.appengine.ext import db
# Create your models here.
# Create your views here.
# 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.
# Explicitly set the name of this package to "appengine".
#
# The rationale for this is so that Django can refer to the database as
# "appengine" even though at a filesystem level it appears as the "db" package
# within the appengine_django package.
__name__ = "appengine"
#!/usr/bin/python2.4
#
# 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.
"""This module looks after initialising the appengine api stubs."""
import logging
import os
from appengine_django import appid
from appengine_django import have_appserver
from appengine_django.db.creation import DatabaseCreation
from django.db.backends import BaseDatabaseWrapper
from django.db.backends import BaseDatabaseFeatures
from django.db.backends import BaseDatabaseOperations
def get_datastore_paths():
"""Returns a tuple with the path to the datastore and history file.
The datastore is stored in the same location as dev_appserver uses by
default, but the name is altered to be unique to this project so multiple
Django projects can be developed on the same machine in parallel.
Returns:
(datastore_path, history_path)
"""
from google.appengine.tools import dev_appserver_main
datastore_path = dev_appserver_main.DEFAULT_ARGS['datastore_path']
history_path = dev_appserver_main.DEFAULT_ARGS['history_path']
datastore_path = datastore_path.replace("dev_appserver", "django_%s" % appid)
history_path = history_path.replace("dev_appserver", "django_%s" % appid)
return datastore_path, history_path
def get_test_datastore_paths(inmemory=True):
"""Returns a tuple with the path to the test datastore and history file.
If inmemory is true, (None, None) is returned to request an in-memory
datastore. If inmemory is false the path returned will be similar to the path
returned by get_datastore_paths but with a different name.
Returns:
(datastore_path, history_path)
"""
if inmemory:
return None, None
datastore_path, history_path = get_datastore_paths()
datastore_path = datastore_path.replace("datastore", "testdatastore")
history_path = history_path.replace("datastore", "testdatastore")
return datastore_path, history_path
def destroy_datastore(datastore_path, history_path):
"""Destroys the appengine datastore at the specified paths."""
for path in [datastore_path, history_path]:
if not path: continue
try:
os.remove(path)
except OSError, e:
if e.errno != 2:
logging.error("Failed to clear datastore: %s" % e)
class DatabaseError(Exception):
"""Stub class for database errors. Required by Django"""
pass
class IntegrityError(Exception):
"""Stub class for database integrity errors. Required by Django"""
pass
class DatabaseFeatures(BaseDatabaseFeatures):
"""Stub class to provide the feaures member expected by Django"""
pass
class DatabaseOperations(BaseDatabaseOperations):
"""Stub class to provide the options member expected by Django"""
pass
class DatabaseWrapper(BaseDatabaseWrapper):
"""App Engine database definition for Django.
This "database" backend does not support any of the standard backend
operations. The only task that it performs is to setup the api stubs required
by the appengine libraries if they have not already been initialised by an
appserver.
"""
def __init__(self, *args, **kwargs):
super(DatabaseWrapper, self).__init__(*args, **kwargs)
self.features = DatabaseFeatures()
self.ops = DatabaseOperations()
self.creation = DatabaseCreation(self)
self.use_test_datastore = kwargs.get("use_test_datastore", False)
self.test_datastore_inmemory = kwargs.get("test_datastore_inmemory", True)
if have_appserver:
return
self._setup_stubs()
def _get_paths(self):
if self.use_test_datastore:
return get_test_datastore_paths(self.test_datastore_inmemory)
else:
return get_datastore_paths()
def _setup_stubs(self):
# If this code is being run without an appserver (eg. via a django
# commandline flag) then setup a default stub environment.
from google.appengine.tools import dev_appserver_main
args = dev_appserver_main.DEFAULT_ARGS.copy()
args['datastore_path'], args['history_path'] = self._get_paths()
from google.appengine.tools import dev_appserver
dev_appserver.SetupStubs(appid, **args)
if self.use_test_datastore:
logging.debug("Configured API stubs for the test datastore")
else:
logging.debug("Configured API stubs for the development datastore")
def flush(self):
"""Helper function to remove the current datastore and re-open the stubs"""
destroy_datastore(*self._get_paths())
self._setup_stubs()
def close(self):
pass
def _commit(self):
pass
def cursor(self, *args):
pass
#!/usr/bin/python2.4
#
# 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.
import logging
from django.conf import settings
from django.db.backends.creation import BaseDatabaseCreation
class DatabaseCreation(BaseDatabaseCreation):
def create_test_db(self, *args, **kw):
"""Destroys the test datastore. A new store will be recreated on demand"""
settings.DATABASE_SUPPORTS_TRANSACTIONS = False
self.destroy_test_db()
self.connection.use_test_datastore = True
self.connection.flush()
def destroy_test_db(self, *args, **kw):
"""Destroys the test datastore files."""
from appengine_django.db.base import destroy_datastore
from appengine_django.db.base import get_test_datastore_paths
destroy_datastore(*get_test_datastore_paths())
logging.debug("Destroyed test datastore")
#!/usr/bin/python2.4
#
# 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.
"""
This module replaces the Django mail implementation with a version that sends
email via the mail API provided by Google App Engine.
Multipart / HTML email is not yet supported.
"""
import logging
from django.core import mail
from django.core.mail import SMTPConnection
from django.conf import settings
from google.appengine.api import mail as gmail
class GoogleSMTPConnection(SMTPConnection):
def __init__(self, host=None, port=None, username=None, password=None,
use_tls=None, fail_silently=False):
self.use_tls = (use_tls is not None) and use_tls or settings.EMAIL_USE_TLS
self.fail_silently = fail_silently
self.connection = None
def open(self):
self.connection = True
def close(self):
pass
def _send(self, email_message):
"""A helper method that does the actual sending."""
if not email_message.to:
return False
try:
if (isinstance(email_message,gmail.EmailMessage)):
e = message
elif (isinstance(email_message,mail.EmailMessage)):
e = gmail.EmailMessage(sender=email_message.from_email,
to=email_message.to,
subject=email_message.subject,
body=email_message.body)
if email_message.extra_headers.get('Reply-To', None):
e.reply_to = email_message.extra_headers['Reply-To']
if email_message.bcc:
e.bcc = list(email_message.bcc)
#TODO - add support for html messages and attachments...
e.send()
except:
if not self.fail_silently:
raise
return False
return True
def mail_admins(subject, message, fail_silently=False):
"""Sends a message to the admins, as defined by the ADMINS setting."""
_mail_group(settings.ADMINS, subject, message, fail_silently)
def mail_managers(subject, message, fail_silently=False):
"""Sends a message to the managers, as defined by the MANAGERS setting."""
_mail_group(settings.MANAGERS, subject, message, fail_silently)
def _mail_group(group, subject, message, fail_silently=False):
"""Sends a message to an administrative group."""
if group:
mail.send_mail(settings.EMAIL_SUBJECT_PREFIX + subject, message,
settings.SERVER_EMAIL, [a[1] for a in group],
fail_silently)
return
# If the group had no recipients defined, default to the App Engine admins.
try:
gmail.send_mail_to_admins(settings.SERVER_EMAIL,
settings.EMAIL_SUBJECT_PREFIX + subject,
message)
except:
if not fail_silently:
raise
#!/usr/bin/python2.4
#
# 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.
import code
import getpass
import os
import sys
from django.conf import settings
from django.core.management.base import BaseCommand
from google.appengine.ext.remote_api import remote_api_stub
def auth_func():
return raw_input('Username:'), getpass.getpass('Password:')
class Command(BaseCommand):
""" Start up an interactive console backed by your app using remote_api """
help = 'Start up an interactive console backed by your app using remote_api.'
def run_from_argv(self, argv):
app_id = argv[2]
if len(argv) > 3:
host = argv[3]
else:
host = '%s.appspot.com' % app_id
remote_api_stub.ConfigureRemoteDatastore(app_id,
'/remote_api',
auth_func,
host)
code.interact('App Engine interactive console for %s' % (app_id,),
None,
locals())
#!/usr/bin/python2.4
#
# 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.
import logging
import os
import sys
from django.core.management.base import BaseCommand
class Command(BaseCommand):
"""Overrides the default Django flush command.
"""
help = 'Clears the current datastore and loads the initial fixture data.'
def run_from_argv(self, argv):
from django.db import connection
connection.flush()
from django.core.management import call_command
call_command('loaddata', 'initial_data')
def handle(self, *args, **kwargs):
self.run_from_argv(None)
#!/usr/bin/python2.4
#
# 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.
import logging
import os
import sys
from django.core.management.base import BaseCommand
class Command(BaseCommand):
"""Overrides the default Django reset command.
"""
help = 'Clears the current datastore.'
def run_from_argv(self, argv):
from django.db import connection
connection.flush()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment