-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathapp0.html
91 lines (86 loc) · 7.48 KB
/
app0.html
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
The Arc distribution includes a simple application server in <code>app.arc</code>. The two main features of the app server are account management and improved forms handling.
<h2>Running the server</h2>
The server can be started simply with
<pre class="repl">
arc>(asv 8080)
</pre>
<p>
However, it is generally better to start the server in a separate thread, so the Arc REPL can be used. This allows the web server to be modified while it is running.
<pre class="repl">
arc> (thread (asv 8080))
</pre>
<h2>Account management</h2>
The app server implements user accounts, so a web user can log into a particular account. Optionally, an account can be an "admin" account with access to the administrative features. A user logs into an account with a login form.
The user can then log out of the account. The app server also provides web-based account creation and password modification.
<p>
The user login uses a simple browser cookie to keep track of the login. Note that the user account management is entirely orthogonal to the fnid-based continuations of the Arc web server. Logins are maintained through a cookie; fnids are passed in the URL or a form field. The app server includes several mechanisms to ensure that a fnid callback is executed by the expected user.
<p>
The app server defines the following pages:
<br><code>/whoami</code>: displays the logged-in userid and IP address, or redirects to login.
<br><code>/login</code>: logs user in or creates new account.
<br><code>/logout</code>: logs the current user out.
<br><code>/admin</code>: displays the administrative page, if the user is logged into an admin account.
<br><code>/mismatch</code>: displays an error "Dead link: users don't match." This page is used when a fnid is accessed by the wrong (or logged-out) user.
<p>
The following is an example page with user authentication; it will run at <a href="http://localhost:8080/example">http://localhost:8080/example</a>. First, the handler ensures the user is logged in, and displays the login page otherwise. The page displays a form saying "This is the example page". When submitted, the page will say, "Hello <i>user</i>". The <code>uform</code> form ensures that the user is still logged in when the form is submitted; otherwise, the page will display the dead link error.
<pre class="code">
(defopl example req
(let user (get-user req)
(uform user req (prn "Hello " user)
(prn "This is the example page.") (submit))))
</pre>
The following example illustrates <code>urform</code>. The page <a href="http://localhost:8080/urexample">http://localhost:8080/urexample</a> will accept a value in a form. When submitted, the continuation function will output a cookie header and redirect to the page "uexample", which will display the cookies.
<pre class="code">
(defopl urexample req
(let user (get-user req)
(urform user req
(do (prn "Set-cookie: mycook=" (alref (req 'args) "foo")) "uexample")
(prn "Enter value:") (input 'foo) (submit))))
(defopl uexample req (prn "User " (get-user req)) (br) (prn "Cookies " (req 'cooks)))
</pre>
<h2>Improved forms</h2>
The second feature provided by the app server is improved form functionality: markdown and typed forms.
<p>
Markdown is a simple mechanism for adding some formatting to plain text. Text surrounded by asterisks is converted to italics. URLs are converted to links. Blank lines indicate paragraph breaks. Lines that are indented and separated from previous lines by a blank line are displayed as preformatted code.
The Arc app server provides mechanisms to convert markdown text to HTML, and supports markdown input in forms.
<p>
The app server also provides a mechanism to create forms consisting of multiple typed fields in a table. For example, a form can have one string input and one integer input. The types are entirely separate from Arc's datatypes. The following table outlines the supported types:
<table class="info"><tr><th>Type</th><th>Form field</th><th>Result</th></tr>
<tr><td><code>string</code></td><td>text input of width <code>formwid*</code></td><td>String</td></tr>
<tr><td><code>string1</code></td><td>text input of width <code>formwid*</code></td><td>String, empty not allowed</td></tr>
<tr><td><code>int</code></td><td>text input of width <code>numwid*</code></td><td>Integer (rounded)</td></tr>
<tr><td><code>num</code></td><td>text input of width <code>numwid*</code></td><td>Number</td></tr>
<tr><td><code>posint</code></td><td>text input of width <code>numwid*</code></td><td>Integer > 0 (rounded)</td></tr>
<tr><td><code>doc</code></td><td>textarea input of width big<code>formwid*</code></td><td>String</td></tr>
<tr><td><code>text</code></td><td>textarea input of width <code>formwid*</code></td><td>String</td></tr>
<tr><td><code>mdtext</code></td><td>textarea input of width <code>formwid*</code></td><td>Markdown text</td></tr>
<tr><td><code>mdtext2</code></td><td>textarea input of width <code>formwid*</code></td><td>Markdown text, no links</td></tr>
<tr><td><code>toks</code></td><td>text input of width <code>formwid*</code></td><td>List of string tokens</td></tr>
<tr><td><code>bigtoks</code></td><td>textarea input of width <code>formwid*</code></td><td>List of tokens</td></tr>
<tr><td><code>sexpr</code></td><td>text input of width <code>formwid*</code></td><td>List of S-expressions.</td></tr>
<tr><td><code>hexcol</code></td><td>text input</td><td>String if the string defines a valid hex color</td></tr>
<tr><td><code>url</code></td><td>text input of width <code>formwid*</code></td><td>URL (empty string allowed).</td></tr>
<tr><td><code>users</code></td><td>text input of width <code>formwid*</code></td><td>List of usernames with bad names filtered out</td></tr>
<tr><td><code>choice</code></td><td>select dropdown menu.</td><td>Type from the choice list</td></tr>
<tr><td><code>yesno</code></td><td>select dropdown with "yes" and "no" choices.</td><td>Boolean, true for input "yes"</td></tr>
</table>
The <code>choice</code> type is specified as a list: <code>choice</code>, the type of the choices, and the choices themselves, for instance <code>'(choice int 1 2 3)</code>. The <code>mdtext</code> and <code>mdtext2</code> inputs include a help link to <code>formatdoc-url*</code>.
<p>
A typed form is generated by <code>vars-form</code>, which is a fairly complex procedure. It takes a list of field specifications, where each field specification is a list
of <code>(type label value view modify question)</code>. The <code>type</code> specifier is from the above table. The <code>label</code> is the name assigned to the input field. The initial value of the field is <code>value</code>. If <code>view</code> is <code>nil</code>, the field is skipped. If <code>modify</code> is nil, the field is not modifiable; it is displayed as text rather than an input field. If <code>question</code> is defined, it appears as a caption above the field; otherwise, the label is displayed before the field.
<p>
The following example shows a form created by <code>vars-form</code>. When the form is submitted, each name and value is printed, followed by "Done!". The user must log in, if not already logged in.
The example runs at the URL <a href="http://localhost:8080/vars-form">http://localhost:8080/vars-form</a>.
<pre class="code">
(defopl vars-form req
(vars-form (get-user req)
'((int field1 42 t t "Enter int:")
(toks field2 (a b c) t t)
(string nil "bar" t nil "Can't touch this."))
(fn (name val) (prn name " " val) (br))
(fn () (prn "Done!"))
"Doit"))
</pre>
The generated form is:
<br>
<img style="border: 1px;" src="vars-form.gif">