Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Portfolio API: Difference between revisions

From MoodleDocs
(Mentioned auto-metadata)
Line 13: Line 13:
# User is able to choose from a list of configured portfolios (this step will be skipped if there's only one).
# User is able to choose from a list of configured portfolios (this step will be skipped if there's only one).
# User may be asked to define the format of the captured content (eg pdf, IMS LD, HTML, XML ...)
# User may be asked to define the format of the captured content (eg pdf, IMS LD, HTML, XML ...)
# User is asked to define some metadata to go with the captured content
# User may be asked to define some metadata to go with the captured content (some will be generated automatically).
# The content and metadata is COPIED to the external portfolio system
# The content and metadata is COPIED to the external portfolio system
# User has an option to "Return to the page you left" or "Visit their portfolio".
# User has an option to "Return to the page you left" or "Visit their portfolio".

Revision as of 14:52, 27 June 2008

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 enabled, every page or major piece of content in Moodle has a little "Save" 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 may be asked to define the format of the captured content (eg pdf, IMS LD, HTML, XML ...)
  5. User may be asked to define some metadata to go with the captured content (some will be generated automatically).
  6. The content and metadata is COPIED to the external portfolio system
  7. User has an option to "Return to the page you left" or "Visit their portfolio".

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

The formatting possibilities will vary depending on the context of the button and the type of external portfolios. So for example, the "Save" button on the course page would allow the user to capture the whole course in IMS LD or Moodle backup format, which you would not have on a forum page.

Architecture

Here is how it will work:

Plugins and libraries

There will be two separate types of plugins

  1. Portfolio (eg Mahara/Elgg/OSP/Facebook/Download) - this will be portfolio/type/xxx
  2. Transport (eg mnet/http/scp/cp/dav etc) - these will be reused across different portfolio plugins

Then there will be different formats that plugins will support (and the part of moodle exporting content must support as well), eg IMS, moodle native, mahara native, pdf, enrypted pdf. These will have good libraries supporting them.

The reason for this is that I can see for abstracting the transport layer to its own plugin type is that it's pretty likely that the same external system might talk both portfolio and repository.

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 disabled if there is an instance already and the plugin doesn't support multiple instances)
  • 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 what the user's portfolio settings are, and then displays either a single 'add to portfolio' button, or a 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 area (activity module or something like course or blog) callback file and function.
  • On this page, the user is presented with a form to enter metadata about the item, and configure any options. At this point if there are multiple formats available for export (based on the intersection of what the plugin and module support), the user can select which format they want. The plugin and module can both export mform elements for this page. The user can at this point also select to send the data and wait (with a warning it might take awhile), or queue it for processing if it's larger.
  • 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.
  • At this point, the portfolio plugin (or transport plugin) might need to take control for a step. For example, facebook or flickr might require the user to log in for the first time and confirm moodle is allowed to access their API
  • 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 elected to wait, the 'instant' event is fired, and when the caller gets control again, it displays the status to the user.
  2. If the user has elected to queue, the delayed event is fired and the user is notified.
  • 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 lib/portfoliolib.php rather than any handler in the portfolio plugins. The event handler in turn calls the original callback that was passed to portfolio/add.php (module//lib.php or course/lib.php or something), which prepares the data in the format the user selected and returns control to the event handler.
  • 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 portfolio plugin for packaging - either to just write out an xml file and zip up the whole package, or send a series of requests)
  5. completion
  • When this is complete, we return control to the event handler (which, 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

  • Portfolio plugin must be allocatable per context (site/course/group etc)
  • How can we assume all users will have an account on the remote system? We could try and silently authenticate them (or at least see if it's possible to) in the background at the first call to portfolio_add_button (and then cache the result in the session)
  • Check MNet policy - it assumes everyone with the role can have an account (assuming they_sso_in or whatever it's called is on) - this doesn't scale though, other transport mechanisms and or plugin types might not follow this assumption. I think this really must be defined by the portfolio plugin only, not the transport plugin.

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)

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

abstract transport base class

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.

portfolio plugins

  1. mahara (will be done for the initial implementation)
  2. download (should be done for the initial implementation)

transport types and formats 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 which means that moodle should support looking in multiple locations for these plugins. (eg mahara native format will be in the mahara portfolio plugin, but pdf format will be in a shared library)

transport types

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

formats

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

  1. pdf
  2. encrypted pdf
  3. ims?
  4. leap/piop? (http://wiki.cetis.ac.uk/LEAP_2.0)
  5. moodle native?
  6. mahara native?
  7. Dublin Core (Enovation implemented this)

Testing

Nico to help (see Development Approach for TDD-related approach)

Interaction between parts of the system

There needs to be a nice way for the different parts (portfolio libraries and scripts, portfolio plugins, and calling modules) to interact.

As I start writing code, I'm starting to think that modules (or indeeed any place in moodle) that wants to implement the ability to export its data to a portfolio should implement a class to handle it. I originally just started thinking that a callback function was enough, but now it has turned into possible multiple callback functions, and imo, the best way to manage this is that rather than just document the list of available callback functions, we should actually enforce this at the *code* level, by the use of abstract functions in a parent class (or even an interface actually) for the module authors to implement. This may seem heavyweight, but really it would only be a small class with one or two functions in it. Additionally it allows for namespacing of portfolio related functions in the module.

Also it makes a nice way to store state between requests - I can just store objects in the session.

Duplication of data

Moodle will keep track of what content it transfers and when. It'll remember the url of the original export location (alphabetisising the url parameters and removing the sessionkey) and a sha1 hash of the data, so that if the user tries to export the same content, Moodle can warn the user (along with a notification of whether it has changed or not).

At this point we can build support into the API for plugins to offer to differentiate between 'replace' and 'add', but won't implement it for any we write for the initial implementation.

Assumptions

  • using the event api
  • we want multiple instances (both to configure and to send to at the same time)

Outstanding questions

  • which parts of moodle will have this button to start with (in order of necessity)
  • Dependance of transport plugins - eg filesystem might depend on http for sending request/finished pings

Development Approach

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

After a conversation with Nico about testing, we decided the most sensible ordering to start with would be:

  1. Write portfolio/add.php
  2. Write *skeleton functions* to support it in portfolio/lib.php and the class structure
  3. Write tests for those methods that are necessary
  4. Implement the functions to make the tests pass
  5. Keep adding module implementations

See also