Developer notes for the A.nnotate Plugin
Connecting Moodle to the A.nnotate service poses a number of technical problems that could be resolved in a variety of ways. Here we explain the problems and why particular solutions were adopted for the plugin.
There are two main requirements: first the plugin should add link buttons next to resources in various pages; second, when the user presses the button, the file should be displayed by the remote server. In addition, plugin installation should be as simple as possible and robust against upgrades of Moodle.
The main issues are first, how to get the buttons in the right place, and second, how to get the file to the server.
Adding buttons to resources in Moodle
One natural choice would be to use a filter to process the html as it is generated, spot resource links, and add the extra button next to them.
Unfortunately, this is not a good solution in Moodle 1.9 because:
- The text for links in the places we want it is not processed by the filter mechanism. In some places, such as the main course listing page, it is written with "echo" rather than "format_string", and in others it is written in small chunks that do not contain enough information to spot the link (icon separate from resource name).
- Filtering imposes a cost on all text generation and slows down page loading in Moodle.
The first problem may be resolved in Moodle 2.0, but the performance costs will remain.
Although the filter mechanism can be made to work for the course summary page, it suffers a couple of major drawbacks:
- Some pages on which it would be useful to show the A.nnotate buttons are outside the filter system. For example the directory listing pages in mod/resource are not filtered.
- Moodle has a text caching option for filters which can generate a page purely from cached text, without loading the filter PHP. To have the filter route display annotate buttons reliably, text caching must be disabled, but this has implications for server performance and will also affect other filters that may be in use.
<?php global $CFG; require_once($CFG->dirroot.'/filter/annotate/filter.php'); ?>
In summary, the approach for adding buttons next to resources is to:
- Package the connector as a Moodle filter
- Load the connector via small PHP files in the custom scripts area.
- Call require_js for other scripts depending on the filter settings
Transferring files to the A.nnotate server
The first decision is whether to push or pull the file. A.nnotate can accept files via http POST, or can fetch files from a specified URL. The latter is generally more robust, since, for example, it can easily be repeated if the first transfer fails. Also, by initiating the transfer from the receiving server, it is clear the server wants the file, rather than making the server accept potentially large posts before knowing what they are. It is preferable therefore to have A.nnotate fetch the file from the Moodle server if possible. However, this raises a security problem: since the connection is coming from A.nnotate server, not from the session where the user is logged in, there will be no session cookies set for A.nnotate, and we won't know whether the request is trusted and Moodle should send a particular file. This means we can't use the normal Moodle file.php to send the file, since it requires an authenticated session. However we also cannot just send a file on request as that would open a security hole.
One option would be to transfer the PHP session id to the remote server so it can access the source server as the original user and get the file that way. Using this route, the plugin would send the Moodle session id to A.nnotate which would then call back to Moodle with the session variable in the GET fields of the request. However, by default Moodle strips session variables from GET part of a requests as a security measure and only accepts them as cookies.
Although this behavior can be changed in Moodle with the "useids" configuration setting, rather than complicating the installation process, the solution adopted for A.nnotate is based on that used by other cloud services such as Box.net which need to securely release documents to remote services. The providing service generates an obscure temporary URL for the resource and gives it to the receiving service. If it then receives a request for that URL within a specified time it ships out the file.
The A.nnotate plugin keeps track of such requests by setting up temporary files with randomly generated codes containing the paths to files to be served. It then uses its own file.php to check a request against the temporary file, and, if the request is valid, it sends the resource.