]> gitweb.factorcode.org Git - factor.git/blob - basis/furnace/actions/actions.factor
1370ae95b2f02653e6d201e0ce138f328bbca688
[factor.git] / basis / furnace / actions / actions.factor
1 ! Copyright (C) 2008 Slava Pestov.\r
2 ! See http://factorcode.org/license.txt for BSD license.\r
3 USING: accessors sequences kernel assocs combinators\r
4 validators http hashtables namespaces fry continuations locals\r
5 io arrays math boxes splitting urls\r
6 xml.entities\r
7 http.server\r
8 http.server.responses\r
9 furnace\r
10 furnace.redirection\r
11 furnace.conversations\r
12 html.forms\r
13 html.elements\r
14 html.components\r
15 html.components\r
16 html.templates.chloe\r
17 html.templates.chloe.syntax ;\r
18 IN: furnace.actions\r
19 \r
20 SYMBOL: params\r
21 \r
22 SYMBOL: rest\r
23 \r
24 : render-validation-messages ( -- )\r
25     form get errors>>\r
26     [\r
27         <ul "errors" =class ul>\r
28             [ <li> escape-string write </li> ] each\r
29         </ul>\r
30     ] unless-empty ;\r
31 \r
32 CHLOE: validation-messages drop render-validation-messages ;\r
33 \r
34 TUPLE: action rest authorize init display validate submit ;\r
35 \r
36 : new-action ( class -- action )\r
37     new [ ] >>init [ ] >>validate [ ] >>authorize ; inline\r
38 \r
39 : <action> ( -- action )\r
40     action new-action ;\r
41 \r
42 : merge-forms ( form -- )\r
43     form get\r
44     [ [ errors>> ] bi@ push-all ]\r
45     [ [ values>> ] bi@ swap update ]\r
46     [ swap validation-failed>> >>validation-failed drop ]\r
47     2tri ;\r
48 \r
49 : set-nested-form ( form name -- )\r
50     [\r
51         merge-forms\r
52     ] [\r
53         unclip [ set-nested-form ] nest-form\r
54     ] if-empty ;\r
55 \r
56 : restore-validation-errors ( -- )\r
57     form cget [\r
58         nested-forms cget set-nested-form\r
59     ] when* ;\r
60 \r
61 : handle-get ( action -- response )\r
62     '[\r
63         , dup display>> [\r
64             {\r
65                 [ init>> call ]\r
66                 [ authorize>> call ]\r
67                 [ drop restore-validation-errors ]\r
68                 [ display>> call ]\r
69             } cleave\r
70         ] [ drop <400> ] if\r
71     ] with-exit-continuation ;\r
72 \r
73 : param ( name -- value )\r
74     params get at ;\r
75 \r
76 : revalidate-url-key "__u" ;\r
77 \r
78 : revalidate-url ( -- url/f )\r
79     revalidate-url-key param\r
80     dup [ >url [ same-host? ] keep and ] when ;\r
81 \r
82 : validation-failed ( -- * )\r
83     post-request? revalidate-url and [\r
84         begin-conversation\r
85         nested-forms-key param " " split harvest nested-forms cset\r
86         form get form cset\r
87         <redirect>\r
88     ] [ <400> ] if*\r
89     exit-with ;\r
90 \r
91 : handle-post ( action -- response )\r
92     '[\r
93         , dup submit>> [\r
94             [ validate>> call ]\r
95             [ authorize>> call ]\r
96             [ submit>> call ]\r
97             tri\r
98         ] [ drop <400> ] if\r
99     ] with-exit-continuation ;\r
100 \r
101 : handle-rest ( path action -- assoc )\r
102     rest>> dup [ [ "/" join ] dip associate ] [ 2drop f ] if ;\r
103 \r
104 : init-action ( path action -- )\r
105     begin-form\r
106     handle-rest\r
107     request get request-params assoc-union params set ;\r
108 \r
109 M: action call-responder* ( path action -- response )\r
110     [ init-action ] keep\r
111     request get method>> {\r
112         { "GET" [ handle-get ] }\r
113         { "HEAD" [ handle-get ] }\r
114         { "POST" [ handle-post ] }\r
115     } case ;\r
116 \r
117 M: action modify-form\r
118     drop url get revalidate-url-key hidden-form-field ;\r
119 \r
120 : check-validation ( -- )\r
121     validation-failed? [ validation-failed ] when ;\r
122 \r
123 : validate-params ( validators -- )\r
124     params get swap validate-values check-validation ;\r
125 \r
126 : validate-integer-id ( -- )\r
127     { { "id" [ v-number ] } } validate-params ;\r
128 \r
129 TUPLE: page-action < action template ;\r
130 \r
131 : <chloe-content> ( path -- response )\r
132     resolve-template-path <chloe> "text/html" <content> ;\r
133 \r
134 : <page-action> ( -- page )\r
135     page-action new-action\r
136         dup '[ , template>> <chloe-content> ] >>display ;\r