[rhmessaging-commits] rhmessaging commits: r2511 - in mgmt/trunk/cumin/python: wooly and 1 other directory.

rhmessaging-commits at lists.jboss.org rhmessaging-commits at lists.jboss.org
Sun Sep 21 13:35:34 EDT 2008


Author: justi9
Date: 2008-09-21 13:35:33 -0400 (Sun, 21 Sep 2008)
New Revision: 2511

Added:
   mgmt/trunk/cumin/python/cumin/user.py
   mgmt/trunk/cumin/python/cumin/user.strings
Modified:
   mgmt/trunk/cumin/python/cumin/__init__.py
   mgmt/trunk/cumin/python/cumin/page.py
   mgmt/trunk/cumin/python/cumin/test.py
   mgmt/trunk/cumin/python/cumin/widgets.strings
   mgmt/trunk/cumin/python/wooly/__init__.py
   mgmt/trunk/cumin/python/wooly/__init__.strings
   mgmt/trunk/cumin/python/wooly/devel.py
   mgmt/trunk/cumin/python/wooly/forms.py
   mgmt/trunk/cumin/python/wooly/forms.strings
   mgmt/trunk/cumin/python/wooly/server.py
Log:
Add support for reading cookies and setting response headers to wooly
Session.

Introduce UserSessions.

Stop using http auth for login.  Instead use a dedicated login UI to
create user sessions.  Revise auth check to work with user sessions.

Change wooly.Session to take a Page in its constructor.  Change sites
that mutate Session.page to instead create a new Session.

Remove get_page from Application, and instead use the pages dict
directly.

Rename FormInputErrorSet to FormErrorSet to reflect its more general
utility.

Add a PasswordInput and PasswordField.

Provide an html string for Page.



Modified: mgmt/trunk/cumin/python/cumin/__init__.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/__init__.py	2008-09-21 01:29:04 UTC (rev 2510)
+++ mgmt/trunk/cumin/python/cumin/__init__.py	2008-09-21 17:35:33 UTC (rev 2511)
@@ -9,16 +9,18 @@
 from mint import *
 from time import sleep
 from threading import Thread, Event
-from base64 import decodestring
-from crypt import crypt
+from urllib import quote
 
 from model import CuminModel, ModelPage
 from demo import DemoData
 from page import CuminPage
 from stat import StatChartPage
 from action import ActionPage
+from user import LoginPage
 from util import Config
 
+from wooly import Session
+
 log = logging.getLogger("cumin")
 
 class Cumin(Application):
@@ -40,14 +42,33 @@
         self.add_page(self.main_page)
         self.set_default_page(self.main_page)
 
-        self.add_page(CssPage(self, "cumin.css"))
-        self.add_page(JavascriptPage(self, "cumin.js"))
-        self.add_page(ResourcePage(self, "resource"))
         self.add_page(DevelPage(self, "devel.html"))
         self.add_page(ModelPage(self, "model.xml"))
         self.add_page(ActionPage(self, "actions.html"))
         self.add_page(StatChartPage(self, "stats.png"))
 
+        unprotected = set()
+
+        self.login_page = LoginPage(self, "login.html")
+        self.add_page(self.login_page)
+        unprotected.add(self.login_page)
+
+        page = CssPage(self, "cumin.css")
+        self.add_page(page)
+        unprotected.add(page)
+
+        page = JavascriptPage(self, "cumin.js")
+        self.add_page(page)
+        unprotected.add(page)
+
+        page = ResourcePage(self, "resource")
+        self.add_page(page)
+        unprotected.add(page)
+        
+        self.unprotected_pages = unprotected
+
+        self.user_sessions_by_id = dict()
+
     def check(self):
         if not os.path.isdir(self.home):
             raise Exception \
@@ -109,38 +130,32 @@
 
 class CuminServer(WebServer):
     def authorized(self, session):
-        name = session.credentials.get("name")
-        password = session.credentials.get("password")
+        auth = False
+        page = session.page
 
-        if name:
-            try:
-                user = Subject.selectBy(name=name)[0]
-            except IndexError:
-                return False
+        if page in self.app.unprotected_pages:
+            return True
 
