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