[cig-commits] r8306 - in cs/portal/trunk: . hello hello/hello
hello/hello/site hello/hello/static hello/hello/templates
hello/hello/templates/hello hello/hello/templates/registration
leif at geodynamics.org
leif at geodynamics.org
Mon Nov 19 17:50:32 PST 2007
Author: leif
Date: 2007-11-19 17:50:31 -0800 (Mon, 19 Nov 2007)
New Revision: 8306
Added:
cs/portal/trunk/hello/
cs/portal/trunk/hello/ez_setup.py
cs/portal/trunk/hello/hello/
cs/portal/trunk/hello/hello/__init__.py
cs/portal/trunk/hello/hello/constants.py
cs/portal/trunk/hello/hello/forms.py
cs/portal/trunk/hello/hello/middleware.py
cs/portal/trunk/hello/hello/models.py
cs/portal/trunk/hello/hello/notifications.py
cs/portal/trunk/hello/hello/site/
cs/portal/trunk/hello/hello/site/__init__.py
cs/portal/trunk/hello/hello/site/manage.py
cs/portal/trunk/hello/hello/site/settings.py
cs/portal/trunk/hello/hello/site/urls.py
cs/portal/trunk/hello/hello/static/
cs/portal/trunk/hello/hello/static/cig.gif
cs/portal/trunk/hello/hello/static/input.txt
cs/portal/trunk/hello/hello/static/style.css
cs/portal/trunk/hello/hello/templates/
cs/portal/trunk/hello/hello/templates/404.html
cs/portal/trunk/hello/hello/templates/500.html
cs/portal/trunk/hello/hello/templates/hello/
cs/portal/trunk/hello/hello/templates/hello/base.html
cs/portal/trunk/hello/hello/templates/hello/home.html
cs/portal/trunk/hello/hello/templates/hello/parameters.txt
cs/portal/trunk/hello/hello/templates/hello/register.html
cs/portal/trunk/hello/hello/templates/hello/registration_form.html
cs/portal/trunk/hello/hello/templates/hello/root.html
cs/portal/trunk/hello/hello/templates/hello/settings.html
cs/portal/trunk/hello/hello/templates/hello/simulation_confirm_delete.html
cs/portal/trunk/hello/hello/templates/hello/simulation_detail.html
cs/portal/trunk/hello/hello/templates/hello/simulation_form.html
cs/portal/trunk/hello/hello/templates/hello/simulation_list.html
cs/portal/trunk/hello/hello/templates/hello/simulation_list.py
cs/portal/trunk/hello/hello/templates/hello/simulation_status.html
cs/portal/trunk/hello/hello/templates/hello/simulations.html
cs/portal/trunk/hello/hello/templates/hello/splash.html
cs/portal/trunk/hello/hello/templates/hello/userinfo_form.html
cs/portal/trunk/hello/hello/templates/registration/
cs/portal/trunk/hello/hello/templates/registration/login.html
cs/portal/trunk/hello/hello/templates/registration/pwchange.html
cs/portal/trunk/hello/hello/templates/registration/pwchange_done.html
cs/portal/trunk/hello/hello/templates/registration/pwreset.html
cs/portal/trunk/hello/hello/templates/registration/pwreset_done.html
cs/portal/trunk/hello/hello/templates/registration/pwreset_email.txt
cs/portal/trunk/hello/hello/urls.py
cs/portal/trunk/hello/hello/views.py
cs/portal/trunk/hello/setup.py
Log:
Created a simple "hello world" web portal based upon the SPECFEM web
portal.
Added: cs/portal/trunk/hello/ez_setup.py
===================================================================
--- cs/portal/trunk/hello/ez_setup.py 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/ez_setup.py 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,222 @@
+#!python
+"""Bootstrap setuptools installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+ from ez_setup import use_setuptools
+ use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import sys
+DEFAULT_VERSION = "0.6c3"
+DEFAULT_URL = "http://cheeseshop.python.org/packages/%s/s/setuptools/" % sys.version[:3]
+
+md5_data = {
+ 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
+ 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
+ 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
+ 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
+ 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
+ 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
+ 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
+ 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
+ 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
+ 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
+ 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
+ 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
+ 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
+ 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
+ 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
+}
+
+import sys, os
+
+def _validate_md5(egg_name, data):
+ if egg_name in md5_data:
+ from md5 import md5
+ digest = md5(data).hexdigest()
+ if digest != md5_data[egg_name]:
+ print >>sys.stderr, (
+ "md5 validation of %s failed! (Possible download problem?)"
+ % egg_name
+ )
+ sys.exit(2)
+ return data
+
+
+def use_setuptools(
+ version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+ download_delay=15
+):
+ """Automatically find/download setuptools and make it available on sys.path
+
+ `version` should be a valid setuptools version number that is available
+ as an egg for download under the `download_base` URL (which should end with
+ a '/'). `to_dir` is the directory where setuptools will be downloaded, if
+ it is not already available. If `download_delay` is specified, it should
+ be the number of seconds that will be paused before initiating a download,
+ should one be required. If an older version of setuptools is installed,
+ this routine will print a message to ``sys.stderr`` and raise SystemExit in
+ an attempt to abort the calling script.
+ """
+ try:
+ import setuptools
+ if setuptools.__version__ == '0.0.1':
+ print >>sys.stderr, (
+ "You have an obsolete version of setuptools installed. Please\n"
+ "remove it from your system entirely before rerunning this script."
+ )
+ sys.exit(2)
+ except ImportError:
+ egg = download_setuptools(version, download_base, to_dir, download_delay)
+ sys.path.insert(0, egg)
+ import setuptools; setuptools.bootstrap_install_from = egg
+
+ import pkg_resources
+ try:
+ pkg_resources.require("setuptools>="+version)
+
+ except pkg_resources.VersionConflict, e:
+ # XXX could we install in a subprocess here?
+ print >>sys.stderr, (
+ "The required version of setuptools (>=%s) is not available, and\n"
+ "can't be installed while this script is running. Please install\n"
+ " a more recent version first.\n\n(Currently using %r)"
+ ) % (version, e.args[0])
+ sys.exit(2)
+
+def download_setuptools(
+ version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+ delay = 15
+):
+ """Download setuptools from a specified location and return its filename
+
+ `version` should be a valid setuptools version number that is available
+ as an egg for download under the `download_base` URL (which should end
+ with a '/'). `to_dir` is the directory where the egg will be downloaded.
+ `delay` is the number of seconds to pause before an actual download attempt.
+ """
+ import urllib2, shutil
+ egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
+ url = download_base + egg_name
+ saveto = os.path.join(to_dir, egg_name)
+ src = dst = None
+ if not os.path.exists(saveto): # Avoid repeated downloads
+ try:
+ from distutils import log
+ if delay:
+ log.warn("""
+---------------------------------------------------------------------------
+This script requires setuptools version %s to run (even to display
+help). I will attempt to download it for you (from
+%s), but
+you may need to enable firewall access for this script first.
+I will start the download in %d seconds.
+
+(Note: if this machine does not have network access, please obtain the file
+
+ %s
+
+and place it in this directory before rerunning this script.)
+---------------------------------------------------------------------------""",
+ version, download_base, delay, url
+ ); from time import sleep; sleep(delay)
+ log.warn("Downloading %s", url)
+ src = urllib2.urlopen(url)
+ # Read/write all in one block, so we don't create a corrupt file
+ # if the download is interrupted.
+ data = _validate_md5(egg_name, src.read())
+ dst = open(saveto,"wb"); dst.write(data)
+ finally:
+ if src: src.close()
+ if dst: dst.close()
+ return os.path.realpath(saveto)
+
+def main(argv, version=DEFAULT_VERSION):
+ """Install or upgrade setuptools and EasyInstall"""
+
+ try:
+ import setuptools
+ except ImportError:
+ egg = None
+ try:
+ egg = download_setuptools(version, delay=0)
+ sys.path.insert(0,egg)
+ from setuptools.command.easy_install import main
+ return main(list(argv)+[egg]) # we're done here
+ finally:
+ if egg and os.path.exists(egg):
+ os.unlink(egg)
+ else:
+ if setuptools.__version__ == '0.0.1':
+ # tell the user to uninstall obsolete version
+ use_setuptools(version)
+
+ req = "setuptools>="+version
+ import pkg_resources
+ try:
+ pkg_resources.require(req)
+ except pkg_resources.VersionConflict:
+ try:
+ from setuptools.command.easy_install import main
+ except ImportError:
+ from easy_install import main
+ main(list(argv)+[download_setuptools(delay=0)])
+ sys.exit(0) # try to force an exit
+ else:
+ if argv:
+ from setuptools.command.easy_install import main
+ main(argv)
+ else:
+ print "Setuptools version",version,"or greater has been installed."
+ print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
+
+
+
+def update_md5(filenames):
+ """Update our built-in md5 registry"""
+
+ import re
+ from md5 import md5
+
+ for name in filenames:
+ base = os.path.basename(name)
+ f = open(name,'rb')
+ md5_data[base] = md5(f.read()).hexdigest()
+ f.close()
+
+ data = [" %r: %r,\n" % it for it in md5_data.items()]
+ data.sort()
+ repl = "".join(data)
+
+ import inspect
+ srcfile = inspect.getsourcefile(sys.modules[__name__])
+ f = open(srcfile, 'rb'); src = f.read(); f.close()
+
+ match = re.search("\nmd5_data = {\n([^}]+)}", src)
+ if not match:
+ print >>sys.stderr, "Internal error!"
+ sys.exit(2)
+
+ src = src[:match.start(1)] + repl + src[match.end(1):]
+ f = open(srcfile,'w')
+ f.write(src)
+ f.close()
+
+
+if __name__=='__main__':
+ if len(sys.argv)>2 and sys.argv[1]=='--md5update':
+ update_md5(sys.argv[2:])
+ else:
+ main(sys.argv[1:])
+
+
+
+
+
Added: cs/portal/trunk/hello/hello/__init__.py
===================================================================
Added: cs/portal/trunk/hello/hello/constants.py
===================================================================
--- cs/portal/trunk/hello/hello/constants.py 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/constants.py 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,4 @@
+
+URL_ROOT = '/hello'
+HOME = URL_ROOT + '/'
+APP_LABEL = __name__.split('.')[-2]
Added: cs/portal/trunk/hello/hello/forms.py
===================================================================
--- cs/portal/trunk/hello/hello/forms.py 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/forms.py 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,204 @@
+
+from django import forms
+from django.contrib.auth import authenticate, login
+from django.contrib.auth.models import User
+from django.core import validators
+from models import UserInfo, Invite
+from constants import *
+
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Registration
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+usernameTaken = "This username is already taken."
+
+
+def isNotExistingUser(field_data, all_data):
+ try:
+ User.objects.get(username = field_data)
+ except User.DoesNotExist:
+ return
+ raise validators.ValidationError(usernameTaken)
+
+
+def passwordsMatch(field_data, all_data):
+ "Validates that the two password fields match."
+ if field_data != all_data['password1']:
+ raise validators.ValidationError, "Your passwords didn't match."
+ return
+
+
+def isValidInvitationCode(field_data, all_data):
+ try:
+ invite = Invite.objects.get(code = field_data)
+ except Invite.DoesNotExist:
+ raise validators.ValidationError, "Invalid invitation code."
+ if invite.hasExpired():
+ raise validators.ValidationError, "This invitation code has expired."
+ return
+
+
+class RegistrationManipulator(forms.Manipulator):
+
+ def __init__(self):
+ self.fields = [
+ # User
+ forms.TextField('first_name', maxlength=30, is_required=True),
+ forms.TextField('last_name', maxlength=30, is_required=True),
+ forms.EmailField('email', is_required=True, validator_list=[self.isUniqueEmail]),
+ # UserInfo
+ forms.TextField('institution', maxlength=100, is_required=True),
+ forms.TextField('address1', maxlength=100),
+ forms.TextField('address2', maxlength=100),
+ forms.TextField('address3', maxlength=100),
+ forms.PhoneNumberField('phone'),
+ ]
+
+ def usernameValidatorList(self):
+ return [validators.isAlphaNumeric]
+
+
+class RegistrationAddManipulator(RegistrationManipulator):
+
+ def __init__(self, request):
+ super(RegistrationAddManipulator, self).__init__()
+ self.request = request
+ self.fields.extend([
+ forms.TextField('username', maxlength=30, is_required=True, validator_list=self.usernameValidatorList()),
+ forms.PasswordField('password1', maxlength=128, is_required=True),
+ forms.PasswordField('password2', maxlength=128, is_required=True, validator_list=[passwordsMatch]),
+
+ forms.TextField('invite', maxlength=128, validator_list=[isValidInvitationCode]),
+ ])
+
+ def save(self, new_data):
+
+ # Check the invitation code, if given.
+ approved = False
+ invite = None
+ inviteCode = new_data['invite']
+ if inviteCode:
+ invite = Invite.objects.get(code = inviteCode)
+ approved = True
+
+ user, created = User.objects.get_or_create(
+ username = new_data['username'],
+ defaults = {'first_name': new_data['first_name'],
+ 'last_name': new_data['last_name'],
+ 'email': new_data['email']})
+ if not created:
+ # Race: the username was just taken!
+ return None, {'username': [usernameTaken]}
+
+ # Now we're committed to creating the user account.
+ user.set_password(new_data['password1'])
+ user.save()
+ UserInfo.objects.create(
+ user = user,
+ institution = new_data['institution'],
+ address1 = new_data['address1'],
+ address2 = new_data['address2'],
+ address3 = new_data['address3'],
+ phone = new_data['phone'],
+ invite = invite,
+ approved = approved,
+ )
+
+ # Log-in the new user.
+ user = authenticate(username=new_data['username'], password=new_data['password1'])
+ if user is not None:
+ login(self.request, user)
+
+ return user, {}
+
+ def flatten_data(self):
+ return {}
+
+ def usernameValidatorList(self):
+ validator_list = super(RegistrationAddManipulator, self).usernameValidatorList()
+ validator_list.append(isNotExistingUser)
+ validator_list.append(self.hasCookiesEnabled)
+ return validator_list
+
+ def hasCookiesEnabled(self, field_data, all_data):
+ if self.request and not self.request.session.test_cookie_worked():
+ raise validators.ValidationError, _("Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in.")
+
+ def isUniqueEmail(self, field_data, all_data):
+ try:
+ User.objects.get(email__iexact = field_data)
+ except User.DoesNotExist:
+ return
+ raise validators.ValidationError(
+"""Someone has already registered using this e-mail address. """
+"""(If you've forgotten your username and/or password, """
+"""try <a href="%s/pwreset/">resetting your password</a>.)""" % URL_ROOT
+ )
+
+
+class RegistrationChangeManipulator(RegistrationManipulator):
+
+ def __init__(self, user):
+ super(RegistrationChangeManipulator, self).__init__()
+ self.user = user
+
+ def flatten_data(self):
+ new_data = {}
+ new_data.update(self.user.__dict__)
+ try:
+ userInfo = self.user.userinfo
+ except UserInfo.DoesNotExist:
+ pass
+ else:
+ new_data.update(userInfo.__dict__)
+ return new_data
+
+ def save(self, new_data):
+ # Create UserInfo if it doesn't exist.
+ user = self.user
+ try:
+ userInfo = user.userinfo
+ except UserInfo.DoesNotExist:
+ userInfo = UserInfo()
+ user.userinfo = userInfo
+ # Save the new user.
+ user.first_name = new_data['first_name']
+ user.last_name = new_data['last_name']
+ user.email = new_data['email']
+ userInfo.institution = new_data['institution']
+ userInfo.address1 = new_data['address1']
+ userInfo.address2 = new_data['address2']
+ userInfo.address3 = new_data['address3']
+ userInfo.phone = new_data['phone']
+ user.save()
+ userInfo.save()
+ return user, {}
+
+ def isUniqueEmail(self, field_data, all_data):
+ try:
+ u = User.objects.get(email__iexact = field_data)
+ except User.DoesNotExist:
+ return
+ if u == self.user:
+ return
+ raise validators.ValidationError("Someone has already registered using this e-mail address (but under a different username).")
+
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Hidden Daemon Forms
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+class SimulationStatusManipulator(forms.Manipulator):
+
+ def __init__(self):
+ self.fields = [
+ forms.TextField(field_name='status', is_required=True),
+ forms.FileUploadField(field_name='output'),
+ ]
+ return
+
+
+# end of file
Added: cs/portal/trunk/hello/hello/middleware.py
===================================================================
--- cs/portal/trunk/hello/hello/middleware.py 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/middleware.py 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,147 @@
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# "Django Admin Hack - Fields varying with user permissions"
+# by Luke Plant
+# with Python 2.3 patch by Joseph Kocherhans
+#
+# from http://lukeplant.me.uk/blog.php?id=1107301634
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+try:
+ # It wasn't until Python 2.4 that they realized they needed this...
+ from threading import local
+except ImportError:
+ # ...thankfully, Django includes a substitute.
+ from django.utils._threading_local import local
+
+_thread_locals = local()
+
+class You_need_to_add_ThreadLocals_to_MIDDLEWARE_CLASSES(object): pass
+
+def get_current_user():
+ return getattr(_thread_locals, 'user', You_need_to_add_ThreadLocals_to_MIDDLEWARE_CLASSES())
+
+# Add this to MIDDLEWARE_CLASSES.
+class ThreadLocals(object):
+ """Middleware that gets various objects from the request object
+ and saves them in thread local storage.
+
+ """
+
+ def process_request(self, request):
+ _thread_locals.user = getattr(request, 'user', None)
+
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Revised django/contrib/sessions/middleware.py
+#
+# The following was backported from Django 0.96 to fix a bug which
+# causes Django to die with a SuspiciousOperation when a visitor
+# arrives with an old, stale cookie (one generated with a different
+# SECRET_KEY)... or (theoretically) when a hacker arrives with a bogus
+# cookie.
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+from django.conf import settings
+from django.contrib.sessions.models import Session
+from django.core.exceptions import SuspiciousOperation
+from django.utils.cache import patch_vary_headers
+import datetime
+
+TEST_COOKIE_NAME = 'testcookie'
+TEST_COOKIE_VALUE = 'worked'
+
+class SessionWrapper(object):
+ def __init__(self, session_key):
+ self.session_key = session_key
+ self.accessed = False
+ self.modified = False
+
+ def __contains__(self, key):
+ return key in self._session
+
+ def __getitem__(self, key):
+ return self._session[key]
+
+ def __setitem__(self, key, value):
+ self._session[key] = value
+ self.modified = True
+
+ def __delitem__(self, key):
+ del self._session[key]
+ self.modified = True
+
+ def keys(self):
+ return self._session.keys()
+
+ def items(self):
+ return self._session.items()
+
+ def get(self, key, default=None):
+ return self._session.get(key, default)
+
+ def set_test_cookie(self):
+ self[TEST_COOKIE_NAME] = TEST_COOKIE_VALUE
+
+ def test_cookie_worked(self):
+ return self.get(TEST_COOKIE_NAME) == TEST_COOKIE_VALUE
+
+ def delete_test_cookie(self):
+ del self[TEST_COOKIE_NAME]
+
+ def _get_session(self):
+ # Lazily loads session from storage.
+ self.accessed = True
+ try:
+ return self._session_cache
+ except AttributeError:
+ if self.session_key is None:
+ self._session_cache = {}
+ else:
+ try:
+ s = Session.objects.get(session_key=self.session_key,
+ expire_date__gt=datetime.datetime.now())
+ self._session_cache = s.get_decoded()
+ except (Session.DoesNotExist, SuspiciousOperation):
+ self._session_cache = {}
+ # Set the session_key to None to force creation of a new
+ # key, for extra security.
+ self.session_key = None
+ return self._session_cache
+
+ _session = property(_get_session)
+
+class SessionMiddleware(object):
+ def process_request(self, request):
+ request.session = SessionWrapper(request.COOKIES.get(settings.SESSION_COOKIE_NAME, None))
+
+ def process_response(self, request, response):
+ # If request.session was modified, or if response.session was set, save
+ # those changes and set a session cookie.
+ try:
+ accessed = request.session.accessed
+ modified = request.session.modified
+ except AttributeError:
+ pass
+ else:
+ if accessed:
+ patch_vary_headers(response, ('Cookie',))
+ if modified or settings.SESSION_SAVE_EVERY_REQUEST:
+ if request.session.session_key:
+ session_key = request.session.session_key
+ else:
+ session_key = Session.objects.get_new_session_key()
+
+ if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE:
+ max_age = None
+ expires = None
+ else:
+ max_age = settings.SESSION_COOKIE_AGE
+ expires = datetime.datetime.strftime(datetime.datetime.utcnow() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S GMT")
+ new_session = Session.objects.save(session_key, request.session._session,
+ datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
+ response.set_cookie(settings.SESSION_COOKIE_NAME, session_key,
+ max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN)
+ return response
+
+# end of file
Added: cs/portal/trunk/hello/hello/models.py
===================================================================
--- cs/portal/trunk/hello/hello/models.py 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/models.py 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,92 @@
+
+from django.db import models
+from django.contrib.auth.models import User
+
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Simulations
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+class Simulation(models.Model):
+ # general info
+ user = models.ForeignKey(User)
+ name = models.CharField(maxlength=100, core=True)
+ created = models.DateTimeField(auto_now_add=True, editable=False)
+ modified = models.DateTimeField(auto_now=True, editable=False)
+
+ # parameters
+ friend = models.CharField(maxlength=100)
+ happy = models.BooleanField(default=True)
+ speed = models.FloatField(max_digits=19, decimal_places=10)
+ steps = models.IntegerField(core=True, default=10)
+ nodes = models.IntegerField(core=True, default=1) # number of processors
+
+ # run/job info from daemon
+ status = models.CharField(maxlength=100, default="new")
+ started = models.DateTimeField(auto_now_add=True, editable=False)
+ finished = models.DateTimeField(null=True, blank=True)
+
+ def __str__(self): return self.name
+
+ class Admin:
+ list_display = ('user', 'name', 'status', 'started', 'finished')
+
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Registration
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+class Invite(models.Model):
+ code = models.CharField(maxlength=100, unique=True, db_index=True)
+ name = models.CharField(maxlength=100)
+ description = models.TextField(blank=True)
+ created = models.DateTimeField(auto_now_add=True, editable=False)
+ modified = models.DateTimeField(auto_now=True, editable=False)
+ expires = models.DateTimeField(null=True, blank=True)
+
+ def __str__(self): return self.name
+
+ def hasExpired(self):
+ import datetime
+ if self.expires is None:
+ return False
+ now = datetime.datetime.now()
+ return self.expires < now
+
+ class Admin:
+ list_display = ('name', 'code', 'expires', 'hasExpired')
+
+
+class UserInfo(models.Model):
+ user = models.OneToOneField(User)
+ institution = models.CharField(maxlength=100, core=True)
+ address1 = models.CharField(maxlength=100, null=True, blank=True)
+ address2 = models.CharField(maxlength=100, null=True, blank=True)
+ address3 = models.CharField(maxlength=100, null=True, blank=True)
+ phone = models.PhoneNumberField(null=True, blank=True)
+
+ # the invitation used, if any
+ invite = models.ForeignKey(Invite, null=True, blank=True)
+
+ # 'True' if this user can run simulations. Users who enter a
+ # valid invitation code are automatically approved.
+ approved = models.BooleanField(default=False)
+ help_visible = models.BooleanField(default=True)
+
+ def __str__(self): return self.user.username
+
+ # forward to User
+ def username(self): return self.user.username
+ def first_name(self): return self.user.first_name
+ def last_name(self): return self.user.last_name
+
+ class Admin:
+ # This is an admittedly crude way to allow admins to scan for
+ # unapproved users in the 'admin' interface.
+ list_display = ('username', 'first_name', 'last_name', 'invite', 'approved')
+ list_filter = ('approved',)
+
+
+# end of file
Added: cs/portal/trunk/hello/hello/notifications.py
===================================================================
--- cs/portal/trunk/hello/hello/notifications.py 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/notifications.py 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,75 @@
+
+from django.core.mail import send_mail, mail_admins, mail_managers
+from constants import *
+
+
+def notify_user_of_successful_simulation(sim):
+
+ user = sim.user
+
+ subject = 'The simulation "%s" has finished running.' % sim.name
+ message = ['The simulation "%s" has finished running.' % sim.name,
+ "",
+ "To download the output, visit the following web page:",
+ "",
+ "https://crust.geodynamics.org%s/simulations/%d/" % (URL_ROOT, sim.id),
+ "",
+ "Sincerely,",
+ "The Web Portal",
+ ]
+ message = "\n".join(message)
+
+ send_mail(subject, message, "Web Portal <portal at geodynamics.org>", [user.email], fail_silently=True)
+
+ return
+
+
+def notify_admins_of_failed_simulation(sim):
+
+ subject = 'simumlation %d failed' % sim.id
+ message = ["Simulation %d has failed." % sim.id,
+ "",
+ ]
+ message = "\n".join(message)
+
+ mail_admins(subject, message, fail_silently=True)
+
+ return
+
+
+def notify_managers_of_new_user(request, user):
+
+ userInfo = user.userinfo
+ invite = userInfo.invite
+
+ subject = 'new user %s (%s)' % (user.username, invite or "UNINVITED")
+ message = ["A new user has registered.",
+ ""]
+ if not invite:
+ message.extend([
+ """NOTE: Before this new user can run simulations, you must approve them by selecting the "approved" checkbox on the following page:""",
+ "",
+ "https://crust.geodynamics.org/admin/%s/userinfo/%d/" % (APP_LABEL, userInfo._get_pk_val()),
+ "",
+ ])
+ message.extend([
+ "username:" + user.username,
+ "first name: " + user.first_name,
+ "last name: " + user.last_name,
+ "e-mail: " + user.email,
+ "institution: " + userInfo.institution,
+ "address1: " + userInfo.address1,
+ "address2: " + userInfo.address2,
+ "address3: " + userInfo.address3,
+ "phone: " + userInfo.phone,
+ "invitation: " + str(invite),
+ "",
+ ])
+ message = "\n".join(message)
+
+ mail_managers(subject, message, fail_silently=True)
+
+ return
+
+
+# end of file
Added: cs/portal/trunk/hello/hello/site/__init__.py
===================================================================
Added: cs/portal/trunk/hello/hello/site/manage.py
===================================================================
--- cs/portal/trunk/hello/hello/site/manage.py 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/site/manage.py 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+from django.core.management import execute_manager
+try:
+ import settings # Assumed to be in the same directory.
+except ImportError:
+ import sys
+ sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
+ sys.exit(1)
+
+if __name__ == "__main__":
+ execute_manager(settings)
Added: cs/portal/trunk/hello/hello/site/settings.py
===================================================================
--- cs/portal/trunk/hello/hello/site/settings.py 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/site/settings.py 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,93 @@
+# Django settings for mysite project.
+
+import os
+
+DEBUG = os.environ.has_key("WEBPORTAL_DEBUG")
+TEMPLATE_DEBUG = DEBUG
+
+if DEBUG:
+ ADMINS = (
+ ("Leif", "leif at geodynamics.org"),
+ )
+else:
+ ADMINS = (
+ ("CIG Portal", "portal at geodynamics.org"),
+ ("Leif", "leif at geodynamics.org"),
+ )
+
+MANAGERS = ADMINS
+
+DATABASE_ENGINE = 'sqlite3' # 'postgresql', 'mysql', 'sqlite3' or 'ado_mssql'.
+# Environment Example: export WEBPORTAL_DATABASE_NAME='/Users/leif/Projects/WebPortal/SiteDatabase.db' # Or path to database file if using sqlite3.
+DATABASE_NAME = os.environ.get("WEBPORTAL_DATABASE_NAME")
+DATABASE_USER = '' # Not used with sqlite3.
+DATABASE_PASSWORD = '' # Not used with sqlite3.
+DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
+DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
+assert DATABASE_NAME # setenv WEBPORTAL_DATABASE_NAME
+
+# Local time zone for this installation. All choices can be found here:
+# http://www.postgresql.org/docs/current/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE
+TIME_ZONE = 'US/Pacific'
+
+# Language code for this installation. All choices can be found here:
+# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
+# http://blogs.law.harvard.edu/tech/stories/storyReader$15
+LANGUAGE_CODE = 'en-us'
+
+SITE_ID = 1
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+# Environment Example: export WEBPORTAL_MEDIA_ROOT= '/Users/leif/Projects/WebPortal'
+MEDIA_ROOT = os.environ.get("WEBPORTAL_MEDIA_ROOT")
+assert MEDIA_ROOT # setenv WEBPORTAL_MEDIA_ROOT
+
+# URL that handles the media served from MEDIA_ROOT.
+# Example: "http://media.lawrence.com"
+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/'
+
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = os.environ.get("WEBPORTAL_SECRET_KEY")
+assert SECRET_KEY # setenv WEBPORTAL_SECRET_KEY
+
+# 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 = 'hello.site.urls'
+
+TEMPLATE_DIRS = (
+ # Put strings here, like "/home/html/django_templates".
+ # Always use forward slashes, even on Windows.
+)
+
+INSTALLED_APPS = (
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.sites',
+ 'django.contrib.admin',
+ 'hello',
+)
+
+#DEFAULT_CHARSET = 'utf-16'
+#DEFAULT_CHARSET = 'us-ascii' # otherwise e-mails are base64-encoded
+
+DEFAULT_FROM_EMAIL = "Leif Strand <leif at geodynamics.org>"
+SERVER_EMAIL = "Leif Strand <leif at geodynamics.org>"
Added: cs/portal/trunk/hello/hello/site/urls.py
===================================================================
--- cs/portal/trunk/hello/hello/site/urls.py 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/site/urls.py 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,14 @@
+from django.conf.urls.defaults import *
+
+urlpatterns = patterns('',
+ # Example:
+ # (r'^mysite/', include('mysite.apps.foo.urls.foo')),
+
+ # Uncomment this for admin:
+ (r'^admin/', include('django.contrib.admin.urls')),
+
+ #(r'^accounts/login/$', 'django.contrib.auth.views.login'),
+
+ (r'^hello/', include('hello.urls')),
+
+)
Added: cs/portal/trunk/hello/hello/static/cig.gif
===================================================================
(Binary files differ)
Property changes on: cs/portal/trunk/hello/hello/static/cig.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: cs/portal/trunk/hello/hello/static/input.txt
===================================================================
--- cs/portal/trunk/hello/hello/static/input.txt 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/static/input.txt 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1 @@
+Hello, world.
Added: cs/portal/trunk/hello/hello/static/style.css
===================================================================
--- cs/portal/trunk/hello/hello/static/style.css 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/static/style.css 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,168 @@
+
+img {
+ border-width: 0;
+}
+
+#logo {
+ vertical-align: middle;
+}
+
+.error {
+ font-weight: bold;
+ color: red;
+}
+
+.messages {
+ font-weight: bold;
+ padding: .2em .2em .2em .2em;
+ border: thin solid black;
+ background-color: yellow;
+}
+
+div.login {
+ float: right;
+}
+
+.login li {
+ list-style: none;
+ display: inline;
+ padding-left: .5em;
+ padding-right: .5em;
+}
+
+
+/* taskbar */
+
+div.taskbar {
+ clear: both;
+}
+
+.taskbar ul {
+ list-style: none;
+ border-top: 1px solid black;
+ border-bottom: 1px solid black;
+ padding-top: 2px;
+ padding-bottom: 2px;
+ margin-left: 0;
+ background-color: #eee;
+ line-height: 200%;
+}
+
+.taskbar li {
+ display: inline;
+ border-style: outset;
+ font-size: large;
+ margin-left: .1em;
+ margin-right: .1em;
+}
+
+.taskbar a {
+ text-decoration: none;
+ color: black;
+ padding-left: 1em;
+ padding-right: 1em;
+}
+
+.taskbar li.selected {
+ border-style: inset;
+ font-weight: bold;
+ color: black;
+ background-color: orange;
+}
+
+
+/* toolbars */
+
+div.toolbar {
+ padding: .4em 1em .4em 1em;
+ margin: .6em 0em .6em 0em;
+ border-top: 1px solid black;
+ border-bottom: 1px solid black;
+ background-color: #eee;
+}
+
+.toolbar form {
+ display: inline;
+}
+
+
+/* tabs */
+
+div.tabs {
+ clear: both;
+}
+
+.tabs ul {
+ list-style: none;
+ margin-left: 0;
+ border-bottom: thick solid orange;
+}
+
+.tabs li {
+ display: inline;
+ border-top: 1px solid black;
+ border-right: 1px solid black;
+ font-size: large;
+}
+
+.tabs li.first {
+ border-left: 1px solid black;
+}
+
+.tabs a {
+ text-decoration: none;
+ color: black;
+ padding-left: 1em;
+ padding-right: 1em;
+}
+
+.tabs li.selected {
+ border-bottom: thin solid orange;
+ font-weight: bold;
+ color: black;
+ background-color: orange;
+}
+
+
+/* tables */
+
+table {
+ border: thin solid black;
+}
+
+.even {
+ background-color: #eef;
+}
+
+th {
+ text-align: left;
+ padding-left: 1em;
+ padding-right: 1em;
+}
+
+td {
+ padding-left: 1em;
+ padding-right: 1em;
+}
+
+
+/* forms */
+
+label {
+ font-weight: bold;
+}
+
+label.before:after {
+ content: ":";
+}
+
+
+/* detail views */
+
+.properties dt {
+ font-weight: bold;
+}
+
+.properties dt:after {
+ content: ":";
+}
Added: cs/portal/trunk/hello/hello/templates/404.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/404.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/404.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,10 @@
+
+{% extends "hello/root.html" %}
+
+{% block body %}
+
+<p><a href="/hello/"><img id=logo src="/hello/static/cig.gif" width=78 height=75>Home</a>
+
+<h1>Not Found</h1>
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/500.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/500.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/500.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,10 @@
+
+{% extends "hello/root.html" %}
+
+{% block body %}
+
+<p><a href="/hello/"><img id=logo src="/hello/static/cig.gif" width=78 height=75>Home</a>
+
+<h1>Internal Server Error</h1>
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/hello/base.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/hello/base.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/hello/base.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,19 @@
+
+{% extends "hello/root.html" %}
+
+{% block body %}
+
+<div class=login>
+ <ul>
+ <li id=greeting>{% if user.is_anonymous %}Welcome.{% else %}Welcome, {{ user.first_name }} ({{ user.username }}).{% endif %}
+ <li><a href="/hello/logout/">logout</a>
+ </ul>
+</div>
+
+<p><a href="/hello/"><img id=logo src="/hello/static/cig.gif" width=78 height=75></a>
+{% if messages %}<span class=messages>{{ messages|join:" " }}</span>{% endif %}
+
+{% block desktop %}
+{% endblock %}
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/hello/home.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/hello/home.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/hello/home.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,27 @@
+
+{% extends "hello/base.html" %}
+
+{% block desktop %}
+
+<div class=taskbar>
+ <ul>
+ <li class="first selected"><a href="/hello/">home</a>
+ <li><a href="/hello/simulations/">simulations</a>
+ <li><a href="/hello/registration/">profile</a>
+ </ul>
+</div>
+
+<h1 class=titlebar>home</h1>
+
+<h3>quick start</h3>
+
+<p>To set-up a new simulation, proceed as follows:
+
+<ol>
+ <li>Click "Simulations".
+ <li>Click "New...".
+ <li>Enter the parameters for the simulation.
+ <li>Click "Run".
+</ol>
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/hello/parameters.txt
===================================================================
--- cs/portal/trunk/hello/hello/templates/hello/parameters.txt 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/hello/parameters.txt 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,5 @@
+friend: {{ object.friend }}
+happy: {{ object.happy }}
+speed: {{ object.speed }}
+steps: {{ object.steps }}
+nodes: {{ object.nodes }}
Added: cs/portal/trunk/hello/hello/templates/hello/register.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/hello/register.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/hello/register.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,17 @@
+
+{% extends "hello/root.html" %}
+
+{% block body %}
+
+<p><a href="/hello/"><img id=logo src="/hello/static/cig.gif" width=78 height=75>Home</a>
+
+<h1 class=titlebar>new user registration</h1>
+
+<p>To create a new account, simply fill-out the form below.
+
+<p>If you've registered before, but have simply forgotten your username and/or password, try <a href="/hello/pwreset/">resetting your password</a>.
+ If you need help, <a href="mailto:portal at geodynamics.org">contact us</a>.
+
+{% include "hello/registration_form.html" %}
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/hello/registration_form.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/hello/registration_form.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/hello/registration_form.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,112 @@
+
+{% if form.has_errors %}
+<p><span class=error>Please correct the following error{{ form.error_dict|pluralize }}.</span>
+{% endif %}
+
+<form method="post" action="/hello/registration/">
+ <div class=tab30ex>
+
+ {% if user.is_anonymous %}
+ <fieldset><legend>username and password</legend>
+
+ <div>
+ <label for="id_username" class=before>username</label>
+ {{ form.username }}
+ {% if form.username.errors %}<span class=error>{{ form.username.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div>
+ <label for="id_password1" class=before>password</label>
+ {{ form.password1 }}
+ {% if form.password1.errors %}<span class=error>{{ form.password1.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div>
+ <label for="id_password2" class=before>confirm password</label>
+ {{ form.password2 }}
+ {% if form.password2.errors %}<span class=error>{{ form.password2.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ </fieldset>
+
+ {% endif %}
+
+ <fieldset><legend>contact information</legend>
+
+ <div>
+ <label for="id_first_name" class=before>first name</label>
+ {{ form.first_name }}
+ {% if form.first_name.errors %}<span class=error>{{ form.first_name.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div>
+ <label for="id_last_name" class=before>last name</label>
+ {{ form.last_name }}
+ {% if form.last_name.errors %}<span class=error>{{ form.last_name.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div>
+ <label for="id_email" class=before>e-mail</label>
+ {{ form.email }}
+ {% if form.email.errors %}<span class=error>{{ form.email.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div>
+ <label for="id_institution" class=before>institution</label>
+ {{ form.institution }}
+ {% if form.institution.errors %}<span class=error>{{ form.institution.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div>
+ <label for="id_address1" class=before>address</label>
+ {{ form.address1 }} (optional)
+ {% if form.address1.errors %}<span class=error>{{ form.address1.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div>
+ <label for="id_address2" class=before>city</label>
+ {{ form.address2 }} (optional)
+ {% if form.address2.errors %}<span class=error>{{ form.address2.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div>
+ <label for="id_address3" class=before>state & ZIP</label>
+ {{ form.address3 }} (optional)
+ {% if form.address3.errors %}<span class=error>{{ form.address3.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div>
+ <label for="id_phone" class=before>phone number</label>
+ {{ form.phone }} (optional)
+ {% if form.phone.errors %}<span class=error>{{ form.phone.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ </fieldset>
+
+
+ {% if user.is_anonymous %}
+
+ <fieldset><legend>invitation</legend>
+
+ <p>If you were given an invitation code, enter it below.
+ A valid invitation enables you to start running simulations immediately!
+
+ <div>
+ <label for="id_invite" class=before>invitation code</label>
+ {{ form.invite }}
+ {% if form.invite.errors %}<span class=error>{{ form.invite.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ </fieldset>
+
+ {% endif %}
+
+ {% if user.is_anonymous %}
+ <div><input class=submit type="submit" value="Register"/></div>
+ {% else %}
+ <div><input class=submit type="submit" value="Save"/></div>
+ {% endif %}
+
+ </div> <!-- tab30ex -->
+
+</form>
Added: cs/portal/trunk/hello/hello/templates/hello/root.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/hello/root.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/hello/root.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,12 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <link href="/hello/static/style.css" type="text/css" rel="stylesheet" media="all" />
+ <title>{% block title %}Hello{% endblock %}</title>
+</head>
+<body>
+{% block body %}
+{% endblock %}
+</body>
+</html>
Added: cs/portal/trunk/hello/hello/templates/hello/settings.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/hello/settings.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/hello/settings.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,17 @@
+
+{% extends "hello/base.html" %}
+
+{% block desktop %}
+
+<div class=taskbar>
+ <ul>
+ <li class=first><a href="/hello/">home</a>
+ <li><a href="/hello/simulations/">simulations</a>
+ <li class=selected><a href="/hello/registration/">profile</a>
+ </ul>
+</div>
+
+{% block content %}
+{% endblock %}
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/hello/simulation_confirm_delete.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/hello/simulation_confirm_delete.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/hello/simulation_confirm_delete.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,13 @@
+
+{% extends "hello/simulations.html" %}
+
+{% block content %}
+
+<h2 class=titlebar>delete simulation</h2>
+
+<form method="post" action="/hello/simulations/{{ object.id }}/delete/">
+ <p>Are you sure you want to delete the simulation "{{ object }}"?
+ <p><input type="submit" value="Delete" />
+</form>
+{% endblock %}
+
Added: cs/portal/trunk/hello/hello/templates/hello/simulation_detail.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/hello/simulation_detail.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/hello/simulation_detail.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,29 @@
+
+{% extends "hello/simulations.html" %}
+
+{% block content %}
+
+<h2 class=titlebar>{{ object.name }}</h2>
+
+<div class=toolbar>
+ <form action="delete/" method="get"><input type="submit" value="Delete" /></form>
+</div>
+
+<div class=properties>
+
+ <div class=box>
+ <dl>
+ <dt>status</dt><dd>{{ object.status }}</dd>
+ <dt>created</dt><dd>{{ object.created|date }} {{ object.created|time }}</dd>
+ <dt>modified</dt><dd>{{ object.modified|date }} {{ object.modified|time }}</dd>
+ <dt>friend</dt><dd>{{ object.friend }}</dd>
+ <dt>happy</dt><dd>{{ object.happy }}</dd>
+ <dt>speed</dt><dd>{{ object.speed }}</dd>
+ <dt>steps</dt><dd>{{ object.steps }}</dd>
+ <dt>nodes</dt><dd>{{ object.nodes }}</dd>
+ </dl>
+ </div>
+
+</div>
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/hello/simulation_form.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/hello/simulation_form.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/hello/simulation_form.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,73 @@
+
+{% extends "hello/simulations.html" %}
+
+{% block content %}
+
+<h2 class=titlebar>{% if object %}edit{% else %}new{% endif %} simulation</h2>
+
+{% if object %}
+<div class=toolbar>
+ <form action="../delete/" method="get"><input type="submit" value="Delete" /></form>
+</div>
+{% endif %}
+
+<form method="post" action="{{ action }}">
+
+ {% if form.has_errors %}
+ <p><span class=error>Please correct the following error{{ form.error_dict|pluralize }}.</span>
+ {% endif %}
+
+ <div class=tab30ex>
+
+ <input type="hidden" name="user" value="{{ user.id }}">
+ <input type="hidden" name="status" value="new">
+
+ <div>
+ <label for="id_name" class=before>name</label>
+ {{ form.name }}
+ {% if form.name.errors %}<span class=error>{{ form.name.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div>
+ <label for="id_friend" class=before>friend</label>
+ {{ form.friend }}
+ {% if form.friend.errors %}<span class=error>{{ form.friend.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div class=checkbox>
+ {{ form.happy }}
+ <label for="id_happy" class=after>happiness</label>
+ {% if form.happy.errors %}<span class=error>{{ form.happy.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div>
+ <label for="id_speed" class=before>speed</label>
+ {{ form.speed }} minutes
+ {% if form.speed.errors %}<span class=error>{{ form.speed.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div>
+ <label for="id_steps" class=before>time steps</label>
+ {{ form.steps }}
+ {% if form.steps.errors %}<span class=error>{{ form.steps.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div>
+ <label for="id_nodes" class=before>nodes</label>
+ {{ form.nodes }}
+ {% if form.nodes.errors %}<span class=error>{{ form.nodes.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div>
+ {% if user.userinfo.approved %}
+ <input type="submit" value="Run" />
+ {% else %}
+ <input type="submit" value="Run" DISABLED />
+ {% endif %}
+ </div>
+
+ </div> <!-- tab30ex -->
+
+</form>
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/hello/simulation_list.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/hello/simulation_list.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/hello/simulation_list.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,38 @@
+
+{% extends "hello/simulations.html" %}
+
+{% block content %}
+
+<div class=toolbar>
+ <form action="create/" method="get"><input type="submit" value="New..." /></form>
+</div>
+
+{% if object_list %}
+ <table rules=groups>
+
+ <colgroup><col class=odd><col class=even><col class=odd><col class=even><col class=odd><col class=even><col class=odd></colgroup>
+
+ <thead>
+ <tr><th>name</th><th>status</th><th>friend</th><th>happy</th><th>speed</th><th>steps</th><th>nodes</th></tr>
+ </thead>
+
+ <tbody>
+ {% for sim in object_list %}
+ <tr>
+ <th><a href="/hello/simulations/{{ sim.id }}/">{{ sim.name }}</a></th>
+ <td>{{ sim.status }}</td>
+ <td>{{ sim.friend }}</td>
+ <td>{{ sim.happy }}</td>
+ <td>{{ sim.speed }}</td>
+ <td>{{ sim.steps }}</td>
+ <td>{{ sim.nodes }}</td>
+ </tr>
+ {% endfor %}
+ </tbody>
+
+ </table>
+{% else %}
+ <p>You have no simulations.
+{% endif %}
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/hello/simulation_list.py
===================================================================
--- cs/portal/trunk/hello/hello/templates/hello/simulation_list.py 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/hello/simulation_list.py 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,5 @@
+(
+ {% for object in object_list %}
+ { 'id': {{ object.id }}, 'status': '{{ object.status }}', 'nodes': {{ object.nodes }} },
+ {% endfor %}
+)
Added: cs/portal/trunk/hello/hello/templates/hello/simulation_status.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/hello/simulation_status.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/hello/simulation_status.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,14 @@
+<html>
+ <head>
+ <title>Simulation Status</title>
+ </head>
+
+ <body>
+
+ <form action="." method="POST" enctype="multipart/form-data">
+ <p>{{ form.status }}
+ <p><input type="submit" value="Save">
+ </form>
+
+ </body>
+</html>
Added: cs/portal/trunk/hello/hello/templates/hello/simulations.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/hello/simulations.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/hello/simulations.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,19 @@
+
+{% extends "hello/base.html" %}
+
+{% block desktop %}
+
+<div class=taskbar>
+ <ul>
+ <li class=first><a href="/hello/">home</a>
+ <li class=selected><a href="/hello/simulations/">simulations</a>
+ <li><a href="/hello/registration/">profile</a>
+ </ul>
+</div>
+
+<h1 class=titlebar>simulations</h1>
+
+{% block content %}
+{% endblock %}
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/hello/splash.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/hello/splash.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/hello/splash.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,27 @@
+
+{% extends "hello/root.html" %}
+
+{% block body %}
+
+<div class=splash>
+
+ <div class=nameplate>
+ <p id=presented>Presented by:</p>
+ <ul class=producers>
+ <li><a href="http://www.geodynamics.org/">Computational Infrastructure for Geodynamics</a>
+ <li><a href="http://www.caltech.edu/">California Institute of Technology</a>
+ </ul>
+ <h1>Hello</h1>
+ <h2>Web Portal</h2>
+ </div>
+
+ <p>Version 1.0
+
+ <p><a class=button href="login/">login</a>
+
+ <p>Are you a new user? If so, please <a href="registration/">register</a>.<br>
+ If you need help, <a href="mailto:portal at geodynamics.org">contact us</a>.
+
+</div> <!-- splash -->
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/hello/userinfo_form.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/hello/userinfo_form.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/hello/userinfo_form.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,17 @@
+
+{% extends "hello/settings.html" %}
+
+{% block content %}
+
+<h1 class=titlebar>profile</h1>
+
+<div class=tabs>
+ <ul>
+ <li class="selected first"><a href="/hello/registration/">registration</a>
+ <li><a href="/hello/registration/password/">password</a>
+ </ul>
+</div>
+
+{% include "hello/registration_form.html" %}
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/registration/login.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/registration/login.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/registration/login.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,57 @@
+
+{% extends "hello/root.html" %}
+
+{% block body %}
+
+<p><a href="/hello/"><img id=logo src="/hello/static/cig.gif" width=78 height=75>Home</a>
+
+<h1 class=titlebar>login</h1>
+
+{% if form.has_errors %}
+<dl class=error>
+ {% for f in form.error_dict.iteritems %}
+ <dt>{{ f.0 }}</dt>
+ <dd>
+ <ul class=error>
+ {% for e in f.1 %}
+ <li>{{ e }}</li>
+ {% endfor %}
+ </ul>
+ </dd>
+ {% endfor %}
+</dl>
+{% endif %}
+
+<form method="post" action="/hello/login/">
+
+ <div class=tab30ex>
+
+ <div>
+ <label for="id_username" class=before>username</label>
+ {{ form.username }}
+ </div>
+
+ <div>
+ <label for="id_password" class=before>password</label>
+ {{ form.password }}
+ </div>
+
+ <div><input class=submit type="submit" value="login" /></div>
+
+ {% if next %}
+ <input type="hidden" name="next" value="{{ next }}" />
+ {% else %}
+ <input type="hidden" name="next" value="/hello/" />
+ {% endif %}
+
+ </div> <!-- tab30ex -->
+
+</form>
+
+<p>Are you a new user? If so, please <a href="/hello/registration/">register</a>.
+
+<p>If you've forgotten your username and/or password, try <a href="/hello/pwreset/">resetting your password</a>.
+
+<p>If you need help, <a href="mailto:portal at geodynamics.org">contact us</a>.
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/registration/pwchange.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/registration/pwchange.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/registration/pwchange.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,46 @@
+
+{% extends "hello/settings.html" %}
+
+{% block content %}
+
+<h1 class=titlebar>profile</h1>
+
+<div class=tabs>
+ <ul>
+ <li class=first><a href="/hello/registration/">registration</a>
+ <li class=selected><a href="/hello/registration/password/">password</a>
+ </ul>
+</div>
+
+{% if form.has_errors %}
+<p><span class=error>Please correct the following error{{ form.error_dict|pluralize }}.</span>
+{% endif %}
+
+<form action="/hello/registration/password/" method="post">
+ <div class=tab30ex>
+
+ <div>
+ <label for="id_old_password" class=before>old password </label>
+ {{ form.old_password }}
+ {% if form.old_password.errors %}<span class=error>{{ form.old_password.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div>
+ <label for="id_new_password1" class=before>new password </label>
+ {{ form.new_password1 }}
+ {% if form.new_password1.errors %}<span class=error>{{ form.new_password1.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div>
+ <label for="id_new_password2" class=before>confirm password </label>
+ {{ form.new_password2 }}
+ {% if form.new_password2.errors %}<span class=error>{{ form.new_password2.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <div><input class=submit type="submit" value="Change" /></div>
+
+ </div> <!-- tab30ex -->
+
+</form>
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/registration/pwchange_done.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/registration/pwchange_done.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/registration/pwchange_done.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,19 @@
+
+{% extends "hello/settings.html" %}
+
+{% block content %}
+
+<h1 class=titlebar>profile</h1>
+
+<div class=tabs>
+ <ul>
+ <li class=first><a href="/hello/registration/">registration</a>
+ <li class=selected><a href="/hello/registration/password/">password</a>
+ </ul>
+</div>
+
+<h2 class=titlebar>password change successful</h2>
+
+<p>Your password was changed.</p>
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/registration/pwreset.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/registration/pwreset.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/registration/pwreset.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,31 @@
+
+{% extends "hello/root.html" %}
+
+{% block body %}
+
+<p><a href="/hello/"><img id=logo src="/hello/static/cig.gif" width=78 height=75>Home</a>
+
+<h1 class=titlebar>password reset</h1>
+
+<p>Forgotten your password? Enter your e-mail address below, and we'll reset your password and e-mail the new one to you.</p>
+
+<form action="/hello/pwreset/" method="post">
+
+ {% if form.has_errors %}
+ <p><span class=error>Please correct the following error{{ form.error_dict|pluralize }}.</span>
+ {% endif %}
+
+ <div class=tab30ex>
+
+ <div>
+ <label for="id_email" class=before>e-mail address</label>
+ {{ form.email }} {% if form.email.errors %}<span class=error>{{ form.email.errors|join:", " }}</span>{% endif %}
+ </div>
+
+ <input class=submit type="submit" value="reset my password" /></p>
+
+ </div> <!-- tab30ex -->
+
+</form>
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/registration/pwreset_done.html
===================================================================
--- cs/portal/trunk/hello/hello/templates/registration/pwreset_done.html 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/registration/pwreset_done.html 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,14 @@
+
+{% extends "hello/root.html" %}
+
+{% block body %}
+
+<p><a href="/hello/"><img id=logo src="/hello/static/cig.gif" width=78 height=75>Home</a>
+
+<h1 class=titlebar>password reset</h1>
+
+<p><b>Success!</b> We've e-mailed a new password to the e-mail address you submitted. You should be receiving it shortly.</p>
+
+<p><a href="/hello/login/">Login</a></p>
+
+{% endblock %}
Added: cs/portal/trunk/hello/hello/templates/registration/pwreset_email.txt
===================================================================
--- cs/portal/trunk/hello/hello/templates/registration/pwreset_email.txt 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/templates/registration/pwreset_email.txt 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,18 @@
+You're receiving this e-mail because you requested a password reset
+for your user account at the Hello Web Portal:
+
+http://crust.geodynamics.org/hello/
+
+Your new password is: {{ new_password }}
+
+Feel free to change this password by going to this page:
+
+https://crust.geodynamics.org/hello/registration/password/
+
+Your username, in case you've forgotten: {{ user.username }}
+
+Thanks for using our site!
+
+--
+Computational Infrastructure for Geodynamics
+http://www.geodynamics.org/
Added: cs/portal/trunk/hello/hello/urls.py
===================================================================
--- cs/portal/trunk/hello/hello/urls.py 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/urls.py 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,60 @@
+
+import os
+import models
+from django.conf.urls.defaults import *
+from constants import *
+
+static_media_root = os.environ.get("WEBPORTAL_MEDIA_ROOT")+'/static'
+
+
+def view(name):
+ return APP_LABEL + '.views.' + name
+
+
+urlpatterns = patterns('',
+ (r'^$', view('home')),
+
+ (r'^login/$', 'django.contrib.auth.views.login'),
+ (r'^logout/$', 'django.contrib.auth.views.logout', dict(next_page = HOME)),
+ (r'^pwreset/$', 'django.contrib.auth.views.password_reset', dict(template_name='registration/pwreset.html',
+ email_template_name='registration/pwreset_email.txt')),
+ (r'^pwreset/done/$', 'django.views.generic.simple.direct_to_template', { 'template': 'registration/pwreset_done.html'}),
+
+ (r'^registration/$', view('registration')),
+ (r'^registration/password/$', 'django.contrib.auth.views.password_change', dict(template_name='registration/pwchange.html')),
+ (r'^registration/password/done/$', 'django.views.generic.simple.direct_to_template', { 'template': 'registration/pwchange_done.html'}),
+
+ (r'^simulations/$', view('simulation_index')),
+ (r'^simulations/create/$', view('create_simulation')),
+ (r'^simulations/(?P<object_id>\d+)/$', view('simulation_detail')),
+ (r'^simulations/(?P<object_id>\d+)/delete/$', 'django.views.generic.create_update.delete_object',
+ dict(model = models.Simulation, post_delete_redirect = URL_ROOT + '/simulations/')),
+
+
+ # ~~~~~ Hidden Daemon Pages ~~~~~
+
+ # the simulation list
+
+ (r'^simulations/list.py$', 'django.views.generic.list_detail.object_list', dict(queryset = models.Simulation.objects.all(),
+ allow_empty = True,
+ template_name = APP_LABEL + '/simulation_list.py',
+ mimetype = 'text/plain')),
+ # input files
+
+ (r'^simulations/(?P<object_id>\d+)/parameters.txt$', view('parameters_txt')),
+ (r'^simulations/(?P<object_id>\d+)/list.txt$', view('list_txt')),
+ (r'^simulations/(?P<object_id>\d+)/input.txt$', view('input_txt')),
+
+ # status form
+
+ (r'^simulations/(?P<object_id>\d+)/status/$', view('update_simulation_status')),
+
+
+ # ~~~~~ Debugging ~~~~~
+
+ # static files
+ (r'^static/(.*)', 'django.views.static.serve', {'document_root':static_media_root}),
+)
+
+
+# end of file
Added: cs/portal/trunk/hello/hello/views.py
===================================================================
--- cs/portal/trunk/hello/hello/views.py 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/hello/views.py 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,205 @@
+# Create your views here.
+
+from django import forms
+from django.conf import settings
+from django.contrib.auth.decorators import user_passes_test
+from django.http import HttpResponse, HttpResponseRedirect, Http404
+from django.shortcuts import render_to_response, get_object_or_404
+from django.template.context import RequestContext
+from django.views.generic.create_update import create_object
+from models import Simulation
+from constants import *
+
+import os, os.path
+import notifications
+
+
+# Create our own version of 'login_required' which redirects to our login page.
+login_required = user_passes_test(lambda u: not u.is_anonymous(), URL_ROOT + '/login/')
+
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Home
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+def home(request):
+ if request.user.is_anonymous():
+ return render_to_response(APP_LABEL + '/splash.html', {},
+ RequestContext(request, {}))
+ return render_to_response(APP_LABEL + '/home.html',
+ {},
+ RequestContext(request, {}))
+
+
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Simulations
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+disapproval = "You cannot run simulations until you are approved by a site administrator."
+
+
+def simulation_index(request):
+ from django.views.generic.list_detail import object_list
+ return object_list(request, Simulation.objects.filter(user=request.user),
+ allow_empty=True)
+simulation_index = login_required(simulation_index)
+
+
+def create_simulation(request):
+ return create_object(request,
+ Simulation,
+ post_save_redirect = URL_ROOT + '/simulations/%(id)d/',
+ )
+create_simulation = login_required(create_simulation)
+
+
+def simulation_detail(request, object_id):
+ from django.views.generic.list_detail import object_detail
+ return object_detail(request, Simulation.objects.all(), object_id)
+simulation_detail = login_required(simulation_detail)
+
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Authentication & Registration
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+def registration(request):
+ from forms import RegistrationAddManipulator, RegistrationChangeManipulator
+
+ isNewUser = request.user.is_anonymous()
+ if isNewUser:
+ manipulator = RegistrationAddManipulator(request)
+ template = APP_LABEL + '/register.html'
+ else:
+ manipulator = RegistrationChangeManipulator(request.user)
+ template = APP_LABEL + '/userinfo_form.html'
+
+ if request.method == 'POST':
+ new_data = request.POST.copy()
+ errors = manipulator.get_validation_errors(new_data)
+ if not errors:
+ manipulator.do_html2python(new_data)
+ user, errors = manipulator.save(new_data)
+ if not errors:
+ if isNewUser:
+ request.session.delete_test_cookie()
+ notifications.notify_managers_of_new_user(request, user)
+ user.message_set.create(message="Welcome to the CIG web portal!")
+ else:
+ user.message_set.create(message="Your contact information has been saved.")
+ return HttpResponseRedirect(HOME)
+ else:
+ # Populate new_data with a 'flattened' version of the current data.
+ new_data = manipulator.flatten_data()
+ errors = {}
+
+ if isNewUser:
+ request.session.set_test_cookie()
+
+ # Populate the FormWrapper.
+ form = forms.FormWrapper(manipulator, new_data, errors, edit_inline = True)
+
+ return render_to_response(template, { 'form': form }, RequestContext(request, {}))
+
+
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Hidden Daemon Pages
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+# ~~~~~ Input Files ~~~~~
+
+
+def parameters_txt(request, object_id):
+ # This illustrates how to generate an input file from a template.
+
+ from django.template import loader, Context
+
+ response = HttpResponse(mimetype='text/plain')
+
+ simulation = get_object_or_404(Simulation, id=object_id)
+
+ t = loader.get_template(APP_LABEL + '/parameters.txt')
+ c = Context({
+ 'object': simulation,
+ })
+ response.write(t.render(c))
+ return response
+
+
+def list_txt(request, object_id):
+ # This illustrates how to generate an input file directly.
+
+ response = HttpResponse(mimetype='text/plain')
+
+ simulation = get_object_or_404(Simulation, id=object_id)
+
+ for i in xrange(0, simulation.steps):
+ response.write("%s %r %8.4f\n" %
+ (simulation.friend, simulation.happy, simulation.speed))
+
+ return response
+
+
+def input_txt(request, object_id):
+ # This illustrates how to send an input file from the filesystem.
+
+ import shutil
+
+ filename = os.path.join(os.environ.get("WEBPORTAL_MEDIA_ROOT"), 'static', 'input.txt')
+
+ response = HttpResponse(mimetype='text/plain')
+ response['Content-Disposition'] = 'attachment; filename=input.txt'
+ stream = open(filename, 'rb')
+ shutil.copyfileobj(stream, response)
+ stream.close()
+ return response
+
+
+
+# ~~~~~ Status Form ~~~~~
+
+
+def update_simulation_status(request, object_id):
+ from forms import SimulationStatusManipulator
+ import datetime
+
+ manipulator = SimulationStatusManipulator()
+
+ simulation = get_object_or_404(Simulation, id=object_id)
+
+ if request.method == 'POST':
+ response = HttpResponse(mimetype='text/plain')
+ new_data = request.POST.copy()
+ new_data.update(request.FILES)
+ errors = manipulator.get_validation_errors(new_data)
+ if errors:
+ response.write(repr(errors))
+ else:
+ manipulator.do_html2python(new_data)
+ simulation.status = new_data['status']
+ if simulation.status in ['done', 'error']:
+ simulation.finished = datetime.datetime.now()
+ if simulation.status == 'error':
+ notifications.notify_admins_of_failed_simulation(simulation)
+ else:
+ notifications.notify_user_of_successful_simulation(simulation)
+ simulation.save()
+ response.write(repr('OK'))
+ return response
+
+ errors = {}
+ new_data = {'status': simulation.status}
+ form = forms.FormWrapper(manipulator, new_data, errors)
+ return render_to_response(APP_LABEL + '/simulation_status.html',
+ {'form': form},
+ RequestContext(request, {}))
+
+
+
+# end of file
Added: cs/portal/trunk/hello/setup.py
===================================================================
--- cs/portal/trunk/hello/setup.py 2007-11-20 01:26:37 UTC (rev 8305)
+++ cs/portal/trunk/hello/setup.py 2007-11-20 01:50:31 UTC (rev 8306)
@@ -0,0 +1,30 @@
+
+try:
+ # If setuptools 0.6b1 or later is installed, run with it.
+ from pkg_resources import require
+ require("setuptools>=0.6b1")
+except:
+ from ez_setup import use_setuptools
+ use_setuptools()
+
+from setuptools import setup
+
+setup(
+ name = 'hello',
+ version = '1.0',
+ url = 'http://www.geodynamics.org/',
+ author = 'Leif Strand',
+ author_email = 'leif at geodynamics.org',
+ packages = [ 'hello' ],
+
+ install_requires = [
+ 'Django >= 0.95',
+ #'pysqlite >= 2.0.3',
+ ],
+
+ dependency_links = [
+ 'http://www.djangoproject.com/download/0.95/tarball/#egg=Django-0.95',
+ 'http://initd.org/tracker/pysqlite',
+ ],
+
+)
More information about the cig-commits
mailing list