-            if user:
-                crypted = user.password
+        id = session.cookies.get("session")
 
-                if crypted and crypt(password, crypted) == crypted:
-                    lch = user.lastChallenged
-                    
-                    if lch:
-                        timeout = timedelta(seconds=3600)
-                        now = datetime.now()
+        if id is not None:
+            usess = self.app.user_sessions_by_id.get(id)
 
-                        if now - lch < timeout:
-                            lout = user.lastLoggedOut
+            if usess is not None:
+                timeout = timedelta(seconds=3600)
+                now = datetime.now()
 
-                            if lout is None or lout < lch:
-                                return True
-                    else:
-                        user.lastChallenged = datetime.now()
-                        user.syncUpdate()
-                        return True
+                if now > usess.created and now < usess.created + timeout:
+                    setattr(session, "user_session", usess)
 
-            user.lastChallenged = datetime.now()
-            user.syncUpdate()
+                    return True
 
+        lpage = self.app.login_page
+        lsess = Session(lpage)
+        lpage.origin.set(lsess, session.marshal())
+
+        page.set_redirect_url(session, lsess.marshal())
+
         return False
 
 class CuminConfig(Config):
@@ -219,7 +234,7 @@
             formatter = logging.Formatter("%(name)-12s - %(message)s")
         
             log.setLevel(level)
-            mlog.setLevel(level)
+            #mlog.setLevel(level)
 
             handler = logging.StreamHandler()
             handler.setLevel(level)

Modified: mgmt/trunk/cumin/python/cumin/page.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/page.py	2008-09-21 01:29:04 UTC (rev 2510)
+++ mgmt/trunk/cumin/python/cumin/page.py	2008-09-21 17:35:33 UTC (rev 2511)
@@ -16,6 +16,7 @@
 
 # We have a wooly.widgets.Link and a mint.Link; we want the former
 from wooly.widgets import Link
+from wooly import Session
 
 strings = StringCatalog(__file__)
 
@@ -101,13 +102,19 @@
         return "Main"
 
     def render_user_name(self, session):
-        return session.credentials.get("name")
+        if hasattr(session, "user_session"):
+            return session.user_session.subject.name
 
     def render_logout_href(self, session):
-        branch = session.branch()
-        self.__logout.set(branch, True)
-        return branch.marshal()
+        page = self.app.login_page
 
+        lsess = Session(page)
+
+        page.logout.set(lsess, True)
+        page.origin.set(lsess, session.marshal())
+
+        return lsess.marshal()
+
     def render_frames(self, session):
         writer = Writer()
 

Modified: mgmt/trunk/cumin/python/cumin/test.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/test.py	2008-09-21 01:29:04 UTC (rev 2510)
+++ mgmt/trunk/cumin/python/cumin/test.py	2008-09-21 17:35:33 UTC (rev 2511)
@@ -88,8 +88,7 @@
         if page is None:
             page = self.app.main_page
 
-        s = wooly.Session(self.app)
-        s.set_page(page)
+        s = wooly.Session(page)
 
         return page, s
 
@@ -99,8 +98,8 @@
         if redirect is None:
             raise Exception("Expected redirect")
 
-        p, s = self.page_and_session()
-        s.unmarshal(redirect)
+        s = wooly.Session.unmarshal(p.app, redirect)
+        p = s.page
 
         p.process(s)
         p.render(s)

