-
Notifications
You must be signed in to change notification settings - Fork 16
/
Router.elm
232 lines (198 loc) · 6.76 KB
/
Router.elm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
module Router (..) where
import Http.Response.Write exposing (writeHtml, writeJson, writeCss, writeElm, writeFile, writeNode, writeRedirect)
import Http.Request exposing (emptyReq, Request, Method(..), parseQuery, getQueryField, getFormField, getFormFiles, setForm)
import Http.Response exposing (Response)
import Model exposing (Connection, Model, Session)
import Client.App exposing (index, genericErrorView)
import Client.Signup.Views exposing (signUpForTakeHomeView)
import Generators exposing (generateSuccessPage, generateSignupPage,
generateWelcomePage, generateTestPage, generateAdminPage, generateSwimPage)
import Client.Admin.Views exposing (loginView, registerUserView)
import Shared.Routes exposing (routes, assets)
import Task exposing (..)
import Signal exposing (..)
import Json.Encode as Json
import Maybe
import Result exposing (Result)
import Effects exposing (Effects)
import Dict
import Regex
import String
import Env
import Converters
import Debug
type Action
= Incoming Connection
| Run ()
| AddSession Session
| Noop
type StartAppAction
= Init Model
| Update Action
{-| when we don't want to 500, write an error view
-}
handleError : Response -> Task a () -> Task b ()
handleError res errTask =
errTask
|> (flip Task.onError) (\err -> writeNode (genericErrorView err) res)
{-| Actually queue the response up
-}
runRoute task =
task
|> Task.map (\_ -> AddSession { token = "hello" } )
|> Effects.task
{-| Get any part of a string past `?`.
Useful for getting a query string out of a url
-}
queryPart : String -> String
queryPart url =
String.indexes "?" url
|> (\xs ->
case xs of
[] ->
""
x :: _ ->
String.dropLeft (x + 1) url
)
{-| Route any `POST` requests
-}
routePost : Connection -> Model -> ( Model, Effects Action )
routePost ( req, res ) model =
let
runRouteWithErrorHandler =
(handleError res) >> runRoute
url =
req.url
generate generator =
(setForm req
|> (flip andThen) (\req -> generator res req model)
|> runRouteWithErrorHandler
)
in
if url == routes.apply then
model
=> generate generateSuccessPage
else if url == routes.signup then
model
=> generate generateSignupPage
else if url == routes.startTest then
model
=> generate generateTestPage
else if url == routes.login then
model
=> generate generateAdminPage
else
model
=> (handleError res (Task.fail "Route not found")
|> runRouteWithErrorHandler
)
{-| Route any `GET` requests
-}
routeGet : Connection -> Model -> ( Model, Effects Action )
routeGet ( req, res ) model =
let
runRouteWithErrorHandler =
(handleError res) >> runRoute
url =
req.url
in
if url == routes.index then
model
=> (writeNode (signUpForTakeHomeView model.testConfig) res
|> runRouteWithErrorHandler
)
else if url == routes.login then
model
=> (writeNode loginView res
|> runRouteWithErrorHandler
)
else if url == routes.registerUser then
model
=> (writeNode registerUserView res
|> runRouteWithErrorHandler
)
else if url == assets.admin.route then
model
=> (writeCss assets.admin.css res
|> runRouteWithErrorHandler
)
else if url == assets.main.route then
model
=> (writeCss assets.main.css res
|> runRouteWithErrorHandler
)
else if url == routes.swimlanes then
model
=> (generateSwimPage res req model
|> runRouteWithErrorHandler
)
else if url == assets.signup.route then
model
=> (writeCss assets.signup.css res
|> runRouteWithErrorHandler
)
else if url == assets.start.route then
model
=> (writeCss assets.start.css res
|> runRouteWithErrorHandler
)
else if url == assets.noredinkLogo.route then
model
=> (writeFile assets.noredinkLogo.file res
|> runRouteWithErrorHandler
)
else
case queryPart url of
"" ->
model
=> (writeFile url res
|> runRouteWithErrorHandler
)
query ->
case parseQuery query of
Err _ ->
model
=> (Task.fail "failed to parse"
|> runRouteWithErrorHandler
)
Ok bag ->
case getQueryField "token" bag of
Nothing ->
model
=> (Task.fail ("Failed to find anything " ++ url)
|> runRouteWithErrorHandler
)
Just token ->
model
=> (generateWelcomePage token res model
|> runRouteWithErrorHandler
)
{-| route each request/response pair and write a response
-}
routeIncoming : Connection -> Model -> ( Model, Effects Action )
routeIncoming ( req, res ) model =
case req.method of
GET ->
routeGet ( req, res ) model
POST ->
routePost ( req, res ) model
NOOP ->
model => Effects.none
_ ->
model
=> (writeJson (Json.string "unknown method!") res
|> runRoute
)
update : Action -> Model -> ( Model, Effects Action )
update action model =
case action of
Incoming connection ->
routeIncoming connection model
Run _ ->
( model, Effects.none )
AddSession token ->
( model, Effects.none )
Noop ->
( model, Effects.none )
(=>) =
(,)