1 ! Copyright (C) 2008, 2009 Slava Pestov.
2 ! See https://factorcode.org/license.txt for BSD license.
3 USING: accessors assocs combinators furnace.conversations furnace.utilities
4 html.forms http http.server http.server.responses kernel namespaces sequences
5 splitting urls validators ;
6 FROM: html.templates.chloe => <chloe> ;
11 TUPLE: action rest init authorize display validate submit update replace delete ;
13 : new-action ( class -- action )
14 new [ ] >>init [ ] >>validate [ ] >>authorize ; inline
16 : <action> ( -- action )
19 : merge-forms ( form -- )
21 [ [ errors>> ] bi@ append! drop ]
22 [ [ values>> ] bi@ assoc-union! drop ]
23 [ validation-failed>> >>validation-failed drop ]
26 : set-nested-form ( form name -- )
30 unclip [ set-nested-form ] nest-form
33 : restore-validation-errors ( -- )
35 nested-forms cget set-nested-form
38 : handle-get ( action -- response )
43 [ authorize>> call( -- ) ]
44 [ drop restore-validation-errors ]
45 [ display>> call( -- response ) ]
48 ] with-exit-continuation ;
50 CONSTANT: revalidate-url-key "__u"
52 : revalidate-url ( -- url/f )
53 revalidate-url-key param
54 dup [ >url ensure-port [ same-host? ] keep and ] when ;
56 : validation-failed ( -- * )
57 post-request? "DELETE" method= or
60 nested-forms-key param split-words harvest nested-forms cset
62 <continue-conversation>
66 : handle-post ( action -- response )
69 [ validate>> call( -- ) ]
70 [ authorize>> call( -- ) ]
71 [ submit>> call( -- response ) ]
74 ] with-exit-continuation ;
76 : handle-put ( action -- response )
79 [ validate>> call( -- ) ]
80 [ authorize>> call( -- ) ]
81 [ replace>> call( -- response ) ]
84 ] with-exit-continuation ;
86 : handle-patch ( action -- response )
89 [ validate>> call( -- ) ]
90 [ authorize>> call( -- ) ]
91 [ update>> call( -- response ) ]
94 ] with-exit-continuation ;
96 : handle-delete ( action -- response )
100 [ authorize>> call( -- ) ]
101 [ delete>> call( -- response ) ]
104 ] with-exit-continuation ;
106 : handle-rest ( path action -- )
107 rest>> [ [ "/" join ] dip set-param ] [ drop ] if* ;
109 : init-action ( path action -- )
113 M: action call-responder*
115 request get method>> {
116 { "GET" [ handle-get ] }
117 { "HEAD" [ handle-get ] }
118 { "POST" [ handle-post ] }
119 { "PUT" [ handle-put ] }
120 { "PATCH" [ handle-patch ] }
121 { "DELETE" [ handle-delete ] }
125 M: action modify-form
126 drop url get revalidate-url-key hidden-form-field ;
128 : check-validation ( -- )
129 validation-failed? [ validation-failed ] when ;
131 : validate-params ( validators -- )
132 params get swap validate-values check-validation ;
134 : validate-integer-id ( -- )
135 { { "id" [ v-number ] } } validate-params ;
137 TUPLE: page-action < action template ;
139 : <chloe-content> ( path -- response )
140 resolve-template-path <chloe> <html-content> ;
142 : <page-action> ( -- page )
143 page-action new-action
144 dup '[ _ template>> <chloe-content> ] >>display ;