Added: mgmt/trunk/cumin/python/cumin/user.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/user.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/user.py	2008-09-21 17:35:33 UTC (rev 2511)
@@ -0,0 +1,122 @@
+from wooly import *
+from wooly.widgets import *
+from wooly.resources import *
+from time import sleep
+from threading import Thread, Event
+from random import randint
+from datetime import datetime
+from crypt import crypt
+from uuid import uuid4
+
+from widgets import *
+from util import *
+
+from wooly import Session
+
+strings = StringCatalog(__file__)
+
+log = logging.getLogger("cumin.user")
+
+class UserSession(object):
+    def __init__(self, app, subject):
+        self.app = app
+        self.subject = subject
+        self.id = str(uuid4())
+        self.created = datetime.now()
+
+        self.app.user_sessions_by_id[self.id] = self
+
+    def delete(self):
+        del self.app.user_sessions_by_id[self.id]
+
+class UserSessionDeleteThread(Thread):
+    pass # every minute cycle through and delete expired sessions
+
+class LoginPage(Page):
+    def __init__(self, app, name):
+        super(LoginPage, self).__init__(app, name)
+
+        self.logout = BooleanParameter(app, "logout")
+        self.add_parameter(self.logout)
+
+        self.origin = self.Origin(app, "origin")
+        self.add_parameter(self.origin)
+
+        form = LoginForm(app, "form")
+        self.add_child(form)
+
+    def do_process(self, session):
+        if self.logout.get(session):
+            #id = session.get_cookie("session")
+            session.expire_cookie("session")
+
+        super(LoginPage, self).do_process(session)
+
+    def render_title(self, session):
+        return "Log In"
+
+    class Origin(Parameter):
+        def get_default(self, session):
+            return Session(self.app.main_page).marshal()
+
+class LoginForm(FieldForm):
+    def __init__(self, app, name):
+        super(LoginForm, self).__init__(app, name)
+
+        self.__login_invalid = Attribute(app, "login_invalid")
+        self.add_attribute(self.__login_invalid)
+
+        self.__name = self.Name(app, "name", self)
+        self.add_field(self.__name)
+        self.__name.get_input().set_size(20)
+
+        self.__password = self.Password(app, "password", self)
+        self.add_field(self.__password)
+        self.__password.get_input().set_size(20)
+
+        self.__submit = self.Submit(app, "submit", self)
+        self.add_child(self.__submit)
+
+    def do_process(self, session):
+        if self.__submit.get(session):
+            name = self.__name.get(session)
+            password = self.__password.get(session)
+
+            errors = self.validate(session)
+
+            if not errors:
+                try:
+                    user = Subject.selectBy(name=name)[0]
+                except IndexError:
+                    self.__login_invalid.set(session, True)
+                    return
+
+                crypted = user.password
+
+                if crypted and crypt(password, crypted) == crypted:
+                    # You're in!
+
+                    usess = UserSession(self.app, user)
+                    session.set_cookie("session", usess.id)
+
+                    url = self.page.origin.get(session)
+
+                    self.page.set_redirect_url(session, url)
+                else:
+                    self.__login_invalid.set(session, True)
+
+    def render_login_invalid(self, session):
+        if self.__login_invalid.get(session):
+            return self.get_string("login_invalid")
+
+    class Name(StringField):
+        def render_title(self, session):
+            return "User Name"
+
+    class Password(PasswordField):
+        def render_title(self, session):
+            return "Password"
+
+    class Submit(FormButton):
+        def render_content(self, session):
+            return "Submit"

Added: mgmt/trunk/cumin/python/cumin/user.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/user.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/user.strings	2008-09-21 17:35:33 UTC (rev 2511)
@@ -0,0 +1,80 @@
+[LoginPage.css]
+body.LoginPage {
+  background: #f7f7f7;
+  padding: 4em;
+}
+
+[LoginPage.html]
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+  <head>
+    <title>{title}</title>
+    <link rel="stylesheet" type="text/css" href="cumin.css"/>
+    <link rel="shortcut icon" href="resource?name=favicon.ico" type="image/x-icon"/>
+    <script src="resource?name=wooly.js" type="text/javascript"> </script>
+    <script src="cumin.js" type="text/javascript"> </script>
+  </head>
+  <body class="LoginPage">
+    {form}
+  </body>
+</html>
+
+[LoginForm.css]
+form.LoginForm {
+  background: #fff;
+  width: 16em;
+  margin: 0 auto;
+  border: 1px solid #ddd;
+  -moz-border-radius: 0.5em;
+  -webkit-border-radius: 0.5em;
+  padding: 2em;
+}
+
+form.LoginForm > h1 {
+  margin: 0 0 1em 0;
+}
+
+form.LoginForm h1 img {
+  vertical-align: -60%;
+  margin: 0 0.25em 0 0;
+}
+
+form.LoginForm input {
+  width: 12em;
+}
+
+form.LoginForm > div.buttons {
+  margin: 1.5em 0 0 0;
+}
+
+form.LoginForm p.login_invalid {
+  color: red;
+}
+
+[LoginForm.html]
+<form id="{id}" class="LoginForm" method="post" action="?">
+  <h1><img src="resource?name=mrg-36.png"/> MRG Management</h1>
+
+  <p>Enter your user name and password to log in.</p>
+
+  <p>If you do not have an account or have trouble logging in, contact
+  the <a href="{operator_email}">site operator</a>.</p>
+
+  {login_invalid}
+
+  {fields}  
+
+  <div class="buttons">{submit}</div>
+
+  <div>{hidden_inputs}</div>
+</form>
+<script type="text/javascript">
+<![CDATA[
+  wooly.doc().elembyid("{id}").node.elements[0].focus();
+]]>
+</script>
+
+[LoginForm.login_invalid]
+<p class="login_invalid">The user name and password you
+entered do not match any account.</p>

