First iteration of a "prototype" Melange app, along with an initial Person
authorTodd Larsen <tlarsen@google.com>
Wed, 21 May 2008 16:27:35 +0000
changeset 31 8b43c541afa7
parent 30 636baa95715c
child 32 670a4571f496
First iteration of a "prototype" Melange app, along with an initial Person Profile view. Patch by: Augie Fackler (with some additions by Todd Larsen) Review by: Todd Larsen Review issue: 46 Review URL: http://codereviews.googleopensourceprograms.com/46
apps/proto/app.yaml
apps/proto/content/logo.jpg
apps/proto/content/proto.css
apps/proto/main.py
apps/proto/settings.py
apps/proto/urls.py
soc/templates/soc/profile.html
soc/views/person.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/proto/app.yaml	Wed May 21 16:27:35 2008 +0000
@@ -0,0 +1,27 @@
+# Copyright 2008 the Melange authors.
+#
+# 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.
+
+# TODO(proto): uncomment and supply a Google App Engine application instance
+# application: FIXME
+version: 1
+runtime: python
+api_version: 1
+
+handlers:
+- url: /content
+  static_dir: content
+
+- url: /.*
+  script: main.py
+
Binary file apps/proto/content/logo.jpg has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/proto/content/proto.css	Wed May 21 16:27:35 2008 +0000
@@ -0,0 +1,20 @@
+/*
+Copyright 2008 the Melange authors.
+
+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.
+ */
+
+body {
+  font-family: Verdana, Helvetica, sans-serif;
+  background-color: #DDDDDD;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/proto/main.py	Wed May 21 16:27:35 2008 +0000
@@ -0,0 +1,73 @@
+#!/usr/bin/python2.5
+#
+# Copyright 2008 the Melange authors.
+#
+# 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.
+
+__authors__ = [
+  # alphabetical order by last name, please
+  '"Augie Fackler" <durin42@gmail.com>',
+  ]
+
+
+import logging
+import os
+import sys
+
+from google.appengine.ext.webapp import util
+
+
+# Remove the standard version of Django.
+for k in [k for k in sys.modules if k.startswith('django')]:
+  del sys.modules[k]
+
+# Force sys.path to have our own directory first, in case we want to import
+# from it. This lets us replace the built-in Django
+sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
+
+# Force Django to reload its settings.
+from django.conf import settings
+settings._target = None
+
+# Must set this env var before importing any part of Django
+os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
+
+import django.core.handlers.wsgi
+import django.core.signals
+import django.db
+import django.dispatch.dispatcher
+
+
+# Log errors.
+def log_exception(*args, **kwds):
+  logging.exception('Exception in request:')
+
+django.dispatch.dispatcher.connect(
+   log_exception, django.core.signals.got_request_exception)
+
+# Unregister the rollback event handler.
+django.dispatch.dispatcher.disconnect(
+    django.db._rollback_on_exception,
+    django.core.signals.got_request_exception)
+
+
+def main():
+  # Create a Django application for WSGI.
+  application = django.core.handlers.wsgi.WSGIHandler()
+
+  # Run the WSGI CGI handler with that application.
+  util.run_wsgi_app(application)
+
+
+if __name__ == '__main__':
+  main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/proto/settings.py	Wed May 21 16:27:35 2008 +0000
@@ -0,0 +1,105 @@
+# Copyright 2008 the Melange authors.
+#
+# 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.
+
+__authors__ = [
+  '"Augie Fackler" <durin42@gmail.com>',
+  ]
+
+
+import os
+
+
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+
+ADMINS = (
+    # ('Your Name', 'your_email@domain.com'),
+)
+
+MANAGERS = ADMINS
+
+# 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
+DATABASE_ENGINE = 'dummy'
+# None of the following are used with appengine
+DATABASE_NAME = ''             # Or path to database file if using sqlite3.
+DATABASE_USER = ''             # Not used with sqlite3.
+DATABASE_PASSWORD = ''         # Not used with sqlite3.
+# Set to empty string for localhost. Not used with sqlite3.
+DATABASE_HOST = ''
+# Set to empty string for default. Not used with sqlite3.
+DATABASE_PORT = ''
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+TIME_ZONE = 'UTC'
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'en-us'
+
+SITE_ID = 1
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = ''
+
+# URL that handles the media served from MEDIA_ROOT. Make sure to use a
+# trailing slash if there is a path component (optional in other cases).
+# Examples: "http://media.lawrence.com", "http://example.com/media/"
+MEDIA_URL = ''
+
+# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
+# trailing slash.
+# Examples: "http://foo.com/media/", "/media/".
+ADMIN_MEDIA_PREFIX = '/media/'
+
+# TODO  Make this unique, and don't share it with anybody.
+SECRET_KEY = 'hvhxfm5u=^*v&doo#oq8x*eg8+1&9sxbye@=umutgn^t_sg_nx'
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+    'django.template.loaders.filesystem.load_template_source',
+    'django.template.loaders.app_directories.load_template_source',
+#     'django.template.loaders.eggs.load_template_source',
+)
+
+MIDDLEWARE_CLASSES = (
+#    'django.middleware.common.CommonMiddleware',
+#    'django.contrib.sessions.middleware.SessionMiddleware',
+#    'django.contrib.auth.middleware.AuthenticationMiddleware',
+#    'django.middleware.doc.XViewMiddleware',
+)
+
+ROOT_URLCONF = 'urls'
+
+ROOT_PATH = os.path.dirname(__file__)
+TEMPLATE_DIRS = (
+    # TODO(proto): customize the template search directories
+    os.path.join(ROOT_PATH, 'proto', 'templates'),
+    os.path.join(ROOT_PATH, 'soc', 'templates'),
+)
+
+INSTALLED_APPS = (
+#    'django.contrib.auth',
+#    'django.contrib.contenttypes',
+#    'django.contrib.sessions',
+#    'django.contrib.sites',
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/proto/urls.py	Wed May 21 16:27:35 2008 +0000
@@ -0,0 +1,27 @@
+# Copyright 2008 the Melange authors.
+#
+# 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.
+
+__authors__ = [
+  '"Augie Fackler" <durin42@gmail.com>',
+  ]
+
+
+from django.conf.urls.defaults import *
+
+
+urlpatterns = patterns(
+    '',
+    (r'^person/profile/$', 'soc.views.person.profile',
+     {'template': 'proto/profile.html'}),
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/soc/templates/soc/profile.html	Wed May 21 16:27:35 2008 +0000
@@ -0,0 +1,30 @@
+{% comment %}
+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.
+{% endcomment %}
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html lang="en">
+ <head>
+  <title>Profile</title>
+  {% block 'stylesheet' %}{% endblock %}
+ </head>
+ <body>
+  <p>
+   {% block 'logo' %}{% endblock %}
+   Welcome, {{user.nickname}}. Please update your profile:
+   <form method="POST">
+    <table>{{form.as_table}}</table>
+    <input type="submit" />
+   </form>
+  </p>
+ </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/soc/views/person.py	Wed May 21 16:27:35 2008 +0000
@@ -0,0 +1,65 @@
+#!/usr/bin/python2.5
+#
+# Copyright 2008 the Melange authors.
+#
+# 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.
+
+"""Views relevant to the Person role.
+"""
+
+__authors__ = [
+  '"Augie Fackler" <durin42@gmail.com>',
+  ]
+
+
+from google.appengine.api import users
+from google.appengine.ext.db import djangoforms
+from django import http
+from django import shortcuts
+from django import newforms as forms
+
+from soc.models import person
+
+
+class ProfileForm(djangoforms.ModelForm):
+  class Meta:
+    """Inner Meta class that defines some behavior for the form.
+
+    """
+    #: the db.Model subclass for which the form will gather information.
+    model = person.Person
+    #: the list of model fields which will *not* be gathered by the form.
+    exclude = ['user', ]
+
+
+def profile(request, template='soc/profile.html'):
+  """View for a Person to modify the properties of a PersonModel.
+
+  Args:
+    request: the standard django request object.
+    template: the template path to use for rendering the template.
+
+  Returns:
+    A subclass of django.http.HttpResponse which either contains the form to
+    be filled out, or a redirect to the correct view in the interface.
+  """
+  user = users.get_current_user()
+  if not user:
+    return http.HttpResponseRedirect(users.create_login_url(request.path))
+  form = ProfileForm()
+  if request.method=='POST':
+    form = ProfileForm(request.POST)
+    if not form.errors:
+      return http.HttpResponse('This would update the model')
+  return shortcuts.render_to_response(
+      template, dictionary={'template': template, 'form': form, 'user': user})