<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="sv">
	<id>https://docs.moodle.org/4x/sv/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dongsheng</id>
	<title>MoodleDocs - Användarbidrag [sv]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/4x/sv/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dongsheng"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/Special:Bidrag/Dongsheng"/>
	<updated>2026-05-12T02:07:33Z</updated>
	<subtitle>Användarbidrag</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=error/moodle/nopermissiontoviewcalendar&amp;diff=142415</id>
		<title>error/moodle/nopermissiontoviewcalendar</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=error/moodle/nopermissiontoviewcalendar&amp;diff=142415"/>
		<updated>2021-10-25T18:18:12Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: Created page with &amp;quot;This error indicates the current user account does not have permission to view the calendar event.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This error indicates the current user account does not have permission to view the calendar event.&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=141483</id>
		<title>Användare:Dongsheng Cai</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=141483"/>
		<updated>2021-08-12T00:13:06Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Hello =&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=140707</id>
		<title>Användare:Dongsheng Cai</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=140707"/>
		<updated>2021-06-21T04:05:04Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: Blanked the page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=139717</id>
		<title>Användare:Dongsheng Cai</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=139717"/>
		<updated>2021-02-24T22:49:04Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;My works:&lt;br /&gt;
&lt;br /&gt;
* [http://tracker.moodle.org/secure/ViewProfile.jspa?name=dongsheng Tracker]&lt;br /&gt;
* [[Chats|Chat module]]&lt;br /&gt;
* [[Development:Repository_API|Moodle Repository API]]&lt;br /&gt;
* [[Development:Comments_2.0|Comments 2.0]]&lt;br /&gt;
* [[Development:Wiki_2.0|Wiki 2]] contributor&lt;br /&gt;
* [[Development:Mobile app|Moodle mobile app for iOS]]&lt;br /&gt;
&lt;br /&gt;
More:&lt;br /&gt;
* [https://www.openhub.net/accounts/dcai/ Open Hub]&lt;br /&gt;
* [https://github.com/dcai My Github]&lt;br /&gt;
* [https://dongsheng.org My website]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=139716</id>
		<title>Användare:Dongsheng Cai</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=139716"/>
		<updated>2021-02-24T22:48:35Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;My works:&lt;br /&gt;
&lt;br /&gt;
* [http://tracker.moodle.org/secure/ViewProfile.jspa?name=dongsheng Tracker]&lt;br /&gt;
* [[Chats|Chat module]]&lt;br /&gt;
* [[Development:Repository_API|Moodle Repository API]]&lt;br /&gt;
* [[Development:Comments_2.0|Comments 2.0]]&lt;br /&gt;
* [[Development:Wiki_2.0|Wiki 2]] contributor&lt;br /&gt;
* [[Development:Mobile app|Moodle mobile app for iOS]]&lt;br /&gt;
&lt;br /&gt;
More:&lt;br /&gt;
* [https://www.openhub.net/accounts/dcai/ Open Hub]&lt;br /&gt;
* [https://github.com/dcai My Github]&lt;br /&gt;
* [https://www.linkedin.com/in/dongsheng Linkedin]&lt;br /&gt;
* [https://dongsheng.org My website]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=129582</id>
		<title>Användare:Dongsheng Cai</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=129582"/>
		<updated>2017-12-03T23:36:03Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;My works:&lt;br /&gt;
&lt;br /&gt;
* [http://tracker.moodle.org/secure/ViewProfile.jspa?name=dongsheng Tracker]&lt;br /&gt;
* [[Chats|Chat module]]&lt;br /&gt;
* [[Development:Repository_API|Moodle Repository API]]&lt;br /&gt;
* [[Development:Comments_2.0|Comments 2.0]]&lt;br /&gt;
* [[Development:Wiki_2.0|Wiki 2]] contributor&lt;br /&gt;
* [[Development:Mobile app|Moodle mobile app for iOS]]&lt;br /&gt;
&lt;br /&gt;
More:&lt;br /&gt;
* [http://www.ohloh.net/accounts/cai  Ohloh]&lt;br /&gt;
* [http://github.com/dongsheng My Github]&lt;br /&gt;
* [http://www.linkedin.com/in/dongsheng Linkedin]&lt;br /&gt;
* [http://dongsheng.org My website]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Mobile_app_Push_Notifications&amp;diff=113350</id>
		<title>Mobile app Push Notifications</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Mobile_app_Push_Notifications&amp;diff=113350"/>
		<updated>2014-06-30T06:54:06Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Starting versions (1.4 ios, iPhone, iPad and 1.4.3 Android) Moodle Mobile support Push Notifications.&lt;br /&gt;
&lt;br /&gt;
1.  Install [https://moodle.org/plugins/view.php?plugin=message_airnotifier this plugin] in 2.4, 2.5 or 2.6* (or simply enable it in 2.7)  &lt;br /&gt;
&lt;br /&gt;
2.  Connect it to a mesaging server, you can use ours in case your Moodle site is registered. Go to Site administration /Plugins /Message outputs /Mobile Notifications and click in Request access key&lt;br /&gt;
&lt;br /&gt;
3.  Users need to connect at least once with the latest version of the app to register their phones with your site.   &lt;br /&gt;
&lt;br /&gt;
4)  Users can configure notificiations in the Moodle messaging preferences (Administration / My profile settings / Messaging)&lt;br /&gt;
&lt;br /&gt;
* For Moodle versions 2.4 and 2.5 the [[Moodle Mobile additional features]] must be also installed&lt;br /&gt;
** Only for Moodle different to 2.7 and onwards: If you upgrade your Moodle installation, you will have to reinstall the plugin since it add a couple of functions to the core Moodle Mobile service. See https://tracker.moodle.org/browse/MDLSITE-2815?focusedCommentId=273741&amp;amp;page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-273741 for more information&lt;br /&gt;
&lt;br /&gt;
== Installing your own Notifications infrastructure ==&lt;br /&gt;
&lt;br /&gt;
If you have a customized version of the Mobile app, or you want to use your own Notifications infrastructure then you have to install a private [http://airnotifier.github.io AirNotifier] (backend server for notifciations)&lt;br /&gt;
&lt;br /&gt;
You have to add your app certificates there, see https://github.com/airnotifier/airnotifier/wiki/Installation&lt;br /&gt;
&lt;br /&gt;
The message AirNotifier plugin allow you to point to your custom AirNotifier instance using your own access keys&lt;br /&gt;
&lt;br /&gt;
Remember to install using GIT (branch moodle)&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
[[Category: Mobile]]&lt;br /&gt;
&lt;br /&gt;
[[es:Mobile app Notificaciones Push]]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Mobile_app_Push_Notifications&amp;diff=113349</id>
		<title>Mobile app Push Notifications</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Mobile_app_Push_Notifications&amp;diff=113349"/>
		<updated>2014-06-30T06:53:23Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Starting versions (1.4 ios, iPhone, iPad and 1.4.3 Android) Moodle Mobile support Push Notifications.&lt;br /&gt;
&lt;br /&gt;
1.  Install [https://moodle.org/plugins/view.php?plugin=message_airnotifier this plugin] in 2.4, 2.5 or 2.6* (or simply enable it in 2.7)  &lt;br /&gt;
&lt;br /&gt;
2.  Connect it to a mesaging server, you can use ours in case your Moodle site is registered. Go to Site administration /Plugins /Message outputs /Mobile Notifications and click in Request access key&lt;br /&gt;
&lt;br /&gt;
3.  Users need to connect at least once with the latest version of the app to register their phones with your site.   &lt;br /&gt;
&lt;br /&gt;
4)  Users can configure notificiations in the Moodle messaging preferences (Administration / My profile settings / Messaging)&lt;br /&gt;
&lt;br /&gt;
* For Moodle versions 2.4 and 2.5 the [[Moodle Mobile additional features]] must be also installed&lt;br /&gt;
** Only for Moodle different to 2.7 and onwards: If you upgrade your Moodle installation, you will have to reinstall the plugin since it add a couple of functions to the core Moodle Mobile service. See https://tracker.moodle.org/browse/MDLSITE-2815?focusedCommentId=273741&amp;amp;page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-273741 for more information&lt;br /&gt;
&lt;br /&gt;
== Installing your own Notifications infrastructure ==&lt;br /&gt;
&lt;br /&gt;
If you have a customized version of the Mobile app, or you want to use your own Notifications infrastructure then you have to install a private [https://github.com/airnotifier/airnotifier AirNotifier] (backend server for notifciations)&lt;br /&gt;
&lt;br /&gt;
You have to add your app certificates there, see https://github.com/airnotifier/airnotifier/wiki/Installation&lt;br /&gt;
&lt;br /&gt;
The message AirNotifier plugin allow you to point to your custom AirNotifier instance using your own access keys&lt;br /&gt;
&lt;br /&gt;
Remember to install using GIT (branch moodle)&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
[[Category: Mobile]]&lt;br /&gt;
&lt;br /&gt;
[[es:Mobile app Notificaciones Push]]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=97459</id>
		<title>Användare:Dongsheng Cai</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=97459"/>
		<updated>2012-05-03T12:31:53Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I am Dongsheng Cai, moodle core developer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
My works:&lt;br /&gt;
&lt;br /&gt;
* [http://tracker.moodle.org/secure/ViewProfile.jspa?name=dongsheng Tracker]&lt;br /&gt;
* [[Chats|Chat module]]&lt;br /&gt;
* [[Development:Repository_API|Moodle Repository API]]&lt;br /&gt;
* [[Development:Comments_2.0|Comments 2.0]]&lt;br /&gt;
* [[Development:Wiki_2.0|Wiki 2]] contributor&lt;br /&gt;
* [[Development:Mobile app|Moodle mobile app for iOS]]&lt;br /&gt;
&lt;br /&gt;
More:&lt;br /&gt;
* [http://www.ohloh.net/accounts/cai  Ohloh]&lt;br /&gt;
* [http://github.com/dongsheng My Github]&lt;br /&gt;
* [http://www.linkedin.com/in/dongsheng Linkedin]&lt;br /&gt;
* [http://dongsheng.org My website]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=97458</id>
		<title>Användare:Dongsheng Cai</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=97458"/>
		<updated>2012-05-03T12:29:30Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I am Dongsheng Cai, moodle core developer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
My works:&lt;br /&gt;
&lt;br /&gt;
* [[Chats|Chat module]]&lt;br /&gt;
* [[Development:Repository_API|Moodle Repository API]]&lt;br /&gt;
* [[Development:Comments_2.0|Comments 2.0]]&lt;br /&gt;
* [[Development:Wiki_2.0|Wiki 2]] contributor&lt;br /&gt;
* [[Development:Mobile app|Moodle mobile app for iOS]]&lt;br /&gt;
&lt;br /&gt;
More:&lt;br /&gt;
* [http://www.ohloh.net/accounts/cai  Ohloh]&lt;br /&gt;
* [http://github.com/dongsheng My Github]&lt;br /&gt;
* [http://www.linkedin.com/in/dongsheng Linkedin]&lt;br /&gt;
* [http://dongsheng.org My website]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=97457</id>
		<title>Användare:Dongsheng Cai</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=97457"/>
		<updated>2012-05-03T12:27:59Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I am Dongsheng Cai, moodle core developer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
My works:&lt;br /&gt;
&lt;br /&gt;
* [[Chats|Chat module]]&lt;br /&gt;
* [[Development:Repository_API|Moodle Repository API]]&lt;br /&gt;
* [[Development:Comments_2.0|Comments 2.0]]&lt;br /&gt;
* [[Development:Wiki_2.0|Wiki 2]] contributor&lt;br /&gt;
* [[Development:Mobile app|Moodle mobile app for iOS]]&lt;br /&gt;
&lt;br /&gt;
More:&lt;br /&gt;
* [http://www.ohloh.net/accounts/cai  Ohloh]&lt;br /&gt;
* [http://github.com/dongsheng My Github]&lt;br /&gt;
* [http://www.linkedin.com/in/dongshengc Linkedin]&lt;br /&gt;
* [http://dongsheng.org My website]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=97456</id>
		<title>Användare:Dongsheng Cai</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=97456"/>
		<updated>2012-05-03T12:27:32Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I am a Moodle developer working at [http://moodle.com/hq/ Moodle HQ]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
My works:&lt;br /&gt;
&lt;br /&gt;
* [[Chats|Chat module]]&lt;br /&gt;
* [[Development:Repository_API|Moodle Repository API]]&lt;br /&gt;
* [[Development:Comments_2.0|Comments 2.0]]&lt;br /&gt;
* [[Development:Wiki_2.0|Wiki 2]] contributor&lt;br /&gt;
* [[Development:Mobile app|Moodle mobile app for iOS]]&lt;br /&gt;
&lt;br /&gt;
More:&lt;br /&gt;
* [http://www.ohloh.net/accounts/cai  Ohloh]&lt;br /&gt;
* [http://github.com/dongsheng My Github]&lt;br /&gt;
* [http://www.linkedin.com/in/dongshengc Linkedin]&lt;br /&gt;
* [http://dongsheng.org My website]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=83210</id>
		<title>Användare:Dongsheng Cai</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=83210"/>
		<updated>2011-05-04T12:50:01Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I am a Moodle developer working at [http://moodle.com/hq/ Moodle HQ]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
My main works with Moodle:&lt;br /&gt;
&lt;br /&gt;
* [[Chats|Chat module]]&lt;br /&gt;
* [[Development:Repository_API|Moodle Repository API]]&lt;br /&gt;
* [[Development:Comments_2.0|Comments 2.0]]&lt;br /&gt;
* [[Development:Wiki_2.0|Wiki 2]] contributor&lt;br /&gt;
* [[Development:Mobile app|Moodle mobile app for iOS]]&lt;br /&gt;
&lt;br /&gt;
More:&lt;br /&gt;
* [http://www.ohloh.net/accounts/cai  Ohloh]&lt;br /&gt;
* [http://github.com/dongsheng My Github]&lt;br /&gt;
* [http://www.linkedin.com/in/dongshengc Linkedin]&lt;br /&gt;
* [http://dongsheng.org My website]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Comments_2.0&amp;diff=83209</id>
		<title>Comments 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Comments_2.0&amp;diff=83209"/>
		<updated>2011-05-04T12:14:29Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: /* Moodle modules callback */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}==Objectives==&lt;br /&gt;
&lt;br /&gt;
The goals of comments 2.0:&lt;br /&gt;
&lt;br /&gt;
* Manage comments centrally&lt;br /&gt;
* Use a consistent approach for all comments throughout Moodle&lt;br /&gt;
* Easily integrate comments 2.0 with existing modules&lt;br /&gt;
* Works no matter Javascript is enabled or not&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The comments 2.0 provides APIs to:&lt;br /&gt;
# Add comments&lt;br /&gt;
# Manage comments&lt;br /&gt;
# Delete comments&lt;br /&gt;
&lt;br /&gt;
And provides a fancy ajax interface to add/delete comments without loading a new page.&lt;br /&gt;
&lt;br /&gt;
==Comments database table==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Default&lt;br /&gt;
! Info&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| int(10)&lt;br /&gt;
| auto-incrementing&lt;br /&gt;
| The unique ID for this comment.&lt;br /&gt;
|-&lt;br /&gt;
| userid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| who wrote this comment&lt;br /&gt;
|-&lt;br /&gt;
| contextid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| The context id defined in context table - identifies the instance of plugin owning the comment.&lt;br /&gt;
|-&lt;br /&gt;
| itemid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| Some plugin specific item id (eg. forum post, blog entry or assignment submission)&lt;br /&gt;
|-&lt;br /&gt;
| commentarea&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| for example, in user profile, you can comment user&#039;s description or interests, but they share the same itemid(==userid), we need comment_area to separate them&lt;br /&gt;
|-&lt;br /&gt;
| timecreated&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| timemodified&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| content&lt;br /&gt;
| text&lt;br /&gt;
|&lt;br /&gt;
| content of comment&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Use Comments API==&lt;br /&gt;
&lt;br /&gt;
===Add an option to format_text function===&lt;br /&gt;
&lt;br /&gt;
Using this format_text function will add a comment icon automatically at the end of the text:&lt;br /&gt;
&lt;br /&gt;
For example, using the following code in the forum module will add a comment icon to every post:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$to = new stdclass;&lt;br /&gt;
$cmt-&amp;gt;contextid = $modcontext-&amp;gt;id;&lt;br /&gt;
$cmt-&amp;gt;area      = &#039;format_post&#039;;&lt;br /&gt;
$cmt-&amp;gt;itemid    = $post-&amp;gt;id;&lt;br /&gt;
$options-&amp;gt;comments = $cmt;&lt;br /&gt;
echo format_text($post-&amp;gt;message, $post-&amp;gt;messageformat, $options, $course-&amp;gt;id).&amp;quot;&amp;lt;hr /&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Use comment class===&lt;br /&gt;
To use Comments API elsewhere, using following code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$options-&amp;gt;area    = &#039;database_entry&#039;;&lt;br /&gt;
$options-&amp;gt;context = $context;&lt;br /&gt;
$options-&amp;gt;itemid  = $record-&amp;gt;id;&lt;br /&gt;
$options-&amp;gt;showcount = true;&lt;br /&gt;
$comment = new comment($options);&lt;br /&gt;
$comment-&amp;gt;output(false);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If you are using comments API in module context, you&#039;d better add pluginname option, it will help comments API find callback functions faster:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$options-&amp;gt;area    = &#039;database_entry&#039;;&lt;br /&gt;
$options-&amp;gt;pluginname = &#039;data&#039;;&lt;br /&gt;
$options-&amp;gt;context = $context;&lt;br /&gt;
$options-&amp;gt;itemid  = $record-&amp;gt;id;&lt;br /&gt;
$options-&amp;gt;component = &#039;mod_data&#039;;&lt;br /&gt;
$options-&amp;gt;showcount = true;&lt;br /&gt;
$comment = new comment($options);&lt;br /&gt;
$comment-&amp;gt;output(false);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==Comments API overview==&lt;br /&gt;
&lt;br /&gt;
Generally speaking, only two functions you need to know to get comments 2.0 worked:&lt;br /&gt;
# Use comment::init to initialize comments 2.0&lt;br /&gt;
# Use $comment-&amp;gt;output to display comments&lt;br /&gt;
&lt;br /&gt;
The comment class has been implemented in comment/lib.php.&lt;br /&gt;
===class comment()===&lt;br /&gt;
====__construct($contextid, $comment_area, $itemid))====&lt;br /&gt;
Initialize class members&lt;br /&gt;
&lt;br /&gt;
====init()====&lt;br /&gt;
It is a static function used to initialize comments, setting up languages, which must be called before html head printed&lt;br /&gt;
&lt;br /&gt;
====output($return = false)====&lt;br /&gt;
Will print the html snippet for commenting interface, if set $return as true, it will return html string instead of printing out.&lt;br /&gt;
&lt;br /&gt;
====print_comments($params = array())====&lt;br /&gt;
Used by non-javascript comment interface, will print a list of comments.&lt;br /&gt;
&lt;br /&gt;
====add($content)====&lt;br /&gt;
Public instance funciton, add a comment to database, used in comment/comment_ajax.php&lt;br /&gt;
&lt;br /&gt;
====count()====&lt;br /&gt;
Counting the number of comments&lt;br /&gt;
&lt;br /&gt;
====delete($id)====&lt;br /&gt;
Delete a comment from database, used in comment/comment_ajax.php&lt;br /&gt;
&lt;br /&gt;
====delete_comments====&lt;br /&gt;
Delete all comments in a specific contexts (like all comments belonging to a forum post)&lt;br /&gt;
&lt;br /&gt;
==Javascript API==&lt;br /&gt;
Comments 2.0 implemented a YUI3 module M.core_comment to deal with the communication between browsers and moodle.&lt;br /&gt;
It can be found in comment/comment.js&lt;br /&gt;
&lt;br /&gt;
Call M.core_comment.init will create an instance of CommentHelper class. You don&#039;t need to make any calls to this instance, it simply works out of box.&lt;br /&gt;
&lt;br /&gt;
== Moodle modules callback ==&lt;br /&gt;
Comments API allows modules/blocks/blog to decide how comments display.&lt;br /&gt;
&lt;br /&gt;
=== Data validation ===&lt;br /&gt;
Plugins must implement pluginname_comment_validate callback to validate comments parameters, it must return true to pass validation.&lt;br /&gt;
&lt;br /&gt;
===Permission control===&lt;br /&gt;
Modules must implement function &#039;&#039;&#039;pluginname_comment_permissions&#039;&#039;&#039; to return post and view permission.&lt;br /&gt;
&lt;br /&gt;
Blocks need to overwrite &#039;&#039;&#039;blockname_comment_permissions&#039;&#039;&#039; function of block_base.&lt;br /&gt;
&lt;br /&gt;
Blog need to implement &#039;&#039;&#039;blog_comment_permissions&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
This function will return an array: array(&#039;post&#039;=&amp;gt;true, &#039;view&#039;=&amp;gt;true)&lt;br /&gt;
&lt;br /&gt;
=== Check new added comment ===&lt;br /&gt;
The callback function allows you to change the comment content before inserting into database or reject this comment.&lt;br /&gt;
&lt;br /&gt;
It takes two arguments, the comment object which contains comment details, and $params which contains context and course information.&lt;br /&gt;
&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;modname_comment_add&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Blocks need to overwrite &#039;&#039;&#039;blockname_comment_add&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
Blog need to implement &#039;&#039;&#039;blog_comment_add&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
This function should return a boolean value. &lt;br /&gt;
&lt;br /&gt;
=== Filter/format comments ===&lt;br /&gt;
This callback allows modules check/format comments when user request to display comments.&lt;br /&gt;
&lt;br /&gt;
It takes the same arguments as pluginname_comment_add&lt;br /&gt;
&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;pluginname_comment_display&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Blocks need to overwrite &#039;&#039;&#039;blockname_comment_display&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
Blog need to implement &#039;&#039;&#039;blog_comment_display&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
It will return the comment object.&lt;br /&gt;
&lt;br /&gt;
=== Define a comment template ===&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;pluginname_comment_template&#039;&#039;&#039;, which allow modules define a comment template.&lt;br /&gt;
The template must have 4 embedding variables, ___id___, ___content___, ___time___, ___name___, they will be replaced with html id, comments content, comment time and commenter name&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* MDL-19118 - Comments 2.0 issue&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=URL_downloader_repository&amp;diff=83186</id>
		<title>URL downloader repository</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=URL_downloader_repository&amp;diff=83186"/>
		<updated>2011-05-03T03:34:46Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: Created page with &amp;quot;URL Downloader plugin is used to obtain resources by providing a url to webpage or file.  If user provides a html web page, Moodle will parse the web page to list all images used...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;URL Downloader plugin is used to obtain resources by providing a url to webpage or file.&lt;br /&gt;
&lt;br /&gt;
If user provides a html web page, Moodle will parse the web page to list all images used in web page.&lt;br /&gt;
&lt;br /&gt;
If user provides a link to file, Moodle will try to download this file no matter what type it is.&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Broken/id:11387&amp;diff=83071</id>
		<title>Broken/id:11387</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Broken/id:11387&amp;diff=83071"/>
		<updated>2011-04-28T06:51:47Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: /* Upload and download files from moodle */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I&#039;d love to see the ability for students to take quizzes be included in a 1.0 mobile app.  Comparative LMS (BB) have not yet achieved this with their own Mobile apps and it would be a boon for mobile learning (or learning utilizing tablet devices).&lt;br /&gt;
&lt;br /&gt;
== Timeframe? ==&lt;br /&gt;
&lt;br /&gt;
Do we have even a ballpark estimate for when this might be available? A year would be sufficient :)&lt;br /&gt;
&lt;br /&gt;
Looks great btw :)&lt;br /&gt;
&lt;br /&gt;
==Obtain web service token==&lt;br /&gt;
In Moodle Mobile apps or other web service clients, we need a secure method to transmit token.&lt;br /&gt;
&lt;br /&gt;
* The easiest way would be using https for token request script, user enter username and password, send them to HTTPS protected script to obtain the token, the disadvantage of this method is the limit of HTTP server, for some shared hosts, HTTPS is not available.&lt;br /&gt;
* I looked OAuth, it&#039;s getting popular, and secure. But it has a few disadvantage:&lt;br /&gt;
# Moodle for iPhone will support multi Moodle instances, so we have to save api and secret for each website, it&#039;s very annoying for mobile users to type such long keys&lt;br /&gt;
# The major problem is OAuth will need two keys: access key and access secret during transmission, then generate a signature using a few factors, the signature will embedded in http header, moodle will need to verify this signature. It looks like another security layer besides web service subsystem, if we only use it for obtaining web service token, I am not sure if worth to use it, we will have to implement OAuth server, and a few scripts to handle access keys exchange, and  database tables including oauth_log, oauth_consumer (store consumer key and secret), consumer_token, access token(store access key) we need at least three new tables, probably another two to store nonce and activity logs.&lt;br /&gt;
* RSA algorithm can be alternative method of HTTPS, before we add a website in moodle app, we request the public key from the website, encrypt the username, password and user secret by public key, then send them to server, moodle will decrypt it by private key, if success, encrypt the key by the user secret (use 3DES or AES), 1024-2048 bits public key is considered to be safe, but it could be slow for mobile device because of the long key. ECC algorithm use shorter key and strong, but it&#039;s more difficult to implement.&lt;br /&gt;
&lt;br /&gt;
My proposal would be the combination of HTTPS and RSA.&lt;br /&gt;
&lt;br /&gt;
It&#039;s related to http://tracker.moodle.org/browse/MOBILE-14&lt;br /&gt;
&lt;br /&gt;
--[[User:Dongsheng Cai|Dongsheng Cai]] 11:08, 20 April 2011 (WST)&lt;br /&gt;
&lt;br /&gt;
==Upload and download files from moodle==&lt;br /&gt;
We already implemented &amp;quot;upload&amp;quot; web service, which only allow users to upload files to user private, the problem is we need to use base64 encoding binary file so it can fit into xml payload, it theoretically  works, but in the real world, if we pick a file from iphone photo library, it&#039;s usually around 1.2Mb, encoding will enlarge the file by 33%, not too bad, but encoding the picture will take more than a minute, it&#039;s very bad user experience.&lt;br /&gt;
&lt;br /&gt;
For better performance, we&#039;d better use POST and GET the upload and download files, then we need to setup session, what we need to do:&lt;br /&gt;
# Assume user already got token, then user send token and file to a special script in Moodle, for example http://yourmoodle.com/files/ws_upload.php Moodle verify the token, if true, setup session, check permission, then allow uploading&lt;br /&gt;
# If users intend to download a moodle file served by pluginfile.php, first users request a special script with token, if token is valid, grant the session, then users will be able to access the files served by pluginfile.php, we need to http request in this case, if we can verify the token in pluginfile.php to reduce the http traffic, I&#039;m not sure if it&#039;s acceptable.&lt;br /&gt;
&lt;br /&gt;
It&#039;s related to http://tracker.moodle.org/browse/MOBILE-19&lt;br /&gt;
&lt;br /&gt;
--[[User:Dongsheng Cai|Dongsheng Cai]] 11:08, 20 April 2011 (WST)&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Broken/id:11387&amp;diff=82899</id>
		<title>Broken/id:11387</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Broken/id:11387&amp;diff=82899"/>
		<updated>2011-04-20T03:18:51Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I&#039;d love to see the ability for students to take quizzes be included in a 1.0 mobile app.  Comparative LMS (BB) have not yet achieved this with their own Mobile apps and it would be a boon for mobile learning (or learning utilizing tablet devices).&lt;br /&gt;
&lt;br /&gt;
== Timeframe? ==&lt;br /&gt;
&lt;br /&gt;
Do we have even a ballpark estimate for when this might be available? A year would be sufficient :)&lt;br /&gt;
&lt;br /&gt;
Looks great btw :)&lt;br /&gt;
&lt;br /&gt;
==Obtain web service token==&lt;br /&gt;
In Moodle Mobile apps or other web service clients, we need a secure method to transmit token.&lt;br /&gt;
&lt;br /&gt;
* The easiest way would be using https for token request script, user enter username and password, send them to HTTPS protected script to obtain the token, the disadvantage of this method is the limit of HTTP server, for some shared hosts, HTTPS is not available.&lt;br /&gt;
* I looked OAuth, it&#039;s getting popular, and secure. But it has a few disadvantage:&lt;br /&gt;
# Moodle for iPhone will support multi Moodle instances, so we have to save api and secret for each website, it&#039;s very annoying for mobile users to type such long keys&lt;br /&gt;
# The major problem is OAuth will need two keys: access key and access secret during transmission, then generate a signature using a few factors, the signature will embedded in http header, moodle will need to verify this signature. It looks like another security layer besides web service subsystem, if we only use it for obtaining web service token, I am not sure if worth to use it, we will have to implement OAuth server, and a few scripts to handle access keys exchange, and  database tables including oauth_log, oauth_consumer (store consumer key and secret), consumer_token, access token(store access key) we need at least three new tables, probably another two to store nonce and activity logs.&lt;br /&gt;
* RSA algorithm can be alternative method of HTTPS, before we add a website in moodle app, we request the public key from the website, encrypt the username, password and user secret by public key, then send them to server, moodle will decrypt it by private key, if success, encrypt the key by the user secret (use 3DES or AES), 1024-2048 bits public key is considered to be safe, but it could be slow for mobile device because of the long key. ECC algorithm use shorter key and strong, but it&#039;s more difficult to implement.&lt;br /&gt;
&lt;br /&gt;
My proposal would be the combination of HTTPS and RSA.&lt;br /&gt;
&lt;br /&gt;
It&#039;s related to http://tracker.moodle.org/browse/MOBILE-14&lt;br /&gt;
&lt;br /&gt;
--[[User:Dongsheng Cai|Dongsheng Cai]] 11:08, 20 April 2011 (WST)&lt;br /&gt;
&lt;br /&gt;
==Upload and download files from moodle==&lt;br /&gt;
We already implemented &amp;quot;upload&amp;quot; web service, which only allow users to upload files to user private, the problem is we need to use base64 encoding binary file so it can fit into xml payload, it theoretically  works, but in the real world, if we pick a file from iphone photo library, it&#039;s usually around 1.2Mb, encoding will enlarge the file by 33%, not bad, but encoding the picture will take more than a minute, it&#039;s very bad user experience.&lt;br /&gt;
&lt;br /&gt;
For better performance, we&#039;d better use POST and GET the upload and download files, then we need to setup session, what we need to do:&lt;br /&gt;
# Assume user already got token, then user send token and file to a special script in Moodle, for example http://yourmoodle.com/files/ws_upload.php Moodle verify the token, if true, setup session, check permission, then allow uploading&lt;br /&gt;
# If users intend to download a moodle file served by pluginfile.php, first users request a special script with token, if token is valid, grant the session, then users will be able to access the files served by pluginfile.php, we need to http request in this case, if we can verify the token in pluginfile.php to reduce the http traffic, I&#039;m not sure if it&#039;s acceptable.&lt;br /&gt;
&lt;br /&gt;
It&#039;s related to http://tracker.moodle.org/browse/MOBILE-19&lt;br /&gt;
&lt;br /&gt;
--[[User:Dongsheng Cai|Dongsheng Cai]] 11:08, 20 April 2011 (WST)&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=82898</id>
		<title>Användare:Dongsheng Cai</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=82898"/>
		<updated>2011-04-20T03:10:41Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I am a Moodle developer working at [http://moodle.com/hq/ Moodle HQ]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
My main works with Moodle:&lt;br /&gt;
&lt;br /&gt;
* [[Chats|Chat module]]&lt;br /&gt;
* [[Development:Repository_API|Moodle Repository API]]&lt;br /&gt;
* [[Development:Comments_2.0|Comments 2.0]]&lt;br /&gt;
* Wiki 2 contributor&lt;br /&gt;
* Moodle mobile&lt;br /&gt;
&lt;br /&gt;
More:&lt;br /&gt;
* [http://www.ohloh.net/accounts/cai  Ohloh]&lt;br /&gt;
* [http://github.com/dongsheng My Github]&lt;br /&gt;
* [http://au.linkedin.com/in/dongshengc Linkedin]&lt;br /&gt;
* [http://dongsheng.org My website (in chinese)]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Broken/id:11387&amp;diff=82897</id>
		<title>Broken/id:11387</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Broken/id:11387&amp;diff=82897"/>
		<updated>2011-04-20T03:08:12Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: /* Moodle for iPhone */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I&#039;d love to see the ability for students to take quizzes be included in a 1.0 mobile app.  Comparative LMS (BB) have not yet achieved this with their own Mobile apps and it would be a boon for mobile learning (or learning utilizing tablet devices).&lt;br /&gt;
&lt;br /&gt;
== Timeframe? ==&lt;br /&gt;
&lt;br /&gt;
Do we have even a ballpark estimate for when this might be available? A year would be sufficient :)&lt;br /&gt;
&lt;br /&gt;
Looks great btw :)&lt;br /&gt;
&lt;br /&gt;
==Obtain web service token==&lt;br /&gt;
In Moodle Mobile apps or other web service clients, we need a secure method to transmit token.&lt;br /&gt;
&lt;br /&gt;
* The easiest way would be using https for token request script, user enter username and password, send them to HTTPS protected script to obtain the token, the disadvantage of this method is the limit of HTTP server, for some shared hosts, HTTPS is not available.&lt;br /&gt;
* I looked OAuth, it&#039;s getting popular, and secure. But it has a few disadvantage:&lt;br /&gt;
# Moodle for iPhone will support multi Moodle instances, so we have to save api and secret for each website, it&#039;s very annoying for mobile users to type such long keys&lt;br /&gt;
# The major problem is OAuth will need two keys: access key and access secret during transmission, then generate a signature using a few factors, the signature will embedded in http header, moodle will need to verify this signature. It looks like another security layer besides web service subsystem, if we only use it for obtaining web service token, I am not sure if worth to use it, we will have to implement OAuth server, and a few scripts to handle access keys exchange, and  database tables including oauth_log, oauth_consumer (store consumer key and secret), consumer_token, access token(store access key) we need at least three new tables, probably another two to store nonce and activity logs.&lt;br /&gt;
* RSA algorithm can be alternative method of HTTPS, before we add a website in moodle app, we request the public key from the website, encrypt the username, password and user secret by public key, then send them to server, moodle will decrypt it by private key, if success, encrypt the key by the user secret (use 3DES or AES), 1024-2048 bits public key is considered to be safe, but it could be slow for mobile device because of the long key. ECC algorithm use shorter key and strong, but it&#039;s more difficult to implement.&lt;br /&gt;
&lt;br /&gt;
My proposal would be the combination of HTTPS and RSA.&lt;br /&gt;
&lt;br /&gt;
--[[User:Dongsheng Cai|Dongsheng Cai]] 11:08, 20 April 2011 (WST)&lt;br /&gt;
&lt;br /&gt;
==Upload and download files from moodle==&lt;br /&gt;
We already implemented &amp;quot;upload&amp;quot; web service, which only allow users to upload files to user private, the problem is we need to use base64 encoding binary file so it can fit into xml payload, it theoretically  works, but in the real world, if we pick a file from iphone photo library, it&#039;s usually around 1.2Mb, encoding will enlarge the file by 33%, not bad, but encoding the picture will take more than a minute, it&#039;s very bad user experience. &lt;br /&gt;
&lt;br /&gt;
For better performance, we&#039;d better use POST and GET the upload and download files, then we need to setup session, what we need to do:&lt;br /&gt;
# Assume user already got token, then user send token and file to a special script in Moodle, for example http://yourmoodle.com/files/ws_upload.php Moodle verify the token, if true, setup session, check permission, then allow uploading&lt;br /&gt;
# If users intend to download a moodle file served by pluginfile.php, first users request a special script with token, if token is valid, grant the session, then users will be able to access the files served by pluginfile.php, we need to http request in this case, if we can verify the token in pluginfile.php to reduce the http traffic, I&#039;m not sure if it&#039;s acceptable.&lt;br /&gt;
&lt;br /&gt;
--[[User:Dongsheng Cai|Dongsheng Cai]] 11:08, 20 April 2011 (WST)&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Dropbox_repository&amp;diff=82683</id>
		<title>Dropbox repository</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Dropbox_repository&amp;diff=82683"/>
		<updated>2011-04-10T03:34:39Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
A Dropbox repository can be enabled by an administrator in &#039;&#039;Site administration &amp;gt; Modules &amp;gt; Repositories &amp;gt; Manage repositories&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Sign up app keys at dropbox==&lt;br /&gt;
&lt;br /&gt;
# Go to https://www.dropbox.com/developers/apps&lt;br /&gt;
# Create an app, you must change app status to Production&lt;br /&gt;
# Copy the app keys&lt;br /&gt;
&lt;br /&gt;
==Configuration==&lt;br /&gt;
Once enabled by the administrator a Dropbox API Key and Secret will need to be added to the Dropbox settings in order for it to work.  This will be &#039;&#039;the&#039;&#039; Dropbox available to all users throughout the site (and each will need the correct Dropbox login credentials to access it from their courses).  To gather the Dropbox API Key and Secret click the &amp;quot;Dropbox Developers&amp;quot; link on the Dropbox repository settings page.  On the next page you&#039;ll be prompted to login with your Dropbox username and password and to create a Dropbox app.  &lt;br /&gt;
&lt;br /&gt;
Once the App has been created at Dropbox.com you&#039;ll have the API Secret and Key available at the bottom of the App page.  Entering those on the Dropbox settings page (and clicking Save) back in Moodle will finish the configuration.  Dropbox is now available to the entire site.  &lt;br /&gt;
&lt;br /&gt;
To access it editing teachers need only &amp;quot;Add...&amp;quot; a new file while editing or creating a resource to see Dropbox as a new option.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [http://www.youtube.com/watch?v=V221JLCywWs Import files from Dropbox into Moodle 2.0 video]&lt;br /&gt;
* MDL-19168&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
[[de:Dropbox]]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Blocks_2.0.3_UI&amp;diff=82645</id>
		<title>Blocks 2.0.3 UI</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Blocks_2.0.3_UI&amp;diff=82645"/>
		<updated>2011-04-08T07:15:05Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page specs some refinements to the blocks config UI for Moodle 2.0.3.  See MDL-26105 for details.&lt;br /&gt;
&lt;br /&gt;
==Home context==&lt;br /&gt;
&lt;br /&gt;
Indicate where the &amp;quot;home&amp;quot; context is for this block.  The place it was created.&lt;br /&gt;
&lt;br /&gt;
==Reduce page types==&lt;br /&gt;
&lt;br /&gt;
Reduce the number of page type options using a callback so that all components can exactly specify what they support.  If the component doesn&#039;t have a callback then fallback to the calculated list we have now.&lt;br /&gt;
&lt;br /&gt;
==Sub-page types==&lt;br /&gt;
&lt;br /&gt;
Instead of showing &amp;quot;This specific page (Page 13)&amp;quot; (the sub page id)&lt;br /&gt;
* Remove the &amp;quot;Page 13&amp;quot; completely&lt;br /&gt;
* Make the navbar show the page name:  Sitename -&amp;gt; Site pages -&amp;gt; Tags -&amp;gt; My funky tag -&amp;gt; XXX Block -&amp;gt; Configuration&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==User blocks==&lt;br /&gt;
&lt;br /&gt;
Blocks created on user pages ie the My Moodle page or profile pages (including those that were copied from the default blocks the first time the user tries to customise the page) just need to show the page types menu to select between:&lt;br /&gt;
&lt;br /&gt;
* Public user profile page (user-profile)&lt;br /&gt;
* Private &amp;quot;My Moodle&amp;quot; page (my-index)&lt;br /&gt;
* All pages (*)&lt;br /&gt;
&lt;br /&gt;
Sub page type option should be hidden too, because it always being applied in user context.&lt;br /&gt;
&lt;br /&gt;
This list will come from a callback function in /user/lib.php&lt;br /&gt;
&lt;br /&gt;
==Module blocks==&lt;br /&gt;
Blocks should looking for page pattern from module callback which comes from /mod/$mod/lib.php&lt;br /&gt;
&lt;br /&gt;
Blocks&#039; page types should be limited to module context only, module will decide what types will be available. Some blocks are created at course level, and allowed to be displayed at the child contexts of course context, in this case, context selection should be kept. The original page type pattern should be kept as well.&lt;br /&gt;
&lt;br /&gt;
Blocks&#039; page contexts options should be module context only, there are no children contexts in modules.&lt;br /&gt;
&lt;br /&gt;
==Course blocks==&lt;br /&gt;
Blocks added in course level can be displayed on module context, in this case , we don&#039;t need to display context options, page type pattern will override the context options.&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Mobile_Open_Auth&amp;diff=82592</id>
		<title>Mobile Open Auth</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Mobile_Open_Auth&amp;diff=82592"/>
		<updated>2011-04-06T12:28:19Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Use case =&lt;br /&gt;
# the user launch the APP&lt;br /&gt;
# the user  goes to settings&lt;br /&gt;
# the user add a site&lt;br /&gt;
# the user enter site url, website consumer key and website consumer secret&lt;br /&gt;
# the user is redirected to Moodle login page (an inside browser)&lt;br /&gt;
# the user login Moodle. Moodle displays a &#039;authentication requested by NAME_OF_THE_APP&#039; button&lt;br /&gt;
# the user accepts and Moodle sends (displays ?) a Mobile ws token to the APP&lt;br /&gt;
# the APP tests the connection&lt;br /&gt;
&lt;br /&gt;
= Technical specifciation =&lt;br /&gt;
A simple intro of how OAuth works, let&#039;s say moodle mobile app is a oauth client, moodle website as oauth server.&lt;br /&gt;
# oauth client needs consumer key and consumer secret to initiate an oauth session&lt;br /&gt;
# oauth client create signature by HMAC-SHA1 using consumer secret, consumer key, timestamp, nonce, callback, sending signature along with these parameters(except secret) to oauth server, then you got oauth token, oauth token secret&lt;br /&gt;
# oauth client open authorize_url (using oauth token as parameter), leave oauth token secret in client, click &#039;approve&#039; button in authorize_url&lt;br /&gt;
# oauth server will direct you to your callback url, The callback request informs the client that user completed the authorization process&lt;br /&gt;
# Now use oauth token and oauth token secret to request access key (need to generate a new signature), store access key and access secret in oauth client, this is the final credentials you need for request protected resource, it need to be included in http header and the signature need to be updated as well.&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Wiki_2.0.3_Files&amp;diff=82214</id>
		<title>Wiki 2.0.3 Files</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Wiki_2.0.3_Files&amp;diff=82214"/>
		<updated>2011-03-24T03:30:45Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: New page: This page specs for cleaning up file handling in wiki 2.  See MDL-26739 for details.  ==File management page== Create a new tab in wiki main page, named &amp;quot;Files&amp;quot;, the Files page will displa...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page specs for cleaning up file handling in wiki 2.  See MDL-26739 for details.&lt;br /&gt;
&lt;br /&gt;
==File management page==&lt;br /&gt;
Create a new tab in wiki main page, named &amp;quot;Files&amp;quot;, the Files page will display all files shared in current wiki instance. Users with manage files capability will see &amp;quot;Manage files&amp;quot; button under the files tree view, click the button will take users to moodle file manager.&lt;br /&gt;
[[Image:Wiki_Files_Tab.jpg]]&lt;br /&gt;
&lt;br /&gt;
==Wiki editors==&lt;br /&gt;
&lt;br /&gt;
Nwiki and creole wiki editors will have a new select to choose existing files from shared area. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Wiki_Editor.jpg]]&lt;br /&gt;
&lt;br /&gt;
==File handling==&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Fil:Wiki_Editor.jpg&amp;diff=82213</id>
		<title>Fil:Wiki Editor.jpg</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Fil:Wiki_Editor.jpg&amp;diff=82213"/>
		<updated>2011-03-24T03:29:45Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Fil:Wiki_Files_Tab.jpg&amp;diff=82212</id>
		<title>Fil:Wiki Files Tab.jpg</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Fil:Wiki_Files_Tab.jpg&amp;diff=82212"/>
		<updated>2011-03-24T03:20:32Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Blocks_2.0.3_UI&amp;diff=82135</id>
		<title>Blocks 2.0.3 UI</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Blocks_2.0.3_UI&amp;diff=82135"/>
		<updated>2011-03-21T10:12:32Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page specs some refinements to the blocks config UI for Moodle 2.0.3.  See MDL-26105 for details.&lt;br /&gt;
&lt;br /&gt;
==Home context==&lt;br /&gt;
&lt;br /&gt;
Indicate where the &amp;quot;home&amp;quot; context is for this block.  The place it was created.&lt;br /&gt;
&lt;br /&gt;
==Reduce page types==&lt;br /&gt;
&lt;br /&gt;
Reduce the number of page type options using a callback so that all components can exactly specify what they support.  If the component doesn&#039;t have a callback then fallback to the calculated list we have now.&lt;br /&gt;
&lt;br /&gt;
==Upgrade block_instances-&amp;gt;page_patterns==&lt;br /&gt;
&lt;br /&gt;
All of the existing instances need to be upgraded to remove any settings that are no longer appearing in the UI.  This will have to be implemented with an upgrade block in each module, added at the same time as the callback.&lt;br /&gt;
&lt;br /&gt;
==Sub-page types==&lt;br /&gt;
&lt;br /&gt;
Instead of showing &amp;quot;This specific page (Page 13)&amp;quot; (the sub page id)&lt;br /&gt;
* Remove the &amp;quot;Page 13&amp;quot; completely&lt;br /&gt;
* Make the navbar show the page name:  Sitename -&amp;gt; Site pages -&amp;gt; Tags -&amp;gt; My funky tag -&amp;gt; XXX Block -&amp;gt; Configuration&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==User blocks==&lt;br /&gt;
&lt;br /&gt;
Blocks created on user pages ie the My Moodle page or profile pages (including those that were copied from the default blocks the first time the user tries to customise the page) just need to show the page types menu to select between:&lt;br /&gt;
&lt;br /&gt;
* Public user profile page (user-profile)&lt;br /&gt;
* Private &amp;quot;My Moodle&amp;quot; page (my-index)&lt;br /&gt;
* All pages (*)&lt;br /&gt;
&lt;br /&gt;
Sub page type option should be hidden too, because it always being applied in user context.&lt;br /&gt;
&lt;br /&gt;
This list will come from a callback function in /user/lib.php&lt;br /&gt;
&lt;br /&gt;
==Module blocks==&lt;br /&gt;
Blocks should looking for page pattern from module callback which comes from /mod/$mod/lib.php&lt;br /&gt;
&lt;br /&gt;
Blocks&#039; page types should be limited to module context only, module will decide what types will be available. Some blocks are created at course level, and allowed to be displayed at the child contexts of course context, in this case, context selection should be kept. The original page type pattern should be kept as well.&lt;br /&gt;
&lt;br /&gt;
Blocks&#039; page contexts options should be module context only, there are no children contexts in modules.&lt;br /&gt;
&lt;br /&gt;
==Course blocks==&lt;br /&gt;
Blocks added in course level can be displayed on module context, in this case , we don&#039;t need to display context options, page type pattern will override the context options.&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Blocks_2.0.3_UI&amp;diff=81896</id>
		<title>Blocks 2.0.3 UI</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Blocks_2.0.3_UI&amp;diff=81896"/>
		<updated>2011-03-14T10:15:24Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: /* Module blocks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page specs some refinements to the blocks config UI for Moodle 2.0.3.  See MDL-26105 for details.&lt;br /&gt;
&lt;br /&gt;
==Home context==&lt;br /&gt;
&lt;br /&gt;
Indicate where the &amp;quot;home&amp;quot; context is for this block.  The place it was created.&lt;br /&gt;
&lt;br /&gt;
==Reduce page types==&lt;br /&gt;
&lt;br /&gt;
Reduce the number of page type options using a callback so that all components can exactly specify what they support.  If the component doesn&#039;t have a callback then fallback to the calculated list we have now.&lt;br /&gt;
&lt;br /&gt;
==Upgrade block_instances-&amp;gt;page_patterns==&lt;br /&gt;
&lt;br /&gt;
All of the existing instances need to be upgraded to remove any settings that are no longer appearing in the UI.  This will have to be implemented with an upgrade block in each module, added at the same time as the callback.&lt;br /&gt;
&lt;br /&gt;
==Sub-page types==&lt;br /&gt;
&lt;br /&gt;
Instead of showing &amp;quot;This specific page (Page 13)&amp;quot; (the sub page id)&lt;br /&gt;
* Remove the &amp;quot;Page 13&amp;quot; completely&lt;br /&gt;
* Make the navbar show the page name:  Sitename -&amp;gt; Site pages -&amp;gt; Tags -&amp;gt; My funky tag -&amp;gt; XXX Block -&amp;gt; Configuration&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==User blocks==&lt;br /&gt;
&lt;br /&gt;
Blocks created on user pages ie the My Moodle page or profile pages (including those that were copied from the default blocks the first time the user tries to customise the page) just need to show the page types menu to select between:&lt;br /&gt;
&lt;br /&gt;
* Public user profile page (user-profile)&lt;br /&gt;
* Private &amp;quot;My Moodle&amp;quot; page (my-index)&lt;br /&gt;
* All pages (*)&lt;br /&gt;
&lt;br /&gt;
This list will come from a callback function in /user/lib.php&lt;br /&gt;
&lt;br /&gt;
==Module blocks==&lt;br /&gt;
Blocks should looking for page pattern from module callback which comes from /mod/$mod/lib.php&lt;br /&gt;
&lt;br /&gt;
Blocks&#039; page types should be limited to module context only, module will decide what types will be available. Some blocks are created at course level, and allowed to be displayed at the child contexts of course context, in this case, context selection should be kept. The original page type pattern should be kept as well.&lt;br /&gt;
&lt;br /&gt;
Blocks&#039; page contexts options should be module context only, there are no children contexts in modules.&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Blocks_2.0.3_UI&amp;diff=81812</id>
		<title>Blocks 2.0.3 UI</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Blocks_2.0.3_UI&amp;diff=81812"/>
		<updated>2011-03-09T02:24:03Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: /* Module blocks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page specs some refinements to the blocks config UI for Moodle 2.0.3.  See MDL-26105 for details.&lt;br /&gt;
&lt;br /&gt;
==Home context==&lt;br /&gt;
&lt;br /&gt;
Indicate where the &amp;quot;home&amp;quot; context is for this block.  The place it was created.&lt;br /&gt;
&lt;br /&gt;
==Reduce page types==&lt;br /&gt;
&lt;br /&gt;
Reduce the number of page type options using a callback so that all components can exactly specify what they support.  If the component doesn&#039;t have a callback then fallback to the calculated list we have now.&lt;br /&gt;
&lt;br /&gt;
==Upgrade block_instances-&amp;gt;page_patterns==&lt;br /&gt;
&lt;br /&gt;
All of the existing instances need to be upgraded to remove any settings that are no longer appearing in the UI.  This will have to be implemented with an upgrade block in each module, added at the same time as the callback.&lt;br /&gt;
&lt;br /&gt;
==Sub-page types==&lt;br /&gt;
&lt;br /&gt;
Instead of showing &amp;quot;This specific page (Page 13)&amp;quot; (the sub page id)&lt;br /&gt;
* Remove the &amp;quot;Page 13&amp;quot; completely&lt;br /&gt;
* Make the navbar show the page name:  Sitename -&amp;gt; Site pages -&amp;gt; Tags -&amp;gt; My funky tag -&amp;gt; XXX Block -&amp;gt; Configuration&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==User blocks==&lt;br /&gt;
&lt;br /&gt;
Blocks created on user pages ie the My Moodle page or profile pages (including those that were copied from the default blocks the first time the user tries to customise the page) just need to show the page types menu to select between:&lt;br /&gt;
&lt;br /&gt;
* Public user profile page (user-profile)&lt;br /&gt;
* Private &amp;quot;My Moodle&amp;quot; page (my-index)&lt;br /&gt;
* All pages (*)&lt;br /&gt;
&lt;br /&gt;
This list will come from a callback function in /user/lib.php&lt;br /&gt;
&lt;br /&gt;
==Module blocks==&lt;br /&gt;
Blocks should looking for page pattern from module callback which comes from /mod/$mod/lib.php&lt;br /&gt;
&lt;br /&gt;
Blocks&#039; page types should be limited to module context only, module will decide what types will be available.&lt;br /&gt;
&lt;br /&gt;
Blocks&#039; page contexts options should be module context only, there are no children contexts in modules.&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Blocks_2.0.3_UI&amp;diff=81811</id>
		<title>Blocks 2.0.3 UI</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Blocks_2.0.3_UI&amp;diff=81811"/>
		<updated>2011-03-09T02:21:28Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page specs some refinements to the blocks config UI for Moodle 2.0.3.  See MDL-26105 for details.&lt;br /&gt;
&lt;br /&gt;
==Home context==&lt;br /&gt;
&lt;br /&gt;
Indicate where the &amp;quot;home&amp;quot; context is for this block.  The place it was created.&lt;br /&gt;
&lt;br /&gt;
==Reduce page types==&lt;br /&gt;
&lt;br /&gt;
Reduce the number of page type options using a callback so that all components can exactly specify what they support.  If the component doesn&#039;t have a callback then fallback to the calculated list we have now.&lt;br /&gt;
&lt;br /&gt;
==Upgrade block_instances-&amp;gt;page_patterns==&lt;br /&gt;
&lt;br /&gt;
All of the existing instances need to be upgraded to remove any settings that are no longer appearing in the UI.  This will have to be implemented with an upgrade block in each module, added at the same time as the callback.&lt;br /&gt;
&lt;br /&gt;
==Sub-page types==&lt;br /&gt;
&lt;br /&gt;
Instead of showing &amp;quot;This specific page (Page 13)&amp;quot; (the sub page id)&lt;br /&gt;
* Remove the &amp;quot;Page 13&amp;quot; completely&lt;br /&gt;
* Make the navbar show the page name:  Sitename -&amp;gt; Site pages -&amp;gt; Tags -&amp;gt; My funky tag -&amp;gt; XXX Block -&amp;gt; Configuration&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==User blocks==&lt;br /&gt;
&lt;br /&gt;
Blocks created on user pages ie the My Moodle page or profile pages (including those that were copied from the default blocks the first time the user tries to customise the page) just need to show the page types menu to select between:&lt;br /&gt;
&lt;br /&gt;
* Public user profile page (user-profile)&lt;br /&gt;
* Private &amp;quot;My Moodle&amp;quot; page (my-index)&lt;br /&gt;
* All pages (*)&lt;br /&gt;
&lt;br /&gt;
This list will come from a callback function in /user/lib.php&lt;br /&gt;
&lt;br /&gt;
==Module blocks==&lt;br /&gt;
Blocks should looking for page pattern from module callback which comes from /mod/$mod/lib.php&lt;br /&gt;
&lt;br /&gt;
Blocks&#039; page types should be limited to module context only, module will decide what types will be available.&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=WebDAV_repository&amp;diff=77605</id>
		<title>WebDAV repository</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=WebDAV_repository&amp;diff=77605"/>
		<updated>2010-11-09T09:47:02Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
A WebDAV repository can be enabled by an administrator in &#039;&#039;Site administration &amp;gt; Modules &amp;gt; Repositories &amp;gt; Manage repositories&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==WebDAV configuration==&lt;br /&gt;
&lt;br /&gt;
[[Image:Webdav config.png|thumb|WebDAV configuration]]After enabling the WebDAV repository, a repository instance can be created in &#039;&#039;Site administration &amp;gt; Modules &amp;gt; Repositories &amp;gt; WebDAV repository&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Options===&lt;br /&gt;
WebDAV type: Choose from HTTP or HTTPS connection&lt;br /&gt;
&lt;br /&gt;
WebDAV server: The server name &lt;br /&gt;
&lt;br /&gt;
WebDAV path: The path to webdav directory&lt;br /&gt;
&lt;br /&gt;
Authentication: We currently only support HTTP Basic Authentication&lt;br /&gt;
&lt;br /&gt;
WebDAV server port: The webdav server port&lt;br /&gt;
&lt;br /&gt;
WebDAV server user: HTTP Basic authentication username&lt;br /&gt;
&lt;br /&gt;
WebDAV server password: HTTP Basic authentication password&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For example, if you are going to added an webdav server at http://webdavserver.tld/path/to/dir, you should use following options:&lt;br /&gt;
WebDAV type: HTTP&lt;br /&gt;
WebDAV Server: webdavserver.tld&lt;br /&gt;
WebDAV path: /path/to/dir/&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* MDL-22663&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=WebDAV_repository&amp;diff=77600</id>
		<title>WebDAV repository</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=WebDAV_repository&amp;diff=77600"/>
		<updated>2010-11-09T06:40:00Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
A WebDAV repository can be enabled by an administrator in &#039;&#039;Site administration &amp;gt; Modules &amp;gt; Repositories &amp;gt; Manage repositories&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==WebDAV configuration==&lt;br /&gt;
&lt;br /&gt;
[[Image:Webdav config.png|thumb|WebDAV configuration]]After enabling the WebDAV repository, a repository instance can be created in &#039;&#039;Site administration &amp;gt; Modules &amp;gt; Repositories &amp;gt; WebDAV repository&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Options===&lt;br /&gt;
WebDAV type: Choose from HTTP or HTTPS connection&lt;br /&gt;
&lt;br /&gt;
WebDAV server: The server name &lt;br /&gt;
&lt;br /&gt;
WebDAV path: The path to webdav directory&lt;br /&gt;
&lt;br /&gt;
Authentication: We currently only support HTTP Basic Authentication&lt;br /&gt;
&lt;br /&gt;
WebDAV server port: The webdav server port&lt;br /&gt;
&lt;br /&gt;
WebDAV server user: HTTP Basic authentication username&lt;br /&gt;
&lt;br /&gt;
WebDAV server password: HTTP Basic authentication password&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* MDL-22663&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Comments&amp;diff=76041</id>
		<title>Comments</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Comments&amp;diff=76041"/>
		<updated>2010-09-22T09:09:54Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Basic Features==&lt;br /&gt;
&lt;br /&gt;
===Comments anywhere===&lt;br /&gt;
Comments 2.0 implemented consistent interface for comments everywhere in Moodle 2.0, a new comment block is introduced, it can be added to all Moodle pages, so users can easily add comments on the page.&lt;br /&gt;
&lt;br /&gt;
===Ajax interface===&lt;br /&gt;
The new comments interface uses Ajax to load/add comments without refresh current page, it is easy to use and consistent in Moodle.&lt;br /&gt;
&lt;br /&gt;
=== Flexible capabilities===&lt;br /&gt;
Administrators are able to control if the user can see or use the comments block based on the context.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Development:Comments 2.0]]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Licences&amp;diff=75426</id>
		<title>Licences</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Licences&amp;diff=75426"/>
		<updated>2010-09-02T02:12:12Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
* Unknown licence: people can use your course, modify your course, sell your course...&lt;br /&gt;
* [http://en.wikipedia.org/wiki/All_rights_reserved All rights reserved]&lt;br /&gt;
* [http://creativecommons.org/licenses/publicdomain/ Public domain]&lt;br /&gt;
* [http://creativecommons.org/licenses/by/3.0/ Creative Commons]&lt;br /&gt;
* [http://creativecommons.org/licenses/by-nd/3.0/ Creative Commons - NoDerivs]&lt;br /&gt;
* [http://creativecommons.org/licenses/by-nc-nd/3.0/ Creative Commons - No Commercial NoDerivs]&lt;br /&gt;
* [http://creativecommons.org/licenses/by-nd/3.0/ Creative Commons - No Commercial]&lt;br /&gt;
* [http://creativecommons.org/licenses/by-nc-sa/3.0/ Creative Commons - No Commercial ShareAlike]&lt;br /&gt;
* [http://creativecommons.org/licenses/by-sa/3.0/ Creative Commons - ShareAlike]&lt;br /&gt;
&lt;br /&gt;
[[Category:Hub]]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Comments_2.0&amp;diff=75164</id>
		<title>Comments 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Comments_2.0&amp;diff=75164"/>
		<updated>2010-08-25T07:17:22Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}==Objectives==&lt;br /&gt;
&lt;br /&gt;
The goals of comments 2.0:&lt;br /&gt;
&lt;br /&gt;
* Manage comments centrally&lt;br /&gt;
* Use a consistent approach for all comments throughout Moodle&lt;br /&gt;
* Easily integrate comments 2.0 with existing modules&lt;br /&gt;
* Works no matter Javascript is enabled or not&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The comments 2.0 provides APIs to:&lt;br /&gt;
# Add comments&lt;br /&gt;
# Manage comments&lt;br /&gt;
# Delete comments&lt;br /&gt;
&lt;br /&gt;
And provides a fancy ajax interface to add/delete comments without loading a new page.&lt;br /&gt;
&lt;br /&gt;
==Comments database table==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Default&lt;br /&gt;
! Info&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| int(10)&lt;br /&gt;
| auto-incrementing&lt;br /&gt;
| The unique ID for this comment.&lt;br /&gt;
|-&lt;br /&gt;
| userid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| who wrote this comment&lt;br /&gt;
|-&lt;br /&gt;
| contextid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| The context id defined in context table - identifies the instance of plugin owning the comment.&lt;br /&gt;
|-&lt;br /&gt;
| itemid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| Some plugin specific item id (eg. forum post, blog entry or assignment submission)&lt;br /&gt;
|-&lt;br /&gt;
| commentarea&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| for example, in user profile, you can comment user&#039;s description or interests, but they share the same itemid(==userid), we need comment_area to separate them&lt;br /&gt;
|-&lt;br /&gt;
| timecreated&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| timemodified&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| content&lt;br /&gt;
| text&lt;br /&gt;
|&lt;br /&gt;
| content of comment&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Use Comments API==&lt;br /&gt;
&lt;br /&gt;
===Add an option to format_text function===&lt;br /&gt;
&lt;br /&gt;
Using this format_text function will add a comment icon automatically at the end of the text:&lt;br /&gt;
&lt;br /&gt;
For example, using the following code in the forum module will add a comment icon to every post:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$to = new stdclass;&lt;br /&gt;
$cmt-&amp;gt;contextid = $modcontext-&amp;gt;id;&lt;br /&gt;
$cmt-&amp;gt;area      = &#039;format_post&#039;;&lt;br /&gt;
$cmt-&amp;gt;itemid    = $post-&amp;gt;id;&lt;br /&gt;
$options-&amp;gt;comments = $cmt;&lt;br /&gt;
echo format_text($post-&amp;gt;message, $post-&amp;gt;messageformat, $options, $course-&amp;gt;id).&amp;quot;&amp;lt;hr /&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Use comment class===&lt;br /&gt;
To use Comments API elsewhere, using following code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$options-&amp;gt;area    = &#039;database_entry&#039;;&lt;br /&gt;
$options-&amp;gt;context = $context;&lt;br /&gt;
$options-&amp;gt;itemid  = $record-&amp;gt;id;&lt;br /&gt;
$options-&amp;gt;showcount = true;&lt;br /&gt;
$comment = new comment($options);&lt;br /&gt;
$comment-&amp;gt;output(false);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If you are using comments API in module context, you&#039;d better add pluginname option, it will help comments API find callback functions faster:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$options-&amp;gt;area    = &#039;database_entry&#039;;&lt;br /&gt;
$options-&amp;gt;pluginname = &#039;data&#039;;&lt;br /&gt;
$options-&amp;gt;context = $context;&lt;br /&gt;
$options-&amp;gt;itemid  = $record-&amp;gt;id;&lt;br /&gt;
$options-&amp;gt;component = &#039;mod_data&#039;;&lt;br /&gt;
$options-&amp;gt;showcount = true;&lt;br /&gt;
$comment = new comment($options);&lt;br /&gt;
$comment-&amp;gt;output(false);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==Comments API overview==&lt;br /&gt;
&lt;br /&gt;
Generally speaking, only two functions you need to know to get comments 2.0 worked:&lt;br /&gt;
# Use comment::init to initialize comments 2.0&lt;br /&gt;
# Use $comment-&amp;gt;output to display comments&lt;br /&gt;
&lt;br /&gt;
The comment class has been implemented in comment/lib.php.&lt;br /&gt;
===class comment()===&lt;br /&gt;
====__construct($contextid, $comment_area, $itemid))====&lt;br /&gt;
Initialize class members&lt;br /&gt;
&lt;br /&gt;
====init()====&lt;br /&gt;
It is a static function used to initialize comments, setting up languages, which must be called before html head printed&lt;br /&gt;
&lt;br /&gt;
====output($return = false)====&lt;br /&gt;
Will print the html snippet for commenting interface, if set $return as true, it will return html string instead of printing out.&lt;br /&gt;
&lt;br /&gt;
====print_comments($params = array())====&lt;br /&gt;
Used by non-javascript comment interface, will print a list of comments.&lt;br /&gt;
&lt;br /&gt;
====add($content)====&lt;br /&gt;
Public instance funciton, add a comment to database, used in comment/comment_ajax.php&lt;br /&gt;
&lt;br /&gt;
====count()====&lt;br /&gt;
Counting the number of comments&lt;br /&gt;
&lt;br /&gt;
====delete($id)====&lt;br /&gt;
Delete a comment from database, used in comment/comment_ajax.php&lt;br /&gt;
&lt;br /&gt;
====delete_comments====&lt;br /&gt;
Delete all comments in a specific contexts (like all comments belonging to a forum post)&lt;br /&gt;
&lt;br /&gt;
==Javascript API==&lt;br /&gt;
Comments 2.0 implemented a YUI3 module M.core_comment to deal with the communication between browsers and moodle.&lt;br /&gt;
It can be found in comment/comment.js&lt;br /&gt;
&lt;br /&gt;
Call M.core_comment.init will create an instance of CommentHelper class. You don&#039;t need to make any calls to this instance, it simply works out of box.&lt;br /&gt;
&lt;br /&gt;
== Moodle modules callback ==&lt;br /&gt;
Comments API allows modules/blocks/blog to decide how comments display.&lt;br /&gt;
&lt;br /&gt;
===Permission control===&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;modname_comment_permissions&#039;&#039;&#039; to control post and view permission.&lt;br /&gt;
&lt;br /&gt;
Blocks need to overwrite &#039;&#039;&#039;comment_permissions&#039;&#039;&#039; function of block_base.&lt;br /&gt;
&lt;br /&gt;
Blog need to implement &#039;&#039;&#039;blog_comment_permissions&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
This function will return an array: array(&#039;post&#039;=&amp;gt;true, &#039;view&#039;=&amp;gt;true)&lt;br /&gt;
&lt;br /&gt;
=== Check new added comment ===&lt;br /&gt;
The callback function allows you to change the comment content before inserting into database or reject this comment.&lt;br /&gt;
&lt;br /&gt;
It takes two arguments, the comment object which contains comment details, and $params which contains context and course information.&lt;br /&gt;
&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;modname_comment_add&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Blocks need to overwrite &#039;&#039;&#039;comment_add&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
Blog need to implement &#039;&#039;&#039;blog_comment_add&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
This function should return a boolean value. &lt;br /&gt;
&lt;br /&gt;
=== Filter/format comments ===&lt;br /&gt;
This callback allows modules check/format comments when user request to display comments.&lt;br /&gt;
&lt;br /&gt;
It takes the same arguments as modname_comment_add&lt;br /&gt;
&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;modname_comment_display&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Blocks need to overwrite &#039;&#039;&#039;comment_display&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
Blog need to implement &#039;&#039;&#039;blog_comment_display&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
It will return the comment object.&lt;br /&gt;
&lt;br /&gt;
=== Define a comment template ===&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;modname_comment_template&#039;&#039;&#039;, which allow modules define a comment template.&lt;br /&gt;
The template must have 4 embedding variables, ___id___, ___content___, ___time___, ___name___, they will be replaced with html id, comments content, comment time and commenter name&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* MDL-19118 - Comments 2.0 issue&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Broken/File_storage_conversion_Quiz_and_Questions&amp;diff=73920</id>
		<title>Broken/File storage conversion Quiz and Questions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Broken/File_storage_conversion_Quiz_and_Questions&amp;diff=73920"/>
		<updated>2010-07-14T09:36:06Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: New page: Hi, Tim FYI, the editor moodle form element has three fields: text, format and itemid, so we don&amp;#039;t need to add extra format and itemid fields to moodle form. Currently , question bank uses...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Hi, Tim&lt;br /&gt;
FYI, the editor moodle form element has three fields: text, format and itemid, so we don&#039;t need to add extra format and itemid fields to moodle form. Currently , question bank uses htmleditor element which doesn&#039;t have format and itemid, I am working on to switch it to the new editor element.&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=File_storage_conversion_Quiz_and_Questions&amp;diff=73918</id>
		<title>File storage conversion Quiz and Questions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=File_storage_conversion_Quiz_and_Questions&amp;diff=73918"/>
		<updated>2010-07-14T09:04:00Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: changes against latest file api update&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page are some notes about what has to be done for MDL-16094.&lt;br /&gt;
&lt;br /&gt;
I would like to review code changes before they are committed for all of this, but I can&#039;t see myself having time to do much work on this, only to help someone else do it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Assumptions==&lt;br /&gt;
&lt;br /&gt;
I believe it is the case that each HTML editor on a form has to use a separate HTML editor (otherwise copying files to and from draft areas does not work). However, for question types, I don&#039;t think that leads to the best usability.&lt;br /&gt;
&lt;br /&gt;
Similarly, each HTML editor has to have a corresponding ...format field (like questiontext, questiontextformat) even though it is silly (from a usability point of view) for different parts of a question to use different formats.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Serving files==&lt;br /&gt;
&lt;br /&gt;
Files belonging to the quiz are served using the quiz_pluginfile() function and other callbacks in mod/quiz/lib.php, as for other modules. There is nothing special here.&lt;br /&gt;
&lt;br /&gt;
The issue is with files belonging to questions. Doing proper access control before serving these files involves coordinating both the question type, and the activity (e.g. the quiz) that is using the questions.&lt;br /&gt;
&lt;br /&gt;
Question components will be given names like question, or qtype_yyy, where yyy is the name of the particular question type, for example multichoice. And question file areas are requires as well, such as intro, feedback etc.&lt;br /&gt;
&lt;br /&gt;
All questions belong to a particular context, via the link mdl_question.category -&amp;gt; mdl_question_categories.id, mdl_question_categories.contextid -&amp;gt; mdl_context.id links. This is the context id that should be used for files belonging to that question.&lt;br /&gt;
&lt;br /&gt;
Therefore, the URL for serving a file belonging to a question will look like one of these examples:&lt;br /&gt;
&lt;br /&gt;
 $CFG-&amp;gt;wwwroot/pluginfile.php/$questioncontextid/question/generalfeeback/$attemptid/$questionid/$itemid/path/to/file.ext&lt;br /&gt;
 $CFG-&amp;gt;wwwroot/pluginfile.php/$questioncontextid/qtype_match/stem/$attemptid/$questionid/$itemid/path/to/file.ext&lt;br /&gt;
&lt;br /&gt;
The $attemptid here is the id from the row of the mdl_question_attempts table for the quiz (or whatever) attempt that is using the question. In the question code, where we are outputting a question, the $attemptid and $questionid are normally available from the $state variable as $state-&amp;gt;attempt and $state-&amp;gt;question. Currently, question/preview.php does not store things in the database. It just uses the session, and a fake $attemptid of 0. That is not a problem (for us here. It is a problem in other ways.)&lt;br /&gt;
&lt;br /&gt;
Therefore in pluginfile.php, we need code for any system, course category, course or module context, sends requests for files in a question_... or qtype_... file area to a question_pluginfile() function in lib/questionlib.php.&lt;br /&gt;
&lt;br /&gt;
Next, we need to get some information from the thing (e.g. quiz) that the attempt belongs to. To identify the &#039;thing&#039;:&lt;br /&gt;
* If $attemptid is 0, then thing is core_question_preview&lt;br /&gt;
* Otherwise, load the row from mdl_question_attempts, and looks at the modulename field. The will contain something like &#039;quiz&#039; which is the thing.&lt;br /&gt;
&lt;br /&gt;
Next question_pluginfile calls a callback:&lt;br /&gt;
 list($question, $state, $options) =&lt;br /&gt;
         thing_check_file_access($attemptid, $questionid, $context);&lt;br /&gt;
This does some basic access checks (For quiz, it will to something similar to the top of attempt.php and review.php, for core preview it just does some capability checks like at the top of question/preview.php.) If the user is not allowed to see the file, based on the quick check, a lot of nulls are returned. If access is allowed, $question, $state, $options are returned. These are the things that would be passed to print_question.&lt;br /&gt;
&lt;br /&gt;
Finally, we call&lt;br /&gt;
 $qtype-&amp;gt;check_file_access($question, $state, $options, $filearea, $itemid);&lt;br /&gt;
which returns true if the file can be served, or false if not. This will contain logic similar to that in -&amp;gt;print_question_formulation_and_controls to determine whether the file should be displayed. It should also check that $itemid for this file area belongs to this question.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==File areas for the quiz==&lt;br /&gt;
&lt;br /&gt;
I have written what follows with reference to database columns, with secondary mention of the editing forms where the value is edited. That determines what itemid should be used with each file area (the id of the row from that table) but for clarity, for each file area I think we need, I have added a notation that looks like {contextid, area_name, itemid} to make it clear what the file areas are.&lt;br /&gt;
&lt;br /&gt;
[[Development:Quiz database structure]]&lt;br /&gt;
&lt;br /&gt;
* We need a file area for quiz.intro. {$quizcontextid, quiz_intro, ???}&lt;br /&gt;
&lt;br /&gt;
* We need a file area for quiz_feedback.feedbacktext. (The overall feedback on the quiz settings form.) If it is possible to do easily, we should replace the overall feedback boxes with HTML editors (the boxes currently accept HTML input into text fields, which is functionally complete, but sucky). {$quizcontextid, quiz_feedback, quiz_feedback.id}&lt;br /&gt;
&lt;br /&gt;
* We need to add a feedbacktextformat column, if it has not already been done.&lt;br /&gt;
&lt;br /&gt;
* Ideally, access to overall feedback files should be controlled by the same logic as whether the feedback itself is displayed. However, I think it would be acceptable to release Moodle 2.0 without this. Just leave an open tracker issue assigned to me, and I can implement that check later.&lt;br /&gt;
&lt;br /&gt;
No other quiz_... tables have files associated with any columns.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==File areas for questions==&lt;br /&gt;
&lt;br /&gt;
[[Development:Question database structure]]&lt;br /&gt;
&lt;br /&gt;
There are no fields in the &#039;question engine&#039; tables that have files. Except:&lt;br /&gt;
&lt;br /&gt;
* There should be a question_sessions.manualcommentformat column. (But manual comment should not support attached files.)&lt;br /&gt;
&lt;br /&gt;
All the issues are in the &#039;question bank&#039; part, which means the core question bank, and the all the question type plugins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Core question bank===&lt;br /&gt;
&lt;br /&gt;
There is a context associated with each question, as explained in the [[#Serving_files|Serving files]] section.&lt;br /&gt;
&lt;br /&gt;
* I think that question_categories.info (which is HTML) should not have files. However, we need a question_categories.infoformat field.&lt;br /&gt;
&lt;br /&gt;
* We need file areas for question.questiontext and question.generalfeedback. We also need to add the missing question.generalfeedbackformat field. {$questioncontextid, question_text, question.id} {$questioncontextid,  question_generalfeedback, question.id}&lt;br /&gt;
&lt;br /&gt;
* We need file areas, and ...format columns for question_answers.answer and question_answers.feedback. (Depending on the question type, question_answers.answer may be HTML, or it may not, but where it is not, we will force the ...format value to something appropriate. Anyway, as an example, answers are HTML for multichoice and truefalse, but not for numerical or shortanswer.) {$questioncontextid, question_answer, question_answer.id} {$questioncontextid, question_answer_feedback, question_answer.id}&lt;br /&gt;
&lt;br /&gt;
* We must get rid of the question.image column. We need an upgrade to:&lt;br /&gt;
*# Do a database upgrade that appends an img tag to the questiontext, if the img column is not empty;&lt;br /&gt;
*# and copy the file into the right file area;&lt;br /&gt;
*# then drop the question.image column;&lt;br /&gt;
*# remove that field from all editing forms;&lt;br /&gt;
*# remove the places where the image is displayed.&lt;br /&gt;
&lt;br /&gt;
Note that all the above changes require changes to the question editing form for all question types, but hopefully that can mostly be done in the form base class.&lt;br /&gt;
&lt;br /&gt;
* Question import needs to use the file-picker.&lt;br /&gt;
&lt;br /&gt;
* Question export should be changed to put the files in an appropriate file area. I am not sure what the best file area is right now, but probably somewhere in the user context. MDL-15573&lt;br /&gt;
&lt;br /&gt;
===Question types===&lt;br /&gt;
&lt;br /&gt;
====Question types where nothing needs to be done====&lt;br /&gt;
&lt;br /&gt;
These only use the core question tables, or do not need files associated with their own tables.&lt;br /&gt;
&lt;br /&gt;
* Description&lt;br /&gt;
* Essay&lt;br /&gt;
* Missing type&lt;br /&gt;
* &#039;&#039;&#039;Numerical&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;The new 2,0 number and unit grading use a new table question_numerical_options where the instructions field is HTML which could include images. This table is also used by calculated and calculated simple.--Pierre Pichet 08:11, 23 May 2010 (UTC)&#039;&#039;&lt;br /&gt;
* Random&lt;br /&gt;
* Random short-answer matching&lt;br /&gt;
* Short answer&lt;br /&gt;
* True-false&lt;br /&gt;
&lt;br /&gt;
====Match====&lt;br /&gt;
&lt;br /&gt;
* question_match_sub.questiontext needs a ...format column and a file area. (answertext does not. It is displayed in a select menu.) {$questioncontextid, qtype_match_stem, question_match_sub.id}&lt;br /&gt;
&lt;br /&gt;
====Multiple choice====&lt;br /&gt;
&lt;br /&gt;
* correctfeedback, partiallycorrectfeedback and incorrectfeedback all need ...format columns and a file area.&lt;br /&gt;
{$questioncontextid, qtype_multichoice_correctfeedback, question_multichoice.id} {$questioncontextid, qtype_multichoice_partiallycorrectfeedback, question_multichoice.id} {$questioncontextid, qtype_multichoice_incorrectfeedback, question_multichoice.id}&lt;br /&gt;
&lt;br /&gt;
* The choice entry boxes on the editing form should be changed to HTML editors.&lt;br /&gt;
&lt;br /&gt;
====Question types I am not really sure about====&lt;br /&gt;
&lt;br /&gt;
* Calculated* - I don&#039;t really know what Pierre is doing here. I need to get my head round it.&lt;br /&gt;
&lt;br /&gt;
So here is the status of calculated in 2.0.&lt;br /&gt;
&lt;br /&gt;
The calculatedsimple is just a regular calculated that can be edited in a one page because it is not using the shared category datasets. In both on them there is no new field with image to store other than question text and answer feedback.&lt;br /&gt;
&lt;br /&gt;
The answer field is just math formula i.e. plain text.&lt;br /&gt;
&lt;br /&gt;
The multichoice calculated is a multichoice where calculated math formula can be inserted {=...} so the requirements are the same as regular multichoice.&lt;br /&gt;
&lt;br /&gt;
Regular calculated and multichoice calculated used the new table question_calculated_options although regular calculated only used the synchronize field, multichoice calculated using the other fields.&lt;br /&gt;
I prefer to use only one new table and the fields for multichoice calculated are a copy of most of the multichoice ones.&lt;br /&gt;
&lt;br /&gt;
This is a new table in 2.0 so no file conversion.&lt;br /&gt;
 &lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 08:01, 23 May 2010 (UTC)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Multi-answer - probably does not need any other file areas, but the code may need fixing a bit.&lt;br /&gt;
&lt;br /&gt;
So here is the status of Multi-answer in 2.0.&lt;br /&gt;
&lt;br /&gt;
Multi-answer code is the same has in 1.9, the improvements has been on the data validation in the edit_form with additional warnings when the user modify the number or question type in the question text peculiarly when the question has attempts stored.&lt;br /&gt;
 &lt;br /&gt;
I am working on the lang strings.&lt;br /&gt;
 &lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 08:01, 23 May 2010 (UTC)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==For the future==&lt;br /&gt;
&lt;br /&gt;
As in, Moodle 2.1 or later.&lt;br /&gt;
&lt;br /&gt;
* Support files in student responses and manual comments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* MDL-16094&lt;br /&gt;
* Feel free to discuss this with Tim Hunt.&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Web_services:Files&amp;diff=73692</id>
		<title>Web services:Files</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Web_services:Files&amp;diff=73692"/>
		<updated>2010-07-09T07:50:40Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;These APIs will be used to browse Moodle files by Moodle Web Services.&lt;br /&gt;
&lt;br /&gt;
===class moodle_file_external()===&lt;br /&gt;
&lt;br /&gt;
This class implements the interface to moodle files, for browsing, downloading and uploading files.  It is defined in files/externals.php.&lt;br /&gt;
&lt;br /&gt;
We cannot return the whole files tree by web service API, because to make sure the web services working in every language and platform, we need to define a fixed data structure of return value, but the files tree can change all the time. See more information about web services at: [[Development:External_services_description]].&lt;br /&gt;
&lt;br /&gt;
The class contains following methods:&lt;br /&gt;
&lt;br /&gt;
====get_files====&lt;br /&gt;
This function is used to browse files.&lt;br /&gt;
&lt;br /&gt;
It takes 5 parameters, all of them are optional, if you provide no parameters, it will return the top level content of moodle repository.&lt;br /&gt;
&lt;br /&gt;
* contextid&lt;br /&gt;
* component&lt;br /&gt;
* filearea&lt;br /&gt;
* itemid&lt;br /&gt;
* filename&lt;br /&gt;
* filepath&lt;br /&gt;
&lt;br /&gt;
It will return an array, can be described as PHP array:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$files = array(&lt;br /&gt;
  &#039;path&#039; =&amp;gt; array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;, &#039;path=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subdir&#039;, &#039;path=&amp;gt;&#039;/sub/&#039;)),&lt;br /&gt;
  &#039;files&#039; =&amp;gt; array(&lt;br /&gt;
       array(&#039;filename&#039;=&amp;gt;&#039;readme&#039;, &#039;filepath&#039;=&amp;gt;&#039;/&#039;, &#039;filearea&#039;=&amp;gt;&#039;forum&#039;, &#039;itemid&#039;=&amp;gt;110, &#039;contextid&#039;=&amp;gt;1, &#039;isdir&#039;=&amp;gt;true),&lt;br /&gt;
       array(&#039;filename&#039;=&amp;gt;&#039;changes&#039;, &#039;filepath&#039;=&amp;gt;&#039;/&#039;, &#039;filearea&#039;=&amp;gt;&#039;forum&#039;, &#039;itemid&#039;=&amp;gt;112, &#039;contextid&#039;=&amp;gt;1, &#039;isdir&#039;=&amp;gt;false),&lt;br /&gt;
     )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The service name is &amp;quot;moodle_file_get_files&amp;quot;, defined in lib/db/services.php.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====upload====&lt;br /&gt;
This function is used to upload a file to user private area.&lt;br /&gt;
&lt;br /&gt;
It takes 7 parameters, all of them are mandatory:&lt;br /&gt;
&lt;br /&gt;
* contextid&lt;br /&gt;
* component&lt;br /&gt;
* filearea&lt;br /&gt;
* itemid&lt;br /&gt;
* filepath&lt;br /&gt;
* filename&lt;br /&gt;
* filecontent&lt;br /&gt;
&lt;br /&gt;
It will return a boolean value, true/false.&lt;br /&gt;
&lt;br /&gt;
The service name is &amp;quot;moodle_file_upload&amp;quot;, defined in lib/db/services.php&lt;br /&gt;
&lt;br /&gt;
Sample code (using Zend Framework):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$url = MOODLE_WSROOT. &#039;?wstoken=xxxxxxxxxxxxxxxxxxxxxx&#039;;&lt;br /&gt;
$zend = new Zend_XmlRpc_Client($url);&lt;br /&gt;
$srv = $zend-&amp;gt;getProxy();&lt;br /&gt;
$files = $srv-&amp;gt;moodle_file_get_files($contextid, $component, $filearea, $itemid, $filepath, $filename);&lt;br /&gt;
$file = $srv-&amp;gt;moodle_file_upload($contextid, &#039;user&#039;, &#039;private&#039;, 0, &#039;/&#039;, &#039;info.txt&#039;, base64_encode(&#039;this is file content&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Repository_plugins&amp;diff=73575</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Repository_plugins&amp;diff=73575"/>
		<updated>2010-07-05T07:39:33Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A guide for developers on how to create a repository plugin.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
There is a template attached to MDL-16543 which might be useful to help get you started.&lt;br /&gt;
&lt;br /&gt;
===First steps===&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;moodle/repository/&#039;&#039; e.g. &#039;&#039;moodle/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files and add them to the plugin folder:&lt;br /&gt;
#* &#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;pix/icon.png&#039;&#039; (the icon displayed in the file picker)&lt;br /&gt;
#* &amp;quot;version.php&amp;quot;&lt;br /&gt;
# Create the language file &#039;&#039;repository_myplugin.php&#039;&#039; and add it to the plugin folder, keeping the following folder structure:&lt;br /&gt;
#*&#039;&#039;moodle/repository/myplugin/lang/en_utf8/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en_utf8/repository_myplugin.php&#039;&#039;&lt;br /&gt;
# Create access.php and upgrade scripts&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    &amp;lt;?php&lt;br /&gt;
    /**&lt;br /&gt;
     * repository_flickr_public class&lt;br /&gt;
     * Moodle user can access public flickr account&lt;br /&gt;
     *&lt;br /&gt;
     * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
    */&lt;br /&gt;
    class repository_flickr_public extends repository {&lt;br /&gt;
    }&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
All of the following functions are optional. If they&#039;re not implemented, your plugin will not have manual settings and will have only one instance displayed in the File Picker (The repository API creates this unique instance when the administrator add the plugin).&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
====instance_config_form(&amp;amp;$mform)====&lt;br /&gt;
This is for modifying the Moodle form displaying the settings specific to an instance.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function return an empty array.&lt;br /&gt;
&lt;br /&gt;
====type_config_form(&amp;amp;$mform)====&lt;br /&gt;
This is for modifying the Moodle form displaying the plugin settings.&lt;br /&gt;
Similar to &#039;&#039;instance_config_form(&amp;amp;$mform)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
==File picker APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
&#039;&#039;&#039;To be completed&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;?&amp;lt;br&amp;gt;&lt;br /&gt;
.....&lt;br /&gt;
&lt;br /&gt;
For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function...&amp;lt;br&amp;gt;&lt;br /&gt;
.....&lt;br /&gt;
&lt;br /&gt;
You wanna display a list of files once the user is logged&amp;lt;br&amp;gt;&lt;br /&gt;
.... get_listing() .....&lt;br /&gt;
&lt;br /&gt;
You wanna retrieve the file that the user selected&amp;lt;br&amp;gt;&lt;br /&gt;
....&lt;br /&gt;
&lt;br /&gt;
Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
.... search() ....&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
====__construct====&lt;br /&gt;
You may initialize your plugin here, such as:&lt;br /&gt;
# Get options from database&lt;br /&gt;
# Get user name and password from HTTP POST&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;01/01/2009&#039;, &#039;size&#039;=&amp;gt;&#039;10MB&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;01/01/2009&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // Used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // dynload tells file picker to fetch list dynamically, when user click&lt;br /&gt;
   // the folder, it will send a ajax request to server side.&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be used&lt;br /&gt;
   // and note, you&#039;d better don&#039;t use pagination and page at the same time&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (pages) how many pages&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // will display a link in file picker&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url of the file manager,&lt;br /&gt;
   // set to true, the login link will be removed from file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login,&lt;br /&gt;
   // set to true, the search link will be removed from file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link,&lt;br /&gt;
   // set this option will display a upload form in file picker&lt;br /&gt;
   // only used in upload plugin currently&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // file picker will build a file tree according this &lt;br /&gt;
   // list&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (string) file last modification time, usually userdate(...),&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039;=&amp;gt; the accessible url of file&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - same as file, but no &#039;source&#039;.&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (string) folder last modification time, usually userdate(...),&lt;br /&gt;
       &#039;size&#039; =&amp;gt; 0,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the folder,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( // an empty folder needs to have &#039;children&#039; defined, but empty.&lt;br /&gt;
         // content (files and folders)&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/lib.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
===Functions you can override===&lt;br /&gt;
====print_login====&lt;br /&gt;
This function will help to print a login form, for the Ajax file picker, this function will return a&lt;br /&gt;
PHP array to define this form.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    public function print_login(){&lt;br /&gt;
        if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
            $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $user_field-&amp;gt;id    = &#039;box_username&#039;;&lt;br /&gt;
            $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
            $user_field-&amp;gt;name  = &#039;boxusername&#039;;&lt;br /&gt;
            $user_field-&amp;gt;value = $ret-&amp;gt;username;&lt;br /&gt;
            &lt;br /&gt;
            $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;id    = &#039;box_password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;name  = &#039;boxpassword&#039;;&lt;br /&gt;
&lt;br /&gt;
            $ret = array();&lt;br /&gt;
            $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
            // if you are going to rename submit button label, use this option&lt;br /&gt;
            //$ret[&#039;login_btn_label&#039;] = get_string(&#039;submit_btn_label&#039;);&lt;br /&gt;
            // if you are going to display a search form instead of login form&lt;br /&gt;
            // set this option to true&lt;br /&gt;
            //$ret[&#039;login_search_form&#039;] = true;&lt;br /&gt;
            return $ret;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
If your plugin don&#039;t require logging in, you don&#039;t need to override it, it will call get_listing to list files automatically by default.&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here.&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the from the form you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
====get_file====&lt;br /&gt;
When a user clicks the &amp;quot;Get&amp;quot; button to transfer the file, this function will be called. Basically, it will download a file to Moodle - you can override it to modify the file then move it to a better location.&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en_utf8/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en_utf8/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;repositorydesc&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
$string[&#039;repositoryname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Standard repository plugins ==&lt;br /&gt;
This is the functional specification list of the officially supported repository plugins.&lt;br /&gt;
For each plugins, the two mains part we are interested in are:&lt;br /&gt;
* How do I administrate the plugin? See [[Development:Repository_Administration_Specification| Repository Administration Specification - UC001-3]]&lt;br /&gt;
* How do I set up an account for this repository? See [[Development:Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
&lt;br /&gt;
=== Functional specifications ===&lt;br /&gt;
*[[Development:Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Development:Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Development:Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Development:Repository API| Repository API]]&lt;br /&gt;
*[[Development:Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
[[Category:Repositories]]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Using_the_File_API_in_Moodle_forms&amp;diff=72484</id>
		<title>Using the File API in Moodle forms</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Using_the_File_API_in_Moodle_forms&amp;diff=72484"/>
		<updated>2010-05-28T03:21:57Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
This document shows you exactly how to use Moodle forms to get files from users in a standard and secure way.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0 all files are stored in a central database accessible via the [[Development:File API|File API]], and every file is associated with a &amp;quot;file area&amp;quot; in Moodle, such as a particular module.&lt;br /&gt;
&lt;br /&gt;
A common use case is to provide a form (using Moodle&#039;s [[Development:lib/formslib.php|Forms API]]) which allows users to upload or import files as attachments or media embedded into HTML.&lt;br /&gt;
&lt;br /&gt;
Normally this works like this:&lt;br /&gt;
# User starts creation or re-edits an existing item in Moodle (eg forum post, resource, glossary entry etc)&lt;br /&gt;
# User presses some sort of button to browse for new files to attach or embed&lt;br /&gt;
# User sees our &amp;quot;Choose file...&amp;quot; dialog, which contains one or more repository instances. &lt;br /&gt;
# User chooses a file, the [[Development:Repository API|Repository API]] takes care of copying the file into a &amp;quot;draft file area&amp;quot; within Moodle&lt;br /&gt;
# File appears in the text or as an attachment in the form.&lt;br /&gt;
# When the user hits save, the [[Development:File API|File API]] is invoked to move the file from the draft file area into a permanent file area associated with that data &lt;br /&gt;
&lt;br /&gt;
This document shows you exactly how to use Moodle forms to interact with users in a standard and secure way.&lt;br /&gt;
&lt;br /&gt;
If you just want to write code to manipulate Moodle files internally (without user input) then see [[Development:Using_the_File_API]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Form elements== &lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0 there are three file-related form elements for interacting with users:&lt;br /&gt;
&lt;br /&gt;
# filemanager - the way to attach one or more files as a set&lt;br /&gt;
# editor - the way to specify a textarea with a HTML editor, and all the handling of images and movies within that HTML&lt;br /&gt;
# filepicker - a way to specify one file for the case when you want to process the file and throw it away &lt;br /&gt;
&lt;br /&gt;
In Moodle 1.9 there were two other types which are now &#039;&#039;&#039;deprecated&#039;&#039;&#039; (they work, but please do not use these anymore)&lt;br /&gt;
# file - used to just allow a normal file upload from the desktop only.&lt;br /&gt;
# htmleditor - this old method of embedding a HTML editor in a textarea is not able to support repositories etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===filepicker===&lt;br /&gt;
&lt;br /&gt;
File picker (&#039;&#039;filepicker&#039;&#039;) is a direct replacement of the older &#039;&#039;file&#039;&#039; formslib element. &lt;br /&gt;
&lt;br /&gt;
It is intended for situations when you want the user to upload &#039;&#039;&#039;one&#039;&#039;&#039; file so you can process it and delete it, such as when you are importing data from a CSV file.&lt;br /&gt;
&lt;br /&gt;
==== Using the filepicker element ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filepicker&#039;, &#039;userfile&#039;, get_string(&#039;file&#039;), null, array(&#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;accepted_types&#039; =&amp;gt; &#039;*&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtain the chosen file ====&lt;br /&gt;
&lt;br /&gt;
The API for getting file contents is exactly the same as for &#039;&#039;file&#039;&#039; element.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$content = $mform-&amp;gt;get_file_content(&#039;userfile&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== filemanager ===&lt;br /&gt;
&lt;br /&gt;
The File Manager element improves on file picker by allowing you to manage more than one file.  It is expected that the files will be stored permanently for future use (such as forum and glossary attachments).&lt;br /&gt;
&lt;br /&gt;
==== Add file manager element ====&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filemanager&#039;, &#039;attachments&#039;, get_string(&#039;attachment&#039;, &#039;moodle&#039;), null,&lt;br /&gt;
                    array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;maxfiles&#039; =&amp;gt; 50, &#039;accepted_types&#039; =&amp;gt; array(&#039;document&#039;) ));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here are the fields for filemanager:&lt;br /&gt;
&lt;br /&gt;
;&#039;filemanager&#039;:This is a filemanager element :)&lt;br /&gt;
;elementname:The unique name of the element in the form&lt;br /&gt;
;elementlabel:The label string that users see &lt;br /&gt;
;attributes:(leave it as null)&lt;br /&gt;
;options: an array of further options for the filepicker (see below)&lt;br /&gt;
&lt;br /&gt;
The options array can contain:&lt;br /&gt;
&lt;br /&gt;
;subdirs:(Default 0) Are subdirectories allowed?  (true or false)&lt;br /&gt;
;maxbytes:(Default 0) Restricts the total size of all the files.&lt;br /&gt;
;maxfiles:(Default -1) Restricts the total number of files.&lt;br /&gt;
;accepted_types:(Default *) You can specify what file types are accepted by filemanager.  All current file types are listed in this file: [http://cvs.moodle.org/moodle/lib/file/file_types.mm moodle/lib/file/file_types.mm].  This is a [http://freemind.sourceforge.net/wiki/index.php/Main_Page freemind] file: if it is edited the changes will be immediately reflected in Moodle.  Example usage:  &#039;&#039;&#039;array(&#039;audio&#039;, &#039;video&#039;, &#039;documents&#039;)&#039;&#039;&#039;, you can include file extensions as well, for example: &#039;&#039;&#039;array(&#039;*.txt&#039;, &#039;*.jpg&#039;, &#039;audio&#039;)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Load existing files into draft area ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (empty($entry-&amp;gt;id)) {&lt;br /&gt;
    $entry = new object();&lt;br /&gt;
    $entry-&amp;gt;id = null;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$draftitemid = file_get_submitted_draft_itemid(&#039;attachments&#039;);&lt;br /&gt;
file_prepare_draft_area($draftitemid, $context-&amp;gt;id, &#039;glossary_attachment&#039;, $entry-&amp;gt;id, array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;maxfiles&#039; =&amp;gt; 50));&lt;br /&gt;
$entry-&amp;gt;attachments = $draftitemid;&lt;br /&gt;
&lt;br /&gt;
$mform-&amp;gt;set_data($entry);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Store updated set of files ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
    // ... store or update $entry&lt;br /&gt;
    file_save_draft_area_files($data-&amp;gt;attachments, $context-&amp;gt;id, &#039;glossary_attachment&#039;, $entry-&amp;gt;id, array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;maxfiles&#039; =&amp;gt; 50));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===editor===&lt;br /&gt;
There are two way for using of editor element in code, the first one is easier but expects some standardized fields. The second method is more low level.&lt;br /&gt;
&lt;br /&gt;
====Simple use====&lt;br /&gt;
# name database fields: &#039;&#039;textfield&#039;&#039;, &#039;&#039;textfieldformat&#039;&#039; (and &#039;&#039;textfieldtrust&#039;&#039; if required)&lt;br /&gt;
# create options array &amp;lt;code php&amp;gt;$textfieldoptions = array(&#039;trusttext&#039;=&amp;gt;true, &#039;subdirs&#039;=&amp;gt;true, &#039;maxfiles&#039;=&amp;gt;$maxfiles, &#039;maxbytes&#039;=&amp;gt;$maxbytes);&amp;lt;/code&amp;gt;&lt;br /&gt;
# add editor &#039;&#039;textfield_editor&#039;&#039; to moodle form, pass options through custom data in form constructor, set $data-&amp;gt;id to null if data not exist yet &amp;lt;code php&amp;gt;$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;textfield_editor&#039;, get_string(&#039;fieldname&#039;, &#039;somemodule&#039;), null, $textfieldoptions);&amp;lt;/code&amp;gt;&lt;br /&gt;
# prepare data &amp;lt;code php&amp;gt;$data = file_prepare_standard_editor($data, &#039;textfield&#039;, $textfieldoptions, $context, &#039;somemodule_somearea&#039;, $data-&amp;gt;id);&amp;lt;/code&amp;gt;&lt;br /&gt;
# get submitted data and after inserting/updating of data &amp;lt;code php&amp;gt;$data = file_postupdate_standard_editor($data, &#039;textfield&#039;, $textfieldoptions, $context, &#039;somemodule_somearea&#039;, $data-&amp;gt;id);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Real world examples are in mod/glossary/edit.php and mod/glossary/comment.php&lt;br /&gt;
&lt;br /&gt;
====Low level use====&lt;br /&gt;
&lt;br /&gt;
When using editor element you  need to preprocess and postprocess the data:&lt;br /&gt;
# detect if form was already submitted (usually means draft is area already exists) - &#039;&#039;file_get_submitted_draft_itemid()&#039;&#039;&lt;br /&gt;
# prepare draft file area, temporary storage of all files attached to the text - &#039;&#039;file_prepare_draft_area()&#039;&#039;&lt;br /&gt;
# convert encoded relative links to absolute links - &#039;&#039;file_prepare_draft_area()&#039;&#039;&lt;br /&gt;
# create form and set current data&lt;br /&gt;
# after submission the changed files must be merged back into original area - &#039;&#039;file_save_draft_area_files()&#039;&#039;&lt;br /&gt;
# absolute links have to be replaced by relative links - &#039;&#039;file_save_draft_area_files()&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=====Replace old htmleditor with editor=====&lt;br /&gt;
&lt;br /&gt;
The file picker has been integrated with with TinyMCE to make the editor element. This new element should support all types on editors and should be able to switch them on-the-fly. Instances of the old htmleditor element in your forms should be replaced by the new editor element, this may need adding of new format and trusttext columns. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;entry&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;), null,&lt;br /&gt;
        array(&#039;maxfiles&#039; =&amp;gt; EDITOR_UNLIMITED_FILES, &#039;filearea&#039; =&amp;gt; &#039;glossary_entry&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The editor element can take following options: maxfiles, maxbytes, filearea, subdirs and changeformat. Please note that the embedded files is optional feature and is not expected be used everywhere.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: the editor element now includes text format option. You should no longer use the separate format element type.&lt;br /&gt;
&lt;br /&gt;
=====Prepare current data - text and files=====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (empty($entry-&amp;gt;id)) {&lt;br /&gt;
  $entry = new object();&lt;br /&gt;
  $entry-&amp;gt;id = null;&lt;br /&gt;
  $entry-&amp;gt;definition = &#039;&#039;;&lt;br /&gt;
  $entry-&amp;gt;format = FORMAT_HTML;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$draftid_editor = file_get_submitted_draft_itemid(&#039;entry&#039;);&lt;br /&gt;
$currenttext = file_prepare_draft_area($draftid_editor, $context-&amp;gt;id, &#039;glossary_entry&#039;, $entry-&amp;gt;id, array(&#039;subdirs&#039;=&amp;gt;true), $entry-&amp;gt;definition);&lt;br /&gt;
$entry-&amp;gt;entry = array(&#039;text&#039;=&amp;gt;$currenttext, &#039;format&#039;=&amp;gt;$entry-&amp;gt;format, &#039;itemid&#039;=&amp;gt;$draftid_editor);&lt;br /&gt;
&lt;br /&gt;
$mform-&amp;gt;set_data($entry);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If there are multiple files, they will share the same itemid.&lt;br /&gt;
&lt;br /&gt;
=====Obtain text, format and save draft files=====&lt;br /&gt;
&lt;br /&gt;
To retrieve editor content, you need to use following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($fromform = $mform-&amp;gt;get_data()) {&lt;br /&gt;
    // content of editor&lt;br /&gt;
    $messagetext = $fromform-&amp;gt;entry[&#039;text&#039;];&lt;br /&gt;
    // format of content&lt;br /&gt;
    $messageformat  = $fromform-&amp;gt;entry[&#039;format&#039;];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When a user selects a file using the file picker, the file is initially stored in a draft file area, and a URL is inserted into the HTML in the editor that lets the person editing the content (but no one else) see the file.&lt;br /&gt;
&lt;br /&gt;
When the user submits the form, we then need to save the draft files to the correct place in permanent storage. (Just like you have to call $DB-&amp;gt;update_record(&#039;tablename&#039;, $data); to have the other parts of the form submission stored correctly.)&lt;br /&gt;
&lt;br /&gt;
The save_files_from_draft_area function and replace absolute links with internal relative links do:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$messagetext = file_save_draft_area_files($draftid_editor, $context-&amp;gt;id, &#039;glossary_entry&#039;, $entry-&amp;gt;id, array(&#039;subdirs&#039;=&amp;gt;true), $messagetext);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
; $context-&amp;gt;id, &#039;proper_file_area&#039; and $entry-&amp;gt;id : correspond to the contextid, filearea and itemid columns in the [[Development:File_API#Table:_files|files table]].&lt;br /&gt;
; $messagetext : this is the message text. As the files are saved to the real file area, the URLs in this content are rewritten.&lt;br /&gt;
&lt;br /&gt;
All URLs in content that point to files managed to the File API are converted to a form that starts &#039;@@PLUGINFILE@@/&#039; before the content is stored in the database. That is what we mean by rewriting.&lt;br /&gt;
&lt;br /&gt;
== File serving==&lt;br /&gt;
&lt;br /&gt;
=== Convert internal relative links to absolute links ===&lt;br /&gt;
&lt;br /&gt;
Before text content is displayed to the user, any URLs in the &#039;@@PLUGINFILE@@/&#039; form in the content need to be rewritten to the real URL where the user can access the files. &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$messagetext = file_rewrite_pluginfile_urls($messagetext, &#039;pluginfile.php&#039;,&lt;br /&gt;
        &amp;quot;$context-&amp;gt;id/proper_file_area/$itemid/&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
; $messagetext : is the content containing the @@PLUGINFILE@@ URLs from the database.&lt;br /&gt;
; &#039;pluginfile.php&#039; : there are a number of different scripts that can serve files with different permissions checks. You need to specify which one to use.&lt;br /&gt;
; &amp;quot;$context-&amp;gt;id/proper_file_area/$itemid/&amp;quot; : uniquely identifies the file area, as before.&lt;br /&gt;
&lt;br /&gt;
=== Implement file serving access control ===&lt;br /&gt;
&lt;br /&gt;
Attachments and embedded images should have the same access control like the text itself, in majority of cases these files are served using pluginfile.php. Access control is defined in &#039;&#039;module/lib.php&#039;&#039; file in function &#039;&#039;module_pluginfile()&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== File browsing support ==&lt;br /&gt;
Only owner of each file area is allowed to use low level File API function to access files, other parts of Moodle should use file browsing API.&lt;br /&gt;
&lt;br /&gt;
Activities may specify browsing support in own module/lib.php file by implementing functions module_get_file_areas() and module_get_file_info().&lt;br /&gt;
&lt;br /&gt;
== Upgrading your code ==&lt;br /&gt;
Here I will attempt to describe some simple steps you can take to upgrade your file-handling form elements from pre-2.0 code to 2.0. We will use the example of glossary, since it has been used above.&lt;br /&gt;
&lt;br /&gt;
=== Preparing your options ===&lt;br /&gt;
Unless you are happy with the defaults, you will need to define an array of options for each file-handling form element. You could define it at different places, but it&#039;s best to put it in one place and make the array(s) available to other files if they need it. In the majority of cases, this will be in a file like edit.php&lt;br /&gt;
&lt;br /&gt;
Previous code in mod/glossary/edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform =&amp;amp; new mod_glossary_entry_form(null, compact(&#039;cm&#039;, &#039;glossary&#039;, &#039;hook&#039;, &#039;mode&#039;, &#039;e&#039;, &#039;context&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$maxbytes = $course-&amp;gt;maxbytes; // Could also use $CFG-&amp;gt;maxbytes if you are not coding within a course context&lt;br /&gt;
$definitionoptions = array(&#039;subdirs&#039;=&amp;gt;false, &#039;maxfiles&#039;=&amp;gt;99, &#039;maxbytes&#039;=&amp;gt;$maxbytes, &#039;trusttext&#039;=&amp;gt;true, &#039;context&#039;=&amp;gt;$context);&lt;br /&gt;
$attachmentoptions = array(&#039;subdirs&#039;=&amp;gt;false, &#039;maxfiles&#039;=&amp;gt;99, &#039;maxbytes&#039;=&amp;gt;$maxbytes);&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&lt;br /&gt;
        &#039;current&#039;=&amp;gt;$entry, &lt;br /&gt;
        &#039;cm&#039;=&amp;gt;$cm, &lt;br /&gt;
        &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
        &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
        &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Note that the data being passed to the form constructor have changed also, but this is not part of the file API changes, I just include them to avoid confusion.&lt;br /&gt;
&lt;br /&gt;
These options are for the htmleditor (definition field) and the filemanager (attachment field). They are used by a file called edit_form.php.&lt;br /&gt;
&lt;br /&gt;
=== Element preparation ===&lt;br /&gt;
Before we look at this, however, we need to &amp;quot;prepare&amp;quot; the elements so that they can correctly display existing embedded images and attached files when you are editing a record instead of just creating one. So, let&#039;s take the code we&#039;ve got so far in edit.php and add to it:&lt;br /&gt;
&lt;br /&gt;
Currently upgraded code in edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&lt;br /&gt;
        &#039;current&#039;=&amp;gt;$entry, &lt;br /&gt;
        &#039;cm&#039;=&amp;gt;$cm, &lt;br /&gt;
        &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
        &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
        &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code with element preparation:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$entry = file_prepare_standard_editor($entry, &#039;definition&#039;, $definitionoptions, $context, &#039;glossary_entry&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$entry = file_prepare_standard_filemanager($entry, &#039;attachment&#039;, $attachmentoptions, $context, &#039;glossary_attachment&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&lt;br /&gt;
        &#039;current&#039;=&amp;gt;$entry, &lt;br /&gt;
        &#039;cm&#039;=&amp;gt;$cm, &lt;br /&gt;
        &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
        &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
        &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Things to note:&lt;br /&gt;
* $entry in this case is simply a stdClass object which may either represent a new glossary entry or an existing one.&lt;br /&gt;
* $entry-&amp;gt;id must be the unique identifier for the current object. If we are creating a new entry, it will be null, but in all cases it must be defined.&lt;br /&gt;
* These two functions (file_prepare_standard_editor and file_prepare_standard_filemanager) are shortcuts functions that take care of some of the tedious setting up for you, but they make a couple of assumptions:&lt;br /&gt;
*# You &#039;&#039;&#039;must&#039;&#039;&#039; name the form element as {element}_editor or {element}_filemanager (see next section)&lt;br /&gt;
*# You &#039;&#039;&#039;must&#039;&#039;&#039; have at least the following fields in the database: {element} and {element}summary, as described earlier in this documentation&lt;br /&gt;
&lt;br /&gt;
We can now look at the upgrades needed in the form definition file.&lt;br /&gt;
&lt;br /&gt;
=== Form definition ===&lt;br /&gt;
Previous code in mod/glossary/edit_form.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;htmleditor&#039;, &#039;definition&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;), array(&#039;rows&#039;=&amp;gt;20));&lt;br /&gt;
$mform-&amp;gt;setType(&#039;definition&#039;, PARAM_RAW);&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;definition&#039;, null, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;definition&#039;, array(&#039;writing&#039;, &#039;richtext&#039;), false, &#039;editorhelpbutton&#039;);&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;format&#039;);&lt;br /&gt;
// a bit further...&lt;br /&gt;
$this-&amp;gt;set_upload_manager(new upload_manager(&#039;attachment&#039;, true, false, $COURSE, false, 0, true, true, false));&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;file&#039;, &#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;forum&#039;));&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;attachment&#039;, array(&#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;glossary&#039;), &#039;glossary&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$definitionoptions = $this-&amp;gt;_customdata[&#039;definitionoptions&#039;];&lt;br /&gt;
$attachmentoptions = $this-&amp;gt;_customdata[&#039;attachmentoptions&#039;];&lt;br /&gt;
// a bit further...&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;definition_editor&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;), null, $definitionoptions);&lt;br /&gt;
$mform-&amp;gt;setType(&#039;definition_editor&#039;, PARAM_RAW);&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;definition_editor&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
// a bit further...&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filemanager&#039;, &#039;attachment_filemanager&#039;, get_string(&#039;attachment&#039;, &#039;glossary&#039;), null, $attachmentoptions);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;attachment_filemanager&#039;, array(&#039;attachment2&#039;, get_string(&#039;attachment&#039;, &#039;glossary&#039;), &#039;glossary&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the following:&lt;br /&gt;
* The format element and the help button are no longer required for the HTML editor element&lt;br /&gt;
* The name of the form element needs to be changed by adding &#039;_editor&#039; or &#039;_manager&#039; to the original name. This is a naming convention that is used by a couple of functions we will look at shortly&lt;br /&gt;
&lt;br /&gt;
=== Handling submitted data ===&lt;br /&gt;
The final step is to handle the submitted data properly, i.e. retrieve the files and save them to disk, associating them with the record we have just created (a glossary entry in our example). This happens in edit.php:&lt;br /&gt;
&lt;br /&gt;
Previous code in edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Section that updates an entry:&lt;br /&gt;
$todb-&amp;gt;id = $e;&lt;br /&gt;
$dir = glossary_file_area_name($todb);&lt;br /&gt;
if ($mform-&amp;gt;save_files($dir) and $newfilename = $mform-&amp;gt;get_new_filename()) {&lt;br /&gt;
    $todb-&amp;gt;attachment = $newfilename;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Section that adds an entry:&lt;br /&gt;
if ($todb-&amp;gt;id = insert_record(&amp;quot;glossary_entries&amp;quot;, $todb)) {&lt;br /&gt;
    $e = $todb-&amp;gt;id;&lt;br /&gt;
    $dir = glossary_file_area_name($todb);&lt;br /&gt;
    if ($mform-&amp;gt;save_files($dir) and $newfilename = $mform-&amp;gt;get_new_filename()) {&lt;br /&gt;
        set_field(&amp;quot;glossary_entries&amp;quot;, &amp;quot;attachment&amp;quot;, $newfilename, &amp;quot;id&amp;quot;, $todb-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// $todb was renamed to $entry, and the code was refactored &lt;br /&gt;
// so that the file-handling code is only used once for either an add or an update action.&lt;br /&gt;
// If an entry is being added, $DB-&amp;gt;insert() has already been called, so we have a valid $entry-&amp;gt;id&lt;br /&gt;
$entry = file_postupdate_standard_editor($entry, &#039;definition&#039;, $definitionoptions, $context, &#039;glossary_entry&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$entry = file_postupdate_standard_filemanager($entry, &#039;attachment&#039;, $attachmentoptions, $context, &#039;glossary_attachment&#039;, $entry-&amp;gt;id);&lt;br /&gt;
// store the updated value values&lt;br /&gt;
$DB-&amp;gt;update_record(&#039;glossary_entries&#039;, $entry);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Things to note:&lt;br /&gt;
* If you are adding a new record, you will still need to call update_record after calling the file_postupdate* functions&lt;br /&gt;
&lt;br /&gt;
=== Gotchas ===&lt;br /&gt;
A few things to keep in mind:&lt;br /&gt;
* Make sure that you instantiate the moodle form before any call to $OUTPUT-&amp;gt;header()&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Development:File API]]&lt;br /&gt;
* [[Development:Using the file API]]&lt;br /&gt;
* [[Development:Repository API]]&lt;br /&gt;
* [[Development:Portfolio API]]&lt;br /&gt;
* MDL-14589 - File API Meta issue&lt;br /&gt;
&lt;br /&gt;
{{CategoryDeveloper}}&lt;br /&gt;
[[Category:Files]]&lt;br /&gt;
[[Category:Repositories]]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Comments_2.0&amp;diff=72006</id>
		<title>Comments 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Comments_2.0&amp;diff=72006"/>
		<updated>2010-05-11T03:21:04Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Objectives==&lt;br /&gt;
&lt;br /&gt;
The goals of comments 2.0:&lt;br /&gt;
&lt;br /&gt;
* Manage comments centrally&lt;br /&gt;
* Use a consistent approach for all comments throughout Moodle&lt;br /&gt;
* Easily integrate comments 2.0 with existing modules&lt;br /&gt;
* Works no matter Javascript is enabled or not&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The comments 2.0 provides APIs to:&lt;br /&gt;
# Add comments&lt;br /&gt;
# Manage comments&lt;br /&gt;
# Delete comments&lt;br /&gt;
&lt;br /&gt;
And provides a fancy ajax interface to add/delete comments without loading a new page.&lt;br /&gt;
&lt;br /&gt;
==Comments database table==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Default&lt;br /&gt;
! Info&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| int(10)&lt;br /&gt;
| auto-incrementing&lt;br /&gt;
| The unique ID for this comment.&lt;br /&gt;
|-&lt;br /&gt;
| userid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| who wrote this comment&lt;br /&gt;
|-&lt;br /&gt;
| contextid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| The context id defined in context table - identifies the instance of plugin owning the comment.&lt;br /&gt;
|-&lt;br /&gt;
| itemid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| Some plugin specific item id (eg. forum post, blog entry or assignment submission)&lt;br /&gt;
|-&lt;br /&gt;
| commentarea&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| for example, in user profile, you can comment user&#039;s description or interests, but they share the same itemid(==userid), we need comment_area to separate them&lt;br /&gt;
|-&lt;br /&gt;
| timecreated&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| timemodified&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| content&lt;br /&gt;
| text&lt;br /&gt;
|&lt;br /&gt;
| content of comment&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Use Comments API==&lt;br /&gt;
&lt;br /&gt;
===Add an option to format_text function===&lt;br /&gt;
&lt;br /&gt;
Using this format_text function will add a comment icon automatically at the end of the text:&lt;br /&gt;
&lt;br /&gt;
For example, using the following code in the forum module will add a comment icon to every post:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$to = new stdclass;&lt;br /&gt;
$cmt-&amp;gt;contextid = $modcontext-&amp;gt;id;&lt;br /&gt;
$cmt-&amp;gt;area      = &#039;format_post&#039;;&lt;br /&gt;
$cmt-&amp;gt;itemid    = $post-&amp;gt;id;&lt;br /&gt;
$options-&amp;gt;comments = $cmt;&lt;br /&gt;
echo format_text($post-&amp;gt;message, $post-&amp;gt;messageformat, $options, $course-&amp;gt;id).&amp;quot;&amp;lt;hr /&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Use comment class===&lt;br /&gt;
To use Comments API elsewhere, using following code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$options-&amp;gt;area    = &#039;database_entry&#039;;&lt;br /&gt;
$options-&amp;gt;context = $context;&lt;br /&gt;
$options-&amp;gt;itemid  = $record-&amp;gt;id;&lt;br /&gt;
$options-&amp;gt;showcount = true;&lt;br /&gt;
$comment = new comment($options);&lt;br /&gt;
$comment-&amp;gt;output(false);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If you are using comments API in module context, you&#039;d better add pluginname option, it will help comments API find callback functions faster:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$options-&amp;gt;area    = &#039;database_entry&#039;;&lt;br /&gt;
$options-&amp;gt;pluginname = &#039;data&#039;;&lt;br /&gt;
$options-&amp;gt;context = $context;&lt;br /&gt;
$options-&amp;gt;itemid  = $record-&amp;gt;id;&lt;br /&gt;
$options-&amp;gt;showcount = true;&lt;br /&gt;
$comment = new comment($options);&lt;br /&gt;
$comment-&amp;gt;output(false);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==Comments API overview==&lt;br /&gt;
&lt;br /&gt;
Generally speaking, only two functions you need to know to get comments 2.0 worked:&lt;br /&gt;
# Use comment::init to initialize comments 2.0&lt;br /&gt;
# Use $comment-&amp;gt;output to display comments&lt;br /&gt;
&lt;br /&gt;
The comment class has been implemented in comment/lib.php.&lt;br /&gt;
===class comment()===&lt;br /&gt;
====__construct($contextid, $comment_area, $itemid))====&lt;br /&gt;
Initialize class members&lt;br /&gt;
&lt;br /&gt;
====init()====&lt;br /&gt;
It is a static function used to initialize comments, setting up languages, which must be called before html head printed&lt;br /&gt;
&lt;br /&gt;
====output($return = false)====&lt;br /&gt;
Will print the html snippet for commenting interface, if set $return as true, it will return html string instead of printing out.&lt;br /&gt;
&lt;br /&gt;
====print_comments($params = array())====&lt;br /&gt;
Used by non-javascript comment interface, will print a list of comments.&lt;br /&gt;
&lt;br /&gt;
====add($content)====&lt;br /&gt;
Public instance funciton, add a comment to database, used in comment/comment_ajax.php&lt;br /&gt;
&lt;br /&gt;
====count()====&lt;br /&gt;
Counting the number of comments&lt;br /&gt;
&lt;br /&gt;
====delete($id)====&lt;br /&gt;
Delete a comment from database, used in comment/comment_ajax.php&lt;br /&gt;
&lt;br /&gt;
====delete_comments====&lt;br /&gt;
Delete all comments in a specific contexts (like all comments belonging to a forum post)&lt;br /&gt;
&lt;br /&gt;
==Javascript API==&lt;br /&gt;
Comments 2.0 implemented a YUI3 module M.core_comment to deal with the communication between browsers and moodle.&lt;br /&gt;
It can be found in comment/comment.js&lt;br /&gt;
&lt;br /&gt;
Call M.core_comment.init will create an instance of CommentHelper class. You don&#039;t need to make any calls to this instance, it simply works out of box.&lt;br /&gt;
&lt;br /&gt;
== Moodle modules callback ==&lt;br /&gt;
Comments API allows modules/blocks/blog to decide how comments display.&lt;br /&gt;
&lt;br /&gt;
===Permission control===&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;modname_comment_permissions&#039;&#039;&#039; to control post and view permission.&lt;br /&gt;
&lt;br /&gt;
Blocks need to overwrite &#039;&#039;&#039;comment_permissions&#039;&#039;&#039; function of block_base.&lt;br /&gt;
&lt;br /&gt;
Blog need to implement &#039;&#039;&#039;blog_comment_permissions&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
This function will return an array: array(&#039;post&#039;=&amp;gt;true, &#039;view&#039;=&amp;gt;true)&lt;br /&gt;
&lt;br /&gt;
=== Check new added comment ===&lt;br /&gt;
The callback function allows you to change the comment content before inserting into database or reject this comment.&lt;br /&gt;
&lt;br /&gt;
It takes two arguments, the comment object which contains comment details, and $params which contains context and course information.&lt;br /&gt;
&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;modname_comment_add&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Blocks need to overwrite &#039;&#039;&#039;comment_add&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
Blog need to implement &#039;&#039;&#039;blog_comment_add&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
This function should return a boolean value. &lt;br /&gt;
&lt;br /&gt;
=== Filter/format comments ===&lt;br /&gt;
This callback allows modules check/format comments when user request to display comments.&lt;br /&gt;
&lt;br /&gt;
It takes the same arguments as modname_comment_add&lt;br /&gt;
&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;modname_comment_display&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Blocks need to overwrite &#039;&#039;&#039;comment_display&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
Blog need to implement &#039;&#039;&#039;blog_comment_display&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
It will return the comment object.&lt;br /&gt;
&lt;br /&gt;
=== Define a comment template ===&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;modname_comment_template&#039;&#039;&#039;, which allow modules define a comment template.&lt;br /&gt;
The template must have 4 embedding variables, ___id___, ___content___, ___time___, ___name___, they will be replaced with html id, comments content, comment time and commenter name&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* MDL-19118 - Comments 2.0 issue&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Repository_plugins&amp;diff=72005</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Repository_plugins&amp;diff=72005"/>
		<updated>2010-05-11T03:00:33Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A guide for developers on how to create a repository plugin.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
There is a template attached to MDL-16543 which might be useful to help get you started.&lt;br /&gt;
&lt;br /&gt;
===First steps===&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;moodle/repository/&#039;&#039; e.g. &#039;&#039;moodle/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files and add them to the plugin folder:&lt;br /&gt;
#* &#039;&#039;repository.class.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;icon.png&#039;&#039; (the icon displayed in the file picker)&lt;br /&gt;
#* &amp;quot;version.php&amp;quot;&lt;br /&gt;
# Create the language file &#039;&#039;repository_myplugin.php&#039;&#039; and add it to the plugin folder, keeping the following folder structure:&lt;br /&gt;
#*&#039;&#039;moodle/repository/myplugin/lang/en_utf8/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en_utf8/repository_myplugin.php&#039;&#039;&lt;br /&gt;
# Create access.php and upgrade scripts&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    &amp;lt;?php&lt;br /&gt;
    /**&lt;br /&gt;
     * repository_flickr_public class&lt;br /&gt;
     * Moodle user can access public flickr account&lt;br /&gt;
     *&lt;br /&gt;
     * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
    */&lt;br /&gt;
    class repository_flickr_public extends repository {&lt;br /&gt;
    }&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
All of the following functions are optional. If they&#039;re not implemented, your plugin will not have manual settings and will have only one instance displayed in the File Picker (The repository API creates this unique instance when the administrator add the plugin).&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
====instance_config_form(&amp;amp;$mform)====&lt;br /&gt;
This is for modifying the Moodle form displaying the settings specific to an instance.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function return an empty array.&lt;br /&gt;
&lt;br /&gt;
====type_config_form(&amp;amp;$mform)====&lt;br /&gt;
This is for modifying the Moodle form displaying the plugin settings.&lt;br /&gt;
Similar to &#039;&#039;instance_config_form(&amp;amp;$mform)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
==File picker APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
&#039;&#039;&#039;To be completed&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;?&amp;lt;br&amp;gt;&lt;br /&gt;
.....&lt;br /&gt;
&lt;br /&gt;
For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function...&amp;lt;br&amp;gt;&lt;br /&gt;
.....&lt;br /&gt;
&lt;br /&gt;
You wanna display a list of files once the user is logged&amp;lt;br&amp;gt;&lt;br /&gt;
.... get_listing() .....&lt;br /&gt;
&lt;br /&gt;
You wanna retrieve the file that the user selected&amp;lt;br&amp;gt;&lt;br /&gt;
....&lt;br /&gt;
&lt;br /&gt;
Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
.... search() ....&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
====__construct====&lt;br /&gt;
You may initialize your plugin here, such as:&lt;br /&gt;
# Get options from database&lt;br /&gt;
# Get user name and password from HTTP POST&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;01/01/2009&#039;, &#039;size&#039;=&amp;gt;&#039;10MB&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;01/01/2009&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // Used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // dynload tells file picker to fetch list dynamically, when user click&lt;br /&gt;
   // the folder, it will send a ajax request to server side.&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be used&lt;br /&gt;
   // and note, you&#039;d better don&#039;t use pagination and page at the same time&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (pages) how many pages&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // will display a link in file picker&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url of the file manager,&lt;br /&gt;
   // set to true, the login link will be removed from file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login,&lt;br /&gt;
   // set to true, the search link will be removed from file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link,&lt;br /&gt;
   // set this option will display a upload form in file picker&lt;br /&gt;
   // only used in upload plugin currently&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // file picker will build a file tree according this &lt;br /&gt;
   // list&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (string) file last modification time, usually userdate(...),&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039;=&amp;gt; the accessible url of file&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - same as file, but no &#039;source&#039;.&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (string) folder last modification time, usually userdate(...),&lt;br /&gt;
       &#039;size&#039; =&amp;gt; 0,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the folder,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( // an empty folder needs to have &#039;children&#039; defined, but empty.&lt;br /&gt;
         // content (files and folders)&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/repository.class.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
===Functions you can override===&lt;br /&gt;
====print_login====&lt;br /&gt;
This function will help to print a login form, for the Ajax file picker, this function will return a&lt;br /&gt;
PHP array to define this form.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    public function print_login(){&lt;br /&gt;
        if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
            $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $user_field-&amp;gt;id    = &#039;box_username&#039;;&lt;br /&gt;
            $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
            $user_field-&amp;gt;name  = &#039;boxusername&#039;;&lt;br /&gt;
            $user_field-&amp;gt;value = $ret-&amp;gt;username;&lt;br /&gt;
            &lt;br /&gt;
            $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;id    = &#039;box_password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;name  = &#039;boxpassword&#039;;&lt;br /&gt;
&lt;br /&gt;
            $ret = array();&lt;br /&gt;
            $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
            // if you are going to rename submit button label, use this option&lt;br /&gt;
            //$ret[&#039;login_btn_label&#039;] = get_string(&#039;submit_btn_label&#039;);&lt;br /&gt;
            // if you are going to display a search form instead of login form&lt;br /&gt;
            // set this option to true&lt;br /&gt;
            //$ret[&#039;login_search_form&#039;] = true;&lt;br /&gt;
            return $ret;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
If your plugin don&#039;t require logging in, you don&#039;t need to override it, it will call get_listing to list files automatically by default.&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here.&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the from the form you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
====get_file====&lt;br /&gt;
When a user clicks the &amp;quot;Get&amp;quot; button to transfer the file, this function will be called. Basically, it will download a file to Moodle - you can override it to modify the file then move it to a better location.&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en_utf8/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en_utf8/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;repositorydesc&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
$string[&#039;repositoryname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Standard repository plugins ==&lt;br /&gt;
This is the functional specification list of the officially supported repository plugins.&lt;br /&gt;
For each plugins, the two mains part we are interested in are:&lt;br /&gt;
* How do I administrate the plugin? See [[Development:Repository_Administration_Specification| Repository Administration Specification - UC001-3]]&lt;br /&gt;
* How do I set up an account for this repository? See [[Development:Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
&lt;br /&gt;
=== Functional specifications ===&lt;br /&gt;
*[[Development:Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Development:Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Development:Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Development:Repository API| Repository API]]&lt;br /&gt;
*[[Development:Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
[[Category:Repositories]]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Broken/Repository_API&amp;diff=72004</id>
		<title>Broken/Repository API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Broken/Repository_API&amp;diff=72004"/>
		<updated>2010-05-11T02:59:03Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: fixed syntax&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
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&#039;ll endeavour to merge all such suggestions into the further development and fix all kinds of problems.&lt;br /&gt;
&lt;br /&gt;
Note that parts of this document have been now split off into a separate [[Development:File_API]]&lt;br /&gt;
&lt;br /&gt;
==Objectives==&lt;br /&gt;
&lt;br /&gt;
# Allow all Moodle users to easily bring content into Moodle from external repositories&lt;br /&gt;
# Provide a consistent interface to any external repository, for any Moodle module&lt;br /&gt;
&lt;br /&gt;
==Use cases==&lt;br /&gt;
&lt;br /&gt;
===Teacher adding an external file as a new resource===&lt;br /&gt;
&lt;br /&gt;
# Teacher wants to add a new resource to a course &lt;br /&gt;
# Teacher clicks the &amp;quot;Choose a resource&amp;quot; button&lt;br /&gt;
# Teacher is presented with a simple file picker to choose a file (with a menu to switch between multiple configured repositories)&lt;br /&gt;
# Teacher chooses a file in an external repository&lt;br /&gt;
# File is COPIED into Moodle and stored by the resource module&lt;br /&gt;
# File is marked as owned by that user&lt;br /&gt;
# Whenever someone wants to view that file, the resource module controls access  (see [[Development:File API]] )&lt;br /&gt;
&lt;br /&gt;
===Teacher linking to an external file as a new resource (think video repository) ===&lt;br /&gt;
&lt;br /&gt;
# Teacher wants to display a file in the repository &lt;br /&gt;
# Teacher clicks the &amp;quot;Choose a resource&amp;quot; button&lt;br /&gt;
# Teacher is presented with a simple file picker to choose a file (with a menu to switch between multiple configured repositories)&lt;br /&gt;
# Teacher chooses a file in an external repository&lt;br /&gt;
# Link to the file is COPIED into Moodle and stored by the resource module&lt;br /&gt;
# Link is marked as owned by that user&lt;br /&gt;
# Whenever someone wants to follow that link, the resource module controls access  (see [[Development:File API]] )&lt;br /&gt;
&lt;br /&gt;
===Student submitting an assignment===&lt;br /&gt;
# Student needs to submit an assignment and presses the &amp;quot;Choose files&amp;quot; button&lt;br /&gt;
# Student sees a &amp;quot;file picker&amp;quot; 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])&lt;br /&gt;
# Student chooses MySpace from the list&lt;br /&gt;
# Student is prompted to enter MySpace username/password (if admin allows it, a checkbox could be there to &amp;quot;remember this for next time&amp;quot; but remember security)&lt;br /&gt;
# Student sees their files in MySpace and chooses one or more&lt;br /&gt;
# Files are copied from MySpace to Moodle &lt;br /&gt;
# Assignment module controls the permissions so that only the Student and assignment graders can see the file (other students would not have permission).&lt;br /&gt;
&lt;br /&gt;
===Student attaching an image to a forum===&lt;br /&gt;
# Student needs to attach an image and presses the &amp;quot;Choose files&amp;quot; button in the posting screen&lt;br /&gt;
# Student sees a &amp;quot;file picker&amp;quot; where they can see files listed on any of several configured repositories&lt;br /&gt;
# Student chooses Mahara from the list&lt;br /&gt;
# Student is prompted to enter Mahara username/password&lt;br /&gt;
# Student sees their files in Mahara and chooses one image&lt;br /&gt;
# Image is copied to Moodle &lt;br /&gt;
# Image file is attached to forum post by Forum module (by reference)&lt;br /&gt;
# Forum module controls permissions so that anyone who can read that forum can see that file&lt;br /&gt;
&lt;br /&gt;
===Student attaching the same image in another forum===&lt;br /&gt;
&lt;br /&gt;
# Student needs to submit an assignment and presses the &amp;quot;Choose files&amp;quot; button&lt;br /&gt;
# Student sees a &amp;quot;file picker&amp;quot; where they can see files listed on any of several configured repositories&lt;br /&gt;
# Student chooses &amp;quot;Local files&amp;quot; from the list and sees all the files they&#039;ve permission to use&lt;br /&gt;
# A COPY of the image file is attached to forum post by Forum module&lt;br /&gt;
# Forum module controls access to this file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please add more use cases in this same format&lt;br /&gt;
&lt;br /&gt;
==Mock screenshots==&lt;br /&gt;
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):&lt;br /&gt;
&lt;br /&gt;
[[Image:Filepicker_login.jpg]]&lt;br /&gt;
&lt;br /&gt;
Browsing files could look something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image:Filepicker_browser.jpg]]&lt;br /&gt;
&lt;br /&gt;
And you can also search:&lt;br /&gt;
&lt;br /&gt;
[[Image:Filepicker_search.jpg]]&lt;br /&gt;
&lt;br /&gt;
==General architecture==&lt;br /&gt;
&lt;br /&gt;
Each repository plugin (a standard Moodle plugin stored under /repository/xxx) will subclass the standard API and override methods specific to that repository.&lt;br /&gt;
&lt;br /&gt;
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 [http://briefcase.yahoo.com Yahoo Briefcase] or [http://docs.google.com Google Docs]) and to select their default repository.&lt;br /&gt;
&lt;br /&gt;
Once a repository has been used the file will usually be copied into Moodle there and then.  However there will also be options to:&lt;br /&gt;
* only return the URL to the file if it&#039;s desired to keep it external (but this does present security and integrity risks), or&lt;br /&gt;
* refresh the local file copy regularly and automatically&lt;br /&gt;
* refresh the file manually if desired&lt;br /&gt;
&lt;br /&gt;
Once in Moodle, it is subject to the [[Development:File API]] for access control like any other file.&lt;br /&gt;
&lt;br /&gt;
==Repository requirements==&lt;br /&gt;
&lt;br /&gt;
From the Moodle point of view, each repository is just a hierarchy of nodes.&lt;br /&gt;
&lt;br /&gt;
The repository MUST provide:&lt;br /&gt;
# A URI to download each node (eg file).&lt;br /&gt;
# 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).&lt;br /&gt;
&lt;br /&gt;
The repository can OPTIONALLY:&lt;br /&gt;
# Require some authentication credentials &lt;br /&gt;
# Provide more metadata about each node (mime type, size, dates, related files, dublin core stuff, etc)&lt;br /&gt;
# Describe a search facility (so that Moodle can construct a search form)&lt;br /&gt;
# Provide copyright and usage rules (or just information about the rules)&lt;br /&gt;
&lt;br /&gt;
==Repository plugins==&lt;br /&gt;
&lt;br /&gt;
Some plugins I&#039;d like to see developed for the first version are:&lt;br /&gt;
* box - an interface to [http://box.net box.net]&lt;br /&gt;
* mahara - an interface to a Mahara installation&lt;br /&gt;
* Server Files - very similar to the current course-based file manager, except user-based&lt;br /&gt;
* Remote Moodle - an interface to another Moodle site, accessed over a secure mnet connection&lt;br /&gt;
* googledocs - an interface to [http://docs.google.com Google Docs]&lt;br /&gt;
* s3 - an interface to [http://www.amazon.com/gp/browse.html?node=16427261 Amazon S3]&lt;br /&gt;
* flickr - an interface to [http://flickr.com flickr]&lt;br /&gt;
* WebDAV - to access arbitrary external WebDAV servers&lt;br /&gt;
* merlot - an interface to the learning materials in [http://www.merlot.org/merlot/materials.htm Merlot.org]&lt;br /&gt;
* File System - a plugin to list files on local file system, of course, you can mount remote files to this local directory&lt;br /&gt;
* youtube - an interface to [http://youtube.com YouTube]&lt;br /&gt;
* jsr170 - an interface that can talk to anything that supports jsr170 (eg [http://www.alfresco.com/ Alfresco])&lt;br /&gt;
* oki - an OKI emulator allowing us to access things with OKI interfaces,like [http://www.fedora.info/ Fedora]&lt;br /&gt;
* briefcase - an interface to [http://briefcase.yahoo.com/ Yahoo Briefcase]&lt;br /&gt;
* myspace - an interface to MySpace files (perhaps via [http://www.programmableweb.com/api/myspace this MySpace API])&lt;br /&gt;
* skydrive - an interface to Microsoft&#039;s [http://skydrive.live.com/ SkyDrive] files&lt;br /&gt;
* facebook - an interface to Facebook files&lt;br /&gt;
* [http://www.dspace.org/ Dspace] - a repository from MIT&lt;br /&gt;
* DOOR - another popular open source repository&lt;br /&gt;
* 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&amp;amp;rid=991 this block] for a linux implementation.&lt;br /&gt;
&lt;br /&gt;
==Tables==&lt;br /&gt;
&lt;br /&gt;
=== repository ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Default&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;id&#039;&#039;&#039;&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|autoincrementing &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;type&#039;&#039;&#039;&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|&lt;br /&gt;
|The type of the repository &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;visible&#039;&#039;&#039;&lt;br /&gt;
|tinyint(1)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|sortorder&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== repository_instances ===&lt;br /&gt;
&lt;br /&gt;
This table contains one entry for every configured external repository instance.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Default&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;id&#039;&#039;&#039;&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|autoincrementing &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|name&lt;br /&gt;
|varchar 255&lt;br /&gt;
|&lt;br /&gt;
|A custom name for this repository (non-unique)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;typeid&#039;&#039;&#039; &lt;br /&gt;
|int(10)&lt;br /&gt;
| &lt;br /&gt;
|The id of repository type&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;userid&#039;&#039;&#039; &lt;br /&gt;
|int(10)&lt;br /&gt;
| &lt;br /&gt;
|The person who created this repository instance&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;contextid&#039;&#039;&#039; &lt;br /&gt;
|int(10)&lt;br /&gt;
| &lt;br /&gt;
|The context that this repository is available to ( = system context for site-wide ones)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|username&lt;br /&gt;
|varchar(255)&lt;br /&gt;
| &lt;br /&gt;
|username to log in with, if required (almost never!)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|password&lt;br /&gt;
|varchar(255)&lt;br /&gt;
| &lt;br /&gt;
|password to log in with, if required (almost never!)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|timecreated&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|The time this repository was created&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|timemodified&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|The last time the repository was modified&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== repository_instance_config ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Default&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;id&#039;&#039;&#039;&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|autoincrementing &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;instanceid&#039;&#039;&#039;&lt;br /&gt;
|int(int)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|value&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File types===&lt;br /&gt;
&lt;br /&gt;
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).  &lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
==Technical walkthrough==&lt;br /&gt;
&lt;br /&gt;
(See also the functional spec for the [[Development:Repository_File_Picker]] )&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
===Case 1: As part of a Moodleform with Javascript===&lt;br /&gt;
&lt;br /&gt;
1. Moodle module code calls a &amp;quot;filepicker&amp;quot; moodleform item whenever a file is required, which includes the following information to pass to the File API:&lt;br /&gt;
&lt;br /&gt;
 eg $mform-&amp;gt;addElement(&#039;filepicker&#039;, &#039;uniqueelementid&#039;, $fullname, $data)&lt;br /&gt;
 &lt;br /&gt;
2. When rendering the form, Moodle will display a read-only filename field with an &#039;&#039;&#039;&amp;quot;Add file&amp;quot;&#039;&#039;&#039; 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).&lt;br /&gt;
&lt;br /&gt;
3. When the add file button is pressed, the form will be &amp;quot;replaced&amp;quot; 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)&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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&#039;ll also ask the plugin to return listing data in response to clicks and searches.  &lt;br /&gt;
&lt;br /&gt;
6. Finally, when the user selects a file and clicks the &amp;quot;Select&amp;quot; button, the AJAX interface will trigger a method in the plugin that will fetch the file and call the File Storage API to &#039;&#039;&#039;store&#039;&#039;&#039; the file using the &#039;&#039;&#039;uniqueelementid&#039;&#039;&#039; and the current user info.  While this is happening, the interface should show some sort of progress bar (ideally) or at least a &amp;quot;loading file&amp;quot; image/sign/message.  &lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;uniqueelementid_formid&#039;&#039;&#039;).  The picker can then rename the read-only filename field before it hides itself.&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;fix&amp;quot; the info for each file and &amp;quot;move&amp;quot; it into the module file area:&lt;br /&gt;
&lt;br /&gt;
  eg $mform-&amp;gt;store_local_file(&#039;uniqueelementid&#039;, $context, $filearename, $itemid, $filepath);&lt;br /&gt;
&lt;br /&gt;
9. Cron jobs in File Storage api should automatically delete any files in the user&#039;s tempfile area that are older than 7 days or move them into a trash can in the user&#039;s file area (perhaps).&lt;br /&gt;
&lt;br /&gt;
===Case 2: As part of a Moodleform without Javascript===&lt;br /&gt;
&lt;br /&gt;
Steps 1-2 are the same as for the case with Javascript.&lt;br /&gt;
&lt;br /&gt;
3. The add file button is a submit button for the form with a different value.  When the add file button is pressed,&lt;br /&gt;
* the whole form will be &#039;&#039;submitted&#039;&#039; to the original location (but with a different submit button value)&lt;br /&gt;
* moodleforms get_data() will detect this is a &amp;quot;repository save&amp;quot; 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&lt;br /&gt;
* moodleforms get_data() then redirects the user to a new page showing the main picker interface&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
5. Finally, when the user selects a file and submits using the &amp;quot;Select&amp;quot; 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 &amp;quot;loading file&amp;quot; image/sign/message.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
Steps 8-9 are the same as for the case with Javascript.&lt;br /&gt;
&lt;br /&gt;
===Case 3: As part of a HTML editor===&lt;br /&gt;
&lt;br /&gt;
The key thing here is a move away from storing any absolute URLs to files in our HTML texts.  Instead we&#039;ll store relative names.&lt;br /&gt;
&lt;br /&gt;
1. The moodleform for a textarea (HTML editor) will require a path to the filearea associated with this HTML.  eg &#039;&#039;&#039;wwwroot/pluginfile.php/13/content/0/&#039;&#039;&#039;.  This would have to be the user_draft area if the filearea doesn&#039;t exist yet  eg &#039;&#039;&#039;wwwroot/draftfile.php/userid/tempfile/uniquelementid&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.)&lt;br /&gt;
&lt;br /&gt;
3. The path parameter also needs to be added to the editor configuration in the current page.&lt;br /&gt;
&lt;br /&gt;
4. Editor plugins can be modified to look for these variables in the editor configuration.&lt;br /&gt;
&lt;br /&gt;
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&#039;t already exist, prefixing the supplied path to the filename and returning a URL back to the dialog text input before closing.&lt;br /&gt;
&lt;br /&gt;
6. On submission, and after the HTML is stored, we might now have a new permanent filearea, so we&#039;ll need to update any associated temporary files to make sure they have the proper file area information.&lt;br /&gt;
&lt;br /&gt;
==Repository plugins==&lt;br /&gt;
&lt;br /&gt;
Each repository plugin is required to contain the following elements:&lt;br /&gt;
&lt;br /&gt;
===class repository()===&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Repositories can redefine any of these methods as required (and in some instances, MUST redefine them):&lt;br /&gt;
&lt;br /&gt;
====__construct($repositoryid, $contextid, $options=array(), $readonly)====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MUST&#039;&#039;&#039; redefine&lt;br /&gt;
&lt;br /&gt;
Accept necessary parameters, and do initialization of repository.&lt;br /&gt;
&lt;br /&gt;
====get_file($url, $file = &#039;&#039;)====&lt;br /&gt;
&lt;br /&gt;
Given a URL, download a file from there, save the file in a temporary directory.&lt;br /&gt;
&lt;br /&gt;
====get_link($info)====&lt;br /&gt;
Get the url of external resource&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&#039;/&#039;, $page=&#039;&#039;&#039;&#039;&#039;&#039;&#039;&#039;)====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
====search($keyword)====&lt;br /&gt;
Search repository by given keyword, it will return an array of the same format of get_listing&lt;br /&gt;
&lt;br /&gt;
====print_login()====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
====print_search==== &lt;br /&gt;
&lt;br /&gt;
Print the search form, it will return a json string&lt;br /&gt;
&lt;br /&gt;
====get_meta()====&lt;br /&gt;
Return information for creating ajax request, it is private function, you don&#039;t need to rewrite it.&lt;br /&gt;
&lt;br /&gt;
====create()====&lt;br /&gt;
Create an instance&lt;br /&gt;
&lt;br /&gt;
====delete()====&lt;br /&gt;
Delete this instance from `repository` table&lt;br /&gt;
&lt;br /&gt;
====hide()====&lt;br /&gt;
Hide a repository instance from file picker list&lt;br /&gt;
&lt;br /&gt;
====set_option()====&lt;br /&gt;
set options in data1-data5 fields, can be overrided&lt;br /&gt;
&lt;br /&gt;
====get_option()====&lt;br /&gt;
get option list or a specific option from database&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names()====&lt;br /&gt;
If this plugin needs admin settings, please refine this function to return option names.&lt;br /&gt;
&lt;br /&gt;
====type_config_form()====&lt;br /&gt;
If get_type_option_names return non empty array, this function &#039;&#039;&#039;MUST&#039;&#039;&#039; redefine, it will help to build the setting form.&lt;br /&gt;
&lt;br /&gt;
====get_instance_option_names()====&lt;br /&gt;
If plugin instance needs settings, this function will return instance option names.&lt;br /&gt;
&lt;br /&gt;
====instance_config_form()====&lt;br /&gt;
If get_instance_option_names return non empty array, this function &#039;&#039;&#039;MUST&#039;&#039;&#039; redefine, it will help to build the instance setting form.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes()====&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes()====&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
====filter()====&lt;br /&gt;
Filter file listing to exclude specific file types&lt;br /&gt;
&lt;br /&gt;
===icon.png===&lt;br /&gt;
&lt;br /&gt;
A logo that represents the repository.  Ideally square but we should handle all sizes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Development:Repository Administration Specification]]&lt;br /&gt;
* [[Development:Repository Interface for Moodle/Course/User]]&lt;br /&gt;
* [[Development:Repository plugins]]&lt;br /&gt;
* [[Development:Repository File Picker]]&lt;br /&gt;
* [[Development:File API]]&lt;br /&gt;
* [[Development:Portfolio API]]&lt;br /&gt;
* MDL-13766 and MDL-16543 Repository API Meta issues&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発:リポジトリAPI]]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Broken/Repository_API&amp;diff=72003</id>
		<title>Broken/Repository API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Broken/Repository_API&amp;diff=72003"/>
		<updated>2010-05-11T02:58:06Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: update&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
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&#039;ll endeavour to merge all such suggestions into the further development and fix all kinds of problems.&lt;br /&gt;
&lt;br /&gt;
Note that parts of this document have been now split off into a separate [[Development:File_API]]&lt;br /&gt;
&lt;br /&gt;
==Objectives==&lt;br /&gt;
&lt;br /&gt;
# Allow all Moodle users to easily bring content into Moodle from external repositories&lt;br /&gt;
# Provide a consistent interface to any external repository, for any Moodle module&lt;br /&gt;
&lt;br /&gt;
==Use cases==&lt;br /&gt;
&lt;br /&gt;
===Teacher adding an external file as a new resource===&lt;br /&gt;
&lt;br /&gt;
# Teacher wants to add a new resource to a course &lt;br /&gt;
# Teacher clicks the &amp;quot;Choose a resource&amp;quot; button&lt;br /&gt;
# Teacher is presented with a simple file picker to choose a file (with a menu to switch between multiple configured repositories)&lt;br /&gt;
# Teacher chooses a file in an external repository&lt;br /&gt;
# File is COPIED into Moodle and stored by the resource module&lt;br /&gt;
# File is marked as owned by that user&lt;br /&gt;
# Whenever someone wants to view that file, the resource module controls access  (see [[Development:File API]] )&lt;br /&gt;
&lt;br /&gt;
===Teacher linking to an external file as a new resource (think video repository) ===&lt;br /&gt;
&lt;br /&gt;
# Teacher wants to display a file in the repository &lt;br /&gt;
# Teacher clicks the &amp;quot;Choose a resource&amp;quot; button&lt;br /&gt;
# Teacher is presented with a simple file picker to choose a file (with a menu to switch between multiple configured repositories)&lt;br /&gt;
# Teacher chooses a file in an external repository&lt;br /&gt;
# Link to the file is COPIED into Moodle and stored by the resource module&lt;br /&gt;
# Link is marked as owned by that user&lt;br /&gt;
# Whenever someone wants to follow that link, the resource module controls access  (see [[Development:File API]] )&lt;br /&gt;
&lt;br /&gt;
===Student submitting an assignment===&lt;br /&gt;
# Student needs to submit an assignment and presses the &amp;quot;Choose files&amp;quot; button&lt;br /&gt;
# Student sees a &amp;quot;file picker&amp;quot; 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])&lt;br /&gt;
# Student chooses MySpace from the list&lt;br /&gt;
# Student is prompted to enter MySpace username/password (if admin allows it, a checkbox could be there to &amp;quot;remember this for next time&amp;quot; but remember security)&lt;br /&gt;
# Student sees their files in MySpace and chooses one or more&lt;br /&gt;
# Files are copied from MySpace to Moodle &lt;br /&gt;
# Assignment module controls the permissions so that only the Student and assignment graders can see the file (other students would not have permission).&lt;br /&gt;
&lt;br /&gt;
===Student attaching an image to a forum===&lt;br /&gt;
# Student needs to attach an image and presses the &amp;quot;Choose files&amp;quot; button in the posting screen&lt;br /&gt;
# Student sees a &amp;quot;file picker&amp;quot; where they can see files listed on any of several configured repositories&lt;br /&gt;
# Student chooses Mahara from the list&lt;br /&gt;
# Student is prompted to enter Mahara username/password&lt;br /&gt;
# Student sees their files in Mahara and chooses one image&lt;br /&gt;
# Image is copied to Moodle &lt;br /&gt;
# Image file is attached to forum post by Forum module (by reference)&lt;br /&gt;
# Forum module controls permissions so that anyone who can read that forum can see that file&lt;br /&gt;
&lt;br /&gt;
===Student attaching the same image in another forum===&lt;br /&gt;
&lt;br /&gt;
# Student needs to submit an assignment and presses the &amp;quot;Choose files&amp;quot; button&lt;br /&gt;
# Student sees a &amp;quot;file picker&amp;quot; where they can see files listed on any of several configured repositories&lt;br /&gt;
# Student chooses &amp;quot;Local files&amp;quot; from the list and sees all the files they&#039;ve permission to use&lt;br /&gt;
# A COPY of the image file is attached to forum post by Forum module&lt;br /&gt;
# Forum module controls access to this file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please add more use cases in this same format&lt;br /&gt;
&lt;br /&gt;
==Mock screenshots==&lt;br /&gt;
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):&lt;br /&gt;
&lt;br /&gt;
[[Image:Filepicker_login.jpg]]&lt;br /&gt;
&lt;br /&gt;
Browsing files could look something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image:Filepicker_browser.jpg]]&lt;br /&gt;
&lt;br /&gt;
And you can also search:&lt;br /&gt;
&lt;br /&gt;
[[Image:Filepicker_search.jpg]]&lt;br /&gt;
&lt;br /&gt;
==General architecture==&lt;br /&gt;
&lt;br /&gt;
Each repository plugin (a standard Moodle plugin stored under /repository/xxx) will subclass the standard API and override methods specific to that repository.&lt;br /&gt;
&lt;br /&gt;
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 [http://briefcase.yahoo.com Yahoo Briefcase] or [http://docs.google.com Google Docs]) and to select their default repository.&lt;br /&gt;
&lt;br /&gt;
Once a repository has been used the file will usually be copied into Moodle there and then.  However there will also be options to:&lt;br /&gt;
* only return the URL to the file if it&#039;s desired to keep it external (but this does present security and integrity risks), or&lt;br /&gt;
* refresh the local file copy regularly and automatically&lt;br /&gt;
* refresh the file manually if desired&lt;br /&gt;
&lt;br /&gt;
Once in Moodle, it is subject to the [[Development:File API]] for access control like any other file.&lt;br /&gt;
&lt;br /&gt;
==Repository requirements==&lt;br /&gt;
&lt;br /&gt;
From the Moodle point of view, each repository is just a hierarchy of nodes.&lt;br /&gt;
&lt;br /&gt;
The repository MUST provide:&lt;br /&gt;
# A URI to download each node (eg file).&lt;br /&gt;
# 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).&lt;br /&gt;
&lt;br /&gt;
The repository can OPTIONALLY:&lt;br /&gt;
# Require some authentication credentials &lt;br /&gt;
# Provide more metadata about each node (mime type, size, dates, related files, dublin core stuff, etc)&lt;br /&gt;
# Describe a search facility (so that Moodle can construct a search form)&lt;br /&gt;
# Provide copyright and usage rules (or just information about the rules)&lt;br /&gt;
&lt;br /&gt;
==Repository plugins==&lt;br /&gt;
&lt;br /&gt;
Some plugins I&#039;d like to see developed for the first version are:&lt;br /&gt;
* box - an interface to [http://box.net box.net]&lt;br /&gt;
* mahara - an interface to a Mahara installation&lt;br /&gt;
* Server Files - very similar to the current course-based file manager, except user-based&lt;br /&gt;
* Remote Moodle - an interface to another Moodle site, accessed over a secure mnet connection&lt;br /&gt;
* googledocs - an interface to [http://docs.google.com Google Docs]&lt;br /&gt;
* s3 - an interface to [http://www.amazon.com/gp/browse.html?node=16427261 Amazon S3]&lt;br /&gt;
* flickr - an interface to [http://flickr.com flickr]&lt;br /&gt;
* WebDAV - to access arbitrary external WebDAV servers&lt;br /&gt;
* merlot - an interface to the learning materials in [http://www.merlot.org/merlot/materials.htm Merlot.org]&lt;br /&gt;
* File System - a plugin to list files on local file system, of course, you can mount remote files to this local directory&lt;br /&gt;
* youtube - an interface to [http://youtube.com YouTube]&lt;br /&gt;
* jsr170 - an interface that can talk to anything that supports jsr170 (eg [http://www.alfresco.com/ Alfresco])&lt;br /&gt;
* oki - an OKI emulator allowing us to access things with OKI interfaces,like [http://www.fedora.info/ Fedora]&lt;br /&gt;
* briefcase - an interface to [http://briefcase.yahoo.com/ Yahoo Briefcase]&lt;br /&gt;
* myspace - an interface to MySpace files (perhaps via [http://www.programmableweb.com/api/myspace this MySpace API])&lt;br /&gt;
* skydrive - an interface to Microsoft&#039;s [http://skydrive.live.com/ SkyDrive] files&lt;br /&gt;
* facebook - an interface to Facebook files&lt;br /&gt;
* [http://www.dspace.org/ Dspace] - a repository from MIT&lt;br /&gt;
* DOOR - another popular open source repository&lt;br /&gt;
* 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&amp;amp;rid=991 this block] for a linux implementation.&lt;br /&gt;
&lt;br /&gt;
==Tables==&lt;br /&gt;
&lt;br /&gt;
=== repository ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Default&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;id&#039;&#039;&#039;&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|autoincrementing &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;type&#039;&#039;&#039;&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|&lt;br /&gt;
|The type of the repository &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;visible&#039;&#039;&#039;&lt;br /&gt;
|tinyint(1)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|sortorder&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== repository_instances ===&lt;br /&gt;
&lt;br /&gt;
This table contains one entry for every configured external repository instance.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Default&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;id&#039;&#039;&#039;&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|autoincrementing &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|name&lt;br /&gt;
|varchar 255&lt;br /&gt;
|&lt;br /&gt;
|A custom name for this repository (non-unique)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;typeid&#039;&#039;&#039; &lt;br /&gt;
|int(10)&lt;br /&gt;
| &lt;br /&gt;
|The id of repository type&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;userid&#039;&#039;&#039; &lt;br /&gt;
|int(10)&lt;br /&gt;
| &lt;br /&gt;
|The person who created this repository instance&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;contextid&#039;&#039;&#039; &lt;br /&gt;
|int(10)&lt;br /&gt;
| &lt;br /&gt;
|The context that this repository is available to ( = system context for site-wide ones)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|username&lt;br /&gt;
|varchar(255)&lt;br /&gt;
| &lt;br /&gt;
|username to log in with, if required (almost never!)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|password&lt;br /&gt;
|varchar(255)&lt;br /&gt;
| &lt;br /&gt;
|password to log in with, if required (almost never!)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|timecreated&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|The time this repository was created&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|timemodified&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|The last time the repository was modified&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== repository_instance_config ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Default&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;id&#039;&#039;&#039;&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|autoincrementing &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;instanceid&#039;&#039;&#039;&lt;br /&gt;
|int(int)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|value&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File types===&lt;br /&gt;
&lt;br /&gt;
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).  &lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
==Technical walkthrough==&lt;br /&gt;
&lt;br /&gt;
(See also the functional spec for the [[Development:Repository_File_Picker]] )&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
===Case 1: As part of a Moodleform with Javascript===&lt;br /&gt;
&lt;br /&gt;
1. Moodle module code calls a &amp;quot;filepicker&amp;quot; moodleform item whenever a file is required, which includes the following information to pass to the File API:&lt;br /&gt;
&lt;br /&gt;
 eg $mform-&amp;gt;addElement(&#039;filepicker&#039;, &#039;uniqueelementid&#039;, $fullname, $data)&lt;br /&gt;
 &lt;br /&gt;
2. When rendering the form, Moodle will display a read-only filename field with an &#039;&#039;&#039;&amp;quot;Add file&amp;quot;&#039;&#039;&#039; 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).&lt;br /&gt;
&lt;br /&gt;
3. When the add file button is pressed, the form will be &amp;quot;replaced&amp;quot; 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)&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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&#039;ll also ask the plugin to return listing data in response to clicks and searches.  &lt;br /&gt;
&lt;br /&gt;
6. Finally, when the user selects a file and clicks the &amp;quot;Select&amp;quot; button, the AJAX interface will trigger a method in the plugin that will fetch the file and call the File Storage API to &#039;&#039;&#039;store&#039;&#039;&#039; the file using the &#039;&#039;&#039;uniqueelementid&#039;&#039;&#039; and the current user info.  While this is happening, the interface should show some sort of progress bar (ideally) or at least a &amp;quot;loading file&amp;quot; image/sign/message.  &lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;uniqueelementid_formid&#039;&#039;&#039;).  The picker can then rename the read-only filename field before it hides itself.&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;fix&amp;quot; the info for each file and &amp;quot;move&amp;quot; it into the module file area:&lt;br /&gt;
&lt;br /&gt;
  eg $mform-&amp;gt;store_local_file(&#039;uniqueelementid&#039;, $context, $filearename, $itemid, $filepath);&lt;br /&gt;
&lt;br /&gt;
9. Cron jobs in File Storage api should automatically delete any files in the user&#039;s tempfile area that are older than 7 days or move them into a trash can in the user&#039;s file area (perhaps).&lt;br /&gt;
&lt;br /&gt;
===Case 2: As part of a Moodleform without Javascript===&lt;br /&gt;
&lt;br /&gt;
Steps 1-2 are the same as for the case with Javascript.&lt;br /&gt;
&lt;br /&gt;
3. The add file button is a submit button for the form with a different value.  When the add file button is pressed,&lt;br /&gt;
* the whole form will be &#039;&#039;submitted&#039;&#039; to the original location (but with a different submit button value)&lt;br /&gt;
* moodleforms get_data() will detect this is a &amp;quot;repository save&amp;quot; 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&lt;br /&gt;
* moodleforms get_data() then redirects the user to a new page showing the main picker interface&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
5. Finally, when the user selects a file and submits using the &amp;quot;Select&amp;quot; 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 &amp;quot;loading file&amp;quot; image/sign/message.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
Steps 8-9 are the same as for the case with Javascript.&lt;br /&gt;
&lt;br /&gt;
===Case 3: As part of a HTML editor===&lt;br /&gt;
&lt;br /&gt;
The key thing here is a move away from storing any absolute URLs to files in our HTML texts.  Instead we&#039;ll store relative names.&lt;br /&gt;
&lt;br /&gt;
1. The moodleform for a textarea (HTML editor) will require a path to the filearea associated with this HTML.  eg &#039;&#039;&#039;wwwroot/pluginfile.php/13/content/0/&#039;&#039;&#039;.  This would have to be the user_draft area if the filearea doesn&#039;t exist yet  eg &#039;&#039;&#039;wwwroot/draftfile.php/userid/tempfile/uniquelementid&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.)&lt;br /&gt;
&lt;br /&gt;
3. The path parameter also needs to be added to the editor configuration in the current page.&lt;br /&gt;
&lt;br /&gt;
4. Editor plugins can be modified to look for these variables in the editor configuration.&lt;br /&gt;
&lt;br /&gt;
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&#039;t already exist, prefixing the supplied path to the filename and returning a URL back to the dialog text input before closing.&lt;br /&gt;
&lt;br /&gt;
6. On submission, and after the HTML is stored, we might now have a new permanent filearea, so we&#039;ll need to update any associated temporary files to make sure they have the proper file area information.&lt;br /&gt;
&lt;br /&gt;
==Repository plugins==&lt;br /&gt;
&lt;br /&gt;
Each repository plugin is required to contain the following elements:&lt;br /&gt;
&lt;br /&gt;
===class repository()===&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
Repositories can redefine any of these methods as required (and in some instances, MUST redefine them):&lt;br /&gt;
&lt;br /&gt;
====__construct($repositoryid, $contextid, $options=array(), $readonly)====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MUST&#039;&#039;&#039; redefine&lt;br /&gt;
&lt;br /&gt;
Accept necessary parameters, and do initialization of repository.&lt;br /&gt;
&lt;br /&gt;
====get_file($url, $file = &#039;&#039;)====&lt;br /&gt;
&lt;br /&gt;
Given a URL, download a file from there, save the file in a temporary directory.&lt;br /&gt;
&lt;br /&gt;
====get_link($info)====&lt;br /&gt;
Get the url of external resource&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&#039;/&#039;, $page=&#039;&#039;&#039;&#039;&#039;&#039;&#039;&#039;)====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
====search($keyword)====&lt;br /&gt;
Search repository by given keyword, it will return an array of the same format of get_listing&lt;br /&gt;
&lt;br /&gt;
====print_login()====&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
====print_search==== &lt;br /&gt;
&lt;br /&gt;
Print the search form, it will return a json string&lt;br /&gt;
&lt;br /&gt;
====get_meta()====&lt;br /&gt;
Return information for creating ajax request, it is private function, you don&#039;t need to rewrite it.&lt;br /&gt;
&lt;br /&gt;
====create()====&lt;br /&gt;
Create an instance&lt;br /&gt;
&lt;br /&gt;
====delete()====&lt;br /&gt;
Delete this instance from `repository` table&lt;br /&gt;
&lt;br /&gt;
====hide()====&lt;br /&gt;
Hide a repository instance from file picker list&lt;br /&gt;
&lt;br /&gt;
====set_option()====&lt;br /&gt;
set options in data1-data5 fields, can be overrided&lt;br /&gt;
&lt;br /&gt;
====get_option()====&lt;br /&gt;
get option list or a specific option from database&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names====&lt;br /&gt;
If this plugin needs admin settings, please refine this function to return option names.&lt;br /&gt;
&lt;br /&gt;
====type_config_form====&lt;br /&gt;
If get_type_option_names return non empty array, this function &#039;&#039;&#039;MUST&#039;&#039;&#039; redefine, it will help to build the setting form.&lt;br /&gt;
&lt;br /&gt;
====get_instance_option_names====&lt;br /&gt;
If plugin instance needs settings, this function will return instance option names.&lt;br /&gt;
&lt;br /&gt;
====instance_config_form====&lt;br /&gt;
If get_instance_option_names return non empty array, this function &#039;&#039;&#039;MUST&#039;&#039;&#039; redefine, it will help to build the instance setting form.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====supported_filetypes====&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
====supported_returntypes====&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
====filter====&lt;br /&gt;
Filter file listing to exclude specific file types&lt;br /&gt;
&lt;br /&gt;
===icon.png===&lt;br /&gt;
&lt;br /&gt;
A logo that represents the repository.  Ideally square but we should handle all sizes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Development:Repository Administration Specification]]&lt;br /&gt;
* [[Development:Repository Interface for Moodle/Course/User]]&lt;br /&gt;
* [[Development:Repository plugins]]&lt;br /&gt;
* [[Development:Repository File Picker]]&lt;br /&gt;
* [[Development:File API]]&lt;br /&gt;
* [[Development:Portfolio API]]&lt;br /&gt;
* MDL-13766 and MDL-16543 Repository API Meta issues&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発:リポジトリAPI]]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Repository_plugins&amp;diff=71213</id>
		<title>Repository plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Repository_plugins&amp;diff=71213"/>
		<updated>2010-04-19T07:25:12Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A guide for developers on how to create a repository plugin.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
===Prerequisites===&lt;br /&gt;
Before starting coding, it is necessary to know how to use repository administration pages and how to use the file picker.&lt;br /&gt;
&lt;br /&gt;
There is a template attached to MDL-16543 which might be useful to help get you started.&lt;br /&gt;
&lt;br /&gt;
===First steps===&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;moodle/repository/&#039;&#039; e.g. &#039;&#039;moodle/repository/myplugin&#039;&#039;&lt;br /&gt;
# Create the following files and add them to the plugin folder:&lt;br /&gt;
#* &#039;&#039;repository.class.php&#039;&#039;&lt;br /&gt;
#* &#039;&#039;icon.png&#039;&#039; (the icon displayed in the file picker)&lt;br /&gt;
#* &amp;quot;version.php&amp;quot;&lt;br /&gt;
# Create the language file &#039;&#039;repository_myplugin.php&#039;&#039; and add it to the plugin folder, keeping the following folder structure:&lt;br /&gt;
#*&#039;&#039;moodle/repository/myplugin/lang/en_utf8/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en_utf8/repository_myplugin.php&#039;&#039;&lt;br /&gt;
# Create access.php and upgrade scripts&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The 3 different parts to write&lt;br /&gt;
# Administration - You can customise the way administrators and users can configure their repositories. &lt;br /&gt;
# File picker integration - The core of your plugin, it will manage communication between Moodle and the repository service, and also the file picker display.&lt;br /&gt;
# I18n - Internationalization should be done at the same time as you&#039;re writing the other parts.&lt;br /&gt;
&lt;br /&gt;
==Administration APIs==&lt;br /&gt;
&lt;br /&gt;
As an example, let&#039;s create a Flickr plugin for accessing a public flickr account. The plugin will be called &amp;quot;Flickr Public&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Firstly the skeleton:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    &amp;lt;?php&lt;br /&gt;
    /**&lt;br /&gt;
     * repository_flickr_public class&lt;br /&gt;
     * Moodle user can access public flickr account&lt;br /&gt;
     *&lt;br /&gt;
     * @license http://www.gnu.org/copyleft/gpl.html GNU Public License&lt;br /&gt;
    */&lt;br /&gt;
    class repository_flickr_public extends repository {&lt;br /&gt;
    }&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then consider the question &amp;quot;What does my plugin do?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In the Moodle file picker, we want to display some flickr public repositories directly linked to a flickr public account. For example &#039;&#039;My Public Flickr Pictures&#039;&#039;, and also &#039;&#039;My Friend&#039;s Flickr Pictures&#039;&#039;. When the user clicks on one of these repositories, the public pictures are displayed in the file picker.&lt;br /&gt;
&lt;br /&gt;
In order to access to a flickr public account, the plugin needs to know the email address of the Flickr public account owner. So the administrator will need to set an email address for every repository. Let&#039;s add an &amp;quot;email address&amp;quot; setting to every repository.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have specific settings: &amp;quot;email address&amp;quot;&lt;br /&gt;
    public static function get_instance_option_names() {&lt;br /&gt;
        return array(&#039;email_address&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;email address&amp;quot; text box to the create/edit repository instance Moodle form&lt;br /&gt;
    public function instance_config_form(&amp;amp;$mform) {&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;email_address&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at this moment all our Flickr Public Repositories will have a specific email address. However this is not enough. In order to communicate with Flickr, Moodle needs to know a Flickr API key (http://www.flickr.com/services/api/). This API key is the same for any repository. We could add it with the email address setting but the administrator would have to enter the same API key for every repository. Hopefully the administrator can add settings to the plugin level, impacting all repositories. The code is similar the repository instance settings:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
//We tell the API that the repositories have general settings: &amp;quot;api_key&amp;quot;&lt;br /&gt;
    public static function get_type_option_names() {&lt;br /&gt;
        return array(&#039;api_key&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//We add an &amp;quot;api key&amp;quot; text box to the create/edit repository plugin Moodle form (also called a Repository type Moodle form)&lt;br /&gt;
    public function type_config_form(&amp;amp;$mform) {&lt;br /&gt;
        //the following line is needed in order to retrieve the API key value from the database when Moodle displays the edit form&lt;br /&gt;
        $api_key = get_config(&#039;flickr_public&#039;, &#039;api_key&#039;);&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;api_key&#039;, get_string(&#039;apikey&#039;, &#039;repository_flickr_public&#039;), &lt;br /&gt;
                           array(&#039;value&#039;=&amp;gt;$api_key,&#039;size&#039; =&amp;gt; &#039;40&#039;));&lt;br /&gt;
        $mform-&amp;gt;addRule(&#039;api_key&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Have we finished yet?&lt;br /&gt;
&lt;br /&gt;
Yes! We have created everything necessary for the administration pages. But let&#039;s go further. It would be good if the user can enter any &amp;quot;Flickr public account email address&amp;quot; in the file picker. In fact we want to display in the file picker a Flickr Public repository that the Moodle administrator can never delete. Let&#039;s add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     //this function is only called one time, when the Moodle administrator add the Flickr Public Plugin into the Moodle site.&lt;br /&gt;
     public static function plugin_init() {&lt;br /&gt;
        //here we create a default repository instance. The last parameter is 1 in order to set the instance as readonly.&lt;br /&gt;
        repository_static_function(&#039;flickr_public&#039;,&#039;create&#039;, &#039;flickr_public&#039;, 0, get_system_context(), &lt;br /&gt;
                                    array(&#039;name&#039; =&amp;gt; &#039;default instance&#039;,&#039;email_address&#039; =&amp;gt; null),1);&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s all - the administration part of our Flickr Public plugin is done. For your information, Box.net, Flickr, and Flickr Public all have similar administration APIs.&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
All of the following functions are optional. If they&#039;re not implemented, your plugin will not have manual settings and will have only one instance displayed in the File Picker (The repository API creates this unique instance when the administrator add the plugin).&lt;br /&gt;
&lt;br /&gt;
==== get_instance_option_names====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Return an array of strings. These strings are setting names. These settings are specific to an instance.&lt;br /&gt;
If the function returns an empty array, the API will consider that the plugin displays only one repository in the file picker.&lt;br /&gt;
Parent function returns an empty array.&lt;br /&gt;
&lt;br /&gt;
====instance_config_form(&amp;amp;$mform)====&lt;br /&gt;
This is for modifying the Moodle form displaying the settings specific to an instance.&lt;br /&gt;
&lt;br /&gt;
For example, to add a required text box called email_address:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;email_address&#039;, get_string(&#039;emailaddress&#039;, &#039;repository_flickr_public&#039;));&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;email_address&#039;, $strrequired, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&#039;&#039;Note: &#039;&#039;mform&#039;&#039; has by default a name text box (cannot be removed).&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
====get_type_option_names====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Return an array of string. These strings are setting names. These settings are shared by all instances.&lt;br /&gt;
Parent function return an empty array.&lt;br /&gt;
&lt;br /&gt;
====type_config_form(&amp;amp;$mform)====&lt;br /&gt;
This is for modifying the Moodle form displaying the plugin settings.&lt;br /&gt;
Similar to &#039;&#039;instance_config_form(&amp;amp;$mform)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
====plugin_init()====&lt;br /&gt;
&#039;&#039;This function must be declared static&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
This function is called when the administrator adds the plugin. So unless the administrator deletes the plugin and re-adds it, it should be called only once.&lt;br /&gt;
Parent function does nothing.&lt;br /&gt;
&lt;br /&gt;
==File picker APIs==&lt;br /&gt;
=== Quick Start ===&lt;br /&gt;
&#039;&#039;&#039;To be completed&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
First of all, the File Picker using intensively Ajax you will need a easy way to debug. Install FirePHP (MDL-16371) and make it works. It will save you a lot of time. (You might give the [http://moodle.org/mod/forum/discuss.php?d=119961 FirePHP plugin for Moodle] a try, it&#039;s still work in progress, though.)&lt;br /&gt;
&lt;br /&gt;
Your first question when you write your plugin specification is &#039;Does the user need to log-in&#039;?&amp;lt;br&amp;gt;&lt;br /&gt;
.....&lt;br /&gt;
&lt;br /&gt;
For most of plugins, you need to establish a connection with the remote repository. This connection can be done into the get_listing(), constructor() function...&amp;lt;br&amp;gt;&lt;br /&gt;
.....&lt;br /&gt;
&lt;br /&gt;
You wanna display a list of files once the user is logged&amp;lt;br&amp;gt;&lt;br /&gt;
.... get_listing() .....&lt;br /&gt;
&lt;br /&gt;
You wanna retrieve the file that the user selected&amp;lt;br&amp;gt;&lt;br /&gt;
....&lt;br /&gt;
&lt;br /&gt;
Optional question that you should ask yourself is &#039;Does the user can execute a search&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
.... search() ....&lt;br /&gt;
&lt;br /&gt;
===Functions you *MUST* override===&lt;br /&gt;
====__construct====&lt;br /&gt;
You may initialize your plugin here, such as:&lt;br /&gt;
# Get options from database&lt;br /&gt;
# Get user name and password from HTTP POST&lt;br /&gt;
&lt;br /&gt;
====get_listing($path=&amp;quot;&amp;quot;, $page=&amp;quot;&amp;quot;)====&lt;br /&gt;
This function will return a list of files, the list must be a array like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$list = array(&lt;br /&gt;
 //this will be used to build navigation bar&lt;br /&gt;
&#039;path&#039;=&amp;gt;array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;)),&lt;br /&gt;
&#039;manage&#039;=&amp;gt;&#039;http://webmgr.moodle.com&#039;,&lt;br /&gt;
&#039;list&#039;=&amp;gt; array(&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;filename1&#039;, &#039;date&#039;=&amp;gt;&#039;01/01/2009&#039;, &#039;size&#039;=&amp;gt;&#039;10MB&#039;, &#039;source&#039;=&amp;gt;&#039;http://www.moodle.com/dl.rar&#039;),&lt;br /&gt;
    array(&#039;title&#039;=&amp;gt;&#039;folder&#039;, &#039;date&#039;=&amp;gt;&#039;01/01/2009&#039;, &#039;size&#039;=&amp;gt;&#039;0&#039;, &#039;children&#039;=&amp;gt;array())&lt;br /&gt;
)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;The full specification of list element:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 array(&lt;br /&gt;
   // iframe&lt;br /&gt;
   &#039;iframe&#039; =&amp;gt; (string) the url of the iframe, once this option is set, the right panel in file picker will display a iframe instead tree view or thumbnail view, in this mode, plugin developers could design the layout of repository freely, there is a function named repository_downoload_btn, it will display a download button which can help to move files to moodle file system.&lt;br /&gt;
   // Used to build navegation bar, so you need to include all parents folders&lt;br /&gt;
   // array(array(&#039;name&#039;=&amp;gt;&#039;root&#039;,&#039;path&#039;=&amp;gt;&#039;/&#039;), array(&#039;name&#039;=&amp;gt;&#039;subfolder&#039;, &#039;path&#039;=&amp;gt;&#039;/subfolder&#039;))&lt;br /&gt;
   &#039;path&#039; =&amp;gt; (array) this will be used to build navigation bar&lt;br /&gt;
   // dynload tells file picker to fetch list dynamically, when user click&lt;br /&gt;
   // the folder, it will send a ajax request to server side.&lt;br /&gt;
   // if you are using pagination, &#039;page&#039; and &#039;pages&#039; parameters should be used&lt;br /&gt;
   // and note, you&#039;d better don&#039;t use pagination and page at the same time&lt;br /&gt;
   &#039;page&#039; =&amp;gt; (int) which page is this list&lt;br /&gt;
   &#039;pages&#039; =&amp;gt; (pages) how many pages&lt;br /&gt;
   &#039;dynload&#039; =&amp;gt; (bool) use dynamic loading,&lt;br /&gt;
   // will display a link in file picker&lt;br /&gt;
   &#039;manage&#039; =&amp;gt; (string) url of the file manager,&lt;br /&gt;
   // set to true, the login link will be removed from file picker&lt;br /&gt;
   &#039;nologin&#039; =&amp;gt; (bool) requires login,&lt;br /&gt;
   // set to true, the search link will be removed from file picker&lt;br /&gt;
   &#039;nosearch&#039; =&amp;gt; (bool) no search link,&lt;br /&gt;
   // set this option will display a upload form in file picker&lt;br /&gt;
   // only used in upload plugin currently&lt;br /&gt;
   &#039;upload&#039; =&amp;gt; array( // upload manager&lt;br /&gt;
     &#039;label&#039; =&amp;gt; (string) label of the form element,&lt;br /&gt;
     &#039;id&#039; =&amp;gt; (string) id of the form element&lt;br /&gt;
   ),&lt;br /&gt;
   // file picker will build a file tree according this &lt;br /&gt;
   // list&lt;br /&gt;
   &#039;list&#039; =&amp;gt; array(&lt;br /&gt;
     array( // file&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) file name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (string) file last modification time, usually userdate(...),&lt;br /&gt;
       &#039;size&#039; =&amp;gt; (int) file size,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the file,&lt;br /&gt;
       &#039;thumbnail_width&#039; =&amp;gt; (int) the width of the thumbnail image,&lt;br /&gt;
       &#039;source&#039; =&amp;gt; plugin-dependent unique path to the file (id, url, path, etc.),&lt;br /&gt;
       &#039;url&#039;=&amp;gt; the accessible url of file&lt;br /&gt;
     ),&lt;br /&gt;
     array( // folder - same as file, but no &#039;source&#039;.&lt;br /&gt;
       &#039;title&#039; =&amp;gt; (string) folder name,&lt;br /&gt;
       &#039;shorttitle&#039; =&amp;gt; (string) optional, if you prefer to display a short title&lt;br /&gt;
       &#039;path&#039; =&amp;gt; (string) path to this folder&lt;br /&gt;
       &#039;date&#039; =&amp;gt; (string) folder last modification time, usually userdate(...),&lt;br /&gt;
       &#039;size&#039; =&amp;gt; 0,&lt;br /&gt;
       &#039;thumbnail&#039; =&amp;gt; (string) url to thumbnail for the folder,&lt;br /&gt;
       &#039;children&#039; =&amp;gt; array( // an empty folder needs to have &#039;children&#039; defined, but empty.&lt;br /&gt;
         // content (files and folders)&lt;br /&gt;
       )&lt;br /&gt;
     ),&lt;br /&gt;
   )&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Dynamically loading&lt;br /&gt;
Some repositories contain many files which cannot load in one time, in this case, we need dynamically loading to fetch them step by step, files in subfolder won&#039;t be listed until user click the folder in file picker treeview.&lt;br /&gt;
&lt;br /&gt;
As a plug-in developer, if you set dynload flag as &#039;&#039;&#039;true&#039;&#039;&#039;, you should return files and folders (set children as a null array) in current path instead of building the whole file tree.&lt;br /&gt;
&lt;br /&gt;
Example of dynamically loading&lt;br /&gt;
See [http://cvs.moodle.org/moodle/repository/alfresco/repository.class.php?view=log Alfresco] plug-in&lt;br /&gt;
&lt;br /&gt;
===Functions you can override===&lt;br /&gt;
====print_login====&lt;br /&gt;
This function will help to print a login form, for the Ajax file picker, this function will return a&lt;br /&gt;
PHP array to define this form.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    public function print_login(){&lt;br /&gt;
        if ($this-&amp;gt;options[&#039;ajax&#039;]) {&lt;br /&gt;
            $user_field-&amp;gt;label = get_string(&#039;username&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $user_field-&amp;gt;id    = &#039;box_username&#039;;&lt;br /&gt;
            $user_field-&amp;gt;type  = &#039;text&#039;;&lt;br /&gt;
            $user_field-&amp;gt;name  = &#039;boxusername&#039;;&lt;br /&gt;
            $user_field-&amp;gt;value = $ret-&amp;gt;username;&lt;br /&gt;
            &lt;br /&gt;
            $passwd_field-&amp;gt;label = get_string(&#039;password&#039;, &#039;repository_boxnet&#039;).&#039;: &#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;id    = &#039;box_password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;type  = &#039;password&#039;;&lt;br /&gt;
            $passwd_field-&amp;gt;name  = &#039;boxpassword&#039;;&lt;br /&gt;
&lt;br /&gt;
            $ret = array();&lt;br /&gt;
            $ret[&#039;login&#039;] = array($user_field, $passwd_field);&lt;br /&gt;
            // if you are going to rename submit button label, use this option&lt;br /&gt;
            //$ret[&#039;login_btn_label&#039;] = get_string(&#039;submit_btn_label&#039;);&lt;br /&gt;
            // if you are going to display a search form instead of login form&lt;br /&gt;
            // set this option to true&lt;br /&gt;
            //$ret[&#039;login_search_form&#039;] = true;&lt;br /&gt;
            return $ret;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will help to generate a form by file picker which contains user name and password input elements.&lt;br /&gt;
&lt;br /&gt;
If your plugin don&#039;t require logging in, you don&#039;t need to override it, it will call get_listing to list files automatically by default.&lt;br /&gt;
====check_login====&lt;br /&gt;
This function will return a boolean value to tell Moodle whether the user has logged in.&lt;br /&gt;
By default, this function will return true.&lt;br /&gt;
====logout====&lt;br /&gt;
When a user clicks the logout button in file picker, this function will be called. You may clean up the session or disconnect the connection with remote server here.&lt;br /&gt;
====global_search====&lt;br /&gt;
Moodle Repository API supports global search, this function will return a boolean value to tell Moodle if this plugin is ready to search. By default, it will return false - you need to override it to enable global search.&lt;br /&gt;
====print_search====&lt;br /&gt;
When a user clicks the search button on file picker, this function will be called to return a search form. By default, it will create a form with single search bar - you can override it to create a advanced search form.&lt;br /&gt;
====search====&lt;br /&gt;
This function will do the searching job. You can obtain the POST parameters from the from the form you created in print_search function&lt;br /&gt;
This function will return a file list exactly like the one from get_listing.&lt;br /&gt;
====get_file====&lt;br /&gt;
When a user clicks the &amp;quot;Get&amp;quot; button to transfer the file, this function will be called. Basically, it will download a file to Moodle - you can override it to modify the file then move it to a better location.&lt;br /&gt;
====get_name====&lt;br /&gt;
This function will return the name of the repository instance.&lt;br /&gt;
&lt;br /&gt;
== I18n - Internationalization ==&lt;br /&gt;
These following strings are required in &#039;&#039;moodle/repository/myplugin/lang/en_utf8/repository_myplugin.php&#039;&#039; or &#039;&#039;moodle/lang/en_utf8/repository_myplugin.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;configplugin&#039;] = &#039;Flickr Public configuration&#039;;&lt;br /&gt;
$string[&#039;repositorydesc&#039;] = &#039;A Flickr public repository&#039;;&lt;br /&gt;
$string[&#039;repositoryname&#039;] = &#039;Flickr Public&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Standard repository plugins ==&lt;br /&gt;
This is the functional specification list of the officially supported repository plugins.&lt;br /&gt;
For each plugins, the two mains part we are interested in are:&lt;br /&gt;
* How do I administrate the plugin? See [[Development:Repository_Administration_Specification| Repository Administration Specification - UC001-3]]&lt;br /&gt;
* How do I set up an account for this repository? See [[Development:Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
&lt;br /&gt;
=== Functional specifications ===&lt;br /&gt;
*[[Development:Box.net Repository Plugin|Box.net Repository Plugin]]&lt;br /&gt;
*[[Development:Flickr Repository Plugin|Flickr Repository Plugin]]&lt;br /&gt;
*[[Development:Moodle Repository Plugin|Remote Moodle Repository Plugin]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Development:Repository API| Repository API]]&lt;br /&gt;
*[[Development:Repository_Interface_for_Moodle/Course/User| Repository Interface for Moodle/Course/User]]&lt;br /&gt;
*[[QA:Use Case Number Attribution| Use Case Number Attribution]]&lt;br /&gt;
* MDL-16543 - A list of officially supported repository plugins&lt;br /&gt;
* MDL-16543 - Template plugin for developers&lt;br /&gt;
[[Category:Repositories]]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Comments_2.0&amp;diff=69710</id>
		<title>Comments 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Comments_2.0&amp;diff=69710"/>
		<updated>2010-03-15T07:49:00Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Objectives==&lt;br /&gt;
&lt;br /&gt;
The goals of comments 2.0:&lt;br /&gt;
&lt;br /&gt;
* Manage comments centrally&lt;br /&gt;
* Use a consistent approach for all comments throughout Moodle&lt;br /&gt;
* Easily integrate comments 2.0 with existing modules&lt;br /&gt;
* Works no matter Javascript is enabled or not&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The comments 2.0 provides APIs to:&lt;br /&gt;
# Add comments&lt;br /&gt;
# Manage comments&lt;br /&gt;
# Delete comments&lt;br /&gt;
&lt;br /&gt;
And provides a fancy ajax interface to add/delete comments without loading a new page.&lt;br /&gt;
&lt;br /&gt;
==Comments database table==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Default&lt;br /&gt;
! Info&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| int(10)&lt;br /&gt;
| auto-incrementing&lt;br /&gt;
| The unique ID for this comment.&lt;br /&gt;
|-&lt;br /&gt;
| userid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| who wrote this comment&lt;br /&gt;
|-&lt;br /&gt;
| contextid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| The context id defined in context table - identifies the instance of plugin owning the comment.&lt;br /&gt;
|-&lt;br /&gt;
| itemid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| Some plugin specific item id (eg. forum post, blog entry or assignment submission)&lt;br /&gt;
|-&lt;br /&gt;
| commentarea&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| for example, in user profile, you can comment user&#039;s description or interests, but they share the same itemid(==userid), we need comment_area to separate them&lt;br /&gt;
|-&lt;br /&gt;
| timecreated&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| timemodified&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| content&lt;br /&gt;
| text&lt;br /&gt;
|&lt;br /&gt;
| content of comment&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Use Comments API==&lt;br /&gt;
&lt;br /&gt;
===Add an option to format_text function===&lt;br /&gt;
&lt;br /&gt;
Using this format_text function will add a comment icon automatically at the end of the text:&lt;br /&gt;
&lt;br /&gt;
For example, using the following code in the forum module will add a comment icon to every post:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$to = new stdclass;&lt;br /&gt;
$cmt-&amp;gt;contextid = $modcontext-&amp;gt;id;&lt;br /&gt;
$cmt-&amp;gt;area      = &#039;format_post&#039;;&lt;br /&gt;
$cmt-&amp;gt;itemid    = $post-&amp;gt;id;&lt;br /&gt;
$options-&amp;gt;comments = $cmt;&lt;br /&gt;
echo format_text($post-&amp;gt;message, $post-&amp;gt;messageformat, $options, $course-&amp;gt;id).&amp;quot;&amp;lt;hr /&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Use comment class===&lt;br /&gt;
To use Comments API elsewhere, using following code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$options-&amp;gt;area    = &#039;database_entry&#039;;&lt;br /&gt;
$options-&amp;gt;context = $context;&lt;br /&gt;
$options-&amp;gt;itemid  = $record-&amp;gt;id;&lt;br /&gt;
$options-&amp;gt;showcount = true;&lt;br /&gt;
$comment = new comment($options);&lt;br /&gt;
$comment-&amp;gt;output(false);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Comments API overview==&lt;br /&gt;
&lt;br /&gt;
Generally speaking, only two functions you need to know to get comments 2.0 worked:&lt;br /&gt;
# Use comment::init to initialize comments 2.0&lt;br /&gt;
# Use $comment-&amp;gt;output to display comments&lt;br /&gt;
&lt;br /&gt;
The comment class has been implemented in comment/lib.php.&lt;br /&gt;
===class comment()===&lt;br /&gt;
====__construct($contextid, $comment_area, $itemid))====&lt;br /&gt;
Initialize class members&lt;br /&gt;
&lt;br /&gt;
====init()====&lt;br /&gt;
It is a static function used to initialize comments, setting up languages, which must be called before html head printed&lt;br /&gt;
&lt;br /&gt;
====output($return = false)====&lt;br /&gt;
Will print the html snippet for commenting interface, if set $return as true, it will return html string instead of printing out.&lt;br /&gt;
&lt;br /&gt;
====print_comments($params = array())====&lt;br /&gt;
Used by non-javascript comment interface, will print a list of comments.&lt;br /&gt;
&lt;br /&gt;
====add($content)====&lt;br /&gt;
Public instance funciton, add a comment to database, used in comment/comment_ajax.php&lt;br /&gt;
&lt;br /&gt;
====count()====&lt;br /&gt;
Counting the number of comments&lt;br /&gt;
&lt;br /&gt;
====delete($id)====&lt;br /&gt;
Delete a comment from database, used in comment/comment_ajax.php&lt;br /&gt;
&lt;br /&gt;
====delete_comments====&lt;br /&gt;
Delete all comments in a specific contexts (like all comments belonging to a forum post)&lt;br /&gt;
&lt;br /&gt;
==Javascript API==&lt;br /&gt;
Comments 2.0 implemented a YUI3 module M.core_comment to deal with the communication between browsers and moodle.&lt;br /&gt;
It can be found in comment/comment.js&lt;br /&gt;
&lt;br /&gt;
Call M.core_comment.init will create an instance of CommentHelper class. You don&#039;t need to make any calls to this instance, it simply works out of box.&lt;br /&gt;
&lt;br /&gt;
== Moodle modules callback ==&lt;br /&gt;
Comments API allows modules/blocks/blog to  how comments display.&lt;br /&gt;
&lt;br /&gt;
===Permission control===&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;modname_comment_permissions&#039;&#039;&#039; to control post and view permission.&lt;br /&gt;
&lt;br /&gt;
Blocks need to overwrite &#039;&#039;&#039;comment_permissions&#039;&#039;&#039; function of block_base.&lt;br /&gt;
&lt;br /&gt;
Blog need to implement &#039;&#039;&#039;blog_comment_permissions&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
This function will return an array: array(&#039;post&#039;=&amp;gt;true, &#039;view&#039;=&amp;gt;true)&lt;br /&gt;
&lt;br /&gt;
=== Check new added comment ===&lt;br /&gt;
The callback function allows you to change the comment content before inserting into database or reject this comment.&lt;br /&gt;
&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;modname_comment_add&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Blocks need to overwrite &#039;&#039;&#039;comment_add&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
Blog need to implement &#039;&#039;&#039;blog_comment_add&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
=== Filter/format comments ===&lt;br /&gt;
This callback allows modules check/format comments when user request to display comments.&lt;br /&gt;
&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;modname_comment_display&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Blocks need to overwrite &#039;&#039;&#039;comment_display&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
Blog need to implement &#039;&#039;&#039;blog_comment_display&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Define a comment template ===&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;modname_comment_template&#039;&#039;&#039;, which allow modules define a comment template.&lt;br /&gt;
The template must have 4 embedding variables, ___id___, ___content___, ___time___, ___name___, they will be replaced with html id, comments content, comment time and commenter name&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* MDL-19118 - Comments 2.0 issue&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=67589</id>
		<title>Användare:Dongsheng Cai</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=67589"/>
		<updated>2010-01-24T13:29:14Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I am a Moodle developer working at [http://moodle.com/hq/ Moodle HQ]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
My main works with Moodle:&lt;br /&gt;
&lt;br /&gt;
* [[Chats|Chat module]]&lt;br /&gt;
* [[Development:Repository_API|Moodle Repository API]]&lt;br /&gt;
* [[Development:Comments_2.0|Comments 2.0]]&lt;br /&gt;
&lt;br /&gt;
More:&lt;br /&gt;
* [http://www.ohloh.net/accounts/cai  Ohloh]&lt;br /&gt;
* [http://github.com/dongsheng My Github]&lt;br /&gt;
* [http://au.linkedin.com/in/dongshengc Linkedin]&lt;br /&gt;
* [http://dongsheng.org My website (in chinese)]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=67588</id>
		<title>Användare:Dongsheng Cai</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Anv%C3%A4ndare:Dongsheng_Cai&amp;diff=67588"/>
		<updated>2010-01-24T13:25:36Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I am a Moodle developer working at [http://moodle.com/hq/ Moodle HQ]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
My main works with Moodle:&lt;br /&gt;
&lt;br /&gt;
* [[Chats|Chat module]]&lt;br /&gt;
* [[Development:Repository_API|Moodle Repository API]]&lt;br /&gt;
* [[Development:Comments_2.0|Comments 2.0]]&lt;br /&gt;
&lt;br /&gt;
More:&lt;br /&gt;
* [http://www.ohloh.net/accounts/cai  Ohloh]&lt;br /&gt;
* [http://github.com/dongsheng My Github]&lt;br /&gt;
* [http://github.com/dongsheng My Github]&lt;br /&gt;
* [http://dongsheng.org My website (in chinese)]&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=blocks/section_links&amp;diff=67317</id>
		<title>blocks/section links</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=blocks/section_links&amp;diff=67317"/>
		<updated>2010-01-18T05:58:44Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This block can help to navigate sections in a course.&lt;br /&gt;
&lt;br /&gt;
Some courses contains a lot sections, it may be hard to find the section you really need. This block will create quick jump links to navigate to sections instantly.&lt;br /&gt;
&lt;br /&gt;
In block setting page, you can determind the &#039;increase by&#039; value to meet your needs.&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Section_Links_block_settings&amp;diff=67316</id>
		<title>Section Links block settings</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Section_Links_block_settings&amp;diff=67316"/>
		<updated>2010-01-18T05:54:19Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;These settings are used to make section links block more flexable.&lt;br /&gt;
&lt;br /&gt;
There are two &#039;number of sections&#039; value in the setting page, say numsections1 and numsections2.&lt;br /&gt;
&lt;br /&gt;
If the number of sections in the course is less than either of them, the section links will increase by 1.&lt;br /&gt;
&lt;br /&gt;
If the number of sections in the source is more than both of numsections1 and numsections2, and numsections2 is more thank numssections1, the increase by value will respect numsections2&#039;s increase by setting.&lt;br /&gt;
&lt;br /&gt;
If the number of sections in the source is more than numsections1, but less than numsections2, the increase by value will respect numsections1&#039;s increase by setting.&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/4x/sv/index.php?title=Section_Links_block_settings&amp;diff=67314</id>
		<title>Section Links block settings</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/4x/sv/index.php?title=Section_Links_block_settings&amp;diff=67314"/>
		<updated>2010-01-18T05:53:58Z</updated>

		<summary type="html">&lt;p&gt;Dongsheng: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;These settings are used to make section links blog more flexable.&lt;br /&gt;
&lt;br /&gt;
There are two &#039;number of sections&#039; value in the setting page, say numsections1 and numsections2.&lt;br /&gt;
&lt;br /&gt;
If the number of sections in the course is less than either of them, the section links will increase by 1.&lt;br /&gt;
&lt;br /&gt;
If the number of sections in the source is more than both of numsections1 and numsections2, and numsections2 is more thank numssections1, the increase by value will respect numsections2&#039;s increase by setting.&lt;br /&gt;
&lt;br /&gt;
If the number of sections in the source is more than numsections1, but less than numsections2, the increase by value will respect numsections1&#039;s increase by setting.&lt;/div&gt;</summary>
		<author><name>Dongsheng</name></author>
	</entry>
</feed>