Modified: mgmt/trunk/cumin/python/cumin/widgets.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/widgets.strings	2008-09-21 01:29:04 UTC (rev 2510)
+++ mgmt/trunk/cumin/python/cumin/widgets.strings	2008-09-21 17:35:33 UTC (rev 2511)
@@ -49,7 +49,7 @@
 </script>
 
 [CuminConfirmForm.html]
-<form id="{id}" class="mform" method="post" action="?">
+<form id="{id}" method="post" action="?">
   <div class="head">
     <h1>{title}</h1>
   </div>

Modified: mgmt/trunk/cumin/python/wooly/__init__.py
===================================================================
--- mgmt/trunk/cumin/python/wooly/__init__.py	2008-09-21 01:29:04 UTC (rev 2510)
+++ mgmt/trunk/cumin/python/wooly/__init__.py	2008-09-21 17:35:33 UTC (rev 2511)
@@ -5,6 +5,7 @@
 from time import clock
 from datetime import datetime
 from urlparse import urlsplit
+from time import gmtime
 
 from resources import ResourceFinder, StringCatalog
 
@@ -374,6 +375,7 @@
             return self.app.get_widget(path)
         
 from parameters import DictParameter
+
 class Application(object):
     def __init__(self):
         self.pages = dict()
@@ -408,13 +410,8 @@
 
         page.init()
 
-    def get_page(self, name):
-        #print "Looking for", name, "in", self.pages
-
-        return self.pages.get(name, self.default_page)
-
     def set_default_page(self, page):
-        self.default_page = page
+        self.pages[""] = page
 
     def add_widget(self, widget):
         if self.widget_index:
@@ -472,13 +469,22 @@
         return "%s(default_page=%s)" % (self.__class__.__name__, self.default_page)
 
 class Session(object):
-    def __init__(self, app, trunk=None):
-        self.app = app
-        self.trunk = trunk
-        self.page = None
+    http_date_gmt = "%a, %d %b %Y %H:%M:%S GMT"
+
+    def __init__(self, page, response_headers=None):
+        assert isinstance(page, Page)
+
+        self.app = page.app
+        self.page = page
+        self.trunk = None
         self.values = dict()
-        self.credentials = dict()
         self.origin = None
+        self.cookies = dict()
+        
+        if response_headers is None:
+            self.response_headers = list()
+        else:
+            self.response_headers = response_headers
 
         if self.app.debug:
             self.debug = self.Debug(self)
@@ -500,21 +506,27 @@
                 self.render_stack[0].write(out)
 
     def branch(self):
-        return Session(self.app, self)
+        session = Session(self.page)
+        session.trunk = self
+        session.response_headers = list(self.response_headers)
+        return session
 
-    def get_page(self):
-        if self.page:
-            page = self.page
-        elif self.trunk:
-            page = self.trunk.get_page()
-        else:
-            page = None
+    def add_header(self, name, value):
+        self.response_headers.append((name, value))
 
