]> gitweb.factorcode.org Git - factor.git/commitdiff
Improved cookie support, and better session manager taking advantage of it
authorSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Sun, 27 Apr 2008 08:09:00 +0000 (03:09 -0500)
committerSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Sun, 27 Apr 2008 08:09:00 +0000 (03:09 -0500)
51 files changed:
extra/calendar/format/format-tests.factor
extra/calendar/format/format.factor
extra/calendar/format/macros/macros-tests.factor [new file with mode: 0644]
extra/calendar/format/macros/macros.factor [new file with mode: 0644]
extra/http/http-tests.factor
extra/http/http.factor
extra/http/server/actions/actions-tests.factor
extra/http/server/actions/actions.factor
extra/http/server/auth/basic/basic.factor
extra/http/server/auth/login/edit-profile.xml
extra/http/server/auth/login/login.factor
extra/http/server/auth/login/login.xml
extra/http/server/auth/login/recover-1.xml
extra/http/server/auth/login/recover-3.xml
extra/http/server/auth/login/recover-4.xml
extra/http/server/auth/login/register.xml
extra/http/server/boilerplate/boilerplate.factor
extra/http/server/callbacks/callbacks.factor
extra/http/server/crud/crud.factor
extra/http/server/db/db.factor
extra/http/server/flows/flows.factor
extra/http/server/server-tests.factor
extra/http/server/server.factor
extra/http/server/sessions/sessions-tests.factor
extra/http/server/sessions/sessions.factor
extra/http/server/sessions/storage/db/db.factor
extra/http/server/static/static.factor
extra/http/server/templating/chloe/chloe.factor
extra/webapps/factor-website/factor-website.factor
extra/webapps/factor-website/page.xml
extra/webapps/pastebin/annotation.xml
extra/webapps/pastebin/new-annotation.xml
extra/webapps/pastebin/new-paste.xml
extra/webapps/pastebin/paste-list.xml
extra/webapps/pastebin/paste-summary.xml
extra/webapps/pastebin/paste.xml
extra/webapps/pastebin/pastebin.factor
extra/webapps/pastebin/pastebin.xml
extra/webapps/planet/admin.xml
extra/webapps/planet/blog-admin-link.xml
extra/webapps/planet/edit-blog.xml
extra/webapps/planet/entry-summary.xml
extra/webapps/planet/entry.xml
extra/webapps/planet/planet.factor
extra/webapps/planet/planet.xml
extra/webapps/planet/postings-summary.xml
extra/webapps/planet/postings.xml
extra/webapps/todo/todo-list.xml
extra/webapps/todo/todo-summary.xml
extra/webapps/todo/todo.xml
extra/webapps/todo/view-todo.xml

index 1ba892bef3fc08e1ff0e7520575cf10070fd2957..0d072f27f6773403423e27804c303d2744bb08ea 100755 (executable)
@@ -43,3 +43,10 @@ IN: calendar.format.tests
 ] unit-test\r
 \r
 [ t ] [ now dup timestamp>rfc822 rfc822>timestamp time- 1 seconds before? ] unit-test\r
+\r
+[ t ] [ now dup timestamp>cookie-string cookie-string>timestamp time- 1 seconds before? ] unit-test\r
+\r
+[ "Sun, 4 May 2008 07:00:00" ] [\r
+    "Sun May 04 07:00:00 2008 GMT" cookie-string>timestamp\r
+    timestamp>string\r
+] unit-test\r
index 7bdaea70b55088fe05f7e612dc402ca972885a3d..af536c25850a508f51961eee1bbdf7ba5d5cdbb3 100755 (executable)
@@ -1,8 +1,50 @@
-USING: math math.parser kernel sequences io calendar\r
+USING: math math.parser kernel sequences io\r
 accessors arrays io.streams.string splitting\r
-combinators accessors debugger ;\r
+combinators accessors debugger\r
+calendar calendar.format.macros ;\r
 IN: calendar.format\r
 \r
+: pad-00 number>string 2 CHAR: 0 pad-left ;\r
+\r
+: pad-0000 number>string 4 CHAR: 0 pad-left ;\r
+\r
+: pad-00000 number>string 5 CHAR: 0 pad-left ;\r
+\r
+: write-00 pad-00 write ;\r
+\r
+: write-0000 pad-0000 write ;\r
+\r
+: write-00000 pad-00000 write ;\r
+\r
+: hh hour>> write-00 ;\r
+\r
+: mm minute>> write-00 ;\r
+\r
+: ss second>> >integer write-00 ;\r
+\r
+: D day>> number>string write ;\r
+\r
+: DD day>> write-00 ;\r
+\r
+: DAY day-of-week day-abbreviations3 nth write ;\r
+\r
+: MM month>> write-00 ;\r
+\r
+: MONTH month>> month-abbreviations nth write ;\r
+\r
+: YYYY year>> write-0000 ;\r
+\r
+: YYYYY year>> write-00000 ;\r
+\r
+: expect ( str -- )\r
+    read1 swap member? [ "Parse error" throw ] unless ;\r
+\r
+: read-00 2 read string>number ;\r
+\r
+: read-000 3 read string>number ;\r
+\r
+: read-0000 4 read string>number ;\r
+\r
 GENERIC: day. ( obj -- )\r
 \r
 M: integer day. ( n -- )\r
@@ -25,7 +67,7 @@ M: array month. ( pair -- )
     ] with each nl ;\r
 \r
 M: timestamp month. ( timestamp -- )\r
-    { year>> month>> } get-slots 2array month. ;\r
+    [ year>> ] [ month>> ] bi 2array month. ;\r
 \r
 GENERIC: year. ( obj -- )\r
 \r
@@ -35,28 +77,14 @@ M: integer year. ( n -- )
 M: timestamp year. ( timestamp -- )\r
     year>> year. ;\r
 \r
-: pad-00 number>string 2 CHAR: 0 pad-left ;\r
-\r
-: pad-0000 number>string 4 CHAR: 0 pad-left ;\r
-\r
-: write-00 pad-00 write ;\r
-\r
-: write-0000 pad-0000 write ;\r
-\r
 : (timestamp>string) ( timestamp -- )\r
-    dup day-of-week day-abbreviations3 nth write ", " write\r
-    dup day>> number>string write bl\r
-    dup month>> month-abbreviations nth write bl\r
-    dup year>> number>string write bl\r
-    dup hour>> write-00 ":" write\r
-    dup minute>> write-00 ":" write\r
-    second>> >integer write-00 ;\r
+    { DAY ", " D " " MONTH " " YYYY " " hh ":" mm ":" ss } formatted ;\r
 \r
 : timestamp>string ( timestamp -- str )\r
     [ (timestamp>string) ] with-string-writer ;\r
 \r
 : (write-gmt-offset) ( duration -- )\r
-    [ hour>> write-00 ] [ minute>> write-00 ] bi ;\r
+    [ hh ] [ mm ] bi ;\r
 \r
 : write-gmt-offset ( gmt-offset -- )\r
     dup instant <=> sgn {\r
@@ -69,9 +97,9 @@ M: timestamp year. ( timestamp -- )
     #! RFC822 timestamp format\r
     #! Example: Tue, 15 Nov 1994 08:12:31 +0200\r
     [\r
-        dup (timestamp>string)\r
-        " " write\r
-        gmt-offset>> write-gmt-offset\r
+        [ (timestamp>string) " " write ]\r
+        [ gmt-offset>> write-gmt-offset ]\r
+        bi\r
     ] with-string-writer ;\r
 \r
 : timestamp>http-string ( timestamp -- str )\r
@@ -79,40 +107,32 @@ M: timestamp year. ( timestamp -- )
     #! Example: Tue, 15 Nov 1994 08:12:31 GMT\r
     >gmt timestamp>rfc822 ;\r
 \r
+: (timestamp>cookie-string) ( timestamp -- )\r
+    >gmt\r
+    { DAY ", " DD "-" MONTH "-" YYYY " " hh ":" mm ":" ss " GMT" } formatted ;\r
+\r
+: timestamp>cookie-string ( timestamp -- str )\r
+    [ (timestamp>cookie-string) ] with-string-writer ;\r
+\r
 : (write-rfc3339-gmt-offset) ( duration -- )\r
-    [ hour>> write-00 CHAR: : write1 ]\r
-    [ minute>> write-00 ] bi ;\r
+    [ hh ":" write ] [ mm ] bi ;\r
 \r
 : write-rfc3339-gmt-offset ( duration -- )\r
     dup instant <=> sgn {\r
         {  0 [ drop "Z" write ] }\r
-        { -1 [ CHAR: - write1 before (write-rfc3339-gmt-offset) ] }\r
-        {  1 [ CHAR: + write1 (write-rfc3339-gmt-offset) ] }\r
+        { -1 [ "-" write before (write-rfc3339-gmt-offset) ] }\r
+        {  1 [ "+" write (write-rfc3339-gmt-offset) ] }\r
     } case ;\r
     \r
 : (timestamp>rfc3339) ( timestamp -- )\r
     {\r
-        [ year>> number>string write CHAR: - write1 ]\r
-        [ month>> write-00 CHAR: - write1 ]\r
-        [ day>> write-00 CHAR: T write1 ]\r
-        [ hour>> write-00 CHAR: : write1 ]\r
-        [ minute>> write-00 CHAR: : write1 ]\r
-        [ second>> >fixnum write-00 ]\r
+        YYYY "-" MM "-" DD "T" hh ":" mm ":" ss\r
         [ gmt-offset>> write-rfc3339-gmt-offset ]\r
-    } cleave ;\r
+    } formatted ;\r
 \r
 : timestamp>rfc3339 ( timestamp -- str )\r
     [ (timestamp>rfc3339) ] with-string-writer ;\r
 \r
