Note: You are currently viewing documentation for Moodle 3.4. Up-to-date documentation for the latest stable version of Moodle is likely available here: Repository API.

Development:Repository API: Difference between revisions

From MoodleDocs
 
(78 intermediate revisions by 11 users not shown)
Line 1: Line 1:
This page describes the specification for a future feature, currently being worked on for Moodle 2.0.  This spec is STILL UNDER CONSTRUCTION.
{{Moodle_2.0}}


See MDL-13766 to track the status of the implementation.
The page is open for everyone so everyone can help correct mistakes and help with the evolution of this document.  However, if you have questions to ask, problems to report or major changes to suggest, please add them to the [[Development_talk:Repository_API|page comments]], or start a discussion in the [http://moodle.org/mod/forum/view.php?id=1807 Repositories forum]. We'll endeavour to merge all such suggestions into the further development and fix all kinds of problems.


The page is open for everyone so everyone can help correct mistakes and help evolution of this document.  However, if you have questions, problems or major changes to suggest please add them to the [[Development_talk:Repository_API|page comments]], or start a discussion in the [http://moodle.org/mod/forum/view.php?id=1807 Repositories forum].  We'll endeavour to merge all such suggestions into the main spec before we start development.
Note that parts of this document have been now split off into a separate [[Development:File_API]]


==Objectives==
==Objectives==


# Allow files to be added directly into Moodle (as we do now)
# Allow all Moodle users to easily bring content into Moodle from external repositories
# Allow all Moodle users to easily bring content into Moodle from external repositories
# Allow content to be used in multiple Moodle contexts securely and simply via capabilities
# Provide a consistent interface to any external repository, for any Moodle module
# Consistency and simplicity for ALL file handling
 
==Overview==
 
The Repository API is a core set of interfaces that all Moodle code will use to:
# copy files from external servers
# store files within Moodle
# display files to Moodle users
 
It's important to remember that a repository will generally be treated as READ-ONLY.  Management of the files will normally be done through the native interface provided by the repository.  Publishing of Moodle content TO a repository is handled by the [[Development:Portfolio API|Portfolio API]].


==Use cases==
==Use cases==
Line 27: Line 16:
# Teacher wants to add a new resource to a course  
# Teacher wants to add a new resource to a course  
# Teacher clicks the "Choose a resource" button
# Teacher clicks the "Choose a resource" button
# Teacher is able to choose from a list of configured repositories (this step will be skipped if there's only one).
# Teacher is presented with a simple file picker to choose a file (with a menu to switch between multiple configured repositories)
# Teacher is presented with a simple file picker to choose a file
# Teacher chooses a file in an external repository
# Teacher chooses a file
# File is COPIED into Moodle and stored by the resource module
# File is COPIED into Moodle and included in the course.
# File is marked as owned by that user
# File is marked as owned by that user
# Access controls are automatically added for that file so that only those with privileges to see that course can see that file (the owner can change those permissions anytime)
# Whenever someone wants to view that file, the resource module controls access  (see [[Development:File API]] )
 
===Teacher linking to an external file as a new resource (think video repository) ===


# Teacher wants to display a file in the repository
# Teacher clicks the "Choose a resource" button
# Teacher is presented with a simple file picker to choose a file (with a menu to switch between multiple configured repositories)
# Teacher chooses a file in an external repository
# Link to the file is COPIED into Moodle and stored by the resource module
# Link is marked as owned by that user
# Whenever someone wants to follow that link, the resource module controls access  (see [[Development:File API]] )


===Student submitting an assignment===
===Student submitting an assignment===
# Student needs to submit an assignment and presses the "Choose files" button
# Student needs to submit an assignment and presses the "Choose files" button
# Student sees a "file picker" where they can see files listed on any of several configured repositories
# Student sees a "file picker" where they can see files listed on any of several configured repositories ([https://docs.moodle.org/en/Image:Filepicker_login.jpg file picker login], [https://docs.moodle.org/en/Image:Filepicker_browser.jpg file picker browser], [https://docs.moodle.org/en/Image:Filepicker_search.jpg file picker search])
# Student chooses MySpace from the list
# Student chooses MySpace from the list
# Student is prompted to enter MySpace username/password (a checkbox could be there to "remember this for next time" but for security perhaps not)
# Student is prompted to enter MySpace username/password (if admin allows it, a checkbox could be there to "remember this for next time" but remember security)
# Student sees their files in MySpace and chooses one or more
# Student sees their files in MySpace and chooses one or more
# Files are copied from MySpace to Moodle  
# Files are copied from MySpace to Moodle  
# Assignment module gives the files permissions so that only the Student and assignment graders can see the file (other students would not have permission).
# Assignment module controls the permissions so that only the Student and assignment graders can see the file (other students would not have permission).
 


===Student attaching an image to a forum===
===Student attaching an image to a forum===
Line 49: Line 45:
# Student sees a "file picker" where they can see files listed on any of several configured repositories
# Student sees a "file picker" where they can see files listed on any of several configured repositories
# Student chooses Mahara from the list
# Student chooses Mahara from the list
# Student is prompted to enter MySpace username/password (a checkbox could be there to "remember this for next time" but for security perhaps not)
# Student is prompted to enter Mahara username/password
# Student sees their files in Mahara and chooses one image
# Student sees their files in Mahara and chooses one image
# Image is copied to Moodle  
# Image is copied to Moodle  
# Image file is attached to forum post by Forum module (by reference)
# Image file is attached to forum post by Forum module (by reference)
# Forum module gives permissions so that anyone who can read that forum can see that file
# Forum module controls permissions so that anyone who can read that forum can see that file


===Student attaching the same image in another forum===
===Student attaching the same image in another forum===
Line 59: Line 55:
# Student needs to submit an assignment and presses the "Choose files" button
# Student needs to submit an assignment and presses the "Choose files" button
# Student sees a "file picker" where they can see files listed on any of several configured repositories
# Student sees a "file picker" where they can see files listed on any of several configured repositories
# Student chooses Mahara from the list
# Student chooses "Local files" from the list and sees all the files they've permission to use
# Student is prompted to enter MySpace username/password (a checkbox could be there to "remember this for next time" but for security perhaps not)
# A COPY of the image file is attached to forum post by Forum module
# Student sees their files in Mahara and chooses one image
# Forum module controls access to this file.
# Moodle detects that the image already exists in Moodle so it it not copied again (or it's just updated)
 
# Image file is attached to forum post by Forum module (by reference)
# Forum module adds some permissions so that anyone who can read the current forum can also see that file


===User managing their files===
# User goes to the "Files" area (similar to current Moodle, but for all users)
# User sees two tabs
# First tab shows listing of current files belonging to self, with buttons to manage them, including buttons to modify the permissions (eg "Allow all people in Course X to see this").  You can also see what repository it came from, including the foreign path, and choose to "update from repository" and get a new copy of the file.
# Second tab shows listing of files belonging to others that you are able to see.


Please add more use cases in this same format
Please add more use cases in this same format


==Mock screenshots==
When you first call up the file picker and choose a repository, you might be asked to log in (if saving of passwords is not allowed):
[[Image:Filepicker_login.jpg]]
Browsing files could look something like this:
[[Image:Filepicker_browser.jpg]]
And you can also search:


==General Architecture==
[[Image:Filepicker_search.jpg]]


All file-handling areas in Moodle (eg adding a new resource, adding attachments to a forum post, uploading assignments) will be rewritten to talk to the standard API class methods in a standard way.
==General architecture==


Each repository plugin (a standard Moodle plugin stored under /repository/xxx) will subclass the standard API and override methods specific to that repository.
Each repository plugin (a standard Moodle plugin stored under /repository/xxx) will subclass the standard API and override methods specific to that repository.
Line 86: Line 85:
* only return the URL to the file if it's desired to keep it external (but this does present security and integrity risks), or
* only return the URL to the file if it's desired to keep it external (but this does present security and integrity risks), or
* refresh the local file copy regularly and automatically
* refresh the local file copy regularly and automatically
* refresh the file manually if desired


All files in Moodle will be listed in a table (see below) allowing us to store various metadata about each file.  The file contents will not be the database (though we could easily offer that option if we want to), they will be on disk with a name related to the id rather than the "human" name (this avoids a lot of OS Unicode problems).
Once in Moodle, it is subject to the [[Development:File API]] for access control like any other file.
 
The current "course file manager" will be replaced by a personal file manager, which basically is a user's view of the internal Moodle repository, showing the files that are available to you in that context (which may include files from other people, repositories etc) and a nice browse/search interface.
 
Finally, normal Moodle modules will have easy functions it can use to add/remove permissions to particular files, according to module rules.  For example, the assignment plugin may, after allowing a student to select a file to be submitted, add permissions so that people who have grade permissions in that assignment can read it.
 
All files will be served via a single control script in Moodle, located at $CFG->fileroot.  This could be the same as $CFG->wwwroot by default, but will be recommended (for security and avoiding XSS) that Moodle admins set up a second DNS name pointing to this script eg the main site could be at http://moodle.domain.edu but files would be served via http://moodlefiles.domain.edu/file.php.  (We'll have to set session cookies on both domains and keep them in sync somehow).
 
The file.php will serve files using slasharguments almost as now.  We just need to replace the courseid with a fileid:  file.php/fileid/dir/dir/file.jpg  (where dir/dir/file.jpg is the virtual path in Moodle).
 


==Repository requirements==
==Repository requirements==
Line 103: Line 94:


The repository MUST provide:
The repository MUST provide:
# A URL to download each node (eg file).
# A URI to download each node (eg file).
# A list of the nodes (eg files and directories) under a given node (eg directory).  This allows Moodle to construct a standard browse interface (much like a standard OS file picker).  However some repository plugins may choose to completely override the repository_browse() method and implement their own interface, that's OK, as long as they end up with a URL for the file.
# A list of the nodes (eg files and directories) under a given node (eg directory).  This allows Moodle to construct a standard browse interface (much like a standard OS file picker).


The repository can OPTIONALLY:
The repository can OPTIONALLY:
Line 115: Line 106:


Some plugins I'd like to see developed for the first version are:
Some plugins I'd like to see developed for the first version are:
* local - very similar to the current course-based file manager, except user-based
* box - an interface to [http://box.net box.net]
* moodle - an interface to another Moodle site, accessed over a secure mnet connection
* mahara - an interface to a Mahara installation
* Server Files - very similar to the current course-based file manager, except user-based
* Remote Moodle - an interface to another Moodle site, accessed over a secure mnet connection
* googledocs - an interface to [http://docs.google.com Google Docs]
* s3 - an interface to [http://www.amazon.com/gp/browse.html?node=16427261 Amazon S3]
* flickr - an interface to [http://flickr.com flickr]
* WebDAV - to access arbitrary external WebDAV servers
* merlot - an interface to the learning materials in [http://www.merlot.org/merlot/materials.htm Merlot.org]
* File System - a plugin to list files on local file system, of course, you can mount remote files to this local directory
* youtube - an interface to [http://youtube.com YouTube]
* jsr170 - an interface that can talk to anything that supports jsr170 (eg [http://www.alfresco.com/ Alfresco])
* jsr170 - an interface that can talk to anything that supports jsr170 (eg [http://www.alfresco.com/ Alfresco])
* oki - an OKI emulator allowing us to access things with OKI interfaces,like [http://www.fedora.info/ Fedora]
* oki - an OKI emulator allowing us to access things with OKI interfaces,like [http://www.fedora.info/ Fedora]
* briefcase - an interface to [http://briefcase.yahoo.com/ Yahoo Briefcase]
* briefcase - an interface to [http://briefcase.yahoo.com/ Yahoo Briefcase]
* myspace - an interface to MySpace files (perhaps via [http://www.programmableweb.com/api/myspace this MySpace API])
* myspace - an interface to MySpace files (perhaps via [http://www.programmableweb.com/api/myspace this MySpace API])
* googledocs - an interface to [http://docs.google.com Google Docs]
* skydrive - an interface to Microsoft's [http://skydrive.live.com/ SkyDrive] files
* skydrive - an interface to Microsoft's [http://skydrive.live.com/ SkyDrive] files
* Dropbox - an interface to Dropbox files [http://www.dropbox.com]
* facebook - an interface to Facebook files
* facebook - an interface to Facebook files
* merlot - an interface to the learning materials in [http://www.merlot.org/merlot/materials.htm Merlot.org]
* [http://www.dspace.org/ Dspace] - a repository from MIT
* flickr - an interface to [http://flickr.com flickr]
* DOOR - another popular open source repository
* youtube - an interface to [http://youtube.com YouTube]
* SMB shares - An interface for windows shares e.g. personal folders on network drives. Would need to link with LDAP as usernames will often be wholly/partially the same as network folder names. This could be done using SAMBA, but would also need to work on windows machines natively. See [http://moodle.org/mod/data/view.php?d=13&rid=991 this block] for a linux implementation.
* mahara - an interface to a Mahara installation
 
==Tables==


==Local Files==
=== repository ===


In general, all external files will be copied locally and stored in Moodle.  This section describes the storage of the files and how we define ACLs (access control lists) for them.  All existing files in the Moodle dataroot course areas will be moved into this new system during the upgrade.
{| border="1" cellpadding="2" cellspacing="0"
|'''Field'''
|'''Type'''
|'''Default'''
|'''Info'''


The files will not be stored as they have been in the past.  The new file system is "flat" with each file stored as an id.  The name and path are stored in tables.  To avoid running out of nodes we'll use a hash-like structure like the users directory does, ie:
|-
|'''id'''
|int(10)
|
|autoincrementing


dataroot
|-
    /files
|'''type'''
      /0
|varchar(255)
      /10000
|
      /20000
|The type of the repository
      /30000
          /3076.jpg


|-
|'''visible'''
|tinyint(1)
|
|


==Tables==
|-
|sortorder
|int(10)
|
|
|}


=== repository ===
=== repository_instances ===


This table contains one entry for every configured external repository instance.
This table contains one entry for every configured external repository instance.
Line 157: Line 174:


|-
|-
|'''id'''  
|'''id'''
|int(10)
|int(10)
|
|
|autoincrementing  
|autoincrementing  


|-
|-
|repositoryname
|name
|varchar
|varchar 255
|
|
|A custom name for this reopsitory (non-unique)
|A custom name for this repository (non-unique)


|-
|-
|'''repositorytype'''  
|'''typeid'''  
|varchar
|int(10)
|  
|  
|The name of the plugin being used
|The id of repository type


|-
|-
Line 188: Line 205:
|-
|-
|username
|username
|varchar
|varchar(255)
|  
|  
|username to log in with, if required
|username to log in with, if required (almost never!)


|-
|-
|password
|password
|varchar
|varchar(255)
|
|password to log in with, if required
 
|-
|option1
|varchar
|
|Other information useful to the plugin
 
|-
|option2
|varchar
|
|Other information useful to the plugin
 
|-
|option3
|varchar
|
|Other information useful to the plugin
 
|-
|option4
|varchar
|
|Other information useful to the plugin
 
|-
|option5
|varchar
|  
|  
|Other information useful to the plugin
|password to log in with, if required (almost never!)


|-
|-
Line 241: Line 228:
|}
|}


 
=== repository_instance_config ===
=== file ===
 
This table contains one entry for every file.  Enough information is kept here so that the file can be fully identified and retrieved again if necessary.


{| border="1" cellpadding="2" cellspacing="0"
{| border="1" cellpadding="2" cellspacing="0"
Line 253: Line 237:


|-
|-
|'''id'''  
|'''id'''
|int(10)
|int(10)
|
|
|autoincrementing  
|autoincrementing  


|-
|-
|'''userid'''  
|'''instanceid'''
|int(10)
|int(int)
|  
|
|The owner of the file (person who created this entry)
|


|-
|-
|filename
|'''name'''
|varchar
|varchar(255)
|
|
|
|The full Unicode name of this file


|-
|-
|'''repositoryid'''
|value
|int(10)
|Text
|
|
|
|The repository instance this is associated with
|}


|-
===File types===
|updates
 
|int(10)
The context at which someone is inserting a file may require certain file types (eg uploading a new user profile image is only looking for images)
|
 
|Specifies the update schedule (0 = none, 1 = on demand, other = some period in seconds)
To support this, the calling code needs to be able to specify the required mimetypes, and the listing code should be able to filter the results based on these mimetypes.  Ideally the repository itself can do the filtering for ultimate speed (though not all repositories will support this).
 
We will have to develop special new mimetypes for Moodle files like backups (application/vnd.moodle.backup) and IMS learning design (application/vnd.moodle.imsld) etc
 
==Technical walkthrough==
 
(See also the functional spec for the [[Development:Repository_File_Picker]] )
 
There are two main cases where the repository API will be used: as part of a Moodleform to add a file and as part of the HTML editor to add a media element into some HTML).  We also have to cater for the using Moodleforms without Javascript.
 
In all of these cases the files will be uploaded to Moodle while using the file picker dialog and stored in a temporary file area owned by the currently active user.  It is only AFTER the submission of the entire Moodleform that we will know the full context, itemids to store the file properly, so at this time the file will be copied into the correct filearea.
 
===Case 1: As part of a Moodleform with Javascript===
 
1. Moodle module code calls a "filepicker" moodleform item whenever a file is required, which includes the following information to pass to the File API:
 
eg $mform->addElement('filepicker', 'uniqueelementid', $fullname, $data)
2. When rendering the form, Moodle will display a read-only filename field with an '''"Add file"''' button next to it.  There will also be a hidden field to store a file reference later (this is what actually gets used, the filename field is just for users to see something).
 
3. When the add file button is pressed, the form will be "replaced" in the page by a larger resizeable area containing an AJAX file picker.  (After picking the display can be closed).  (There could be a user option to make this a popup window instead, if required)
 
4. The AJAX file picker interface will list all the active repositories as a menu, and list files in one of several formats (like Windows/Mac/Linux): Details, Names, Icons.
 
5. For each plugin, the AJAX interface will prompt the user to login first (if required) asking the plugin to log in behind the scenes.  It'll also ask the plugin to return listing data in response to clicks and searches. 
 
6. Finally, when the user selects a file and clicks the "Select" button, the AJAX interface will trigger a method in the plugin that will fetch the file and call the File Storage API to '''store''' the file using the '''uniqueelementid''' and the current user info.  While this is happening, the interface should show some sort of progress bar (ideally) or at least a "loading file" image/sign/message. 
 
7. After a file has finally been selected we will have a file ID which we can pass back to the original Moodle form (to the hidden field named '''uniqueelementid_formid''').  The picker can then rename the read-only filename field before it hides itself.
 
8. Submitting the form will trigger the mform processing for this field, which will check fields, create things in the module etc.  Once this has been finally successful the developer must call an mform function to "fix" the info for each file and "move" it into the module file area:
 
  eg $mform->store_local_file('uniqueelementid', $context, $filearename, $itemid, $filepath);
 
9. Cron jobs in File Storage api should automatically delete any files in the user's tempfile area that are older than 7 days or move them into a trash can in the user's file area (perhaps).
 
===Case 2: As part of a Moodleform without Javascript===
 
Steps 1-2 are the same as for the case with Javascript.
 
3. The add file button is a submit button for the form with a different value.  When the add file button is pressed,
* the whole form will be ''submitted'' to the original location (but with a different submit button value)
* moodleforms get_data() will detect this is a "repository save" and can save the full POST info in the current session tagged with the id of the openfile element, together with the URL to return to
* moodleforms get_data() then redirects the user to a new page showing the main picker interface
 
4. The file picker interface will have to be a completely new and separate interface from the AJAX one.  It could be a long hierarchy listing, or reload a lot.
 
5. Finally, when the user selects a file and submits using the "Select" button to picker.php, it will trigger a method in the plugin that will fetch the file and call the [[Development:File_API|File API]] to store the file using the filearea and context information we already had.  While this is happening, the interface can show some sort of progress bar (ideally) or at least a "loading file" image/sign/message.
 
6. After this, picker.php will redirect/continue back to the original form page.  The form can be constructed as usual, however, when the form is rendered using display() method moodleforms should now look for relevant saved content in the session and use that to override any content in the form (and then delete the saved info in the session).
 
Steps 8-9 are the same as for the case with Javascript.
 
===Case 3: As part of a HTML editor===
 
The key thing here is a move away from storing any absolute URLs to files in our HTML texts.  Instead we'll store relative names.
 
1. The moodleform for a textarea (HTML editor) will require a path to the filearea associated with this HTML.  eg '''wwwroot/pluginfile.php/13/content/0/'''.  This would have to be the user_draft area if the filearea doesn't exist yet  eg '''wwwroot/draftfile.php/userid/tempfile/uniquelementid'''
 
2. All textarea content will also need to have str_replace done on it to replace @@pluginfile@@/somefilenames.jpg in the content to use this path so that it comes up right in the editor.  (Note this also needs to be done on every format_text command too when showing this text.)
 
3. The path parameter also needs to be added to the editor configuration in the current page.


|-
4. Editor plugins can be modified to look for these variables in the editor configuration.
|cachetime
|int(10)
|
|Specifies how long this file can be cached by browsers


5. When adding an image or other media element,  the same AJAX repository picker will show up as a popup div to allow people to pick from any repository and choose files to download.  The repository picker is responsible for downloading the file in real-time, storing it as a user temporary file if the filearea doesn't already exist, prefixing the supplied path to the filename and returning a URL back to the dialog text input before closing.


|-
6. On submission, and after the HTML is stored, we might now have a new permanent filearea, so we'll need to update any associated temporary files to make sure they have the proper file area information.
|moodlepath
|text
|
|The virtual path to the file locally (so we can still have apparent subdirectories etc)


==Repository plugins==


|-
Each repository plugin is required to contain the following elements:
|repositorypath
|text
|
|The full path to the original file on the repository


|-
===class repository()===
|timeimportfirst
|int(10)
|
|The first time this file was imported into Moodle


|-
This class implements the interface to a particular repository, for browsing, selecting and updating files.  The base class (repository) is defined in /repository/lib.php, while each repository defines an inherited class (eg repository_alfresco) in /repository/repositoryname/repository.class.php
|timeimportlast
|int(10)
|
|The most recent time that this file was imported into Moodle


|-
Repositories can redefine any of these methods as required (and in some instances, MUST redefine them):
|timecreated
|int(10)
|
|The time this file was created (if known), otherwise same as time imported


|-
====__construct($repositoryid, $contextid, $options=array(), $readonly)====
|timemodified
|int(10)
|
|The last time the file was modified


|-
'''MUST''' redefine
|timeaccessed
|int(10)
|
|The last time this file was accessed for any reason
|}


Accept necessary parameters, and do initialization of repository.


=== file_instances ===
====get_file($url, $file = '')====


This table contains one entry for every "place" a file is published to.  For example, one file might appear in an assignment but also in a forum attachment, so there would be two entries here.
Given a URL, download a file from there, save the file in a temporary directory.


{| border="1" cellpadding="2" cellspacing="0"
====get_link($info)====
|'''Field'''
Get the url of external resource
|'''Type'''
|'''Default'''
|'''Info'''


|-
====get_listing($path='/', $page='''''''')====
|'''id'''  
|int(10)
|
|autoincrementing


|-
Given a path, and perhaps a search, get a listing of files. In the case of AJAX file picker, this function should return json format Javascript array.
|'''fileid'''
|int(10) 
|
|The file we are defining access for


|-
====search($keyword)====
|instancetype
Search repository by given keyword, it will return an array of the same format of get_listing
|varchar
|
|This defines the table in Moodle that this instance is associated with (eg 'forum_posts', 'assignment_submissions' etc


|-
====print_login()====
|'''instanceid'''
|int(10)
|
|The id in the foreign table (of name instancetype) that this instance is associated with
|}


=== file_access ===
Show the login screen, if required. In the case of AJAX file picker, this function should return json format array which defined the login form.


This table describes the ACL for each file, so that checks can easily be made on whether someone can see this file or not.  Note there can be multiple entries per file.  Users can ALWAYS see their own files, so there are no entries here for that.
====print_search====


{| border="1" cellpadding="2" cellspacing="0"
Print the search form, it will return a json string
|'''Field'''
|'''Type'''
|'''Default'''
|'''Info'''


|-
====get_meta()====
|'''id'''
Return information for creating ajax request, it is private function, you don't need to rewrite it.
|int(10)
|
|autoincrementing


|-
====create()====
|'''fileid'''
Create an instance
|int(10)
|
|The file we are defining access for


|-
====delete()====
|'''contextid'''
Delete this instance from `repository` table
|int(10)
|
|The context where this file is being published


|-
====hide()====
|'''capability'''
Hide a repository instance from file picker list
|text
|
|The capability that is required to see this file
|}


====set_option()====
set options in data1-data5 fields, can be overrided


==Class methods==
====get_option()====
get option list or a specific option from database


===Repository class===
====get_type_option_names()====
If this plugin needs admin settings, please refine this function to return option names.


This class implements the interface to a particular repository, for browsing, selecting and updating files.
====type_config_form()====
If get_type_option_names return non empty array, this function '''MUST''' redefine, it will help to build the setting form.


====get_file($path)====
====get_instance_option_names()====
If plugin instance needs settings, this function will return instance option names.


====get_listing($parent='/', $search='''''''')====
====instance_config_form()====
If get_instance_option_names return non empty array, this function '''MUST''' redefine, it will help to build the instance setting form.


====cron()====


====etc====
====supported_filetypes()====
What file types are supported by this repository plugin, it will return an array, the file type name is defined in a [http://freemind.sourceforge.net/wiki/index.php/Main_Page freemind] file in lib/file/file_types.mm


===File class===
====supported_returntypes()====
The repository plugin could support external link or copying files to moodle. If the plugin support file link only, developer should override this function to return FILE_EXTERNAL, if plugin support copying file only, it should return FILE_INTERNAL, by default, plugin supports both.


This class implements the display and management of files from local storage, with full access checking.  Some of the functions are for single files, while some are optimised for bulk display and searching (eg in the personal files interface).
====filter()====
Filter file listing to exclude specific file types


====display_file()====
===icon.png===


sort of like file.php is now, except smarter
A logo that represents the repository.  Ideally square but we should handle all sizes.


====set_access($fileid, $accessstuff)====


Grant some access to people to a file
==See also==


====has_access($fileid, $userid=NULL)====
* [[Development:Repository Administration Specification]]
* [[Development:Repository Interface for Moodle/Course/User]]
* [[Development:Repository plugins]]
* [[Development:Repository File Picker]]
* [[Development:File API]]
* [[Development:Portfolio API]]
* MDL-13766 and MDL-16543 Repository API Meta issues


Returns true or false depending on access to a file
[[Category:Repositories]]


==Areas in Moodle that need re-writing==
[[ja:開発:リポジトリAPI]]

Latest revision as of 10:48, 3 November 2010

Template:Moodle 2.0

The page is open for everyone so everyone can help correct mistakes and help with the evolution of this document. However, if you have questions to ask, problems to report or major changes to suggest, please add them to the page comments, or start a discussion in the Repositories forum. We'll endeavour to merge all such suggestions into the further development and fix all kinds of problems.

Note that parts of this document have been now split off into a separate Development:File_API

Objectives

  1. Allow all Moodle users to easily bring content into Moodle from external repositories
  2. Provide a consistent interface to any external repository, for any Moodle module

Use cases

Teacher adding an external file as a new resource

  1. Teacher wants to add a new resource to a course
  2. Teacher clicks the "Choose a resource" button
  3. Teacher is presented with a simple file picker to choose a file (with a menu to switch between multiple configured repositories)
  4. Teacher chooses a file in an external repository
  5. File is COPIED into Moodle and stored by the resource module
  6. File is marked as owned by that user
  7. Whenever someone wants to view that file, the resource module controls access (see Development:File API )

Teacher linking to an external file as a new resource (think video repository)

  1. Teacher wants to display a file in the repository
  2. Teacher clicks the "Choose a resource" button
  3. Teacher is presented with a simple file picker to choose a file (with a menu to switch between multiple configured repositories)
  4. Teacher chooses a file in an external repository
  5. Link to the file is COPIED into Moodle and stored by the resource module
  6. Link is marked as owned by that user
  7. Whenever someone wants to follow that link, the resource module controls access (see Development:File API )

Student submitting an assignment

  1. Student needs to submit an assignment and presses the "Choose files" button
  2. Student sees a "file picker" where they can see files listed on any of several configured repositories (file picker login, file picker browser, file picker search)
  3. Student chooses MySpace from the list
  4. Student is prompted to enter MySpace username/password (if admin allows it, a checkbox could be there to "remember this for next time" but remember security)
  5. Student sees their files in MySpace and chooses one or more
  6. Files are copied from MySpace to Moodle
  7. Assignment module controls the permissions so that only the Student and assignment graders can see the file (other students would not have permission).

Student attaching an image to a forum

  1. Student needs to attach an image and presses the "Choose files" button in the posting screen
  2. Student sees a "file picker" where they can see files listed on any of several configured repositories
  3. Student chooses Mahara from the list
  4. Student is prompted to enter Mahara username/password
  5. Student sees their files in Mahara and chooses one image
  6. Image is copied to Moodle
  7. Image file is attached to forum post by Forum module (by reference)
  8. Forum module controls permissions so that anyone who can read that forum can see that file

Student attaching the same image in another forum

  1. Student needs to submit an assignment and presses the "Choose files" button
  2. Student sees a "file picker" where they can see files listed on any of several configured repositories
  3. Student chooses "Local files" from the list and sees all the files they've permission to use
  4. A COPY of the image file is attached to forum post by Forum module
  5. Forum module controls access to this file.


Please add more use cases in this same format

Mock screenshots

When you first call up the file picker and choose a repository, you might be asked to log in (if saving of passwords is not allowed):

Filepicker login.jpg

Browsing files could look something like this:

Filepicker browser.jpg

And you can also search:

Filepicker search.jpg

General architecture

Each repository plugin (a standard Moodle plugin stored under /repository/xxx) will subclass the standard API and override methods specific to that repository.

As is usual in Moodle, there will be admin settings to disable/enable certain repository plugins as standard, as well as user settings so that users can add their own personal repositories to the standard list (eg Yahoo Briefcase or Google Docs) and to select their default repository.

Once a repository has been used the file will usually be copied into Moodle there and then. However there will also be options to:

  • only return the URL to the file if it's desired to keep it external (but this does present security and integrity risks), or
  • refresh the local file copy regularly and automatically
  • refresh the file manually if desired

Once in Moodle, it is subject to the Development:File API for access control like any other file.

Repository requirements

From the Moodle point of view, each repository is just a hierarchy of nodes.

The repository MUST provide:

  1. A URI to download each node (eg file).
  2. A list of the nodes (eg files and directories) under a given node (eg directory). This allows Moodle to construct a standard browse interface (much like a standard OS file picker).

The repository can OPTIONALLY:

  1. Require some authentication credentials
  2. Provide more metadata about each node (mime type, size, dates, related files, dublin core stuff, etc)
  3. Describe a search facility (so that Moodle can construct a search form)
  4. Provide copyright and usage rules (or just information about the rules)

Repository plugins

Some plugins I'd like to see developed for the first version are:

  • box - an interface to box.net
  • mahara - an interface to a Mahara installation
  • Server Files - very similar to the current course-based file manager, except user-based
  • Remote Moodle - an interface to another Moodle site, accessed over a secure mnet connection
  • googledocs - an interface to Google Docs
  • s3 - an interface to Amazon S3
  • flickr - an interface to flickr
  • WebDAV - to access arbitrary external WebDAV servers
  • merlot - an interface to the learning materials in Merlot.org
  • File System - a plugin to list files on local file system, of course, you can mount remote files to this local directory
  • youtube - an interface to YouTube
  • jsr170 - an interface that can talk to anything that supports jsr170 (eg Alfresco)
  • oki - an OKI emulator allowing us to access things with OKI interfaces,like Fedora
  • briefcase - an interface to Yahoo Briefcase
  • myspace - an interface to MySpace files (perhaps via this MySpace API)
  • skydrive - an interface to Microsoft's SkyDrive files
  • Dropbox - an interface to Dropbox files [1]
  • facebook - an interface to Facebook files
  • Dspace - a repository from MIT
  • DOOR - another popular open source repository
  • SMB shares - An interface for windows shares e.g. personal folders on network drives. Would need to link with LDAP as usernames will often be wholly/partially the same as network folder names. This could be done using SAMBA, but would also need to work on windows machines natively. See this block for a linux implementation.

Tables

repository

Field Type Default Info
id int(10) autoincrementing
type varchar(255) The type of the repository
visible tinyint(1)
sortorder int(10)

repository_instances

This table contains one entry for every configured external repository instance.

Field Type Default Info
id int(10) autoincrementing
name varchar 255 A custom name for this repository (non-unique)
typeid int(10) The id of repository type
userid int(10) The person who created this repository instance
contextid int(10) The context that this repository is available to ( = system context for site-wide ones)
username varchar(255) username to log in with, if required (almost never!)
password varchar(255) password to log in with, if required (almost never!)
timecreated int(10) The time this repository was created
timemodified int(10) The last time the repository was modified

repository_instance_config

Field Type Default Info
id int(10) autoincrementing
instanceid int(int)
name varchar(255)
value Text

File types

The context at which someone is inserting a file may require certain file types (eg uploading a new user profile image is only looking for images).

To support this, the calling code needs to be able to specify the required mimetypes, and the listing code should be able to filter the results based on these mimetypes. Ideally the repository itself can do the filtering for ultimate speed (though not all repositories will support this).

We will have to develop special new mimetypes for Moodle files like backups (application/vnd.moodle.backup) and IMS learning design (application/vnd.moodle.imsld) etc

Technical walkthrough

(See also the functional spec for the Development:Repository_File_Picker )

There are two main cases where the repository API will be used: as part of a Moodleform to add a file and as part of the HTML editor to add a media element into some HTML). We also have to cater for the using Moodleforms without Javascript.

In all of these cases the files will be uploaded to Moodle while using the file picker dialog and stored in a temporary file area owned by the currently active user. It is only AFTER the submission of the entire Moodleform that we will know the full context, itemids to store the file properly, so at this time the file will be copied into the correct filearea.

Case 1: As part of a Moodleform with Javascript

1. Moodle module code calls a "filepicker" moodleform item whenever a file is required, which includes the following information to pass to the File API:

eg $mform->addElement('filepicker', 'uniqueelementid', $fullname, $data)

2. When rendering the form, Moodle will display a read-only filename field with an "Add file" button next to it. There will also be a hidden field to store a file reference later (this is what actually gets used, the filename field is just for users to see something).

3. When the add file button is pressed, the form will be "replaced" in the page by a larger resizeable area containing an AJAX file picker. (After picking the display can be closed). (There could be a user option to make this a popup window instead, if required)

4. The AJAX file picker interface will list all the active repositories as a menu, and list files in one of several formats (like Windows/Mac/Linux): Details, Names, Icons.

5. For each plugin, the AJAX interface will prompt the user to login first (if required) asking the plugin to log in behind the scenes. It'll also ask the plugin to return listing data in response to clicks and searches.

6. Finally, when the user selects a file and clicks the "Select" button, the AJAX interface will trigger a method in the plugin that will fetch the file and call the File Storage API to store the file using the uniqueelementid and the current user info. While this is happening, the interface should show some sort of progress bar (ideally) or at least a "loading file" image/sign/message.

7. After a file has finally been selected we will have a file ID which we can pass back to the original Moodle form (to the hidden field named uniqueelementid_formid). The picker can then rename the read-only filename field before it hides itself.

8. Submitting the form will trigger the mform processing for this field, which will check fields, create things in the module etc. Once this has been finally successful the developer must call an mform function to "fix" the info for each file and "move" it into the module file area:

 eg $mform->store_local_file('uniqueelementid', $context, $filearename, $itemid, $filepath);

9. Cron jobs in File Storage api should automatically delete any files in the user's tempfile area that are older than 7 days or move them into a trash can in the user's file area (perhaps).

Case 2: As part of a Moodleform without Javascript

Steps 1-2 are the same as for the case with Javascript.

3. The add file button is a submit button for the form with a different value. When the add file button is pressed,

  • the whole form will be submitted to the original location (but with a different submit button value)
  • moodleforms get_data() will detect this is a "repository save" and can save the full POST info in the current session tagged with the id of the openfile element, together with the URL to return to
  • moodleforms get_data() then redirects the user to a new page showing the main picker interface

4. The file picker interface will have to be a completely new and separate interface from the AJAX one. It could be a long hierarchy listing, or reload a lot.

5. Finally, when the user selects a file and submits using the "Select" button to picker.php, it will trigger a method in the plugin that will fetch the file and call the File API to store the file using the filearea and context information we already had. While this is happening, the interface can show some sort of progress bar (ideally) or at least a "loading file" image/sign/message.

6. After this, picker.php will redirect/continue back to the original form page. The form can be constructed as usual, however, when the form is rendered using display() method moodleforms should now look for relevant saved content in the session and use that to override any content in the form (and then delete the saved info in the session).

Steps 8-9 are the same as for the case with Javascript.

Case 3: As part of a HTML editor

The key thing here is a move away from storing any absolute URLs to files in our HTML texts. Instead we'll store relative names.

1. The moodleform for a textarea (HTML editor) will require a path to the filearea associated with this HTML. eg wwwroot/pluginfile.php/13/content/0/. This would have to be the user_draft area if the filearea doesn't exist yet eg wwwroot/draftfile.php/userid/tempfile/uniquelementid

2. All textarea content will also need to have str_replace done on it to replace @@pluginfile@@/somefilenames.jpg in the content to use this path so that it comes up right in the editor. (Note this also needs to be done on every format_text command too when showing this text.)

3. The path parameter also needs to be added to the editor configuration in the current page.

4. Editor plugins can be modified to look for these variables in the editor configuration.

5. When adding an image or other media element, the same AJAX repository picker will show up as a popup div to allow people to pick from any repository and choose files to download. The repository picker is responsible for downloading the file in real-time, storing it as a user temporary file if the filearea doesn't already exist, prefixing the supplied path to the filename and returning a URL back to the dialog text input before closing.

6. On submission, and after the HTML is stored, we might now have a new permanent filearea, so we'll need to update any associated temporary files to make sure they have the proper file area information.

Repository plugins

Each repository plugin is required to contain the following elements:

class repository()

This class implements the interface to a particular repository, for browsing, selecting and updating files. The base class (repository) is defined in /repository/lib.php, while each repository defines an inherited class (eg repository_alfresco) in /repository/repositoryname/repository.class.php

Repositories can redefine any of these methods as required (and in some instances, MUST redefine them):

__construct($repositoryid, $contextid, $options=array(), $readonly)

MUST redefine

Accept necessary parameters, and do initialization of repository.

get_file($url, $file = )

Given a URL, download a file from there, save the file in a temporary directory.

get_link($info)

Get the url of external resource

get_listing($path='/', $page=''')

Given a path, and perhaps a search, get a listing of files. In the case of AJAX file picker, this function should return json format Javascript array.

search($keyword)

Search repository by given keyword, it will return an array of the same format of get_listing

print_login()

Show the login screen, if required. In the case of AJAX file picker, this function should return json format array which defined the login form.

print_search

Print the search form, it will return a json string

get_meta()

Return information for creating ajax request, it is private function, you don't need to rewrite it.

create()

Create an instance

delete()

Delete this instance from `repository` table

hide()

Hide a repository instance from file picker list

set_option()

set options in data1-data5 fields, can be overrided

get_option()

get option list or a specific option from database

get_type_option_names()

If this plugin needs admin settings, please refine this function to return option names.

type_config_form()

If get_type_option_names return non empty array, this function MUST redefine, it will help to build the setting form.

get_instance_option_names()

If plugin instance needs settings, this function will return instance option names.

instance_config_form()

If get_instance_option_names return non empty array, this function MUST redefine, it will help to build the instance setting form.


supported_filetypes()

What file types are supported by this repository plugin, it will return an array, the file type name is defined in a freemind file in lib/file/file_types.mm

supported_returntypes()

The repository plugin could support external link or copying files to moodle. If the plugin support file link only, developer should override this function to return FILE_EXTERNAL, if plugin support copying file only, it should return FILE_INTERNAL, by default, plugin supports both.

filter()

Filter file listing to exclude specific file types

icon.png

A logo that represents the repository. Ideally square but we should handle all sizes.


See also