Note: You are currently viewing documentation for Moodle 2.2. Up-to-date documentation for the latest stable version is available here: Portfolio API.

Development:Portfolio API

From MoodleDocs
Revision as of 10:05, 17 June 2008 by Penny Leach (talk | contribs) (added comments after discussion with nigel mcnie (catalyst/mahara))

This page describes the specification for a future feature, currently being worked on for Moodle 2.0. This spec is STILL UNDER CONSTRUCTION.

Overview

The Portfolio API is a core set of interfaces that all Moodle code will/should use so that we can easily publish files to all kinds of external document repository systems.

It's important to remember that portfolios are generally treated as WRITE-ONLY. All we are doing in Moodle is grabbing stuff and pushing it out to somewhere. Management of the files and further combining/reflecting is done through the native interface provided by the portfolio system. Reading of files from a repository is handled by the Repository API.

A typical user story:

  1. When portfolios are enable, every page or major piece of content in Moodle has a little "Capture this" button beside it.
  2. User clicks one of these buttons
  3. User is able to choose from a list of configured portfolios (this step will be skipped if there's only one).
  4. User is asked to define some metadata to go with the captured content
  5. The content and metadata is COPIED to the external portfolio system
  6. User has an option to "Return to the course" or "Visit their portfolio".

Note this will be just as useful for teachers as for students.


Architecture

Here is how it will work:

Plugins

There will be three separate types plugins (note that *two* of these can be re-used across portfolio/repository):

  1. System (eg Mahara/Elgg/OSP) - this is really portfolio/type/xxx
  2. Transport (eg http/scp/cp/dav etc) - this could be re-used across both
  3. Contenttype/manifest (eg IMS/Mahara native/Moodle native (0) ) - this could be re-used across both

The reason for this is that I can see it's pretty likely that the same "system" might talk both portfolio and repository, so it makes sense to abstract transport layer and manifest into separate plugins.

0: We're in the process of defining the way data gets in and out of Mahara as well - obviously this is partially to do with the Moodle Portfolio api development, but also the ability to transfer content between Maharas - similar to Moodle backup and restore. If one of the content types is "Moodle native" this could possibly eventually be expanded to include the moodle backups.

Admin

It is important to be allowed to have multiple instances of (some) plugins. The workflow for adding a new one is:

  • Admin navigates to portfolio config
  • Selects from the list of available portfolio plugins, and clicks 'add a new external portfolio' (some may be unable if there are is an instance already and the plugin doesn't support multi instance)
  • Configure the plugin - select which transport and content types to use if there are multiple supported and installed, urls, authentication keys, etc.
  • Set permissions (maybe) - handled by roles.

Exporting

  • User is viewing a page that calls portfolio_add_button(). This checks to see if there are any configured portfolio plugin instances, and also (maybe) any permissions related to portfolios, and then displays either a single 'add to portfolio' button, or a (multiple select?) drop down menu of the available systems with the add button.
  • When this button is pressed, the user is redirected to portfolio/add.php, with some post data containing the responsible module's callback file and function.
  • On this page, the user is presented with a form to enter metadata about the item. In the background, the portfolio plugin(s) have been polled to see which content type they're using, and those content types have exported parts of moodle forms containing the fields that they want. If the user is exporting to more than one portfolio, there may have to be some cleverness around displaying shared components.
  • When the user has submitted the form, they are displayed a summary of what they're about to export, with 'confirm' and 'edit' buttons. Edit just relaunches the form, and confirm goes to the next step.
  • When the user has confirmed their summary, a 'portfolio_send' event will be triggered. At this point, one of two things happen.
  1. If the user has ajax enabled, an ajax request is made to a controller that fires an 'instant' event, displays a loading icon to the user until the event returns, and then tells the user the portfolio send was successful.
  2. If the user doesn't have ajax enabled, a delayed event is fired, and the user is notified that there will be a delay sending their data.
  3. The user is given the option to continue to their portfolio, or return to where they were.
  • When the event is handled (either through the cron or instant event), the following happens:
  • The event handler is invoked. This is almost certainly going to be a function in portfolio/lib.php rather than any handler in the portfolio *lugins. The event handler in turn calls the original callback that was passed to portfolio/add.php, which prepares either the file or composes some html, writes them to a temporary directory, and returns control.
  • At this point we have all the metadata we need, and we have the content to send, so it's time to start transport negotiation, which happens in stages. Note that some plugins might not implement all stages, and 3 and 4 might be interchangeable in order, depending on the external system.
  1. request
  2. authentication
  3. content
  4. metadata (some control is passed to the contenttype plugin - either to just write out an xml file and zip up the whole package, or send a series of requests) # TODO
  5. completion
  • When this is complete, we return control to the event handler (which hopefully, if it's an 'instant' one, will return true to the caller, which will be the ajax request)

Storage

Obviously during this process, state is going to be lost between webserver requests and also between user input and event handling. Some data will be stored in the user's session (the result of the metadata form, for example) and some in temporary files on the file system. these will be stored in dataroot/temp/portfolio/$userid-$timestamp/

Access/permissions

Do we want to somehow restrict particular users/courses/modules/groups (via roles) to particular instances of portfolios? (or none at all, even)

Event API

It is probably worth using the event api to handle the sending of data, mostly just because it provides a handy way of detached processing. However, any portfolio_send event will be 'owned' by particular "instances" of plugins - and each plugin that subscribes to portfolio_send event (all of them by definition) will have to check if the event data belongs to any of their instances, which is potentially quite messy.



Technical

abstract portfolio base class

  1. get_name
  2. supports_multiple (boolean)
  3. get_transport_types (returns ordered array of types to use as available)
  4. get_content_types (returns ordered array of content types to use)

(these last two will be configurable by administrators)

abstract transport base class

abstract contenttype base class

defines basic metadata, subclasses can override metadata or call parent:: and then append to it

database tables

we are just going to use the moodle event api for the queue so probably only need plugin instances and their config, as well as standard moodle 'what plugins are installed and what versions' tables for the three new plugin types.

transport types

(note that we don't necessarily want more than one of these for the initial implementation)

  1. http
  2. filesystem (could be local/nfs/samba whatever) (cp)
  3. ssh based (eg scp - should find and re-use the elgg block code as it deals with using ssh keys nicely)
  4. webdav
  5. open social? (http://code.google.com/apis/opensocial/)

content types

(note that we don't necessarily want more than one of these for the initial implementation)

  1. ims?
  2. leap/piop? (http://wiki.cetis.ac.uk/LEAP_2.0)
  3. moodle native?
  4. mahara native?

transport types and content types should be able to be found in a shared location for multiple plugins of both portfolio and repository type to use, but also might be specific to one type of plugin (maybe) which means that moodle should support looking in multiple locations for these plugins.

Duplication of data

What happens if a user tries to copy the same content twice? The system could keep track of what is sent where (by some unique id - perhaps url is best for this as it's not a clear case of course / course module) and then notify the user. This record could perhaps just be stored in the moodle log table (actually we should log portfolio transfers *anyway*). What we then do however, is more complicated. The options are:

  1. Just notify the user with a warning that they've already copied this content to that particular portfolio in the past
  2. Force all portfolios to be able to deal with add/replace and ask the user which option they want
  3. Support portfolios that do deal with add/replace and ask the user which option they want if available, else make a new copy (warning the user)


Assumptions

  • using the event api
  • we want multiple instances (both to configure and to send to at the same time)
  • manifest is always a file (as opposed to a series of xmlrpc instructions, say)

Outstanding questions

  • do instant events return?
  • which content-types will be implemented
  • which parts of moodle will have this button to start with (in order of necessity)
  • which plugin specifies the package (zip, a series of xmlrpc requests etc)? content or transport? or maybe it's actually core.
  • I'm still unsure about at which point the mainfest file should be written or handled.

Development Approach

  1. create three base classes
  2. create mahara portfolio plugin
  3. create mnet transport plugin
  4. create dummy content plugin (until we decided on a format)
  5. create portfolio/add.php and portfolio/lib.php
  6. start adding calls to the portfolio_add_button function to various places in moodle, with their callbacks.
  7. create a dummy listener in mahara until the mahara side is specified


See also