-        return page
+    def set_cookie(self, name, value, expires=None):
+        crumbs = list()
+        crumbs.append("%s=%s" % (name, value))
 
-    def set_page(self, page):
-        self.page = page
+        if expires:
+            when = expires.strftime(self.http_date_gmt)
+            crumbs.append("expires=%s" % when)
 
+        self.add_header("Set-Cookie", "; ".join(crumbs))
+
+    def expire_cookie(self, name):
+        self.set_cookie(name, "", datetime(*gmtime(1)[0:6]))
+
     # This is the biggest hotspot in cumin-bench profiling
     def get(self, key):
         if key in self.values:
@@ -539,7 +551,7 @@
             del self.values[key]
 
     def marshal(self):
-        page = self.marshal_page()
+        page = self.page.name
         vars = self.marshal_url_vars()
 
         if vars:
@@ -552,11 +564,8 @@
 
         return url
 
-    def marshal_page(self):
-        return self.get_page().name
-
     def marshal_url_vars(self, separator=";"):
-        params = self.get_page().get_saved_parameters(self)
+        params = self.page.get_saved_parameters(self)
         vars = list()
 
         for param in params:
@@ -590,21 +599,29 @@
 
         return separator.join(vars)
 
-    def unmarshal(self, string):
+    def unmarshal(cls, app, string):
         elems = string.split("?")
 
-        self.unmarshal_page(elems[0])
+        try:
+            name = elems[0]
 
+            if name.startswith("/"):
+                name = name[1:]
+
+            page = app.pages[name]
+        except KeyError:
+            raise Exception("Page '%s' not found" % name)
+
+        session = Session(page)
+
         try:
-            self.unmarshal_url_vars(elems[1])
+            session.unmarshal_url_vars(elems[1])
         except IndexError:
             pass
 
-    def unmarshal_page(self, string):
-        if string.startswith("/"):
-            string = string[1:]
+        return session
 
-        self.set_page(self.app.get_page(string))
+    unmarshal = classmethod(unmarshal)
 
     def unmarshal_url_vars(self, string, separator=";"):
         vars = string.split(separator)
@@ -615,7 +632,7 @@
                 key = unquote(skey)
                 value = unquote_plus(svalue)
 
-                param = self.app.get_parameter(self.get_page(), key)
+                param = self.app.get_parameter(self.page, key)
 
                 if param:
                     if param.is_dictionary:
@@ -625,6 +642,17 @@
             except ValueError:
                 pass
 
+    def unmarshal_cookies(self, string):
+        if string is not None:
+            cookies = dict()
+            crumbs = string.split(";")
+
+            for crumb in crumbs:
+                name, value = crumb.split("=", 1)
+                cookies[name.strip()] = value.strip()
+
+        self.cookies = cookies
+
     def set_origin(self, origin):
         self.origin = self.fix_origin(origin)
     
@@ -766,7 +794,7 @@
             if type(frag) is str:
                 writer.write(frag)
             elif callable(frag):
-                #print "tc", elem, args
+                #print "tc", frag, args
 
                 result = frag(self.__object, session, *args)
 

Modified: mgmt/trunk/cumin/python/wooly/__init__.strings
===================================================================
--- mgmt/trunk/cumin/python/wooly/__init__.strings	2008-09-21 01:29:04 UTC (rev 2510)
+++ mgmt/trunk/cumin/python/wooly/__init__.strings	2008-09-21 17:35:33 UTC (rev 2511)
@@ -1,2 +1,14 @@
 [Widget.html]
 {content}
+
+[Page.html]
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+  <head>
+    <title>{title}</title>
+  </head>
+  <body>
+    {content}
+  </body>
+</html>

Modified: mgmt/trunk/cumin/python/wooly/devel.py
===================================================================
--- mgmt/trunk/cumin/python/wooly/devel.py	2008-09-21 01:29:04 UTC (rev 2510)
+++ mgmt/trunk/cumin/python/wooly/devel.py	2008-09-21 17:35:33 UTC (rev 2511)
@@ -24,11 +24,10 @@
             print count, url,
 
             start = clock()
-            
-            session = Session(self.app)
-            session.unmarshal(url)
 
