Saturday, January 15, 2011

Nitrogen, an Erlang web application library/framework Part 5

Slide 48: Session State


I"m going to do minor variant on the exercise: the incrementing counter will belong to the session, the doubling counter will belong to the page. That way we're a few clicks further away from overflow.... Here's my result:

body() ->
#panel { style="margin: 50px", body=[
#button { id=mybutton, text="Submit", postback=click },
#panel { id=placeholder1, body=wf:f("~B", [wf:session_default(click_counter, 0)]) },
#panel { id=placeholder2, body="1" }
]}.

event(click) ->
Counter = wf:session_default(click_counter, 0) + 1,
wf:update(placeholder1, wf:f("~B", [Counter])),
wf:session(click_counter, Counter),
Doubler = wf:state_default(click_doubler, 1) * 2,
wf:update(placeholder2, wf:f("~B", [Doubler])),
wf:state(click_doubler, Doubler).

Slide 49: Their answer


Note: second argument to wf:update/2 is a string; I originally surrounded it with a #panel (i.e., div element) so I could say body=, but that was unnecessary, so the result above incorporates Slide 49's simplified answer (although I'm using the helper function wf:f because it's less to type than io_lib:format).

Slide 50: Security


Slide 51: Limiting Access to a Page (roles)


Slide 52: Authentication and Authorization Functions


wf:user/0 and wf:user/1 seem straightforward. wf:role/1 and wf:role/2 are opaque to me. Hypothesis: wf:role(Role) returns true/false whether the session has that role; wf:role(Role, IsInRole) uses IsInRole false to revoke that role from the session or IsInRole true to add that role to the session. It looks liek they're going to make me read the manual.

Slide 53: Page Redirection functions


wf:redirect/1

wf:redirect_to_login/1

wf:redirect_from_login/1

There is apparently something special about the LoginUrl.

Slde 54: Creating a Secure Page - Step 1


They don't give the name of this page. I'm going to name it managers.erl.

Note! The main/0 function has to this point done nothing but specify the html template. This code is orthogonal to that for title, body, and events.


bash-4.1$ ./dev page managers
Created page: ./site/src/managers.erl
Remember to recompile!

Slide 55: Creating a Secure Page - Step 2



bash-4.1$ ./dev page login
Created page: ./site/src/login.erl
Remember to recompile!

First - hey, I guessed correctly as to how wf:role works! Second, since the example redirects a successful login to /, I infer that the main/0 function that was supposed to have the authorization guard was index.erl. I'll go fix that page.

I'm getting an error on the login page, somewhere in the click event handler. My broken code:

body() ->
#button { text="Login", postback=login }.

event(click) ->
wf:role(managers, true),
wf:redirect_from_login("/").

Let's review: Events have types. Types have triggers. Triggers are associated with elements. The element in this case is a button which has an implicit type of "click". The associated trigger is named "login". In the event/1 definition, I need to specify the trigger, not the type. So replace event(click) with event(login). That worked.

Slide 56: Creating a Secure Page - Step 3


When I first tried the example, it let me right in. Roles are associated with sessions, and I'd already acquired the "managers" role with the previous example. Let's kill off the Nitrogen server and start it back up. Yup, that was it. "flash{}" wasn't the obnoxious tag I was afraid of :-).

Slide 57: Creating a Secure Page - Step 4


Ok. Where to put a "logout" button? index.erl and my_page; not login since you don't get there unless you're not logged in. index.erl looks like this:

body() ->
#container_12 { body=[
#grid_8 { alpha=true, prefix=2, suffix=2, omega=true, body=inner_body() }
]}.

inner_body() ->
[
#h1 { text="Welcome to My Nitrogen Tutorial" },
#p{},
"
If you can see this page, then your Nitrogen server is up and
running. Click the button below to test postbacks.
",
#p{},
#button { id=button, text="Click me!", postback=click },
#p{},
"
Run ./bin/dev help to see some useful developer commands.
",
#p{},
#button { text="Logout", postback=logout }
].

event(logout) ->
wf:logout(),
wf:redirect("/");
event(click) ->
wf:replace(button, #panel {
body="You clicked the button!",
actions=#effect { effect=highlight }
}).

HOWEVER, a logout button is something you'd want on every page. Is there a way to do that with the template "bare.html"?

The page template might interpolate [[[logout:logout_body]]] to put the logout button on the page, but how do we augment every event/1 function with the event(logout) action?

No comments:

Post a Comment