-: expect ( str -- )\r
-    read1 swap member? [ "Parse error" throw ] unless ;\r
-\r
-: read-00 2 read string>number ;\r
-\r
-: read-000 3 read string>number ;\r
-\r
-: read-0000 4 read string>number ;\r
-\r
 : signed-gmt-offset ( dt ch -- dt' )\r
     { { CHAR: + [ 1 ] } { CHAR: - [ -1 ] } } case time* ;\r
 \r
@@ -142,17 +162,18 @@ M: timestamp year. ( timestamp -- )
 : rfc3339>timestamp ( str -- timestamp )\r
     [ (rfc3339>timestamp) ] with-string-reader ;\r
 \r
-ERROR: invalid-rfc822-date ;\r
+ERROR: invalid-timestamp-format ;\r
 \r
-: check-rfc822-date ( obj/f -- obj ) [ invalid-rfc822-date ] unless* ;\r
+: check-timestamp ( obj/f -- obj )\r
+    [ invalid-timestamp-format ] unless* ;\r
 \r
 : read-token ( seps -- token )\r
-    [ read-until ] keep member? check-rfc822-date drop ;\r
+    [ read-until ] keep member? check-timestamp drop ;\r
 \r
 : read-sp ( -- token ) " " read-token ;\r
 \r
 : checked-number ( str -- n )\r
-    string>number check-rfc822-date ;\r
+    string>number check-timestamp ;\r
 \r
 : parse-rfc822-gmt-offset ( string -- dt )\r
     dup "GMT" = [ drop instant ] [\r
@@ -163,10 +184,10 @@ ERROR: invalid-rfc822-date ;
 \r
 : (rfc822>timestamp) ( -- timestamp )\r
     timestamp new\r
-        "," read-token day-abbreviations3 member? check-rfc822-date drop\r
+        "," read-token day-abbreviations3 member? check-timestamp drop\r
         read1 CHAR: \s assert=\r
         read-sp checked-number >>day\r
-        read-sp month-abbreviations index check-rfc822-date >>month\r
+        read-sp month-abbreviations index check-timestamp >>month\r
         read-sp checked-number >>year\r
         ":" read-token checked-number >>hour\r
         ":" read-token checked-number >>minute\r
@@ -176,6 +197,42 @@ ERROR: invalid-rfc822-date ;
 : rfc822>timestamp ( str -- timestamp )\r
     [ (rfc822>timestamp) ] with-string-reader ;\r
 \r
+: (cookie-string>timestamp-1) ( -- timestamp )\r
+    timestamp new\r
+        "," read-token day-abbreviations3 member? check-timestamp drop\r
+        read1 CHAR: \s assert=\r
+        "-" read-token checked-number >>day\r
+        "-" read-token month-abbreviations index check-timestamp >>month\r
+        read-sp checked-number >>year\r
+        ":" read-token checked-number >>hour\r
+        ":" read-token checked-number >>minute\r
+        " " read-token checked-number >>second\r
+        readln parse-rfc822-gmt-offset >>gmt-offset ;\r
+\r
+: cookie-string>timestamp-1 ( str -- timestamp )\r
+    [ (cookie-string>timestamp-1) ] with-string-reader ;\r
+\r
+: (cookie-string>timestamp-2) ( -- timestamp )\r
+    timestamp new\r
+        read-sp day-abbreviations3 member? check-timestamp drop\r
+        read-sp month-abbreviations index check-timestamp >>month\r
+        read-sp checked-number >>day\r
+        ":" read-token checked-number >>hour\r
+        ":" read-token checked-number >>minute\r
+        " " read-token checked-number >>second\r
+        read-sp checked-number >>year\r
+        readln parse-rfc822-gmt-offset >>gmt-offset ;\r
+\r
+: cookie-string>timestamp-2 ( str -- timestamp )\r
+    [ (cookie-string>timestamp-2) ] with-string-reader ;\r
+\r
+: cookie-string>timestamp ( str -- timestamp )\r
+    {\r
+        [ cookie-string>timestamp-1 ]\r
+        [ cookie-string>timestamp-2 ]\r
+        [ rfc822>timestamp ]\r
+    } attempt-all-quots ;\r
+\r
 : (ymdhms>timestamp) ( -- timestamp )\r
     read-ymd " " expect read-hms instant <timestamp> ;\r
 \r
@@ -195,41 +252,30 @@ ERROR: invalid-rfc822-date ;
     [ (ymd>timestamp) ] with-string-reader ;\r
 \r
 : (timestamp>ymd) ( timestamp -- )\r
-    dup timestamp-year write-0000\r
-    "-" write\r
-    dup timestamp-month write-00\r
-    "-" write\r
-    timestamp-day write-00 ;\r
+    { YYYY "-" MM "-" DD } formatted ;\r
 \r
 : timestamp>ymd ( timestamp -- str )\r
     [ (timestamp>ymd) ] with-string-writer ;\r
 \r
 : (timestamp>hms)\r
-    dup timestamp-hour write-00\r
-    ":" write\r
-    dup timestamp-minute write-00\r
-    ":" write\r
-    timestamp-second >integer write-00 ;\r
+    { hh ":" mm ":" ss } formatted ;\r
 \r
 : timestamp>hms ( timestamp -- str )\r
     [ (timestamp>hms) ] with-string-writer ;\r
 \r
 : timestamp>ymdhms ( timestamp -- str )\r
-    >gmt\r
     [\r
-        dup (timestamp>ymd)\r
-        " " write\r
-        (timestamp>hms)\r
+        >gmt\r
+        { (timestamp>ymd) " " (timestamp>hms) } formatted\r
     ] with-string-writer ;\r
 \r
 : file-time-string ( timestamp -- string )\r
     [\r
-        [ month>> month-abbreviations nth write ] keep bl\r
-        [ day>> number>string 2 32 pad-left write ] keep bl\r
-        dup now [ year>> ] bi@ = [\r
-            [ hour>> write-00 ] keep ":" write\r
-            minute>> write-00\r
-        ] [\r
-            year>> number>string 5 32 pad-left write\r
-        ] if\r
+        {\r
+            MONTH " " DD " "\r
+            [\r
+                dup now [ year>> ] bi@ =\r
+                [ [ hh ":" write ] [ mm ] bi ] [ YYYYY ] if\r
+            ]\r
+        } formatted\r
     ] with-string-writer ;\r
diff --git a/extra/calendar/format/macros/macros-tests.factor b/extra/calendar/format/macros/macros-tests.factor
new file mode 100644 (file)
index 0000000..91a8f80
--- /dev/null
@@ -0,0 +1,14 @@
+USING: tools.test kernel ;
+IN: calendar.format.macros
+
+[ 2 ] [ { [ 2 ] } attempt-all-quots ] unit-test
+
+[ 2 ] [ { [ 1 throw ] [ 2 ] } attempt-all-quots ] unit-test
+
+[ { [ 1 throw ] } attempt-all-quots ] [ 1 = ] must-fail-with
+
+: compiled-test-1 { [ 1 throw ] [ 2 ] } attempt-all-quots ;
+
+\ compiled-test-1 must-infer
+
+[ 2 ] [ compiled-test-1 ] unit-test
diff --git a/extra/calendar/format/macros/macros.factor b/extra/calendar/format/macros/macros.factor
new file mode 100644 (file)
index 0000000..6d6dd3a
--- /dev/null
@@ -0,0 +1,19 @@
+USING: macros kernel words quotations io sequences combinators
+continuations ;
+IN: calendar.format.macros
+
+MACRO: formatted ( spec -- )
+    [
+        {
+            { [ dup word? ] [ 1quotation ] }
+            { [ dup quotation? ] [ ] }
+            [ [ nip write ] curry [ ] like ]
+        } cond
+    ] map [ cleave ] curry ;
+
+MACRO: attempt-all-quots ( quots -- )
+    dup length 1 = [ first ] [
+        unclip swap
+        [ nip attempt-all-quots ] curry
+        [ recover ] 2curry
+    ] if ;
index a9e539c2a563cbbfdb0f6a1337f7ead9c0b1f238..e624f56573499de58f92bcf8ca68e945c85d8237 100755 (executable)
@@ -158,7 +158,7 @@ test-db [
                 "extra/http/test" resource-path <static> >>default
             "nested" add-responder
             <action>
-                [ "redirect-loop" f <permanent-redirect> ] >>display
+                [ "redirect-loop" f <standard-redirect> ] >>display
             "redirect-loop" add-responder
         main-responder set
 
index 3e81fccd24b620cb61551f3eb6dc106a06477f35..99a48e58d8a1ac0bb40fb82fa654c90e6b9c3be0 100755 (executable)
@@ -135,11 +135,12 @@ IN: http
     ] { } assoc>map
     "&" join ;
 
-TUPLE: cookie name value path domain expires http-only ;
+TUPLE: cookie name value path domain expires max-age http-only ;
 
 : <cookie> ( value name -- cookie )
     cookie new
-    swap >>name swap >>value ;
+        swap >>name
+        swap >>value ;
 
 : parse-cookies ( string -- seq )
     [
@@ -147,7 +148,8 @@ TUPLE: cookie name value path domain expires http-only ;
 
         ";" split [
             [ blank? ] trim "=" split1 swap >lower {
-                { "expires" [ >>expires ] }
+                { "expires" [ cookie-string>timestamp >>expires ] }
+                { "max-age" [ string>number seconds ] }
                 { "domain" [ >>domain ] }
                 { "path" [ >>path ] }
                 { "httponly" [ drop t >>http-only ] }
@@ -163,7 +165,14 @@ TUPLE: cookie name value path domain expires http-only ;
     {
         { f [ drop ] }
         { t [ , ] }
-        [ "=" swap 3append , ]
+        [
+            {
+                { [ dup timestamp? ] [ timestamp>cookie-string ] }
+                { [ dup duration? ] [ dt>seconds number>string ] }
+                [ ]
+            } cond
+            "=" swap 3append ,
+        ]
     } case ;
 
 : unparse-cookie ( cookie -- strings )
@@ -172,6 +181,7 @@ TUPLE: cookie name value path domain expires http-only ;
         "path" over path>> (unparse-cookie)
         "domain" over domain>> (unparse-cookie)
         "expires" over expires>> (unparse-cookie)
+        "max-age" over max-age>> (unparse-cookie)
         "httponly" over http-only>> (unparse-cookie)
         drop
     ] { } make ;
index 615077821af9160f91c326b13df1cc269eb14a58..5aa761603fc33c94ac72889b1398b76e1f240eb9 100755 (executable)
@@ -22,6 +22,7 @@ blah
 ;
 
 [ 25 ] [
+    init-request
     action-request-test-1 lf>crlf
     [ read-request ] with-string-reader
     request set
index bfcbd20ccadf2551ce3c0aed46816b78350c56de..6e1aac96272ceb0d4780a782b4ef7d1325c99fe2 100755 (executable)
@@ -37,16 +37,19 @@ TUPLE: action init display submit get-params post-params ;
 : validation-failed ( -- * )\r
     action get display>> call exit-with ;\r
 \r
-M: action call-responder ( path action -- response )\r
+M: action call-responder* ( path action -- response )\r
     '[\r
         , [ CHAR: / = ] right-trim empty? [\r
             , action set\r
-            request-params params set\r
-            request get method>> {\r
-                { "GET" [ handle-get ] }\r
-                { "HEAD" [ handle-get ] }\r
-                { "POST" [ handle-post ] }\r
-            } case\r
+            request get\r
+            [ request-params params set ]\r
+            [\r
+                method>> {\r
+                    { "GET" [ handle-get ] }\r
+                    { "HEAD" [ handle-get ] }\r
+                    { "POST" [ handle-post ] }\r
+                } case\r
+            ] bi\r
         ] [\r
             <404>\r
         ] if\r
index 62625e116b10daa28d59676a6c904db56cef0206..daf6e30eae0926d852eb2232d8da2eaf2f47466d 100755 (executable)
@@ -36,6 +36,6 @@ C: <basic-auth> basic-auth
 : logged-in? ( request responder -- ? )\r
     provider>> swap "authorization" header authorization-ok? ;\r
 \r
-M: basic-auth call-responder ( request path responder -- response )\r
+M: basic-auth call-responder* ( request path responder -- response )\r
     pick over logged-in?\r
     [ call-next-method ] [ 2nip realm>> <401> ] if ;\r
index 86a4e865515c6f1f33e54d32d1b50abc4a02c54e..c19b18c947d0f2a0d28f58d3bff908173e9859a5 100644 (file)
@@ -4,18 +4,18 @@
 
        <t:title>Edit Profile</t:title>
 
-       <t:form action="edit-profile">
+       <t:form t:action="edit-profile">
 
        <table>
        
        <tr>
                <th class="field-label">User name:</th>
-               <td><t:view component="username" /></td>
+               <td><t:view t:component="username" /></td>
        </tr>
        
        <tr>
                <th class="field-label">Real name:</th>
-               <td><t:edit component="realname" /></td>
+               <td><t:edit t:component="realname" /></td>
        </tr>
        
        <tr>
@@ -25,7 +25,7 @@
        
        <tr>
                <th class="field-label">Current password:</th>
-               <td><t:edit component="password" /></td>
+               <td><t:edit t:component="password" /></td>
        </tr>
        
        <tr>
        
        <tr>
                <th class="field-label">New password:</th>
-               <td><t:edit component="new-password" /></td>
+               <td><t:edit t:component="new-password" /></td>
        </tr>
        
        <tr>
                <th class="field-label">Verify:</th>
-               <td><t:edit component="verify-password" /></td>
+               <td><t:edit t:component="verify-password" /></td>
        </tr>
        
        <tr>
@@ -50,7 +50,7 @@
        
        <tr>
                <th class="field-label">E-mail:</th>
-               <td><t:edit component="email" /></td>
+               <td><t:edit t:component="email" /></td>
        </tr>
        
        <tr>
        <p>
                <input type="submit" value="Update" />
 
-               <t:if var="http.server.auth.login:login-failed?">
+               <t:if t:var="http.server.auth.login:login-failed?">
                        <t:error>invalid password</t:error>
                </t:if>
                
-               <t:if var="http.server.auth.login:password-mismatch?">
+               <t:if t:var="http.server.auth.login:password-mismatch?">
                        <t:error>passwords do not match</t:error>
                </t:if>
        </p>
index 5f58f51adb150a760ed00647968ddf3b8d6dabe6..716996dc5a08193f86ae592ac828c6a00a493482 100755 (executable)
@@ -331,7 +331,7 @@ SYMBOL: lost-password-from
     <action>\r
         [\r
             f logged-in-user sset\r
-            "$login/login" f <permanent-redirect>\r
+            "$login/login" end-flow\r
         ] >>submit ;\r
 \r
 ! ! ! Authentication logic\r
@@ -342,19 +342,17 @@ C: <protected> protected
 \r
 : show-login-page ( -- response )\r
     begin-flow\r
-    "$login/login" f <temporary-redirect> ;\r
+    "$login/login" f <standard-redirect> ;\r
 \r
-M: protected call-responder ( path responder -- response )\r
+M: protected call-responder* ( path responder -- response )\r
     logged-in-user sget dup [\r
         save-user-after\r
         call-next-method\r
     ] [\r
-        3drop\r
-        request get method>> { "GET" "HEAD" } member?\r
-        [ show-login-page ] [ <400> ] if\r
+        3drop show-login-page\r
     ] if ;\r
 \r
-M: login call-responder ( path responder -- response )\r
+M: login call-responder* ( path responder -- response )\r
     dup login set\r
     call-next-method ;\r
 \r
index 2f16c09d8d91b82726abb16501f774c9e10d7d60..0524d0889fdc04ca1debf4d99ce607f5ae34bc79 100644 (file)
@@ -4,18 +4,18 @@
 
        <t:title>Login</t:title>
 
-       <t:form action="login">
+       <t:form t:action="login">
 
                <table>
 
                        <tr>
                                <th class="field-label">User name:</th>
-                               <td><t:edit component="username" /></td>
+                               <td><t:edit t:component="username" /></td>
                        </tr>
 
                        <tr>
                                <th class="field-label">Password:</th>
-                               <td><t:edit component="password" /></td>
+                               <td><t:edit t:component="password" /></td>
                        </tr>
 
                </table>
@@ -24,7 +24,7 @@
 
                        <input type="submit" value="Log in" />
 
-                       <t:if var="http.server.auth.login:login-failed?">
+                       <t:if t:var="http.server.auth.login:login-failed?">
                                <t:error>invalid username or password</t:error>
                        </t:if>
                </p>
 
        <p>
                <t:if code="http.server.auth.login:login-failed?">
-                       <t:a href="register">Register</t:a>
+                       <t:a t:href="register">Register</t:a>
                </t:if>
                |
                <t:if code="http.server.auth.login:allow-password-recovery?">
-                       <t:a href="recover-password">Recover Password</t:a>
+                       <t:a t:href="recover-password">Recover Password</t:a>
                </t:if>
        </p>
 
index dd3a60f1d1f75f435645fe18310f84de8b69d922..7c72181c10e27ff5cc8b35b4c752d3d4aff03aee 100644 (file)
@@ -6,23 +6,23 @@
 
        <p>Enter the username and e-mail address you used to register for this site, and you will receive a link for activating a new password.</p>
 
-       <t:form action="recover-password">
+       <t:form t:action="recover-password">
 
                <table>
 
                <tr>
                <th class="field-label">User name:</th>
-               <td><t:edit component="username" /></td>
+               <td><t:edit t:component="username" /></td>
                </tr>
 
                <tr>
                <th class="field-label">E-mail:</th>
-               <td><t:edit component="email" /></td>
+               <td><t:edit t:component="email" /></td>
                </tr>
 
                <tr>
                <th class="field-label">Captcha:</th>
-               <td><t:edit component="captcha" /></td>
+               <td><t:edit t:component="captcha" /></td>
                </tr>
 
                <tr>
index 115c2cea21f9d6bb511e43822f4ab2fea3658ac1..61ef0aef869229ec7f9cd0bb3a1b80144a051b29 100644 (file)
@@ -6,21 +6,21 @@
 
        <p>Choose a new password for your account.</p>
 
-       <t:form action="new-password">
+       <t:form t:action="new-password">
 
                <table>
 
-                       <t:edit component="username" />
-                       <t:edit component="ticket" />
+                       <t:edit t:component="username" />
+                       <t:edit t:component="ticket" />
 
                        <tr>
                        <th class="field-label">Password:</th>
-                       <td><t:edit component="new-password" /></td>
+                       <td><t:edit t:component="new-password" /></td>
                        </tr>
 
                        <tr>
                        <th class="field-label">Verify password:</th>
-                       <td><t:edit component="verify-password" /></td>
+                       <td><t:edit t:component="verify-password" /></td>
                        </tr>
 
                        <tr>
@@ -33,7 +33,7 @@
                <p>
                        <input type="submit" value="Set password" />
 
-                       <t:if var="http.server.auth.login:password-mismatch?">
+                       <t:if t:var="http.server.auth.login:password-mismatch?">
                                <t:error>passwords do not match</t:error>
                        </t:if>
                </p>
index 3c10869fbd3d9d380a0b7cbe6ca5505fb87689c9..f5d02fa858a073b417da3b2a7a6c505bbe54c5c1 100755 (executable)
@@ -4,6 +4,6 @@
 \r
        <t:title>Recover lost password: step 4 of 4</t:title>\r
 \r
-       <p>Your password has been reset. You may now <t:a href="login">log in</t:a>.</p>\r
+       <p>Your password has been reset. You may now <t:a t:href="login">log in</t:a>.</p>\r
 \r
 </t:chloe>\r
index 1bacf71801197156811a2a39ac68b8ab09ad8b8c..19917002b5d621e72b1dd5706f165881ddd69cb1 100644 (file)
@@ -4,18 +4,18 @@
 
        <t:title>New User Registration</t:title>
 
-       <t:form action="register">
+       <t:form t:action="register">
 
                <table>
 
                <tr>
                <th class="field-label">User name:</th>
-               <td><t:edit component="username" /></td>
+               <td><t:edit t:component="username" /></td>
                </tr>
 
                <tr>
                <th class="field-label">Real name:</th>
-               <td><t:edit component="realname" /></td>
+               <td><t:edit t:component="realname" /></td>
                </tr>
 
                <tr>
 
                <tr>
                <th class="field-label">Password:</th>
-               <td><t:edit component="new-password" /></td>
+               <td><t:edit t:component="new-password" /></td>
                </tr>
 
                <tr>
                <th class="field-label">Verify:</th>
-               <td><t:edit component="verify-password" /></td>
+               <td><t:edit t:component="verify-password" /></td>
                </tr>
 
                <tr>
@@ -40,7 +40,7 @@
 
                <tr>
                <th class="field-label">E-mail:</th>
-               <td><t:edit component="email" /></td>
+               <td><t:edit t:component="email" /></td>
                </tr>
 
                <tr>
@@ -50,7 +50,7 @@
 
                <tr>
                <th class="field-label">Captcha:</th>
-               <td><t:edit component="captcha" /></td>
+               <td><t:edit t:component="captcha" /></td>
                </tr>
 
                <tr>
 
                        <input type="submit" value="Register" />
 
-                       <t:if var="http.server.auth.login:user-exists?">
+                       <t:if t:var="http.server.auth.login:user-exists?">
                                <t:error>username taken</t:error>
                        </t:if>
 
-                       <t:if var="http.server.auth.login:password-mismatch?">
+                       <t:if t:var="http.server.auth.login:password-mismatch?">
                                <t:error>passwords do not match</t:error>
                        </t:if>
 
index fbe027cc052b85044f64596eea010c7ba389cf35..1dc5effbe20956e50840a745061a14598240bbb7 100644 (file)
@@ -68,7 +68,7 @@ M: f call-template* drop call-next-template ;
         bi*
     ] with-scope ; inline
 
-M: boilerplate call-responder
+M: boilerplate call-responder*
     tuck call-next-method
     dup "content-type" header "text/html" = [
         clone swap template>>
index 42213d015f4f796205c55e2b9078bfc46e990f87..5325ee3b55c66e50a967ad3b59358cbb369bc00f 100755 (executable)
@@ -96,7 +96,7 @@ SYMBOL: current-show
 : resuming-callback ( responder request -- id )\r
     cont-id query-param swap callbacks>> at ;\r
 \r
-M: callback-responder call-responder ( path responder -- response )\r
+M: callback-responder call-responder* ( path responder -- response )\r
     '[\r
         , ,\r
 \r
index 65de881adbfad022dcbde17b34b962780aefc9a9..90af25df5be1b40bc2f4b6358e1502912c0efb2f 100755 (executable)
@@ -18,7 +18,7 @@ IN: http.server.crud
         [ form view-form ] >>display ;
 
 : <id-redirect> ( id next -- response )
-    swap number>string "id" associate <permanent-redirect> ;
+    swap number>string "id" associate <standard-redirect> ;
 
 :: <edit-action> ( form ctor next -- action )
     <action>
@@ -53,7 +53,7 @@ IN: http.server.crud
         [
             "id" get ctor call delete-tuple
 
-            next f <permanent-redirect>
+            next f <standard-redirect>
         ] >>submit ;
 
 :: <list-action> ( form ctor -- action )
index 221608fc91ea25fbd1c9e940dd6717c3881e23df..047af3f4ac4fa4fd9f6c9c7cf7f79e530f8e2dae 100755 (executable)
@@ -12,5 +12,5 @@ C: <db-persistence> db-persistence
     [ db>> ] [ params>> ] bi make-db db-open\r
     [ db set ] [ add-always-destructor ] bi ;\r
 \r
-M: db-persistence call-responder\r
+M: db-persistence call-responder*\r
     [ connect-db ] [ call-next-method ] bi ;\r
index 14ac1d8d799baf2386ae8768480c05f1ca029cf4..7a9b362111499a95d598496db5bb2fcfd8146f8d 100644 (file)
@@ -10,12 +10,25 @@ TUPLE: flows < filter-responder ;
 C: <flows> flows
 
 : begin-flow* ( -- id )
-    request get [ path>> ] [ query>> ] bi 2array
+    request get
+    [ path>> ] [ request-params ] [ method>> ] tri 3array
     flows sget set-at-unique
     session-changed ;
 
+: end-flow-post ( path params -- response )
+    request [
+        clone
+            "POST" >>method
+            swap >>post-data
+            swap >>path
+    ] change
+    request get path>> split-path
+    flows get responder>> call-responder ;
+
 : end-flow* ( default id -- response )
-    flows sget at [ first2 ] [ f ] ?if <permanent-redirect> ;
+    flows sget at
+    [ first3 "POST" = [ end-flow-post ] [ <standard-redirect> ] if ]
+    [ f <standard-redirect> ] ?if ;
 
 SYMBOL: flow-id
 
@@ -39,10 +52,11 @@ SYMBOL: flow-id
         input/>
     ] when* ;
 
-M: flows call-responder
+M: flows call-responder*
+    dup flows set
     [ add-flow-id ] add-link-hook
     [ flow-form-field ] add-form-hook
-    flow-id-key request-params at flow-id set
+    flow-id-key request get request-params at flow-id set
     call-next-method ;
 
 M: flows init-session*
index 20481648849091a24f0f18128b235669e96d6c21..a5dffbc58b394b7ff43cc9ab8adbed636fdc6c4d 100755 (executable)
@@ -27,7 +27,7 @@ TUPLE: mock-responder path ;
 
 C: <mock-responder> mock-responder
 
-M: mock-responder call-responder
+M: mock-responder call-responder*
     nip
     path>> on
     "text/plain" <content> ;
@@ -81,7 +81,7 @@ TUPLE: path-check-responder ;
 
 C: <path-check-responder> path-check-responder
 
-M: path-check-responder call-responder
+M: path-check-responder call-responder*
     drop
     "text/plain" <content> swap >array >>body ;
 
@@ -121,7 +121,7 @@ TUPLE: base-path-check-responder ;
 
 C: <base-path-check-responder> base-path-check-responder
 
-M: base-path-check-responder call-responder
+M: base-path-check-responder call-responder*
     2drop
     "$funny-dispatcher" resolve-base-path
     "text/plain" <content> swap >>body ;
index 13ed36ec6518006a14ce2d6ef3c6875657ee99f2..6c128b3d83f7c590270da8460342dee8f1f0c585 100755 (executable)
@@ -9,10 +9,10 @@ IN: http.server
 
 ! path is a sequence of path component strings
 
-GENERIC: call-responder ( path responder -- response )
+GENERIC: call-responder* ( path responder -- response )
 
-: request-params ( -- assoc )
-    request get dup method>> {
+: request-params ( request -- assoc )
+    dup method>> {
         { "GET" [ query>> ] }
         { "HEAD" [ query>> ] }
         { "POST" [ post-data>> ] }
@@ -28,7 +28,7 @@ TUPLE: trivial-responder response ;
 
 C: <trivial-responder> trivial-responder
 
-M: trivial-responder call-responder nip response>> call ;
+M: trivial-responder call-responder* nip response>> call ;
 
 : trivial-response-body ( code message -- )
     <html>
@@ -67,6 +67,9 @@ SYMBOL: base-paths
     [ invert-slice ] [ class word-name ] bi*
     base-paths get set-at ;
 
+: call-responder ( path responder -- response )
+    [ add-base-path ] [ call-responder* ] 2bi ;
+
 SYMBOL: link-hook
 
 : add-link-hook ( quot -- )
@@ -139,6 +142,10 @@ SYMBOL: form-hook
 : <temporary-redirect> ( to query -- response )
     307 "Temporary Redirect" <redirect> ;
 
+: <standard-redirect> ( to query -- response )
+    request get method>> "POST" =
+    [ <permanent-redirect> ] [ <temporary-redirect> ] if ;
+
 TUPLE: dispatcher default responders ;
 
 : new-dispatcher ( class -- dispatcher )
@@ -158,8 +165,8 @@ TUPLE: dispatcher default responders ;
         [ >r drop 1 tail-slice r> ] [ drop default>> ] if
     ] if ;
 
-M: dispatcher call-responder ( path dispatcher -- response )
-    [ add-base-path ] [ find-responder call-responder ] 2bi ;
+M: dispatcher call-responder* ( path dispatcher -- response )
+    find-responder call-responder ;
 
 TUPLE: vhost-dispatcher default responders ;
 
@@ -170,7 +177,7 @@ TUPLE: vhost-dispatcher default responders ;
     request get host>> over responders>> at*
     [ nip ] [ drop default>> ] if ;
 
-M: vhost-dispatcher call-responder ( path dispatcher -- response )
+M: vhost-dispatcher call-responder* ( path dispatcher -- response )
     find-vhost call-responder ;
 
 : add-responder ( dispatcher responder path -- dispatcher )
@@ -183,7 +190,7 @@ M: vhost-dispatcher call-responder ( path dispatcher -- response )
 
 TUPLE: filter-responder responder ;
 
-M: filter-responder call-responder
+M: filter-responder call-responder*
     responder>> call-responder ;
 
 SYMBOL: main-responder
@@ -234,14 +241,16 @@ SYMBOL: exit-continuation
 : split-path ( string -- path )
     "/" split [ empty? not ] subset ;
 
+: init-request ( -- )
+    H{ } clone base-paths set
+    [ ] link-hook set
+    [ ] form-hook set ;
+
 : do-request ( request -- response )
     [
-        H{ } clone base-paths set
-        [ ] link-hook set
-        [ ] form-hook set
-
-        [ log-request ]
+        init-request
         [ request set ]
+        [ log-request ]
         [ path>> split-path main-responder get call-responder ] tri
         [ <404> ] unless*
     ] [
index 4ff26c3a8f5d388cdd6d8fd596d6d2e770ca57d2..548f3dc00bc624507e58ff53ea3726141572fb29 100755 (executable)
@@ -16,7 +16,7 @@ C: <foo> foo
 \r
 M: foo init-session* drop 0 "x" sset ;\r
 \r
-M: foo call-responder\r
+M: foo call-responder*\r
     2drop\r
     "x" [ 1+ ] schange\r
     "text/html" <content> [ "x" sget pprint ] >>body ;\r
@@ -53,8 +53,15 @@ M: foo call-responder
 \r
 "auth-test.db" temp-file sqlite-db [\r
 \r
+    init-request\r
     init-sessions-table\r
 \r
+    [ ] [\r
+        <foo> <session-manager>\r
+            sessions-in-db >>sessions\r
+        session-manager set\r
+    ] unit-test\r
+\r
     [\r
         empty-session\r
             123 >>id session set\r
@@ -70,12 +77,6 @@ M: foo call-responder
         [ t ] [ session get changed?>> ] unit-test\r
     ] with-scope\r
 \r
-    [ ] [\r
-        <foo> <session-manager>\r
-            sessions-in-db >>sessions\r
-        session-manager set\r
-    ] unit-test\r
-\r
     [ t ] [\r
         session-manager get begin-session id>>\r
         session-manager get sessions>> get-session session?\r
index d2c1d90e0abbab1afa17be43bfeebb2860d5360f..df2a5bbd28a0037a174edc55508de1e11dc34bc7 100755 (executable)
@@ -10,7 +10,7 @@ http.server.sessions.storage.null
 html.elements ;
 IN: http.server.sessions
 
-TUPLE: session id expiry namespace changed? ;
+TUPLE: session id expires namespace changed? ;
 
 : <session> ( id -- session )
     session new
@@ -24,10 +24,13 @@ M: dispatcher init-session* default>> init-session* ;
 
 M: filter-responder init-session* responder>> init-session* ;
 
-TUPLE: session-manager < filter-responder sessions ;
+TUPLE: session-manager < filter-responder sessions timeout domain ;
 
 : <session-manager> ( responder -- responder' )
-    null-sessions session-manager boa ;
+    session-manager new
+        swap >>responder
+        null-sessions >>sessions
+        20 minutes >>timeout ;
 
 : (session-changed) ( session -- )
     t >>changed? drop ;
@@ -47,18 +50,14 @@ TUPLE: session-manager < filter-responder sessions ;
     [ namespace>> swap change-at ] keep
     (session-changed) ; inline
 
-: sessions session-manager get sessions>> ;
-
 : init-session ( session managed -- )
     >r session r> '[ , init-session* ] with-variable ;
 
-: timeout 20 minutes ;
-
 : cutoff-time ( -- time )
-    now timeout time+ timestamp>millis ;
+    session-manager get timeout>> from-now timestamp>millis ;
 
 : touch-session ( session -- )
-    cutoff-time >>expiry drop ;
+    cutoff-time >>expires drop ;
 
 : empty-session ( -- session )
     f <session>
@@ -73,21 +72,24 @@ TUPLE: session-manager < filter-responder sessions ;
     2tri ;
 
 ! Destructor
-TUPLE: session-saver session ;
+TUPLE: session-saver manager session ;
 
 C: <session-saver> session-saver
 
 M: session-saver dispose
-    session>> dup changed?>> [
-        [ touch-session ] [ sessions update-session ] bi
-    ] [ drop ] if ;
+    [ session>> ] [ manager>> sessions>> ] bi
+    over changed?>> [
+        [ drop touch-session ] [ update-session ] 2bi
+    ] [ 2drop ] if ;
 
-: save-session-after ( session -- )
+: save-session-after ( manager session -- )
     <session-saver> add-always-destructor ;
 
-: existing-session ( path responder session -- response )
-    [ session set ] [ save-session-after ] bi
-    [ session-manager set ] [ responder>> call-responder ] bi ;
+: existing-session ( path manager session -- response )
+    [ nip session set ]
+    [ save-session-after ]
+    [ drop responder>> ] 2tri
+    call-responder ;
 
 : session-id-key "factorsessid" ;
 
@@ -109,13 +111,13 @@ M: session-saver dispose
     >r request-session-id r> sessions>> get-session ;
 
 : <session-cookie> ( id -- cookie )
-    session-id-key <cookie> ;
+    session-id-key <cookie>
+        "$session-manager" resolve-base-path >>path
+        session-manager get timeout>> from-now >>expires
+        session-manager get domain>> >>domain ;
 
-: new-session ( path responder -- response )
-    dup begin-session
-    [ existing-session ]
-    [ id>> number>string <session-cookie> ] bi
-    put-cookie ;
+: put-session-cookie ( response -- response' )
+    session get id>> number>string <session-cookie> put-cookie ;
 
 : session-form-field ( -- )
     <input
@@ -124,6 +126,8 @@ M: session-saver dispose
         session get id>> number>string =value
     input/> ;
 
-M: session-manager call-responder ( path responder -- response )
+M: session-manager call-responder* ( path responder -- response )
     [ session-form-field ] add-form-hook
-    dup request-session [ existing-session ] [ new-session ] if* ;
+    dup session-manager set
+    dup request-session [ dup begin-session ] unless*
+    existing-session put-session-cookie ;
index 637d86670feba29b340c156c78b19b3ef0603505..58a0130b368f3655a9be03b9b2eae1b798272ae6 100755 (executable)
@@ -11,7 +11,7 @@ session "SESSIONS"
 {
     ! { "id" "ID" +random-id+ system-random-generator }
     { "id" "ID" INTEGER +native-id+ }
-    { "expiry" "EXPIRY" BIG-INTEGER +not-null+ }
+    { "expires" "EXPIRES" BIG-INTEGER +not-null+ }
     { "namespace" "NAMESPACE" FACTOR-BLOB }
 } define-persistent
 
@@ -31,7 +31,7 @@ M: sessions-in-db new-session ( session storage -- )
 
 : expired-sessions ( -- session )
     f <session>
-    USE: math now timestamp>millis [ 60 60 * 1000 * - ] keep [a,b] >>expiry
+    USE: math now timestamp>millis [ 60 60 * 1000 * - ] keep [a,b] >>expires
     select-tuples ;
 
 : start-expiring-sessions ( db seq -- )
index 1605144b616aff2d169d2ce8534f97be23a0279c..af6018fbdc18c1fdd1264abec2f53804fce27193 100755 (executable)
@@ -77,7 +77,7 @@ TUPLE: file-responder root hook special ;
         find-index [ serve-file ] [ list-directory ] ?if\r
     ] [\r
         drop\r
-        request get path>> "/" append f <permanent-redirect>\r
+        request get path>> "/" append f <standard-redirect>\r
     ] if ;\r
 \r
 : serve-object ( filename -- response )\r
@@ -86,7 +86,7 @@ TUPLE: file-responder root hook special ;
     [ drop <404> ]\r
     if ;\r
 \r
-M: file-responder call-responder ( path responder -- response )\r
+M: file-responder call-responder* ( path responder -- response )\r
     file-responder set\r
     ".." over member?\r
     [ drop <400> ] [ "/" join serve-object ] if ;\r
index 99d6376fe8b59c77ce66be4fb78cc6e24cea881c..622cfe900f8ac377457108cc4a508db7497529e1 100644 (file)
@@ -1,5 +1,5 @@
 USING: accessors kernel sequences combinators kernel namespaces
-classes.tuple assocs splitting words arrays
+classes.tuple assocs splitting words arrays memoize
 io io.files io.encodings.utf8 html.elements unicode.case
 tuple-syntax xml xml.data xml.writer xml.utilities
 http.server
@@ -19,23 +19,31 @@ C: <chloe> chloe
 
 DEFER: process-template
 
-: chloe-ns TUPLE{ name url: "http://factorcode.org/chloe/1.0" } ;
+: chloe-ns "http://factorcode.org/chloe/1.0" ; inline
+
+: filter-chloe-attrs ( assoc -- assoc' )
+    [ drop name-url chloe-ns = not ] assoc-subset ;
 
 : chloe-tag? ( tag -- ? )
     {
         { [ dup tag? not ] [ f ] }
-        { [ dup chloe-ns names-match? not ] [ f ] }
+        { [ dup url>> chloe-ns = not ] [ f ] }
         [ t ]
     } cond nip ;
 
 SYMBOL: tags
 
+MEMO: chloe-name ( string -- name )
+    name new
+        swap >>tag
+        chloe-ns >>url ;
+
 : required-attr ( tag name -- value )
-    dup rot at*
+    dup chloe-name rot at*
     [ nip ] [ drop " attribute is required" append throw ] if ;
 
 : optional-attr ( tag name -- value )
-    swap at ;
+    chloe-name swap at ;
 
 : write-title-tag ( tag -- )
     drop
@@ -84,7 +92,7 @@ SYMBOL: tags
     dup empty?
     [ drop f ] [ "," split [ dup value ] H{ } map>assoc ] if ;
 
-: a-flow-attr ( tag -- )
+: flow-attr ( tag -- )
     "flow" optional-attr {
         { "none" [ flow-id off ] }
         { "begin" [ begin-flow ] }
@@ -92,7 +100,7 @@ SYMBOL: tags
         { f [ ] }
     } case ;
 
-: a-session-attr ( tag -- )
+: session-attr ( tag -- )
     "session" optional-attr {
         { "none" [ session off flow-id off ] }
         { "current" [ ] }
@@ -102,8 +110,8 @@ SYMBOL: tags
 : a-start-tag ( tag -- )
     [
         <a
-        dup a-flow-attr
-        dup a-session-attr
+        dup flow-attr
+        dup session-attr
         dup "value" optional-attr [ value f ] [
             [ "href" required-attr ]
             [ "query" optional-attr parse-query-attr ]
@@ -122,12 +130,18 @@ SYMBOL: tags
     tri ;
 
 : form-start-tag ( tag -- )
-    <form
-    "POST" =method
-    [ "action" required-attr resolve-base-path =action ]
-    [ tag-attrs [ drop name-tag "action" = not ] assoc-subset print-attrs ] bi
-    form>
-    hidden-form-field ;
+    [
+        <form
+        "POST" =method
+        {
+            [ flow-attr ]
+            [ session-attr ]
+            [ "action" required-attr resolve-base-path =action ]
+            [ tag-attrs filter-chloe-attrs print-attrs ]
+        } cleave
+        form>
+        hidden-form-field
+    ] with-scope ;
 
 : form-tag ( tag -- )
     [ form-start-tag ]
index d6ddeb32bbd68990c84213ea77c38d5cbc67ab22..0c7b95525e0dc59d5db575923499a22248895588 100644 (file)
@@ -47,7 +47,7 @@ IN: webapps.factor-website
     <boilerplate>
         "page" factor-template >>template
     <flows>
-    <url-sessions>
+    <session-manager>
         sessions-in-db >>sessions
     test-db <db-persistence> ;
 
index 2f67b5e8576bacd4de257cee49c2912490f81213..3e2f43845a1cdb0d1fc3f21d3d4d2e90cb2d8469 100644 (file)
@@ -10,7 +10,7 @@
                <head>
                        <t:write-title />
 
-                       <t:style include="resource:extra/xmode/code2html/stylesheet.css" />
+                       <t:style t:include="resource:extra/xmode/code2html/stylesheet.css" />
 
                        <t:style>
                                body, button {
index af6a835a64a2ad95f6988abf9b89b2db6b220cf6..e5a95d8908c4fbdebc7a993106f28abd79c7580b 100644 (file)
@@ -2,21 +2,21 @@
 
 <t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
 
-       <h2>Annotation: <t:view component="summary" /></h2>
+       <h2>Annotation: <t:view t:component="summary" /></h2>
 
        <table>
-               <tr><th class="field-label">Author:  </th><td><t:view component="author"  /></td></tr>
-               <tr><th class="field-label">Mode:    </th><td><t:view component="mode"    /></td></tr>
-               <tr><th class="field-label">Date:    </th><td><t:view component="date"    /></td></tr>
+               <tr><th class="field-label">Author:  </th><td><t:view t:component="author"  /></td></tr>
+               <tr><th class="field-label">Mode:    </th><td><t:view t:component="mode"    /></td></tr>
+               <tr><th class="field-label">Date:    </th><td><t:view t:component="date"    /></td></tr>
        </table>
 
        <div class="description">
-               <t:view component="contents" />
+               <t:view t:component="contents" />
        </div>
 
-       <t:form action="$pastebin/delete-annotation" class="inline">
-               <t:edit component="id" />
-               <t:edit component="aid" />
+       <t:form t:action="$pastebin/delete-annotation" class="inline">
+               <t:edit t:component="id" />
+               <t:edit t:component="aid" />
                <button class="link-button link">Delete Annotation</button>
        </t:form>
 
index 4afc5cfec5af60b490c3edb7454514e43cb81ee5..ad7152d20995736603151c0fe93b5f79b92cb87b 100644 (file)
@@ -4,15 +4,15 @@
 
        <t:title>New Annotation</t:title>
 
-       <t:form action="$pastebin/annotate">
-               <t:edit component="id" />
+       <t:form t:action="$pastebin/annotate">
+               <t:edit t:component="id" />
 
                <table>
-                       <tr><th class="field-label">Summary: </th><td><t:edit component="summary" /></td></tr>
-                       <tr><th class="field-label">Author: </th><td><t:edit component="author" /></td></tr>
-                       <tr><th class="field-label">Mode: </th><td><t:edit component="mode" /></td></tr>
-                       <tr><th class="field-label big-field-label">Description:</th><td><t:edit component="contents" /></td></tr>
-                       <tr><th class="field-label">Captcha: </th><td><t:edit component="captcha" /></td></tr>
+                       <tr><th class="field-label">Summary: </th><td><t:edit t:component="summary" /></td></tr>
+                       <tr><th class="field-label">Author: </th><td><t:edit t:component="author" /></td></tr>
+                       <tr><th class="field-label">Mode: </th><td><t:edit t:component="mode" /></td></tr>
+                       <tr><th class="field-label big-field-label">Description:</th><td><t:edit t:component="contents" /></td></tr>
+                       <tr><th class="field-label">Captcha: </th><td><t:edit t:component="captcha" /></td></tr>
                        <tr>
                        <td></td>
                        <td>Leave the captcha blank. Spam-bots will fill it indiscriminantly, so their attempts to register will be blocked.</td>
index 4b2b4a46ce5fb6fa79abbce32c43e0fc71ad29f2..86daf09aeb5560112c699250d5af158d1f30800a 100644 (file)
@@ -4,14 +4,14 @@
 
        <t:title>New Paste</t:title>
 
-       <t:form action="$pastebin/new-paste">
+       <t:form t:action="$pastebin/new-paste">
 
                <table>
-                       <tr><th class="field-label">Summary: </th><td><t:edit component="summary" /></td></tr>
-                       <tr><th class="field-label">Author: </th><td><t:edit component="author" /></td></tr>
-                       <tr><th class="field-label">Mode: </th><td><t:edit component="mode" /></td></tr>
-                       <tr><th class="field-label big-field-label">Description: </th><td><t:edit component="contents" /></td></tr>
-                       <tr><th class="field-label">Captcha: </th><td><t:edit component="captcha" /></td></tr>
+                       <tr><th class="field-label">Summary: </th><td><t:edit t:component="summary" /></td></tr>
+                       <tr><th class="field-label">Author: </th><td><t:edit t:component="author" /></td></tr>
+                       <tr><th class="field-label">Mode: </th><td><t:edit t:component="mode" /></td></tr>
+                       <tr><th class="field-label big-field-label">Description: </th><td><t:edit t:component="contents" /></td></tr>
+                       <tr><th class="field-label">Captcha: </th><td><t:edit t:component="captcha" /></td></tr>
                        <tr>
                        <td></td>
                        <td>Leave the captcha blank. Spam-bots will fill it indiscriminantly, so their attempts to register will be blocked.</td>
index 12b926c7d1bc79ac4e441360689ddb5e138d8b7a..c91aa6fc42a5b74616a498f91fecbf0998c988a8 100644 (file)
@@ -9,7 +9,7 @@
                <th align="left" width="100">Paste by:</th>
                <th align="left" width="200">Date:</th>
 
-               <t:summary component="pastes" />
+               <t:summary t:component="pastes" />
        </table>
 
 </t:chloe>
index 952d0de73d5f31354658a22142bc9f9a78d9df0f..eca46e254d714007eb64e26b28cab04398b05fcd 100644 (file)
@@ -3,9 +3,9 @@
 <t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
 
        <tr>
-               <td><t:a href="view-paste" query="id"><t:view component="summary" /></t:a></td>
-               <td><t:view component="author" /></td>
-               <td><t:view component="date" /></td>
+               <td><t:a t:href="view-paste" query="id"><t:view t:component="summary" /></t:a></td>
+               <td><t:view t:component="author" /></td>
+               <td><t:view t:component="date" /></td>
        </tr>
 
 </t:chloe>
index 89d18912211508325f5f7b7f5b78a4548ea9bbe8..9db60bfcc321f22e21f771651cf3f3acd632173e 100644 (file)
@@ -4,24 +4,22 @@
 
        <t:title>Pastebin</t:title>
 
-       <h2>Paste: <t:view component="summary" /></h2>
+       <h2>Paste: <t:view t:component="summary" /></h2>
 
        <table>
-               <tr><th class="field-label">Author:  </th><td><t:view component="author"  /></td></tr>
-               <tr><th class="field-label">Mode:    </th><td><t:view component="mode"    /></td></tr>
-               <tr><th class="field-label">Date:    </th><td><t:view component="date"    /></td></tr>
+               <tr><th class="field-label">Author:  </th><td><t:view t:component="author"  /></td></tr>
+               <tr><th class="field-label">Mode:    </th><td><t:view t:component="mode"    /></td></tr>
+               <tr><th class="field-label">Date:    </th><td><t:view t:component="date"    /></td></tr>
        </table>
 
-       <div class="description">
-               <t:view component="contents" />
-       </div>
+       <pre class="description"><t:view t:component="contents" /></pre>
 
-       <t:form action="$pastebin/delete-paste" class="inline">
-               <t:edit component="id" />
+       <t:form t:action="$pastebin/delete-paste" class="inline">
+               <t:edit t:component="id" />
                <button class="link-button link">Delete Paste</button>
        </t:form>
        |
-       <t:a href="$pastebin/annotate" query="id">Annotate</t:a>
+       <t:a t:href="$pastebin/annotate" t:query="id">Annotate</t:a>
 
-       <t:view component="annotations" />
+       <t:view t:component="annotations" />
 </t:chloe>
index 07b3e9c02d050d596bc8d66a3c6a504933d8b35f..9301b143536a287cebb9e6c0b1b4d0215b3757fb 100644 (file)
@@ -242,7 +242,7 @@ TUPLE: pastebin < dispatcher ;
         <feed-action> "feed.xml" add-responder
         <paste-form> [ <paste> ] <view-paste-action> "view-paste" add-responder
                    [ <paste> ] "$pastebin/list" <delete-paste-action> <protected> "delete-paste" add-responder
-                   [ <annotation> ] "$pastebin/view-paste" <protected> <delete-annotation-action> "delete-annotation" add-responder
+                   [ <annotation> ] "$pastebin/view-paste" <delete-annotation-action> <protected> "delete-annotation" add-responder
         <paste-form> [ <paste> ]    <view-paste-action>     "$pastebin/view-paste"   add-responder
         <new-paste-form> [ <paste> now >>date ] "$pastebin/view-paste" <new-paste-action>     "new-paste"    add-responder
         <new-annotation-form> [ <annotation> now >>date ] "$pastebin/view-paste" <annotate-action> "annotate" add-responder
index 6b491626372755ab5ae1bc187944a1e2e4fbf96d..99fede727ed1bafd2e1a6751c874d1855fc78f0d 100644 (file)
@@ -2,24 +2,27 @@
 
 <t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
 
-       <t:atom title="Pastebin - Atom" href="$pastebin/feed.xml" />
+       <t:atom t:title="Pastebin - Atom" t:href="$pastebin/feed.xml" />
 
-       <t:style include="resource:extra/webapps/pastebin/pastebin.css" />
+       <t:style t:include="resource:extra/webapps/pastebin/pastebin.css" />
 
        <div class="navbar">
-                 <t:a href="$pastebin/list">Pastes</t:a>
-               | <t:a href="$pastebin/new-paste">New Paste</t:a>
-               | <t:a href="$pastebin/feed.xml">Atom Feed</t:a>
+                 <t:a t:href="$pastebin/list">Pastes</t:a>
+               | <t:a t:href="$pastebin/new-paste">New Paste</t:a>
+               | <t:a t:href="$pastebin/feed.xml">Atom Feed</t:a>
+
+               <t:if t:svar="http.server.auth:logged-in-user">
+
+                       <t:if t:code="http.server.auth.login:allow-edit-profile?">
+                               | <t:a t:href="$login/edit-profile" t:flow="begin">Edit Profile</t:a>
+                       </t:if>
+
+                       <t:form t:action="$login/logout" t:flow="begin" class="inline">
+                               | <button type="submit" class="link-button link">Logout</button>
+                       </t:form>
 
-               <t:comment>
-               <t:if code="http.server.auth.login:allow-edit-profile?">
-                       | <t:a href="$login/edit-profile" flow="begin">Edit Profile</t:a>
                </t:if>
 
-               <t:form action="$login/logout" class="inline">
-                       | <button type="submit" class="link-button link">Logout</button>
-               </t:form>
-               </t:comment>
        </div>
 
        <h1><t:write-title /></h1>
index 3bd406ee3851e3cc3441f2ec214eaf057bede09f..c79fe2efd1db52702ad64df1fdf43555445303b5 100644 (file)
@@ -4,11 +4,11 @@
 
        <t:title>Planet Factor Administration</t:title>
 
-       <t:summary component="blogroll" />
+       <t:summary t:component="blogroll" />
 
        <p>
-               <t:a href="$planet-factor/admin/edit-blog">Add Blog</t:a>
-               | <t:a href="$planet-factor/admin/update">Update</t:a>
+               <t:a t:href="$planet-factor/admin/edit-blog">Add Blog</t:a>
+               | <t:a t:href="$planet-factor/admin/update">Update</t:a>
        </p>
 
 </t:chloe>
index a92af8dd1d6a440400ce87fdb16767cff6a15aaf..8d6c890643f46df00ae275e7221acb45800bfebb 100644 (file)
@@ -2,6 +2,6 @@
 
 <t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
 
-       <t:a href="$planet-factor/admin/edit-blog" query="id"><t:view component="name" /></t:a>
+       <t:a t:href="$planet-factor/admin/edit-blog" t:query="id"><t:view t:component="name" /></t:a>
 
 </t:chloe>
index 83273540a560474c7320725c65613a8c7b38e327..b2eab2b0b48d1565f3a6f01ba21395e712760252 100644 (file)
@@ -4,25 +4,25 @@
 
        <t:title>Edit Blog</t:title>
 
-       <t:form action="$planet-factor/admin/edit-blog">
+       <t:form t:action="$planet-factor/admin/edit-blog">
 
-               <t:edit component="id" />
+               <t:edit t:component="id" />
 
                <table>
 
                        <tr>
                                <th class="field-label">Blog name:</th>
-                               <td><t:edit component="name" /></td>
+                               <td><t:edit t:component="name" /></td>
                        </tr>
 
                        <tr>
                                <th class="field-label">Home page:</th>
-                               <td><t:edit component="www-url" /></td>
+                               <td><t:edit t:component="www-url" /></td>
                        </tr>
 
                        <tr>
                                <th class="field-label">Feed:</th>
-                               <td><t:edit component="feed-url" /></td>
+                               <td><t:edit t:component="feed-url" /></td>
                        </tr>
 
                </table>
@@ -31,8 +31,8 @@
 
        </t:form>
 
-       <t:form action="$planet-factor/admin/delete-blog" class="inline">
-               <t:edit component="id" />
+       <t:form t:action="$planet-factor/admin/delete-blog" class="inline">
+               <t:edit t:component="id" />
                <button type="submit" class="link-button link">Delete</button>
        </t:form>
 </t:chloe>
index 905795373b237e210deac21d58cb2abf67d5edd4..741b12345679e59bf8c8c9136be8c72201193f1c 100644 (file)
@@ -3,8 +3,8 @@
 <t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
 
        <p class="news">
-               <strong><t:view component="title" /></strong> <br/>
-               <t:a value="link" session="none" class="more">Read More...</t:a>
+               <strong><t:view t:component="title" /></strong> <br/>
+               <t:a value="link" t:session="none" class="more">Read More...</t:a>
        </p>
 
 </t:chloe>
index 0e52c191a561d90a8ae7205adb0db8d5653afb22..5e437173849549e961fcb3b3fbde05a385a7d61f 100644 (file)
@@ -3,15 +3,15 @@
 <t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
 
        <h2 class="posting-title">
-               <t:a value="link" session="none"><t:view component="title" /></t:a>
+               <t:a t:value="link" t:session="none"><t:view t:component="title" /></t:a>
        </h2>
 
        <p class="posting-body">
-               <t:view component="description" />
+               <t:view t:component="description" />
        </p>
 
        <p class="posting-date">
-               <t:a value="link" session="none"><t:view component="pub-date" /></t:a>
+               <t:a t:value="link" t:session="none"><t:view t:component="pub-date" /></t:a>
        </p>
 
 </t:chloe>
index 752db18ee7d30d838e073cd8fa77f436c9929228..2acff094c3619aed66d999d9caadc904abc9fbf8 100755 (executable)
@@ -169,5 +169,8 @@ blog "BLOGS"
 
 : start-update-task ( planet db seq -- )
     '[
-        , , , [ update-cached-postings ] with-db
+        , , , [
+            dup filter-responder? [ responder>> ] when
+            update-cached-postings
+        ] with-db
     ] 10 minutes every drop ;
index 328be845446c573b2271cc47af016ffa1f51a4f8..fdbfe6d841a69d8401f5430c55286cc6372ee654 100644 (file)
@@ -8,19 +8,19 @@
        <t:style include="resource:extra/webapps/planet/planet.css" />
 
        <div class="navbar">
-                 <t:a href="$planet-factor/list">Front Page</t:a>
-               | <t:a href="$planet-factor/feed.xml">Atom Feed</t:a>
-               | <t:a href="$planet-factor/admin">Admin</t:a>
-
-               <t:comment>
-               <t:if code="http.server.auth.login:allow-edit-profile?">
-                       | <t:a href="$login/edit-profile" flow="begin">Edit Profile</t:a>
+                 <t:a t:href="$planet-factor/list">Front Page</t:a>
+               | <t:a t:href="$planet-factor/feed.xml">Atom Feed</t:a>
+               | <t:a t:href="$planet-factor/admin">Admin</t:a>
+
+               <t:if t:svar="http.server.auth:logged-in-user">
+                       <t:if t:code="http.server.auth.login:allow-edit-profile?">
+                               | <t:a t:href="$login/edit-profile" t:flow="begin">Edit Profile</t:a>
+                       </t:if>
+       
+                       <t:form t:action="$login/logout" t:flow="begin" class="inline">
+                               | <button type="submit" class="link-button link">Logout</button>
+                       </t:form>
                </t:if>
-
-               <t:form action="$login/logout" class="inline">
-                       | <button type="submit" class="link-button link">Logout</button>
-               </t:form>
-               </t:comment>
        </div>
 
        <h1><t:write-title /></h1>
index 950191e4c3f1830ecbd9bd91616af894a16db3aa..765c3a80060caf6e25f8e910bf50f76327512a7c 100644 (file)
@@ -2,6 +2,6 @@
 
 <t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
 
-       <t:summary component="postings" />
+       <t:summary t:component="postings" />
 
 </t:chloe>
index f59a4f61b82b2e75a34f5df1d1d0b7a355995408..c2c73d7e894eff61ff12755891d1655a482cf632 100644 (file)
@@ -6,12 +6,12 @@
 
        <table width="100%" cellpadding="10">
                 <tr>
-                        <td> <t:view component="postings" /> </td>
+                        <td> <t:view t:component="postings" /> </td>
   
                         <td valign="top" width="25%" class="infobox">
                                 <h2>Blogroll</h2>
   
-                                <t:summary component="blogroll" />
+                                <t:summary t:component="blogroll" />
                         </td>
                 </tr>
         </table>
index 1887fccdc1f3cb7ddbc9f95f9b83d1b2ef7593ce..66abeafc868b7a6c5058ce633285b6dc042b7a6d 100644 (file)
@@ -6,7 +6,7 @@
 
        <table class="todo-list">
                <tr><th>Summary</th><th>Priority</th><th>View</th><th>Edit</th></tr>
-               <t:summary component="list" />
+               <t:summary t:component="list" />
        </table>
 
 </t:chloe>
index 008b0acaf5fd4eaa85ad77d7c5944e8d7fe7573e..056c9cab0aabc94302847fe99161f039fc87e390 100644 (file)
@@ -4,16 +4,16 @@
 
        <tr>
                <td>
-                       <t:view component="summary" />
+                       <t:view t:component="summary" />
                </td>
                <td>
-                       <t:view component="priority" />
+                       <t:view t:component="priority" />
                </td>
                <td>
-                       <t:a href="$todo-list/view" query="id">View</t:a>
+                       <t:a t:href="$todo-list/view" t:query="id">View</t:a>
                </td>
                <td>
-                       <t:a href="$todo-list/edit" query="id">Edit</t:a>
+                       <t:a t:href="$todo-list/edit" t:query="id">Edit</t:a>
                </td>
        </tr>
 
index 4e307b7caec6e727c4f27c5067bbd8585bc25d73..ff58b27df2df755309a4081ae99ac071ecd8d504 100644 (file)
@@ -5,14 +5,14 @@
        <t:style include="resource:extra/webapps/todo/todo.css" />
 
        <div class="navbar">
-                 <t:a href="$todo-list/list">List Items</t:a>
-               | <t:a href="$todo-list/edit">Add Item</t:a>
+                 <t:a t:href="$todo-list/list">List Items</t:a>
+               | <t:a t:href="$todo-list/edit">Add Item</t:a>
 
-               <t:if code="http.server.auth.login:allow-edit-profile?">
-                       | <t:a href="$login/edit-profile" flow="begin">Edit Profile</t:a>
+               <t:if t:code="http.server.auth.login:allow-edit-profile?">
+                       | <t:a t:href="$login/edit-profile" t:flow="begin">Edit Profile</t:a>
                </t:if>
 
-               <t:form action="$login/logout" class="inline">
+               <t:form t:action="$login/logout" t:flow="begin" class="inline">
                        | <button type="submit" class="link-button link">Logout</button>
                </t:form>
        </div>
index e8c2fd39834ab9e1afe1777857cc85175927fb0e..f77396c73c39dd834e34daa087b72cd4646e06e3 100644 (file)
        </table>
 
        <div class="description">
-               <t:view component="description" />
+               <t:view t:component="description" />
        </div>
 
-       <t:a href="$todo-list/edit" query="id">Edit</t:a>
+       <t:a t:href="$todo-list/edit" t:query="id">Edit</t:a>
        |
-       <t:form action="$todo-list/delete" class="inline">
-               <t:edit component="id" />
+       <t:form t:action="$todo-list/delete" class="inline">
+               <t:edit t:component="id" />
                <button class="link-button link">Delete</button>
        </t:form>