-            page = session.get_page()
+            session = Session.unmarshal(self.app, url)
+
+            page = session.page
             page.process(session)
 
             html = page.render(session)

Modified: mgmt/trunk/cumin/python/wooly/forms.py
===================================================================
--- mgmt/trunk/cumin/python/wooly/forms.py	2008-09-21 01:29:04 UTC (rev 2510)
+++ mgmt/trunk/cumin/python/wooly/forms.py	2008-09-21 17:35:33 UTC (rev 2511)
@@ -39,7 +39,7 @@
         if not self.origin.get(session):
             self.origin.set(session, session.get_origin())
 
-        params = set(session.get_page().get_saved_parameters(session))
+        params = set(session.page.get_saved_parameters(session))
         params.difference_update(self.form_params)
 
         for param in params:
@@ -66,6 +66,42 @@
         writer.write("<input type='hidden' name='%s' value='%s'/>" \
                      % (name, value))
         
+class FormError(object):
+    def __init__(self, message=None):
+        self.message = message
+
+    def get_message(self, session):
+        return self.message
+
+class FormErrorSet(ItemSet):
+    def __init__(self, app, name):
+        super(FormErrorSet, self).__init__(app, name)
+
+        self.__errors = self.Errors(app, "errors")
+        self.add_attribute(self.__errors)
+
+    def add(self, session, error):
+        assert isinstance(error, FormError)
+
+        self.__errors.get(session).append(error)
+
+    def get(self, session):
+        return self.__errors.get(session)
+
+    def get_items(self, session, *args):
+        return self.get(session)
+
+#    def do_render(self, session, *args):
+#        if self.get(session):
+#            super(FormErrorSet, self).do_render(session, *args)
+
+    def render_item_content(self, session, item):
+        return item.get_message(session)
+
+    class Errors(Attribute):
+        def get_default(self, session):
+            return list()
+
 class FormInput(Widget):
     def __init__(self, app, name, form):
         super(FormInput, self).__init__(app, name)
@@ -113,23 +149,14 @@
     def render_disabled_attr(self, session, *args):
         return self.disabled and "disabled=\"disabled\"" or None
 
-class FormError(object):
-    def __init__(self, message=None):
-        self.message = message
-
-    def get_message(self, session):
-        return self.message
-
 class MissingValueError(FormError):
     def get_message(self, session):
         return "This value is required"
 
 class EmptyInputError(FormError):
     def __init__(self):
-        message = "This value is required"
+        super(EmptyInputError, self).__init__("This value is required")
 
-        super(EmptyInputError, self).__init__(message)
-
 class ScalarInput(FormInput):
     def __init__(self, app, name, form):
         super(ScalarInput, self).__init__(app, name, form)
@@ -151,6 +178,9 @@
 
         self.set_size(30)
 
+class PasswordInput(StringInput):
+    pass
+
 class IntegerInput(ScalarInput):
     def __init__(self, app, name, form):
         super(IntegerInput, self).__init__(app, name, form)
@@ -260,7 +290,7 @@
         self.__form = form
         self.__param = None
 
-        self.__errors = FormFieldErrors(app, "errors")
+        self.__errors = FormErrorSet(app, "errors")
         self.add_child(self.__errors)
 
     def get_parameter(self):
@@ -282,7 +312,7 @@
         return self.__param.set(session, value)
 
     def validate(self, session):
-        errors = self.__errors.attr.get(session)
+        errors = self.__errors.get(session)
 
         self.do_validate(session, errors)
 
@@ -291,27 +321,6 @@
     def do_validate(self, session, errors):
         pass
 
-    def render_errors(self, session, *args):
-        if self.__errors.attr.get(session):
-            return self.__errors.render(session)
-
-class FormFieldErrors(ItemSet):
-    def __init__(self, app, name):
-        super(FormFieldErrors, self).__init__(app, name)
-
-        self.attr = self.Errors(app, "attr")
-        self.add_attribute(self.attr)
-
-    def get_items(self, session, *args):
-        return self.attr.get(session)
-
-    def render_item_content(self, session, item):
-        return item.get_message(session)
-
-    class Errors(Attribute):
-        def get_default(self, session):
-            return list()
-
 class ScalarField(FormField):
     def __init__(self, app, name, form):
         super(ScalarField, self).__init__(app, name, form)
