67
by mattgiuca
doc: Added app_howto doc, a guide on IVLE apps interface. |
1 |
IVLE - App Authoring Guide |
2 |
========================== |
|
3 |
||
4 |
Author: Matt Giuca |
|
5 |
Date: 17/12/2007 |
|
6 |
||
7 |
Intended audience: IVLE developers who wish to write a new application for |
|
8 |
IVLE's plugin interface. |
|
9 |
||
10 |
IVLE's modular architecture allows new applications ("apps") to be easily |
|
11 |
written and added to the site. An app is just a Python program which conforms |
|
12 |
to a small API, plus a few additional configurations. |
|
13 |
||
14 |
Application Specification |
|
15 |
------------------------- |
|
16 |
||
17 |
An application consists of two parts: |
|
18 |
||
19 |
* A Python package in the `apps` directory of IVLE. (That is, a directory with |
|
20 |
the name of the application containing a file `__init__.py`). |
|
21 |
* An entry in the applications database, stored in the file `conf/apps.py`. |
|
22 |
||
23 |
The entry in the apps database allows IVLE to locate and run the application. |
|
24 |
The package contains the application's code. |
|
25 |
||
26 |
### App name ### |
|
27 |
||
28 |
Applications may be known by three distinct names: |
|
29 |
||
30 |
* The "directory name" ("`dir`") is the most common identifier used for an |
|
31 |
app. This is the name of the app's package directory. |
|
32 |
* The "URL name" is the URL path segment used to publically identify the |
|
33 |
application. Is is usually the same as the dir name but may be distinct. |
|
34 |
* The "friendly name" ("`name`") is the name shown to users, eg, in the title |
|
35 |
bar and in the tabs. |
|
36 |
||
37 |
Applications Database Entry |
|
38 |
--------------------------- |
|
39 |
||
40 |
The file `conf/apps.py` is the applications database. (No, it isn't a real |
|
41 |
database, just a Python file with a dictionary in it). Each application is |
|
42 |
defined in a variable. This is merely a convenience so they don't all have |
|
43 |
to be defined inside the dictionary. |
|
44 |
||
45 |
Each application should be created by calling the App constructor, with the |
|
46 |
following fields: |
|
47 |
||
48 |
* `dir` : string - The "directory name" of the app. |
|
49 |
* `name` : string - The "friendly name" of the app. |
|
50 |
* `requireauth` : bool - If True, will automatically require authentication |
|
51 |
(but not authorization). |
|
52 |
* `hashelp` : bool - If True, this app will be given a help entry. |
|
53 |
||
54 |
Each application should be given an entry in the `app_url` dict, mapping its |
|
55 |
"url name" to the App variable. |
|
56 |
||
57 |
Applications which require a tab in the IVLE interface should have their "url |
|
58 |
names" added to the `apps_in_tabs` list as well. |
|
59 |
||
60 |
Application Interface |
|
61 |
--------------------- |
|
62 |
||
63 |
Example Application |
|
64 |
------------------- |
|
65 |
||
66 |
This section shows the creation of a "Hello World" application which simply |
|
67 |
prints some text, inside the IVLE interface. The app's name will be "hello", |
|
68 |
"hello" and "Hello World" respectively. |
|
69 |
||
70 |
Firstly, create a directory, `apps/hello`. Create a file |
|
71 |
`apps/hello/__init__.py` with the following contents: |
|
72 |
||
73 |
def handle(req): |
|
74 |
req.content_type = "text/html" |
|
75 |
req.write_html_head_foot = True |
|
76 |
req.write("<p>Hello, IVLE!</p>\n") |
|
77 |
||
78 |
Now, edit the file `conf/apps.py`, and add the following lines: |
|
79 |
||
80 |
app_hello = App() |
|
81 |
app_hello.dir = "hello" |
|
82 |
app_hello.name = "Hello World" |
|
83 |
app_hello.requireauth = False |
|
84 |
app_hello.hashelp = False |
|
85 |
||
86 |
Add `"hello" : app_hello,` to the app_url dictionary. Add `"hello"` to the |
|
87 |
apps_in_tabs list. |
|
88 |
||
89 |
Now restart the web server, and the "Hello World" tab should appear. Click |
|
90 |
the tab to call your new app. |
|
91 |
||
92 |
Note that the page output includes the standard IVLE interface and style |
|
93 |
theme (by virtue of setting `req.write_html_head_foot` to True). The data that |
|
94 |
the Hello World app itself outputs should be written assuming it is inside an |
|
95 |
XHTML body element. The final output will be valid XHTML 1.0 Strict if the |
|
96 |
application's output is. |
|
97 |
||
98 |
### Making a file dump ### |
|
99 |
||
100 |
You can modify the application to dump files from the students directories |
|
101 |
easily. You may wish to set `requireauth` to True, which will require that a |
|
102 |
user is logged in. (Note that it doesn't say anything about which user must be |
|
103 |
logged in - any student will still be able to read any other student's files). |
|
104 |
||
105 |
You will need to import the `studpath` module from `common` - this provides |
|
106 |
utilities for accessing student files. |
|
107 |
||
108 |
from common import studpath |
|
109 |
||
110 |
def handle(req): |
|
111 |
req.content_type = "text/html" |
|
112 |
req.write_html_head_foot = True |
|
113 |
||
114 |
(user, path) = studpath.url_to_local(req.path) |
|
115 |
req.write("<p>") |
|
116 |
try: |
|
117 |
req.sendfile(path) |
|
118 |
except IOError, msg: |
|
119 |
req.write("Error: %s" % msg) |
|
120 |
req.write("</p>") |
|
121 |
||
122 |
`studpath.url_to_local` gives you a path on the local file system which the |
|
123 |
file corresponds to. (It also gives you the name of the user or group who owns |
|
124 |
the file, though we don't use that here). |
|
125 |
||
126 |
**Important**: This simple example does not escape characters for HTML, so it |
|
127 |
will not display some files correctly, and could be vulnerable to JavaScript |
|
128 |
injections. In a real app, characters (at the very least, '<', '>' and '&') |
|
129 |
should be escaped correctly. |