@@ -326,6 +335,7 @@
 
         self.set_parameter(input.get_parameter())
         self.__input = input
+
         return input
 
     def render_inputs(self, session, *args):
@@ -339,11 +349,19 @@
         self.add_child(input)
         self.set_input(input)
 
+class PasswordField(ScalarField):
+    def __init__(self, app, name, form):
+        super(PasswordField, self).__init__(app, name, form)
+        
+        input = PasswordInput(app, "input", form)
+        self.add_child(input)
+        self.set_input(input)
+
 class IntegerField(ScalarField):
     def __init__(self, app, name, form):
         super(IntegerInputField, self).__init__(app, name, form)
 
-        input = Integer(app, "input", form)
+        input = IntegerInput(app, "input", form)
         self.add_child(input)
         self.set_input(input)
 

Modified: mgmt/trunk/cumin/python/wooly/forms.strings
===================================================================
--- mgmt/trunk/cumin/python/wooly/forms.strings	2008-09-21 01:29:04 UTC (rev 2510)
+++ mgmt/trunk/cumin/python/wooly/forms.strings	2008-09-21 17:35:33 UTC (rev 2511)
@@ -1,3 +1,15 @@
+[FormErrorSet.css]
+ul.errors {
+  color: red;
+  font-weight: bold;
+}
+
+[FormErrorSet.html]
+<ul class="errors">{items}</ul>
+
+[FormErrorSet.item_html]
+<li>{item_content}</li>
+
 [FormButton.html]
 <button class="{class}" id="{id}" type="submit" name="{name}" value="{value}" tabindex="{tab_index}" {disabled_attr}>{content}</button>
 
@@ -4,6 +16,9 @@
 [ScalarInput.html]
 <input type="text" name="{name}" value="{value}" tabindex="{tab_index}" {disabled_attr} size="{size}"/>
 
+[PasswordInput.html]
+<input type="password" name="{name}" value="{value}" tabindex="{tab_index}" {disabled_attr} size="{size}"/>
+
 [CheckboxInput.html]
 <input type="checkbox" name="{name}" value="{value}" tabindex="{tab_index}" {checked_attr} {disabled_attr}/>
 
@@ -63,12 +78,6 @@
   <div class="inputs">{inputs}</div>
 </div>
 
-[FormFieldErrors.html]
-<ul class="errors">{items}</ul>
-
-[FormFieldErrors.item_html]
-<li>{item_content}</li>
-
 [RadioFieldOption.html]
 <div>
   <input type="radio" name="{name}" id="{id}" value="{value}"

Modified: mgmt/trunk/cumin/python/wooly/server.py
===================================================================
--- mgmt/trunk/cumin/python/wooly/server.py	2008-09-21 01:29:04 UTC (rev 2510)
+++ mgmt/trunk/cumin/python/wooly/server.py	2008-09-21 17:35:33 UTC (rev 2511)
@@ -9,6 +9,7 @@
 
 class WebServer(object):
     http_date = "%a, %d %b %Y %H:%M:%S %Z"
+    http_date_gmt = "%a, %d %b %Y %H:%M:%S GMT"
 
     def __init__(self, app, addr, port):
         self.app = app
@@ -31,24 +32,22 @@
     def stop(self):
         self.__server.stop()
 
+    def authorized(self, session):
+        return False
+
     def service(self, env, respond):
-        session = Session(self.app)
-        session.unmarshal_page(env["PATH_INFO"])
-        session.unmarshal_url_vars(env["QUERY_STRING"])
-        if "HTTP_REFERER" in env:
-            session.set_origin(env["HTTP_REFERER"])
+        headers = list()
 
-        if "HTTP_AUTHORIZATION" in env:
-            auth = env["HTTP_AUTHORIZATION"].split(" ")[1]
-            name, password = decodestring(auth).split(":", 1)
-            session.credentials["name"] = name
-            session.credentials["password"] = password
+        name = env["PATH_INFO"][1:]
 
-        if not self.authorized(session):
-            headers = [("WWW-Authenticate", "Basic realm=\"MRG Management\"")]
-            respond("401 Unauthorized", headers)
-            return ()
+        try:
+            page = self.app.pages[name]
+        except KeyError:
+            return self.not_found(respond, headers)
 
+        session = Session(page, headers)
+        session.unmarshal_url_vars(env["QUERY_STRING"])
+
         if env["REQUEST_METHOD"] == "POST":
             if env["CONTENT_TYPE"] == "application/x-www-form-urlencoded":
                 length = int(env["CONTENT_LENGTH"])
@@ -60,19 +59,32 @@
             if vars:
                 session.unmarshal_url_vars(vars, "&")
 
-        page = session.get_page()
+        try:
+            session.unmarshal_cookies(env["HTTP_COOKIE"])
+        except KeyError:
+            pass
 
+        if "HTTP_REFERER" in env:
+            # XXX set this on page instead
+            session.set_origin(env["HTTP_REFERER"])
+
+        if not self.authorized(session):
+            url = page.get_redirect_url(session)
+
+            if url:
+                return self.redirect(respond, headers, url)
+            else:
+                return self.unauthorized(respond, headers)
+        
         try:
             page.process(session)
         except:
-            return self.error(session, respond)
+            return self.error(respond, session)
 
-        redirect = page.get_redirect_url(session)
+        url = page.get_redirect_url(session)
 
-        if redirect:
-            respond("303 See Other", (("Location", redirect),
-                                      ("Content-Length", "0")))
-            return ()
+        if url:
+            return self.redirect(respond, headers, url)
 
         ims = env.get("HTTP_IF_MODIFIED_SINCE")
         modified = page.get_last_modified(session).replace(microsecond=0)
@@ -81,19 +93,10 @@
             since = datetime(*strptime(str(ims), self.http_date)[0:6])
 
             if modified <= since:
-                respond("304 Not Modified", (("Content-Length", "0"),))
-                return ()
+                return self.not_modified(respond, headers)
 
-        try:
-            response = page.render(session)
-        except:
-            return self.error(session, respond)
-
-        headers = list()
-        headers.append(("Content-Length", str(len(response))))
-
         if modified:
-            ts = modified.strftime("%a, %d %b %Y %H:%M:%S GMT")
+            ts = modified.strftime(self.http_date_gmt)
             headers.append(("Last-Modified", ts))
 
         type = page.get_content_type(session)
@@ -106,18 +109,53 @@
         if cache:
             headers.append(("Cache-Control", cache))
 
+        try:
+            response = page.render(session)
+        except:
+            return self.error(respond, session)
+
+        headers.append(("Content-Length", str(len(response))))
+
         respond("200 OK", headers)
 
         page.save_session(session)
 
-        return response
+        return (response,)
 
-    def authorized(self, session):
-        return False
+    def message(self, respond, headers, message):
+        headers.append(("Content-Length", str(len(message))))
+        headers.append(("Content-Type", "text/plain"))
 
-    def error(self, session, respond):
-        respond("500 Error", [("Content-Type", "text/plain")])
+        respond(message, headers)
 
+        return (message,)
+
+    def not_found(self, respond, headers):
+        return self.message(respond, headers, "404 Not Found")
+
+    def unauthorized(self, respond, headers):
+        return self.message(respond, headers, "401 Unauthorized")
+
+    def redirect(self, respond, headers, url):
+        headers.append(("Location", url))
+        headers.append(("Content-Length", "0"))
+
+        respond("303 See Other", headers)
+
+        return ()
+
+    def not_modified(self, respond, headers):
+        headers.append(("Content-Length", "0"))
+
+        respond("304 Not Modified", headers)
+
+        return ()
+
+    def error(self, respond, session):
+        session.add_header("Content-Type", "text/plain")
+
+        respond("500 Error", session.response_headers)
+
         if session.debug:
             writer = Writer()
             writer.write("APPLICATION ERROR\n")




More information about the rhmessaging-commits mailing list