<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mayel</id>
	<title>MoodleDocs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mayel"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Mayel"/>
	<updated>2026-06-09T04:58:02Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/Contributing&amp;diff=56116</id>
		<title>MoodleNet/Contributing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/Contributing&amp;diff=56116"/>
		<updated>2019-06-04T16:04:11Z</updated>

		<summary type="html">&lt;p&gt;Mayel: /* How we collaborate */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Contribution guidelines ==&lt;br /&gt;
&lt;br /&gt;
=== How we collaborate ===&lt;br /&gt;
&lt;br /&gt;
First off, thank you for considering contributing to MoodleNet!&lt;br /&gt;
&lt;br /&gt;
Our aim is for this project to make you feel welcome as a contributor. We hugely value the comments and contributions of community members in the various publicly-accessible areas in use, which currently are:&lt;br /&gt;
&lt;br /&gt;
* Home: [https://moodle.com/moodlenet Project Wiki]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Code_of_Conduct Code of conduct] &lt;br /&gt;
* Code: [https://gitlab.com/moodlenet GitLab]&lt;br /&gt;
* Feature/improvement requests: [https://changemap.co/moodle/moodlenet/ ChangeMap]&lt;br /&gt;
* Issue tracking: [https://tracker.moodle.org/projects/MDLNET?selectedItem=com.atlassian.jira.jira-projects-plugin:components-page Moodle Tracker (Jira)]&lt;br /&gt;
* Discussion: [https://moodle.org/mod/forum/view.php?id=8352 MoodleNet forum]&lt;br /&gt;
* Chat: [https://t.me/moodlenet_devs Telegram (for developers)]&lt;br /&gt;
&lt;br /&gt;
=== Other useful information ===&lt;br /&gt;
&lt;br /&gt;
* It’s early days for MoodleNet, so we’re focused on laying down the foundations for the project. This means that you won’t find much usable code yet.&lt;br /&gt;
* We’re working as openly and transparently as possible with this project. As a contributor or member of the MoodleNet community, almost everything you come across will link to some other things that you should have access to. If you don’t have access, and you think you should, just ask!&lt;br /&gt;
* We&#039;re planning to resurrect our monthly [https://docs.moodle.org/dev/MoodleNet/Community-calls community calls] in 2019, which you’ll find announced on [https://blog.moodle.net/ our blog].&lt;br /&gt;
&lt;br /&gt;
=== We practice [https://2017.ind.ie/ethical-design/ Ethical Design] ===&lt;br /&gt;
&lt;br /&gt;
We endeavour to build technology that respects human rights, human effort, and human experience, and hope you will join in this effort.&lt;br /&gt;
&lt;br /&gt;
[[File:ethical-design.png|600px|Ethical Design diagram]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Find out more about ethical design at: https://2017.ind.ie/ethical-design&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== How Can I Contribute? ==&lt;br /&gt;
&lt;br /&gt;
=== Submitting Feature Requests, Enhancement Suggestions or Bug Reports ===&lt;br /&gt;
&lt;br /&gt;
This section guides you through submitting a ✨ feature request, 💄 enhancement suggestions, and 🐛 bug reports for MoodleNet - anything from errors and crashes, to minor improvements, to completely new features.&lt;br /&gt;
&lt;br /&gt;
When you post an issue, please include as many details as possible. &#039;&#039;&#039;Fill in the issue template&#039;&#039;&#039; (available below) to help us resolve issues faster.&lt;br /&gt;
&lt;br /&gt;
All issue tickets should be “bite-sized”, and definitely no more than a sprint’s worth of coding work (currently we do 2 week sprints). Larger tasks/projects are represented as [https://tracker.moodle.org/browse/MDLNET-26?jql=project%20%3D%20MDLNET%20AND%20issuetype%20%3D%20Epic Epics].&lt;br /&gt;
&lt;br /&gt;
=== Before making a submission ===&lt;br /&gt;
&lt;br /&gt;
Please go through the checklist below before posting any ✨ 💄 🐛&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Check if you’re using the latest version&#039;&#039;&#039; of MoodleNet and all its relevant components and if you can get the desired behaviour by changing some config settings.&lt;br /&gt;
* &#039;&#039;&#039;Check if there’s already a community extension or app which provides that enhancement.&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Perform a cursory search&#039;&#039;&#039; in the feature/improvement list and issue tracker to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.&lt;br /&gt;
* Never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to [mailto:moodlenet-moderators@moodle.com moodlenet-moderators@moodle.com].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; If you find a &#039;&#039;&#039;Closed&#039;&#039;&#039; issue that seems like it is the same thing that you’re experiencing, open a new issue and include a link to the original issue in the body of your new one.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Suggesting Features &amp;amp;amp; Enhancements ===&lt;br /&gt;
&lt;br /&gt;
If you find yourself wishing for a feature that doesn’t exist in MoodleNet, you are probably not alone. There are probably others out there with similar needs. Make a post on [https://changemap.co/moodle/moodlenet/ ChangeMap] which describes the feature you would like to see, why you need it, and how it might work.&lt;br /&gt;
&lt;br /&gt;
Open an issue providing the following information: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Use a clear and descriptive title&#039;&#039;&#039; for the issue to identify the suggestion. &lt;br /&gt;
* &#039;&#039;&#039;Provide a description of the suggested enhancement&#039;&#039;&#039; in as many details as possible, including the steps that you imagine you (as a user) would take if the feature you’re requesting existed. &lt;br /&gt;
* &#039;&#039;&#039;Describe the current behaviour&#039;&#039;&#039; and &#039;&#039;&#039;explain which behaviour you would like to see instead&#039;&#039;&#039; and why. &lt;br /&gt;
* &#039;&#039;&#039;Include screenshots and animated GIFs&#039;&#039;&#039; which help you demonstrate the steps or point out the parts of MoodleNet which the suggestion is related to. You can use a tool called [https://www.cockos.com/licecap/ LICEcap] to record GIFs on macOS and Windows, and [https://github.com/colinkeenan/silentcast Silentcast] or [https://github.com/GNOME/byzanz Byzanz] on Linux. &lt;br /&gt;
* &#039;&#039;&#039;Provide specific examples to demonstrate the enhancements&#039;&#039;&#039;. If possible, include drawings, screenshots, or gifs of similar features in another app. &lt;br /&gt;
* &#039;&#039;&#039;Explain why this enhancement would be useful&#039;&#039;&#039; to most participants of MoodleNet and isn’t something that can or should be implemented as a community extension. &lt;br /&gt;
* &#039;&#039;&#039;List some other communities, platforms or apps where this enhancement exists.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Reporting Bugs 🐛 ===&lt;br /&gt;
&lt;br /&gt;
Open an issue providing the following information by filling in issue template below, explaining the problem and including additional details to help maintainers reproduce the problem:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Use a clear and descriptive title&#039;&#039;&#039; for the issue to identify the problem.&lt;br /&gt;
* &#039;&#039;&#039;Describe the exact steps which reproduce the problem&#039;&#039;&#039; in as many details as possible. For example, start by explaining where you started in MoodleNet, and then which actions you took. When listing steps, &#039;&#039;&#039;don’t just say what you did, but explain how you did it&#039;&#039;&#039;. For example, if you moved the cursor to the end of a line, explain if you used the mouse or a keyboard shortcut, and if so which one?&lt;br /&gt;
* &#039;&#039;&#039;Provide specific examples to demonstrate the steps&#039;&#039;&#039;. Include links to files, screenshots, or copy/pasteable snippets, which you use in those examples. If you’re providing snippets in the issue, use Markdown code blocks.&lt;br /&gt;
* &#039;&#039;&#039;Describe the behaviour you observed after following the steps&#039;&#039;&#039; and point out what exactly is the problem with that behaviour.&lt;br /&gt;
* &#039;&#039;&#039;Explain which behaviour you expected to see instead and why.&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Include screenshots and animated GIFs&#039;&#039;&#039; which show you following the described steps and clearly demonstrate the problem. You can use [https://www.cockos.com/licecap/ this tool] to record GIFs on macOS and Windows, and [https://github.com/colinkeenan/silentcast this tool] or [https://github.com/GNOME/byzanz this tool] on Linux.&lt;br /&gt;
* &#039;&#039;&#039;If you’re reporting a crash&#039;&#039;&#039;, include a crash report with error logs.&lt;br /&gt;
* &#039;&#039;&#039;If the problem wasn’t triggered by a specific action&#039;&#039;&#039;, describe what you were doing before the problem happened and share more information using the guidelines below.&lt;br /&gt;
&lt;br /&gt;
Provide more context by answering these questions:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Did the problem start happening recently&#039;&#039;&#039; (e.g. after updating to a new version) or was this always a problem?&lt;br /&gt;
* If the problem started happening recently, &#039;&#039;&#039;can you reproduce the problem in an older version?&#039;&#039;&#039; What’s the most recent version in which the problem doesn’t happen?&lt;br /&gt;
* &#039;&#039;&#039;Can you reliably reproduce the issue?&#039;&#039;&#039; If not, provide details about how often the problem happens and under which conditions it normally happens.&lt;br /&gt;
* If the problem is related to a user or item (eg. collection or resource), &#039;&#039;&#039;does the problem happen for all of them or only some?&#039;&#039;&#039; Does the problem happen only when working with local (originating from your MoodleNet instance) or remote ones, with items of a specific type (e.g. only PDFs)? Is there anything else special about the users or items in question?&lt;br /&gt;
&lt;br /&gt;
Include details about your configuration and environment:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Which version of each component are you using?&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;What’s the name and version of the OS you’re using&#039;&#039;&#039;?&lt;br /&gt;
* &#039;&#039;&#039;Are you running in a virtual machine?&#039;&#039;&#039; If so, which VM software are you using and which operating systems and versions are used for the host and the guest?&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
=== Template for submitting issues ===&lt;br /&gt;
&lt;br /&gt;
==== Description ====&lt;br /&gt;
&lt;br /&gt;
[Description of the issue]&lt;br /&gt;
&lt;br /&gt;
==== Steps to Reproduce ====&lt;br /&gt;
&lt;br /&gt;
# [First Step]&lt;br /&gt;
# [Second Step]&lt;br /&gt;
# [and so on…]&lt;br /&gt;
&lt;br /&gt;
==== Expected behaviour: ====&lt;br /&gt;
&lt;br /&gt;
[What you expect to happen]&lt;br /&gt;
&lt;br /&gt;
==== Actual behaviour: ====&lt;br /&gt;
&lt;br /&gt;
[What actually happens]&lt;br /&gt;
&lt;br /&gt;
==== Reproduces how often: ====&lt;br /&gt;
&lt;br /&gt;
[What percentage of the time does it reproduce?]&lt;br /&gt;
&lt;br /&gt;
==== Versions ====&lt;br /&gt;
&lt;br /&gt;
[What MoodleNet instance you’re using, and the versions of each relevant app or component, including your OS and browser.]&lt;br /&gt;
&lt;br /&gt;
==== Additional Information ====&lt;br /&gt;
&lt;br /&gt;
[Any additional information, configuration or data that might be necessary to reproduce the issue.]&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
=== Contributing ===&lt;br /&gt;
&lt;br /&gt;
A common misconception about contributing to free and open source projects is that you need to contribute code. In fact, it’s often the other parts of a project that are most overlooked. You’ll do the project a huge favour by offering to pitch in with these types of contributions!&lt;br /&gt;
&lt;br /&gt;
Even if you like to write code, other types of contributions are a great way to get involved with a project and meet other community members. Building those relationships may open up unexpected opportunities.&lt;br /&gt;
&lt;br /&gt;
==== Do you like to design? 🎨 ====&lt;br /&gt;
&lt;br /&gt;
* Restructure layouts to improve the project&#039;s usability&lt;br /&gt;
* Conduct user research to reorganise and refine the project&#039;s navigation or menus&lt;br /&gt;
* Create art for icons and app screens&lt;br /&gt;
&lt;br /&gt;
==== Do you like to write? 🖉 ====&lt;br /&gt;
&lt;br /&gt;
* Write and improve the project&#039;s documentation&lt;br /&gt;
* Write tutorials for the project&lt;br /&gt;
* Curate a wiki page of examples showing how the project can be used&lt;br /&gt;
&lt;br /&gt;
==== Do you like organising? 📥 ====&lt;br /&gt;
&lt;br /&gt;
* Link to duplicate issues, and suggest new issue labels, to keep things organised&lt;br /&gt;
* Go through open issues and suggest revisiting or closing old ones&lt;br /&gt;
* Ask clarifying questions on recently opened issues to move the discussion forward&lt;br /&gt;
&lt;br /&gt;
==== Do you like helping people? 🙋‍♀️====&lt;br /&gt;
&lt;br /&gt;
* Answer questions about the project on forums and other sites&lt;br /&gt;
* Answer questions for people on open issues&lt;br /&gt;
&lt;br /&gt;
==== Do you like helping others code? 👐 ====&lt;br /&gt;
&lt;br /&gt;
* Review code on other people’s submissions&lt;br /&gt;
* Write tutorials for how a project can be used&lt;br /&gt;
* Offer to mentor another contributor&lt;br /&gt;
&lt;br /&gt;
==== Do you like to code? 🔩 ====&lt;br /&gt;
&lt;br /&gt;
* Find an open issue to tackle&lt;br /&gt;
* Offer to help write a new feature&lt;br /&gt;
* Improve tooling, testing &amp;amp; deployment options&lt;br /&gt;
* Read the **next section for guidelines**&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== Contributing Code ===&lt;br /&gt;
&lt;br /&gt;
Unsure where to begin contributing? You can start by looking through issues tagged with:&lt;br /&gt;
&lt;br /&gt;
* [https://www.firsttimersonly.com &amp;lt;code&amp;gt;first-timers-only&amp;lt;/code&amp;gt;]- issues which should only require a few lines of code, and a test or two.&lt;br /&gt;
* &amp;lt;code&amp;gt;help-wanted&amp;lt;/code&amp;gt; - issues which should be a bit more involved than &amp;lt;code&amp;gt;first-timers-only&amp;lt;/code&amp;gt; issues.&lt;br /&gt;
&lt;br /&gt;
==== Modularity ====&lt;br /&gt;
&lt;br /&gt;
MoodleNet is a large project that is intentionally very modular — it will be made up of many components in many repositories. When you initially consider contributing, you might be unsure about which of those repositories should implement the functionality you want to add or improve - the project maintainers can help with that.&lt;br /&gt;
&lt;br /&gt;
==== Local development ====&lt;br /&gt;
&lt;br /&gt;
MoodleNet and all packages can be developed locally. For instructions on how to do this, please see the documentation (TBD).&lt;br /&gt;
&lt;br /&gt;
==== Coding &amp;amp;amp; git practices ====&lt;br /&gt;
&lt;br /&gt;
* We use GitLab’s merge requests as our code review tool&lt;br /&gt;
* We encourage any dev to comment on merge requests and we think of the merge request not as a “please approve my code” but as a space for co-developing.&lt;br /&gt;
* We develop features on separate branches identified by issue numbers.&lt;br /&gt;
* We use merge to &amp;lt;code&amp;gt;develop&amp;lt;/code&amp;gt; (not rebase) so that commits related to an issue can be retroactively explored.&lt;br /&gt;
* We don’t currently use release branches or tags because we don’t have release management at this phase of development.&lt;br /&gt;
&lt;br /&gt;
==== How to make changes ====&lt;br /&gt;
&lt;br /&gt;
* Make your changes on a seperate branch which includes an issue number e.g. &amp;lt;code&amp;gt;1234-some-new-feature&amp;lt;/code&amp;gt; where 1234 is the issue number where the feature is documented. Make sure the branch is based on &amp;lt;code&amp;gt;develop&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Do not commit changes to files that are irrelevant to your feature or bugfix.&lt;br /&gt;
* Use commit messages descriptive of your changes.&lt;br /&gt;
* Push to the upstream of your new branch.&lt;br /&gt;
* Create a merge request at GitLab.&lt;br /&gt;
&lt;br /&gt;
==== Git commit messages ====&lt;br /&gt;
&lt;br /&gt;
* Limit the first line to 72 characters or less, referencing relevant issue numbers&lt;br /&gt;
* Be as descriptive as you want after the first line&lt;br /&gt;
* Consider starting the commit message with an applicable emoji (see Issue &amp;amp;amp; Commit Categories below)&lt;br /&gt;
&lt;br /&gt;
==== Merge requests ====&lt;br /&gt;
&lt;br /&gt;
* Follow the code styleguides (TBD).&lt;br /&gt;
* Document new code based on the documentation styleguide (TBD)&lt;br /&gt;
* Each merge request should implement ONE feature or bugfix. If you want to add or fix more than one thing, submit more than one merge request.&lt;br /&gt;
* Fill in the merge request template below&lt;br /&gt;
* Include relevant issue number(s) in the merge request title&lt;br /&gt;
* Include screenshots or animated GIFs in your merge request whenever possible.&lt;br /&gt;
* End all files with a newline&lt;br /&gt;
&lt;br /&gt;
==== Template for merge requests ====&lt;br /&gt;
&lt;br /&gt;
* Description of the change&lt;br /&gt;
* Applicable issue numbers&lt;br /&gt;
* Alternate designs/implementations&lt;br /&gt;
* Benefits of this implementation&lt;br /&gt;
* Possible drawbacks&lt;br /&gt;
* Why should this be part of a core component?&lt;br /&gt;
* Testing process&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
==== Issue &amp;amp; Commit Categories ====&lt;br /&gt;
&lt;br /&gt;
* 🚑 `critical` : Critical hotfix!&lt;br /&gt;
* 💄 `enhancement` : General improvements.&lt;br /&gt;
* ✨ `feature` : New features.&lt;br /&gt;
* 🐛 `bug` : Confirmed bugs, or reports that are likely to be bugs.&lt;br /&gt;
* 🙋‍♀️ `question` : Questions (e.g. how can I do X?)&lt;br /&gt;
* 📮 `feedback` : General feedback.&lt;br /&gt;
* 🎨 `ui` : Visual design.&lt;br /&gt;
* 📜 `copy` : Text in the apps, or translations.&lt;br /&gt;
* ℹ️ `documentation` : Documentation.&lt;br /&gt;
* 🏇 `performance` : Performance.&lt;br /&gt;
* 🔒 `security` : Security.&lt;br /&gt;
* 🔌 `api` : MoodleNet&#039;s APIs.&lt;br /&gt;
* 👽 `external` : External libraries or API integrations.&lt;br /&gt;
* ⚠️ `exception` : Uncaught exceptions.&lt;br /&gt;
* 🔥 `crash` : Crash.&lt;br /&gt;
* 🔣 `encoding` : Character encoding or data serialization issue.&lt;br /&gt;
* 🚚 `cleanup` : Removing, moving or refactoring code or files.&lt;br /&gt;
* ✅ `tests` : Testing&lt;br /&gt;
&lt;br /&gt;
==== Issue Status ====&lt;br /&gt;
&lt;br /&gt;
* 💬 `discussion` : Discussion to clarify this issue is ongoing.&lt;br /&gt;
* 🔜 `todo` : This has been discussed and now needs work.&lt;br /&gt;
* 🔁 `needs-more-info` : More information needs to be collected about these problems or feature requests (e.g. steps to reproduce).&lt;br /&gt;
* 💡 `idea` : Needs to be discussed further. Could be a feature request which might be good to first implement as a community extension.&lt;br /&gt;
* 🚧 `in-progress` : Someone is working on this...&lt;br /&gt;
* 🙏 `help-wanted` : The MoodleNet core team would appreciate help from the community in resolving these issues.&lt;br /&gt;
* 🌱 `first-timers-only` : Less complex issues which would be good first issues to work on for users who want to contribute.&lt;br /&gt;
* 🔢 `needs-reproduction` : Likely bugs, but haven&#039;t been reliably reproduced.&lt;br /&gt;
* 🔴 `blocked` : Blocked on other issues.&lt;br /&gt;
* 2️⃣ `duplicate` : Duplicate of another issue, i.e. has been reported before.&lt;br /&gt;
* 🙅 `wontfix` : The MoodleNet core team has decided not to fix these issues (or add these features) for now, because they&#039;re working as intended, or some other reason.&lt;br /&gt;
* 🚮 `invalid` : Issues which are not valid (e.g. spam or submitted by error).&lt;br /&gt;
&lt;br /&gt;
==== Merge Request Status ====&lt;br /&gt;
&lt;br /&gt;
* 🚧 `in-progress` : Still being worked on, more changes will follow.&lt;br /&gt;
* 🚏 `needs-review` : Needs code review and approval from maintainers.&lt;br /&gt;
* 🔍 `under-review` : Being reviewed by maintainers.&lt;br /&gt;
* 🔧 `changes-required` : Needs to be updated based on review comments and then reviewed again.&lt;br /&gt;
* 👀 `needs-testing` : Needs manual testing.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
The following documents have greatly helped us put this together. A big thank you to their authors and contributors!&lt;br /&gt;
* [https://www.contributor-covenant.org/version/1/4/code-of-conduct Contributor Covenant]&lt;br /&gt;
* [https://opensource.guide Open Source Guides]&lt;br /&gt;
* [https://github.com/holochain/holochain-proto/wiki/Development-Protocols Holochain&#039;s Development Protocols]&lt;br /&gt;
* [https://github.com/atom/atom/blob/master/CONTRIBUTING.md Atom&#039;s contributing guide]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/Contributing&amp;diff=56115</id>
		<title>MoodleNet/Contributing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/Contributing&amp;diff=56115"/>
		<updated>2019-06-04T16:03:51Z</updated>

		<summary type="html">&lt;p&gt;Mayel: /* How we collaborate */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Contribution guidelines ==&lt;br /&gt;
&lt;br /&gt;
=== How we collaborate ===&lt;br /&gt;
&lt;br /&gt;
First off, thank you for considering contributing to MoodleNet!&lt;br /&gt;
&lt;br /&gt;
Our aim is for this project to make you feel welcome as a contributor. We hugely value the comments and contributions of community members in the various publicly-accessible areas in use, which currently are:&lt;br /&gt;
&lt;br /&gt;
* Home: [https://moodle.com/moodlenet Project Wiki]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Code_of_Conduct Code of conduct] &lt;br /&gt;
* Code: [https://gitlab.com/moodlenet GitLab]&lt;br /&gt;
* Feature/improvement requests: [https://changemap.co/moodle/moodlenet/ ChangeMap]&lt;br /&gt;
* Issue tracking: [https://tracker.moodle.org/projects/MDLNET?selectedItem=com.atlassian.jira.jira-projects-plugin:components-page Moodle Tracker (Jira)]&lt;br /&gt;
* Discussion: [https://moodle.org/mod/forum/view.php?id=8352 MoodleNet forum]&lt;br /&gt;
* Chat: [https://t.me/moodlenet_devs Telegram]&lt;br /&gt;
&lt;br /&gt;
=== Other useful information ===&lt;br /&gt;
&lt;br /&gt;
* It’s early days for MoodleNet, so we’re focused on laying down the foundations for the project. This means that you won’t find much usable code yet.&lt;br /&gt;
* We’re working as openly and transparently as possible with this project. As a contributor or member of the MoodleNet community, almost everything you come across will link to some other things that you should have access to. If you don’t have access, and you think you should, just ask!&lt;br /&gt;
* We&#039;re planning to resurrect our monthly [https://docs.moodle.org/dev/MoodleNet/Community-calls community calls] in 2019, which you’ll find announced on [https://blog.moodle.net/ our blog].&lt;br /&gt;
&lt;br /&gt;
=== We practice [https://2017.ind.ie/ethical-design/ Ethical Design] ===&lt;br /&gt;
&lt;br /&gt;
We endeavour to build technology that respects human rights, human effort, and human experience, and hope you will join in this effort.&lt;br /&gt;
&lt;br /&gt;
[[File:ethical-design.png|600px|Ethical Design diagram]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Find out more about ethical design at: https://2017.ind.ie/ethical-design&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== How Can I Contribute? ==&lt;br /&gt;
&lt;br /&gt;
=== Submitting Feature Requests, Enhancement Suggestions or Bug Reports ===&lt;br /&gt;
&lt;br /&gt;
This section guides you through submitting a ✨ feature request, 💄 enhancement suggestions, and 🐛 bug reports for MoodleNet - anything from errors and crashes, to minor improvements, to completely new features.&lt;br /&gt;
&lt;br /&gt;
When you post an issue, please include as many details as possible. &#039;&#039;&#039;Fill in the issue template&#039;&#039;&#039; (available below) to help us resolve issues faster.&lt;br /&gt;
&lt;br /&gt;
All issue tickets should be “bite-sized”, and definitely no more than a sprint’s worth of coding work (currently we do 2 week sprints). Larger tasks/projects are represented as [https://tracker.moodle.org/browse/MDLNET-26?jql=project%20%3D%20MDLNET%20AND%20issuetype%20%3D%20Epic Epics].&lt;br /&gt;
&lt;br /&gt;
=== Before making a submission ===&lt;br /&gt;
&lt;br /&gt;
Please go through the checklist below before posting any ✨ 💄 🐛&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Check if you’re using the latest version&#039;&#039;&#039; of MoodleNet and all its relevant components and if you can get the desired behaviour by changing some config settings.&lt;br /&gt;
* &#039;&#039;&#039;Check if there’s already a community extension or app which provides that enhancement.&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Perform a cursory search&#039;&#039;&#039; in the feature/improvement list and issue tracker to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.&lt;br /&gt;
* Never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to [mailto:moodlenet-moderators@moodle.com moodlenet-moderators@moodle.com].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; If you find a &#039;&#039;&#039;Closed&#039;&#039;&#039; issue that seems like it is the same thing that you’re experiencing, open a new issue and include a link to the original issue in the body of your new one.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Suggesting Features &amp;amp;amp; Enhancements ===&lt;br /&gt;
&lt;br /&gt;
If you find yourself wishing for a feature that doesn’t exist in MoodleNet, you are probably not alone. There are probably others out there with similar needs. Make a post on [https://changemap.co/moodle/moodlenet/ ChangeMap] which describes the feature you would like to see, why you need it, and how it might work.&lt;br /&gt;
&lt;br /&gt;
Open an issue providing the following information: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Use a clear and descriptive title&#039;&#039;&#039; for the issue to identify the suggestion. &lt;br /&gt;
* &#039;&#039;&#039;Provide a description of the suggested enhancement&#039;&#039;&#039; in as many details as possible, including the steps that you imagine you (as a user) would take if the feature you’re requesting existed. &lt;br /&gt;
* &#039;&#039;&#039;Describe the current behaviour&#039;&#039;&#039; and &#039;&#039;&#039;explain which behaviour you would like to see instead&#039;&#039;&#039; and why. &lt;br /&gt;
* &#039;&#039;&#039;Include screenshots and animated GIFs&#039;&#039;&#039; which help you demonstrate the steps or point out the parts of MoodleNet which the suggestion is related to. You can use a tool called [https://www.cockos.com/licecap/ LICEcap] to record GIFs on macOS and Windows, and [https://github.com/colinkeenan/silentcast Silentcast] or [https://github.com/GNOME/byzanz Byzanz] on Linux. &lt;br /&gt;
* &#039;&#039;&#039;Provide specific examples to demonstrate the enhancements&#039;&#039;&#039;. If possible, include drawings, screenshots, or gifs of similar features in another app. &lt;br /&gt;
* &#039;&#039;&#039;Explain why this enhancement would be useful&#039;&#039;&#039; to most participants of MoodleNet and isn’t something that can or should be implemented as a community extension. &lt;br /&gt;
* &#039;&#039;&#039;List some other communities, platforms or apps where this enhancement exists.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Reporting Bugs 🐛 ===&lt;br /&gt;
&lt;br /&gt;
Open an issue providing the following information by filling in issue template below, explaining the problem and including additional details to help maintainers reproduce the problem:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Use a clear and descriptive title&#039;&#039;&#039; for the issue to identify the problem.&lt;br /&gt;
* &#039;&#039;&#039;Describe the exact steps which reproduce the problem&#039;&#039;&#039; in as many details as possible. For example, start by explaining where you started in MoodleNet, and then which actions you took. When listing steps, &#039;&#039;&#039;don’t just say what you did, but explain how you did it&#039;&#039;&#039;. For example, if you moved the cursor to the end of a line, explain if you used the mouse or a keyboard shortcut, and if so which one?&lt;br /&gt;
* &#039;&#039;&#039;Provide specific examples to demonstrate the steps&#039;&#039;&#039;. Include links to files, screenshots, or copy/pasteable snippets, which you use in those examples. If you’re providing snippets in the issue, use Markdown code blocks.&lt;br /&gt;
* &#039;&#039;&#039;Describe the behaviour you observed after following the steps&#039;&#039;&#039; and point out what exactly is the problem with that behaviour.&lt;br /&gt;
* &#039;&#039;&#039;Explain which behaviour you expected to see instead and why.&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Include screenshots and animated GIFs&#039;&#039;&#039; which show you following the described steps and clearly demonstrate the problem. You can use [https://www.cockos.com/licecap/ this tool] to record GIFs on macOS and Windows, and [https://github.com/colinkeenan/silentcast this tool] or [https://github.com/GNOME/byzanz this tool] on Linux.&lt;br /&gt;
* &#039;&#039;&#039;If you’re reporting a crash&#039;&#039;&#039;, include a crash report with error logs.&lt;br /&gt;
* &#039;&#039;&#039;If the problem wasn’t triggered by a specific action&#039;&#039;&#039;, describe what you were doing before the problem happened and share more information using the guidelines below.&lt;br /&gt;
&lt;br /&gt;
Provide more context by answering these questions:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Did the problem start happening recently&#039;&#039;&#039; (e.g. after updating to a new version) or was this always a problem?&lt;br /&gt;
* If the problem started happening recently, &#039;&#039;&#039;can you reproduce the problem in an older version?&#039;&#039;&#039; What’s the most recent version in which the problem doesn’t happen?&lt;br /&gt;
* &#039;&#039;&#039;Can you reliably reproduce the issue?&#039;&#039;&#039; If not, provide details about how often the problem happens and under which conditions it normally happens.&lt;br /&gt;
* If the problem is related to a user or item (eg. collection or resource), &#039;&#039;&#039;does the problem happen for all of them or only some?&#039;&#039;&#039; Does the problem happen only when working with local (originating from your MoodleNet instance) or remote ones, with items of a specific type (e.g. only PDFs)? Is there anything else special about the users or items in question?&lt;br /&gt;
&lt;br /&gt;
Include details about your configuration and environment:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Which version of each component are you using?&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;What’s the name and version of the OS you’re using&#039;&#039;&#039;?&lt;br /&gt;
* &#039;&#039;&#039;Are you running in a virtual machine?&#039;&#039;&#039; If so, which VM software are you using and which operating systems and versions are used for the host and the guest?&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
=== Template for submitting issues ===&lt;br /&gt;
&lt;br /&gt;
==== Description ====&lt;br /&gt;
&lt;br /&gt;
[Description of the issue]&lt;br /&gt;
&lt;br /&gt;
==== Steps to Reproduce ====&lt;br /&gt;
&lt;br /&gt;
# [First Step]&lt;br /&gt;
# [Second Step]&lt;br /&gt;
# [and so on…]&lt;br /&gt;
&lt;br /&gt;
==== Expected behaviour: ====&lt;br /&gt;
&lt;br /&gt;
[What you expect to happen]&lt;br /&gt;
&lt;br /&gt;
==== Actual behaviour: ====&lt;br /&gt;
&lt;br /&gt;
[What actually happens]&lt;br /&gt;
&lt;br /&gt;
==== Reproduces how often: ====&lt;br /&gt;
&lt;br /&gt;
[What percentage of the time does it reproduce?]&lt;br /&gt;
&lt;br /&gt;
==== Versions ====&lt;br /&gt;
&lt;br /&gt;
[What MoodleNet instance you’re using, and the versions of each relevant app or component, including your OS and browser.]&lt;br /&gt;
&lt;br /&gt;
==== Additional Information ====&lt;br /&gt;
&lt;br /&gt;
[Any additional information, configuration or data that might be necessary to reproduce the issue.]&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
=== Contributing ===&lt;br /&gt;
&lt;br /&gt;
A common misconception about contributing to free and open source projects is that you need to contribute code. In fact, it’s often the other parts of a project that are most overlooked. You’ll do the project a huge favour by offering to pitch in with these types of contributions!&lt;br /&gt;
&lt;br /&gt;
Even if you like to write code, other types of contributions are a great way to get involved with a project and meet other community members. Building those relationships may open up unexpected opportunities.&lt;br /&gt;
&lt;br /&gt;
==== Do you like to design? 🎨 ====&lt;br /&gt;
&lt;br /&gt;
* Restructure layouts to improve the project&#039;s usability&lt;br /&gt;
* Conduct user research to reorganise and refine the project&#039;s navigation or menus&lt;br /&gt;
* Create art for icons and app screens&lt;br /&gt;
&lt;br /&gt;
==== Do you like to write? 🖉 ====&lt;br /&gt;
&lt;br /&gt;
* Write and improve the project&#039;s documentation&lt;br /&gt;
* Write tutorials for the project&lt;br /&gt;
* Curate a wiki page of examples showing how the project can be used&lt;br /&gt;
&lt;br /&gt;
==== Do you like organising? 📥 ====&lt;br /&gt;
&lt;br /&gt;
* Link to duplicate issues, and suggest new issue labels, to keep things organised&lt;br /&gt;
* Go through open issues and suggest revisiting or closing old ones&lt;br /&gt;
* Ask clarifying questions on recently opened issues to move the discussion forward&lt;br /&gt;
&lt;br /&gt;
==== Do you like helping people? 🙋‍♀️====&lt;br /&gt;
&lt;br /&gt;
* Answer questions about the project on forums and other sites&lt;br /&gt;
* Answer questions for people on open issues&lt;br /&gt;
&lt;br /&gt;
==== Do you like helping others code? 👐 ====&lt;br /&gt;
&lt;br /&gt;
* Review code on other people’s submissions&lt;br /&gt;
* Write tutorials for how a project can be used&lt;br /&gt;
* Offer to mentor another contributor&lt;br /&gt;
&lt;br /&gt;
==== Do you like to code? 🔩 ====&lt;br /&gt;
&lt;br /&gt;
* Find an open issue to tackle&lt;br /&gt;
* Offer to help write a new feature&lt;br /&gt;
* Improve tooling, testing &amp;amp; deployment options&lt;br /&gt;
* Read the **next section for guidelines**&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== Contributing Code ===&lt;br /&gt;
&lt;br /&gt;
Unsure where to begin contributing? You can start by looking through issues tagged with:&lt;br /&gt;
&lt;br /&gt;
* [https://www.firsttimersonly.com &amp;lt;code&amp;gt;first-timers-only&amp;lt;/code&amp;gt;]- issues which should only require a few lines of code, and a test or two.&lt;br /&gt;
* &amp;lt;code&amp;gt;help-wanted&amp;lt;/code&amp;gt; - issues which should be a bit more involved than &amp;lt;code&amp;gt;first-timers-only&amp;lt;/code&amp;gt; issues.&lt;br /&gt;
&lt;br /&gt;
==== Modularity ====&lt;br /&gt;
&lt;br /&gt;
MoodleNet is a large project that is intentionally very modular — it will be made up of many components in many repositories. When you initially consider contributing, you might be unsure about which of those repositories should implement the functionality you want to add or improve - the project maintainers can help with that.&lt;br /&gt;
&lt;br /&gt;
==== Local development ====&lt;br /&gt;
&lt;br /&gt;
MoodleNet and all packages can be developed locally. For instructions on how to do this, please see the documentation (TBD).&lt;br /&gt;
&lt;br /&gt;
==== Coding &amp;amp;amp; git practices ====&lt;br /&gt;
&lt;br /&gt;
* We use GitLab’s merge requests as our code review tool&lt;br /&gt;
* We encourage any dev to comment on merge requests and we think of the merge request not as a “please approve my code” but as a space for co-developing.&lt;br /&gt;
* We develop features on separate branches identified by issue numbers.&lt;br /&gt;
* We use merge to &amp;lt;code&amp;gt;develop&amp;lt;/code&amp;gt; (not rebase) so that commits related to an issue can be retroactively explored.&lt;br /&gt;
* We don’t currently use release branches or tags because we don’t have release management at this phase of development.&lt;br /&gt;
&lt;br /&gt;
==== How to make changes ====&lt;br /&gt;
&lt;br /&gt;
* Make your changes on a seperate branch which includes an issue number e.g. &amp;lt;code&amp;gt;1234-some-new-feature&amp;lt;/code&amp;gt; where 1234 is the issue number where the feature is documented. Make sure the branch is based on &amp;lt;code&amp;gt;develop&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Do not commit changes to files that are irrelevant to your feature or bugfix.&lt;br /&gt;
* Use commit messages descriptive of your changes.&lt;br /&gt;
* Push to the upstream of your new branch.&lt;br /&gt;
* Create a merge request at GitLab.&lt;br /&gt;
&lt;br /&gt;
==== Git commit messages ====&lt;br /&gt;
&lt;br /&gt;
* Limit the first line to 72 characters or less, referencing relevant issue numbers&lt;br /&gt;
* Be as descriptive as you want after the first line&lt;br /&gt;
* Consider starting the commit message with an applicable emoji (see Issue &amp;amp;amp; Commit Categories below)&lt;br /&gt;
&lt;br /&gt;
==== Merge requests ====&lt;br /&gt;
&lt;br /&gt;
* Follow the code styleguides (TBD).&lt;br /&gt;
* Document new code based on the documentation styleguide (TBD)&lt;br /&gt;
* Each merge request should implement ONE feature or bugfix. If you want to add or fix more than one thing, submit more than one merge request.&lt;br /&gt;
* Fill in the merge request template below&lt;br /&gt;
* Include relevant issue number(s) in the merge request title&lt;br /&gt;
* Include screenshots or animated GIFs in your merge request whenever possible.&lt;br /&gt;
* End all files with a newline&lt;br /&gt;
&lt;br /&gt;
==== Template for merge requests ====&lt;br /&gt;
&lt;br /&gt;
* Description of the change&lt;br /&gt;
* Applicable issue numbers&lt;br /&gt;
* Alternate designs/implementations&lt;br /&gt;
* Benefits of this implementation&lt;br /&gt;
* Possible drawbacks&lt;br /&gt;
* Why should this be part of a core component?&lt;br /&gt;
* Testing process&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
==== Issue &amp;amp; Commit Categories ====&lt;br /&gt;
&lt;br /&gt;
* 🚑 `critical` : Critical hotfix!&lt;br /&gt;
* 💄 `enhancement` : General improvements.&lt;br /&gt;
* ✨ `feature` : New features.&lt;br /&gt;
* 🐛 `bug` : Confirmed bugs, or reports that are likely to be bugs.&lt;br /&gt;
* 🙋‍♀️ `question` : Questions (e.g. how can I do X?)&lt;br /&gt;
* 📮 `feedback` : General feedback.&lt;br /&gt;
* 🎨 `ui` : Visual design.&lt;br /&gt;
* 📜 `copy` : Text in the apps, or translations.&lt;br /&gt;
* ℹ️ `documentation` : Documentation.&lt;br /&gt;
* 🏇 `performance` : Performance.&lt;br /&gt;
* 🔒 `security` : Security.&lt;br /&gt;
* 🔌 `api` : MoodleNet&#039;s APIs.&lt;br /&gt;
* 👽 `external` : External libraries or API integrations.&lt;br /&gt;
* ⚠️ `exception` : Uncaught exceptions.&lt;br /&gt;
* 🔥 `crash` : Crash.&lt;br /&gt;
* 🔣 `encoding` : Character encoding or data serialization issue.&lt;br /&gt;
* 🚚 `cleanup` : Removing, moving or refactoring code or files.&lt;br /&gt;
* ✅ `tests` : Testing&lt;br /&gt;
&lt;br /&gt;
==== Issue Status ====&lt;br /&gt;
&lt;br /&gt;
* 💬 `discussion` : Discussion to clarify this issue is ongoing.&lt;br /&gt;
* 🔜 `todo` : This has been discussed and now needs work.&lt;br /&gt;
* 🔁 `needs-more-info` : More information needs to be collected about these problems or feature requests (e.g. steps to reproduce).&lt;br /&gt;
* 💡 `idea` : Needs to be discussed further. Could be a feature request which might be good to first implement as a community extension.&lt;br /&gt;
* 🚧 `in-progress` : Someone is working on this...&lt;br /&gt;
* 🙏 `help-wanted` : The MoodleNet core team would appreciate help from the community in resolving these issues.&lt;br /&gt;
* 🌱 `first-timers-only` : Less complex issues which would be good first issues to work on for users who want to contribute.&lt;br /&gt;
* 🔢 `needs-reproduction` : Likely bugs, but haven&#039;t been reliably reproduced.&lt;br /&gt;
* 🔴 `blocked` : Blocked on other issues.&lt;br /&gt;
* 2️⃣ `duplicate` : Duplicate of another issue, i.e. has been reported before.&lt;br /&gt;
* 🙅 `wontfix` : The MoodleNet core team has decided not to fix these issues (or add these features) for now, because they&#039;re working as intended, or some other reason.&lt;br /&gt;
* 🚮 `invalid` : Issues which are not valid (e.g. spam or submitted by error).&lt;br /&gt;
&lt;br /&gt;
==== Merge Request Status ====&lt;br /&gt;
&lt;br /&gt;
* 🚧 `in-progress` : Still being worked on, more changes will follow.&lt;br /&gt;
* 🚏 `needs-review` : Needs code review and approval from maintainers.&lt;br /&gt;
* 🔍 `under-review` : Being reviewed by maintainers.&lt;br /&gt;
* 🔧 `changes-required` : Needs to be updated based on review comments and then reviewed again.&lt;br /&gt;
* 👀 `needs-testing` : Needs manual testing.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
The following documents have greatly helped us put this together. A big thank you to their authors and contributors!&lt;br /&gt;
* [https://www.contributor-covenant.org/version/1/4/code-of-conduct Contributor Covenant]&lt;br /&gt;
* [https://opensource.guide Open Source Guides]&lt;br /&gt;
* [https://github.com/holochain/holochain-proto/wiki/Development-Protocols Holochain&#039;s Development Protocols]&lt;br /&gt;
* [https://github.com/atom/atom/blob/master/CONTRIBUTING.md Atom&#039;s contributing guide]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/Contributing&amp;diff=56025</id>
		<title>MoodleNet/Contributing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/Contributing&amp;diff=56025"/>
		<updated>2019-05-09T09:25:15Z</updated>

		<summary type="html">&lt;p&gt;Mayel: /* How we collaborate */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Contribution guidelines ==&lt;br /&gt;
&lt;br /&gt;
=== How we collaborate ===&lt;br /&gt;
&lt;br /&gt;
First off, thank you for considering contributing to MoodleNet!&lt;br /&gt;
&lt;br /&gt;
Our aim is for this project to make you feel welcome as a contributor. We hugely value the comments and contributions of community members in the various publicly-accessible areas in use, which currently are:&lt;br /&gt;
&lt;br /&gt;
* Home: [https://moodle.com/moodlenet Project Wiki]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Code_of_Conduct Code of conduct] &lt;br /&gt;
* Code: [https://gitlab.com/moodlenet GitLab]&lt;br /&gt;
* Feature/improvement requests: [https://changemap.co/moodle/moodlenet/ ChangeMap]&lt;br /&gt;
* Issue tracking: [https://tracker.moodle.org/projects/MDLNET?selectedItem=com.atlassian.jira.jira-projects-plugin:components-page Moodle Tracker (Jira)]&lt;br /&gt;
* Discussion: [https://moodle.org/mod/forum/view.php?id=8352 MoodleNet forum]&lt;br /&gt;
* Chat: Telegram (TBC)&lt;br /&gt;
&lt;br /&gt;
=== Other useful information ===&lt;br /&gt;
&lt;br /&gt;
* It’s early days for MoodleNet, so we’re focused on laying down the foundations for the project. This means that you won’t find much usable code yet.&lt;br /&gt;
* We’re working as openly and transparently as possible with this project. As a contributor or member of the MoodleNet community, almost everything you come across will link to some other things that you should have access to. If you don’t have access, and you think you should, just ask!&lt;br /&gt;
* We&#039;re planning to resurrect our monthly [https://docs.moodle.org/dev/MoodleNet/Community-calls community calls] in 2019, which you’ll find announced on [https://blog.moodle.net/ our blog].&lt;br /&gt;
&lt;br /&gt;
=== We practice [https://2017.ind.ie/ethical-design/ Ethical Design] ===&lt;br /&gt;
&lt;br /&gt;
We endeavour to build technology that respects human rights, human effort, and human experience, and hope you will join in this effort.&lt;br /&gt;
&lt;br /&gt;
[[File:ethical-design.png|600px|Ethical Design diagram]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Find out more about ethical design at: https://2017.ind.ie/ethical-design&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== How Can I Contribute? ==&lt;br /&gt;
&lt;br /&gt;
=== Submitting Feature Requests, Enhancement Suggestions or Bug Reports ===&lt;br /&gt;
&lt;br /&gt;
This section guides you through submitting a ✨ feature request, 💄 enhancement suggestions, and 🐛 bug reports for MoodleNet - anything from errors and crashes, to minor improvements, to completely new features.&lt;br /&gt;
&lt;br /&gt;
When you post an issue, please include as many details as possible. &#039;&#039;&#039;Fill in the issue template&#039;&#039;&#039; (available below) to help us resolve issues faster.&lt;br /&gt;
&lt;br /&gt;
All issue tickets should be “bite-sized”, and definitely no more than a sprint’s worth of coding work (currently we do 2 week sprints). Larger tasks/projects are represented as [https://tracker.moodle.org/browse/MDLNET-26?jql=project%20%3D%20MDLNET%20AND%20issuetype%20%3D%20Epic Epics].&lt;br /&gt;
&lt;br /&gt;
=== Before making a submission ===&lt;br /&gt;
&lt;br /&gt;
Please go through the checklist below before posting any ✨ 💄 🐛&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Check if you’re using the latest version&#039;&#039;&#039; of MoodleNet and all its relevant components and if you can get the desired behaviour by changing some config settings.&lt;br /&gt;
* &#039;&#039;&#039;Check if there’s already a community extension or app which provides that enhancement.&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Perform a cursory search&#039;&#039;&#039; in the feature/improvement list and issue tracker to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.&lt;br /&gt;
* Never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to [mailto:moodlenet-moderators@moodle.com moodlenet-moderators@moodle.com].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Note:&#039;&#039;&#039; If you find a &#039;&#039;&#039;Closed&#039;&#039;&#039; issue that seems like it is the same thing that you’re experiencing, open a new issue and include a link to the original issue in the body of your new one.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Suggesting Features &amp;amp;amp; Enhancements ===&lt;br /&gt;
&lt;br /&gt;
If you find yourself wishing for a feature that doesn’t exist in MoodleNet, you are probably not alone. There are probably others out there with similar needs. Make a post on [https://changemap.co/moodle/moodlenet/ ChangeMap] which describes the feature you would like to see, why you need it, and how it might work.&lt;br /&gt;
&lt;br /&gt;
Open an issue providing the following information: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Use a clear and descriptive title&#039;&#039;&#039; for the issue to identify the suggestion. &lt;br /&gt;
* &#039;&#039;&#039;Provide a description of the suggested enhancement&#039;&#039;&#039; in as many details as possible, including the steps that you imagine you (as a user) would take if the feature you’re requesting existed. &lt;br /&gt;
* &#039;&#039;&#039;Describe the current behaviour&#039;&#039;&#039; and &#039;&#039;&#039;explain which behaviour you would like to see instead&#039;&#039;&#039; and why. &lt;br /&gt;
* &#039;&#039;&#039;Include screenshots and animated GIFs&#039;&#039;&#039; which help you demonstrate the steps or point out the parts of MoodleNet which the suggestion is related to. You can use a tool called [https://www.cockos.com/licecap/ LICEcap] to record GIFs on macOS and Windows, and [https://github.com/colinkeenan/silentcast Silentcast] or [https://github.com/GNOME/byzanz Byzanz] on Linux. &lt;br /&gt;
* &#039;&#039;&#039;Provide specific examples to demonstrate the enhancements&#039;&#039;&#039;. If possible, include drawings, screenshots, or gifs of similar features in another app. &lt;br /&gt;
* &#039;&#039;&#039;Explain why this enhancement would be useful&#039;&#039;&#039; to most participants of MoodleNet and isn’t something that can or should be implemented as a community extension. &lt;br /&gt;
* &#039;&#039;&#039;List some other communities, platforms or apps where this enhancement exists.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Reporting Bugs 🐛 ===&lt;br /&gt;
&lt;br /&gt;
Open an issue providing the following information by filling in issue template below, explaining the problem and including additional details to help maintainers reproduce the problem:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Use a clear and descriptive title&#039;&#039;&#039; for the issue to identify the problem.&lt;br /&gt;
* &#039;&#039;&#039;Describe the exact steps which reproduce the problem&#039;&#039;&#039; in as many details as possible. For example, start by explaining where you started in MoodleNet, and then which actions you took. When listing steps, &#039;&#039;&#039;don’t just say what you did, but explain how you did it&#039;&#039;&#039;. For example, if you moved the cursor to the end of a line, explain if you used the mouse or a keyboard shortcut, and if so which one?&lt;br /&gt;
* &#039;&#039;&#039;Provide specific examples to demonstrate the steps&#039;&#039;&#039;. Include links to files, screenshots, or copy/pasteable snippets, which you use in those examples. If you’re providing snippets in the issue, use Markdown code blocks.&lt;br /&gt;
* &#039;&#039;&#039;Describe the behaviour you observed after following the steps&#039;&#039;&#039; and point out what exactly is the problem with that behaviour.&lt;br /&gt;
* &#039;&#039;&#039;Explain which behaviour you expected to see instead and why.&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Include screenshots and animated GIFs&#039;&#039;&#039; which show you following the described steps and clearly demonstrate the problem. You can use [https://www.cockos.com/licecap/ this tool] to record GIFs on macOS and Windows, and [https://github.com/colinkeenan/silentcast this tool] or [https://github.com/GNOME/byzanz this tool] on Linux.&lt;br /&gt;
* &#039;&#039;&#039;If you’re reporting a crash&#039;&#039;&#039;, include a crash report with error logs.&lt;br /&gt;
* &#039;&#039;&#039;If the problem wasn’t triggered by a specific action&#039;&#039;&#039;, describe what you were doing before the problem happened and share more information using the guidelines below.&lt;br /&gt;
&lt;br /&gt;
Provide more context by answering these questions:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Did the problem start happening recently&#039;&#039;&#039; (e.g. after updating to a new version) or was this always a problem?&lt;br /&gt;
* If the problem started happening recently, &#039;&#039;&#039;can you reproduce the problem in an older version?&#039;&#039;&#039; What’s the most recent version in which the problem doesn’t happen?&lt;br /&gt;
* &#039;&#039;&#039;Can you reliably reproduce the issue?&#039;&#039;&#039; If not, provide details about how often the problem happens and under which conditions it normally happens.&lt;br /&gt;
* If the problem is related to a user or item (eg. collection or resource), &#039;&#039;&#039;does the problem happen for all of them or only some?&#039;&#039;&#039; Does the problem happen only when working with local (originating from your MoodleNet instance) or remote ones, with items of a specific type (e.g. only PDFs)? Is there anything else special about the users or items in question?&lt;br /&gt;
&lt;br /&gt;
Include details about your configuration and environment:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Which version of each component are you using?&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;What’s the name and version of the OS you’re using&#039;&#039;&#039;?&lt;br /&gt;
* &#039;&#039;&#039;Are you running in a virtual machine?&#039;&#039;&#039; If so, which VM software are you using and which operating systems and versions are used for the host and the guest?&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
=== Template for submitting issues ===&lt;br /&gt;
&lt;br /&gt;
==== Description ====&lt;br /&gt;
&lt;br /&gt;
[Description of the issue]&lt;br /&gt;
&lt;br /&gt;
==== Steps to Reproduce ====&lt;br /&gt;
&lt;br /&gt;
# [First Step]&lt;br /&gt;
# [Second Step]&lt;br /&gt;
# [and so on…]&lt;br /&gt;
&lt;br /&gt;
==== Expected behaviour: ====&lt;br /&gt;
&lt;br /&gt;
[What you expect to happen]&lt;br /&gt;
&lt;br /&gt;
==== Actual behaviour: ====&lt;br /&gt;
&lt;br /&gt;
[What actually happens]&lt;br /&gt;
&lt;br /&gt;
==== Reproduces how often: ====&lt;br /&gt;
&lt;br /&gt;
[What percentage of the time does it reproduce?]&lt;br /&gt;
&lt;br /&gt;
==== Versions ====&lt;br /&gt;
&lt;br /&gt;
[What MoodleNet instance you’re using, and the versions of each relevant app or component, including your OS and browser.]&lt;br /&gt;
&lt;br /&gt;
==== Additional Information ====&lt;br /&gt;
&lt;br /&gt;
[Any additional information, configuration or data that might be necessary to reproduce the issue.]&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
=== Contributing ===&lt;br /&gt;
&lt;br /&gt;
A common misconception about contributing to free and open source projects is that you need to contribute code. In fact, it’s often the other parts of a project that are most overlooked. You’ll do the project a huge favour by offering to pitch in with these types of contributions!&lt;br /&gt;
&lt;br /&gt;
Even if you like to write code, other types of contributions are a great way to get involved with a project and meet other community members. Building those relationships may open up unexpected opportunities.&lt;br /&gt;
&lt;br /&gt;
==== Do you like to design? 🎨 ====&lt;br /&gt;
&lt;br /&gt;
* Restructure layouts to improve the project&#039;s usability&lt;br /&gt;
* Conduct user research to reorganise and refine the project&#039;s navigation or menus&lt;br /&gt;
* Create art for icons and app screens&lt;br /&gt;
&lt;br /&gt;
==== Do you like to write? 🖉 ====&lt;br /&gt;
&lt;br /&gt;
* Write and improve the project&#039;s documentation&lt;br /&gt;
* Write tutorials for the project&lt;br /&gt;
* Curate a wiki page of examples showing how the project can be used&lt;br /&gt;
&lt;br /&gt;
==== Do you like organising? 📥 ====&lt;br /&gt;
&lt;br /&gt;
* Link to duplicate issues, and suggest new issue labels, to keep things organised&lt;br /&gt;
* Go through open issues and suggest revisiting or closing old ones&lt;br /&gt;
* Ask clarifying questions on recently opened issues to move the discussion forward&lt;br /&gt;
&lt;br /&gt;
==== Do you like helping people? 🙋‍♀️====&lt;br /&gt;
&lt;br /&gt;
* Answer questions about the project on forums and other sites&lt;br /&gt;
* Answer questions for people on open issues&lt;br /&gt;
&lt;br /&gt;
==== Do you like helping others code? 👐 ====&lt;br /&gt;
&lt;br /&gt;
* Review code on other people’s submissions&lt;br /&gt;
* Write tutorials for how a project can be used&lt;br /&gt;
* Offer to mentor another contributor&lt;br /&gt;
&lt;br /&gt;
==== Do you like to code? 🔩 ====&lt;br /&gt;
&lt;br /&gt;
* Find an open issue to tackle&lt;br /&gt;
* Offer to help write a new feature&lt;br /&gt;
* Improve tooling, testing &amp;amp; deployment options&lt;br /&gt;
* Read the **next section for guidelines**&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== Contributing Code ===&lt;br /&gt;
&lt;br /&gt;
Unsure where to begin contributing? You can start by looking through issues tagged with:&lt;br /&gt;
&lt;br /&gt;
* [https://www.firsttimersonly.com &amp;lt;code&amp;gt;first-timers-only&amp;lt;/code&amp;gt;]- issues which should only require a few lines of code, and a test or two.&lt;br /&gt;
* &amp;lt;code&amp;gt;help-wanted&amp;lt;/code&amp;gt; - issues which should be a bit more involved than &amp;lt;code&amp;gt;first-timers-only&amp;lt;/code&amp;gt; issues.&lt;br /&gt;
&lt;br /&gt;
==== Modularity ====&lt;br /&gt;
&lt;br /&gt;
MoodleNet is a large project that is intentionally very modular — it will be made up of many components in many repositories. When you initially consider contributing, you might be unsure about which of those repositories should implement the functionality you want to add or improve - the project maintainers can help with that.&lt;br /&gt;
&lt;br /&gt;
==== Local development ====&lt;br /&gt;
&lt;br /&gt;
MoodleNet and all packages can be developed locally. For instructions on how to do this, please see the documentation (TBD).&lt;br /&gt;
&lt;br /&gt;
==== Coding &amp;amp;amp; git practices ====&lt;br /&gt;
&lt;br /&gt;
* We use GitLab’s merge requests as our code review tool&lt;br /&gt;
* We encourage any dev to comment on merge requests and we think of the merge request not as a “please approve my code” but as a space for co-developing.&lt;br /&gt;
* We develop features on separate branches identified by issue numbers.&lt;br /&gt;
* We use merge to &amp;lt;code&amp;gt;develop&amp;lt;/code&amp;gt; (not rebase) so that commits related to an issue can be retroactively explored.&lt;br /&gt;
* We don’t currently use release branches or tags because we don’t have release management at this phase of development.&lt;br /&gt;
&lt;br /&gt;
==== How to make changes ====&lt;br /&gt;
&lt;br /&gt;
* Make your changes on a seperate branch which includes an issue number e.g. &amp;lt;code&amp;gt;1234-some-new-feature&amp;lt;/code&amp;gt; where 1234 is the issue number where the feature is documented. Make sure the branch is based on &amp;lt;code&amp;gt;develop&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Do not commit changes to files that are irrelevant to your feature or bugfix.&lt;br /&gt;
* Use commit messages descriptive of your changes.&lt;br /&gt;
* Push to the upstream of your new branch.&lt;br /&gt;
* Create a merge request at GitLab.&lt;br /&gt;
&lt;br /&gt;
==== Git commit messages ====&lt;br /&gt;
&lt;br /&gt;
* Limit the first line to 72 characters or less, referencing relevant issue numbers&lt;br /&gt;
* Be as descriptive as you want after the first line&lt;br /&gt;
* Consider starting the commit message with an applicable emoji (see Issue &amp;amp;amp; Commit Categories below)&lt;br /&gt;
&lt;br /&gt;
==== Merge requests ====&lt;br /&gt;
&lt;br /&gt;
* Follow the code styleguides (TBD).&lt;br /&gt;
* Document new code based on the documentation styleguide (TBD)&lt;br /&gt;
* Each merge request should implement ONE feature or bugfix. If you want to add or fix more than one thing, submit more than one merge request.&lt;br /&gt;
* Fill in the merge request template below&lt;br /&gt;
* Include relevant issue number(s) in the merge request title&lt;br /&gt;
* Include screenshots or animated GIFs in your merge request whenever possible.&lt;br /&gt;
* End all files with a newline&lt;br /&gt;
&lt;br /&gt;
==== Template for merge requests ====&lt;br /&gt;
&lt;br /&gt;
* Description of the change&lt;br /&gt;
* Applicable issue numbers&lt;br /&gt;
* Alternate designs/implementations&lt;br /&gt;
* Benefits of this implementation&lt;br /&gt;
* Possible drawbacks&lt;br /&gt;
* Why should this be part of a core component?&lt;br /&gt;
* Testing process&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
==== Issue &amp;amp; Commit Categories ====&lt;br /&gt;
&lt;br /&gt;
* 🚑 `critical` : Critical hotfix!&lt;br /&gt;
* 💄 `enhancement` : General improvements.&lt;br /&gt;
* ✨ `feature` : New features.&lt;br /&gt;
* 🐛 `bug` : Confirmed bugs, or reports that are likely to be bugs.&lt;br /&gt;
* 🙋‍♀️ `question` : Questions (e.g. how can I do X?)&lt;br /&gt;
* 📮 `feedback` : General feedback.&lt;br /&gt;
* 🎨 `ui` : Visual design.&lt;br /&gt;
* 📜 `copy` : Text in the apps, or translations.&lt;br /&gt;
* ℹ️ `documentation` : Documentation.&lt;br /&gt;
* 🏇 `performance` : Performance.&lt;br /&gt;
* 🔒 `security` : Security.&lt;br /&gt;
* 🔌 `api` : MoodleNet&#039;s APIs.&lt;br /&gt;
* 👽 `external` : External libraries or API integrations.&lt;br /&gt;
* ⚠️ `exception` : Uncaught exceptions.&lt;br /&gt;
* 🔥 `crash` : Crash.&lt;br /&gt;
* 🔣 `encoding` : Character encoding or data serialization issue.&lt;br /&gt;
* 🚚 `cleanup` : Removing, moving or refactoring code or files.&lt;br /&gt;
* ✅ `tests` : Testing&lt;br /&gt;
&lt;br /&gt;
==== Issue Status ====&lt;br /&gt;
&lt;br /&gt;
* 💬 `discussion` : Discussion to clarify this issue is ongoing.&lt;br /&gt;
* 🔜 `todo` : This has been discussed and now needs work.&lt;br /&gt;
* 🔁 `needs-more-info` : More information needs to be collected about these problems or feature requests (e.g. steps to reproduce).&lt;br /&gt;
* 💡 `idea` : Needs to be discussed further. Could be a feature request which might be good to first implement as a community extension.&lt;br /&gt;
* 🚧 `in-progress` : Someone is working on this...&lt;br /&gt;
* 🙏 `help-wanted` : The MoodleNet core team would appreciate help from the community in resolving these issues.&lt;br /&gt;
* 🌱 `first-timers-only` : Less complex issues which would be good first issues to work on for users who want to contribute.&lt;br /&gt;
* 🔢 `needs-reproduction` : Likely bugs, but haven&#039;t been reliably reproduced.&lt;br /&gt;
* 🔴 `blocked` : Blocked on other issues.&lt;br /&gt;
* 2️⃣ `duplicate` : Duplicate of another issue, i.e. has been reported before.&lt;br /&gt;
* 🙅 `wontfix` : The MoodleNet core team has decided not to fix these issues (or add these features) for now, because they&#039;re working as intended, or some other reason.&lt;br /&gt;
* 🚮 `invalid` : Issues which are not valid (e.g. spam or submitted by error).&lt;br /&gt;
&lt;br /&gt;
==== Merge Request Status ====&lt;br /&gt;
&lt;br /&gt;
* 🚧 `in-progress` : Still being worked on, more changes will follow.&lt;br /&gt;
* 🚏 `needs-review` : Needs code review and approval from maintainers.&lt;br /&gt;
* 🔍 `under-review` : Being reviewed by maintainers.&lt;br /&gt;
* 🔧 `changes-required` : Needs to be updated based on review comments and then reviewed again.&lt;br /&gt;
* 👀 `needs-testing` : Needs manual testing.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
The following documents have greatly helped us put this together. A big thank you to their authors and contributors!&lt;br /&gt;
* [https://www.contributor-covenant.org/version/1/4/code-of-conduct Contributor Covenant]&lt;br /&gt;
* [https://opensource.guide Open Source Guides]&lt;br /&gt;
* [https://github.com/holochain/holochain-proto/wiki/Development-Protocols Holochain&#039;s Development Protocols]&lt;br /&gt;
* [https://github.com/atom/atom/blob/master/CONTRIBUTING.md Atom&#039;s contributing guide]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet&amp;diff=55765</id>
		<title>MoodleNet</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet&amp;diff=55765"/>
		<updated>2019-03-20T09:30:05Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Moodlenet-logo.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Short URL: &#039;&#039;&#039;https://moodle.com/moodlenet&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;background-color:yellow; padding:10px; text-align:center; font-size:1.2em; margin-bottom:1%;&amp;quot;&amp;gt;Interested in contributing to this project? [https://docs.moodle.org/dev/MoodleNet/Contributing Click here!]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: This page describes a new project started in 2017. For the legacy mechanism of inter-connecting multiple Moodle and Mahara sites into a network, please see the [https://docs.moodle.org/en/MNet MNet] page.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== What is MoodleNet? ==&lt;br /&gt;
&lt;br /&gt;
MoodleNet sustainably empowers communities of educators to share and learn from each other to improve the quality of education. It is a new open social media platform for educators, focussed on professional development and open content. It will be an integral part of the Moodle ecosystem. This is the wiki about the project, and will be updated as the project develops.&lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet_overview_(v0.9).png|thumb|Latest project overview (v0.9)|link=http://bit.ly/2Bjvie7 &lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
* [https://new.moodle.net/ new.moodle.net] - project homepage&lt;br /&gt;
* [https://blog.moodle.net/ Blog] - official project updates by the team&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Contributing Contributing] - ways to get involved!&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Code_of_Conduct Code of Conduct] - how to act to ensure a positive community environment&lt;br /&gt;
&lt;br /&gt;
== Documentation ==&lt;br /&gt;
&lt;br /&gt;
There are some further details in this [https://docs.moodle.org/dev/MoodleNet_whitepaper draft white paper] from early 2018.&lt;br /&gt;
&lt;br /&gt;
[[File:moodlenet-prototype.png|thumb|Prototype overview from the May 2018 MoodleNet design sprint|link=https://blog.moodle.net/2018/prototype-overview/]]&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/inspiration Inspiration]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet-research Other research]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet-consultancy MoodleNet consultancy]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/ Tech choices]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/VPD Value Proposition Design]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Sustainability Sustainability]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Security Security]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/FAQ FAQ] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb|MoodleNet tech stack|link=https://docs.moodle.org/dev/MoodleNet/tech/]]&lt;br /&gt;
&lt;br /&gt;
== Next steps ==&lt;br /&gt;
&lt;br /&gt;
* [https://changemap.co/moodle/moodlenet/ Suggestions from users]&lt;br /&gt;
* [https://bit.ly/epic-MN Milestones &amp;amp; work in progress]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Testing Beta testing]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Roadmap Roadmap]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Decision_Log Decision log]&lt;br /&gt;
&lt;br /&gt;
== Meetings and events ==&lt;br /&gt;
&lt;br /&gt;
* [https://blog.moodle.net/2018/sign-up-feedback/ Barcelona workweek (November 2018)]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/MootUS18-workshop MoodleMoot US (October 2018)]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/MozFest18-workshop Mozilla Festival workshop (October 2018)]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Front-end_dev_workshop Front-end development workshop (September 2018)]&lt;br /&gt;
* [https://blog.moodle.net/2018/alt-c/ ALT-C presentation (September 2018)]&lt;br /&gt;
* [https://docs.moodle.org/dev/MountainMoot18 MountainMoot session (July 2018)]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet-MootES18 MoodleMoot Spain session (June 2018)]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Design_Sprint Design Sprint (May 2018)]&lt;br /&gt;
* [https://blog.moodle.net/2018/project-moodlenet-overview-v0-4/ UK &amp;amp; Ireland MoodleMoot sessions (March 2018)]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet-MootUS17  Miami MoodleMoot sessions (Nov 2017)]&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
Icons from [https://www.flaticon.com flaticon.com]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[es:MoodleNet]]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/Beta_testing&amp;diff=55352</id>
		<title>MoodleNet/Beta testing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/Beta_testing&amp;diff=55352"/>
		<updated>2019-01-04T10:18:35Z</updated>

		<summary type="html">&lt;p&gt;Mayel: /* Open registrations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[File:moodlenet-testing-approach.png|thumb|400px]]&lt;br /&gt;
&lt;br /&gt;
== Timeline ==&lt;br /&gt;
&lt;br /&gt;
Right now, the plan for 2019 is: &lt;br /&gt;
&lt;br /&gt;
* January&lt;br /&gt;
** Open applications to the beta testing programme&lt;br /&gt;
** Create two HQ-run MoodleNet instances (English and Spanish)&lt;br /&gt;
** Invite 100 people to take part in the testing, based on meeting certain criteria (language, location, experience, etc.) &lt;br /&gt;
* February&lt;br /&gt;
** Receive daily/regular feedback from these 100 testers, and improve MoodleNet iteratively&lt;br /&gt;
** Once we&#039;re happy with progress, give 10 invites to each test user, increasing the number of people using MoodleNet to 1,000&lt;br /&gt;
* March&lt;br /&gt;
** Test federation between HQ-run instances&lt;br /&gt;
** Continue iteration based on feedback&lt;br /&gt;
** Start developing Moodle Core plugin&lt;br /&gt;
* April&lt;br /&gt;
** Test Moodle Core plugin&lt;br /&gt;
** Test federation with non-HQ instances&lt;br /&gt;
* May&lt;br /&gt;
** Integrate Moodle Core plugin in 3.7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Approach to testing ==&lt;br /&gt;
&lt;br /&gt;
=== Why? ===&lt;br /&gt;
&#039;&#039;Why does MoodleNet exist?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
MoodleNet exists to better connect the existing Moodle community, and also to attract new educators. To date, the only Moodle-provided way for educators and other users to share content has been within their Moodle Core installation, backing up and importing activities, or by sharing entire courses. MoodleNet will be an upgrade to this, connecting educators via a Moodle-provided open social media platform which focuses on professional development and open content.&lt;br /&gt;
&lt;br /&gt;
=== What? ===&lt;br /&gt;
&#039;&#039;What is the value proposition we&#039;re testing?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We have done some [https://docs.moodle.org/dev/MoodleNet/VPD Value Proposition Design] for different groups using MoodleNet and have decided that it will begin life as a place for educators to curate and share collections of resources. Our hypothesis is that the problem of discovery for educators cannot be solved by simply providing a more powerful search engine for the millions of resources already available. This is for at least three reasons: &lt;br /&gt;
&lt;br /&gt;
* Learning is a &#039;&#039;social&#039;&#039; activity - and likewise teaching should be something that is not done entirely on one&#039;s own&lt;br /&gt;
* Search engines rely on &#039;&#039;already knowing&#039;&#039; what you&#039;re looking for - which is not always the case when planning a lesson, scheme of work, or course&lt;br /&gt;
* Individual resources exist in a wider context - including their relation to other resources, the educator&#039;s approach to learning, and where the &#039;classroom&#039; is located&lt;br /&gt;
&lt;br /&gt;
Initially, then, MoodleNet will be a simple web-based application allowing educators to form communities that curate collections of resources. Most of these, we imagine, will be free and openly-licensed, although MoodleNet will be resource-agnostic. Uploading resources directly to MoodleNet is out of scope for the first phase of testing, as we need to decide our approach to file hosting.&lt;br /&gt;
&lt;br /&gt;
=== How? ===&lt;br /&gt;
&#039;&#039;How are we going to test MoodleNet?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In early January 2019, we&#039;ll put out a call for educators to be involved in MoodleNet testing. We can use something simple such as a Google Form for this, ensuring that there is a privacy notice that they have to agree to on the application. &lt;br /&gt;
&lt;br /&gt;
We&#039;re looking for a diverse mix of educators, with our only limiting factor being their ability to speak English and/or Spanish. The kind of information we&#039;re looking to capture to make a selection includes:&lt;br /&gt;
&lt;br /&gt;
* Name&lt;br /&gt;
* Location (country)&lt;br /&gt;
* Languages(s) spoken&lt;br /&gt;
* Current role&lt;br /&gt;
* Subject area(s)&lt;br /&gt;
* Teaching experience (years)&lt;br /&gt;
* Moodle experience (years)&lt;br /&gt;
* Resource-sharing sites currently used&lt;br /&gt;
* Social networks currently used&lt;br /&gt;
* Reason(s) for wanting to be involved in testing&lt;br /&gt;
&lt;br /&gt;
We&#039;re interested in every aspect of how they decide to use MoodleNet, including:&lt;br /&gt;
&lt;br /&gt;
* The communities and collections they decide to create&lt;br /&gt;
* What type of collections they create &#039;&#039;(subject-based? topic-based? other?)&#039;&#039;&lt;br /&gt;
* The number and type of communities they decide to join&lt;br /&gt;
* How and when they use tags&lt;br /&gt;
* What kind of comments they add in collections&lt;br /&gt;
* How they respond to a 10-item limit on resource collections&lt;br /&gt;
&lt;br /&gt;
=== Who? ===&lt;br /&gt;
&#039;&#039;Who is going to be involved in the testing?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The plan is to recruit 100 people to test MoodleNet. Although we need learning technologists, system administrators, and other techies to test it eventually, our initial focus should be on early-adopter educators. These will agree our [http://bit.ly/2FvqrM0 Guidelines for Contributors] and agree to give us regular feedback.&lt;br /&gt;
&lt;br /&gt;
We should aim to have 50 people on the English-speaking HQ MoodleNet instance, and 50 people on the Spanish-speaking instance. On both, we need a mix of:&lt;br /&gt;
&lt;br /&gt;
* Moodlers / non-Moodlers&lt;br /&gt;
* Experienced / inexperienced teachers&lt;br /&gt;
* Genders&lt;br /&gt;
* Experience with other social networks and OER repositories&lt;br /&gt;
* Educational sectors&lt;br /&gt;
&lt;br /&gt;
=== When? === &lt;br /&gt;
&#039;&#039;When will the testing take place? what comes next?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The first phase of testing MoodleNet is scheduled to begin week beginning January 21st. We need to have a testing period long enough that allows us to observe behaviours and make changes, but short enough so that it&#039;s a focused effort. Therefore, we&#039;re proposing a three-week period from Monday 21st January to Monday 11th February. &lt;br /&gt;
&lt;br /&gt;
After this, we need to test at least three more things:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Inviting a new cohort of users&#039;&#039;&#039; - we&#039;re envisaging that this will be done by giving every existing (active) user 10 invites. That theoretically takes us from 100 to 1,000 users of MoodleNet. &lt;br /&gt;
* &#039;&#039;&#039;Federation&#039;&#039;&#039; - first of all we can test this between HQ-run instances, but we then need to allow users and organisations to set up their own MoodleNet instances&lt;br /&gt;
* &#039;&#039;&#039;Moodle plugin&#039;&#039;&#039; - users should be able to send MoodleNet collections to their Moodle Core installation, and resources from Moodle Core to MoodleNet&lt;br /&gt;
&lt;br /&gt;
The last of these is not well-scoped yet, for a variety of reasons. However, we&#039;re aiming for the Moodle plugin to be integrated into Moodle Core 3.7 in May 2019. The major blocker is a decision to be made about how to deal with uploaded resources. Previous proposals around Moodle Core installations hosting files have been rejected, as this was based on initial testing with MoodleCloud.&lt;br /&gt;
&lt;br /&gt;
=== Where? === &lt;br /&gt;
&#039;&#039;Where will users go to test MoodleNet and give their feedback?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
There will be two HQ-run MoodleNet instances that beta testers can sign up to. We are planning for feedback to be captured in several ways:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;In-situ&#039;&#039;&#039; - when testers perform an action such as create a community, add a resource, or make a comment, they will have the opportunity to give feedback on the experience (including suggestions to improve it). This is for tweaks to the existing functionality and interface.&lt;br /&gt;
* &#039;&#039;&#039;[https://changemap.co/moodle/moodlenet/ Changemap]&#039;&#039;&#039; - when testers have requests around new functionality, integrations, or approach, they can use this tool.&lt;br /&gt;
* &#039;&#039;&#039;[https://moodle.org/mod/forum/view.php?id=8352 Forum]&#039;&#039;&#039; - more public feedback and wider philosophical speculations can be posted to the existing MoodleNet forum&lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
&lt;br /&gt;
This section is a work in progress.&lt;br /&gt;
&lt;br /&gt;
=== Pilot (100 users) ===&lt;br /&gt;
&lt;br /&gt;
Although MoodleNet will eventually feature a lot more functionality, in the first instance we&#039;re aiming to test a very specific value proposition: &#039;&#039;do educators want to join communities to curate collections of resources?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
So for this initial test, users will be able to:&lt;br /&gt;
&lt;br /&gt;
* Create a profile &lt;br /&gt;
* Create, join, and leave a community&lt;br /&gt;
* Create, add to, and follow collections&lt;br /&gt;
* Add resources to collections &lt;br /&gt;
* Start (and reply to) discussions within communities and collections&lt;br /&gt;
* Be notified about activity within joined communities, followed collections (+recommendations)&lt;br /&gt;
* Moderate a community (basic)&lt;br /&gt;
&lt;br /&gt;
=== Pilot (1,000) users ===&lt;br /&gt;
&lt;br /&gt;
We&#039;ll be continuing to iterate based on user feedback during the pilot, using [https://changemap.co/moodle/moodlenet/ Changemap]. In addition to this, we have planned the ability for users to:&lt;br /&gt;
&lt;br /&gt;
* Invite someone to create a MoodleNet account&lt;br /&gt;
* Sign-in with social accounts&lt;br /&gt;
* Follow other users&lt;br /&gt;
* Add other users to a contact list&lt;br /&gt;
* View a list other users&#039; joined communities and followed collections via their profile&lt;br /&gt;
* Flag a resource/collection/community/profile as inappropriate&lt;br /&gt;
* Provide additioanl community moderator functionality&lt;br /&gt;
* Show &#039;related&#039; communities and collections&lt;br /&gt;
* Like/favourite/star comments within communities and collections&lt;br /&gt;
* Like/favourite/star resources within collections&lt;br /&gt;
* Select a tag to find related communities, collections, and profiles&lt;br /&gt;
* Be reminded to post and keep their profile up-to-date by &#039;MoodleBot&#039;&lt;br /&gt;
&lt;br /&gt;
=== Open registrations ===&lt;br /&gt;
&lt;br /&gt;
By the time we allow anyone to register, we want MoodleNet to be federated. This is something that we&#039;ve been building towards since the start, and means that anyone will be able to install their own MoodleNet instance and have it be part of the wider MoodleNet network. So there&#039;s a lot of technical work to do with that, but by this stage we envisage users will be able to:&lt;br /&gt;
&lt;br /&gt;
* Set up their own MoodleNet instance and connect to the wider network via ActivityPub&lt;br /&gt;
* Create an Emoji ID to help with identity across federated instances&lt;br /&gt;
* Use an admin interface to control sharing within an instance or community&lt;br /&gt;
* Easily share a link to a community, collection, or profile on social media&lt;br /&gt;
* Search for resources&lt;br /&gt;
* See &#039;recent activity&#039; on user profiles (likes, follows, discussions, last active)&lt;br /&gt;
* Invite someone from your contact list to join a community&lt;br /&gt;
* Block other users&lt;br /&gt;
* Pull in resources from third-party sites via API (e.g. Creative Commons Beta Search)&lt;br /&gt;
* Send a MoodleNet collection to a Moodle Core site&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/Security&amp;diff=55349</id>
		<title>MoodleNet/Security</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/Security&amp;diff=55349"/>
		<updated>2019-01-04T09:51:49Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[https://moodle.com Moodle] takes security, privacy and user control seriously, and want to put them front and centre of our project.&lt;br /&gt;
&lt;br /&gt;
=== Goals ===&lt;br /&gt;
&lt;br /&gt;
* MoodleNet users can understand the distinctions between public data and private data/metadata on MoodleNet.&lt;br /&gt;
* Users know where their private data/metadata resides and who has access to it, and can access, export, and delete it.&lt;br /&gt;
* Protect private user data/metadata, not just from hackers but also (as much as is possible) from other users, instance admins, community moderators, and external applications&lt;br /&gt;
* Secure from malicious creation, alteration or deletion of public data&lt;br /&gt;
* GDPR compliance&lt;br /&gt;
&lt;br /&gt;
Moodle is both a developer of open source self-hosted software, and a cloud service provider with users in the European Union. As a result, we are putting user privacy, data sovereignty, and GDPR compliance into our security plans, including asking both the Moodle community and outside experts to review our approaches and implementations.&lt;br /&gt;
&lt;br /&gt;
=== Challenges ===&lt;br /&gt;
&lt;br /&gt;
[https://moodle.com/moodlenet MoodleNet] will be challenging to keep secure, as it is:&lt;br /&gt;
&lt;br /&gt;
* open source, both back-end and front-end&lt;br /&gt;
* self-hosted by diverse organisations&lt;br /&gt;
* federated (data is transmitted between different hosted instances)&lt;br /&gt;
&lt;br /&gt;
This means there are more attack surfaces compared to typical proprietary, centralised platforms, but also means that hackers and even users can review every part of MoodleNet and make sure that it works as expected. This should result in more secure software, and higher trust in the application and its ecosystem.&lt;br /&gt;
&lt;br /&gt;
=== Bug bounty programme ===&lt;br /&gt;
&lt;br /&gt;
Maintaining effective security is a community effort, so if you find a security bug that could potentially impact the security or privacy of MoodleNet users, please report it, with our thanks and potentially a cash reward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“We obviously can’t hire enough engineers to protect against every possible vulnerability, but we can use our bug bounty program to add on-demand expertise where we need it and continuous coverage nearly everywhere else.” – Frank, founder of Nextcloud&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We’re hoping that a well-managed security bug bounty program will help us demonstrate how seriously we take privacy.&lt;br /&gt;
&lt;br /&gt;
We believe in transparency about our security, so any valid vulnerabilities discovered are always publicly disclosed after a grace period, to give time for a fix to be developed and deployed by as many self-hosted instances as possible.&lt;br /&gt;
&lt;br /&gt;
During the initial beta phase, Moodle will be hosting the only official instance(s) of MoodleNet, so will be able to quickly deploy the first wave of security fixes. The developers will be aware when the bounty program will start and have time to prepare for the work to receive some real scrutiny.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;By participating in the MoodleNet bounty program, you agree to be bound by the rules in this document and the [https://docs.moodle.org/dev/MoodleNet/Code_of_Conduct MoodleNet Code of Conduct].&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Rewards ===&lt;br /&gt;
&lt;br /&gt;
Depending on their impact, issues may qualify for a monetary reward; all reports are reviewed on a case-by-case basis, though here are some guidelines:&lt;br /&gt;
&lt;br /&gt;
* Critical: $800 - i.e gaining remote code execution on the server or full database access.&lt;br /&gt;
* High: $400 - i.e. gaining access to private data of any other user.&lt;br /&gt;
* Medium: $200 - i.e. limited disclosure of private user data or attacks granting access to a single users’ user session (e.g. XSS)&lt;br /&gt;
* Low: $100 - i.e. very limited disclosure of user data or attacks involving a high amount of unlikely user interaction&lt;br /&gt;
&lt;br /&gt;
Only bugs that show a clear exploit that puts users or their private data at risk are eligible for rewards, not theoretical vectors. Multiple vulnerabilities caused by one underlying issue will be awarded one bounty. We only reward the first reporter of a vulnerability. Public disclosure of the vulnerability prior to resolution may cancel a pending reward.&lt;br /&gt;
&lt;br /&gt;
We are aware these rewards may be lower than those offered by bigger, more mature, software projects, but we think that starting this bounty programme at such an early stage of the project might mean that many bugs will be found and fixed early, and thus result in less security exposure for our users.&lt;br /&gt;
&lt;br /&gt;
Found a bug that isn’t a security issue? While we can’t offer you a monetary reward in that case, we will acknowledge the issue and happily accept reports for it.&lt;br /&gt;
&lt;br /&gt;
=== Scope (final scope TBD upon bounty programme launch) ===&lt;br /&gt;
&lt;br /&gt;
* CommonsPub, the ActivityPub server used by MoodleNet: https://gitlab.com/OpenCoop/CommonsPub/Server&lt;br /&gt;
* MoodleNet back-end: https://gitlab.com/moodlenet/servers/federated&lt;br /&gt;
* MoodleNet front-end: https://gitlab.com/moodlenet/clients/react&lt;br /&gt;
* Server configurations: https://gitlab.com/moodlenet/servers/deploy&lt;br /&gt;
&lt;br /&gt;
=== Responsible Disclosure Guidelines ===&lt;br /&gt;
&lt;br /&gt;
We are committed to working with security researchers to verify, reproduce, and respond to legitimate reported vulnerabilities. You can help us by following these simple guidelines:&lt;br /&gt;
&lt;br /&gt;
* Alert us about the vulnerability as soon as you become aware of it&lt;br /&gt;
* Follow up with details needed to reproduce and validate the vulnerability and a Proof of Concept (PoC) as soon as possible (if not detailed enough to reproduce the issue, it will not be eligible for a reward)&lt;br /&gt;
* Act in good faith to avoid privacy violations, destruction of data, and interruption or degradation of services&lt;br /&gt;
* Do not access or modify users’ private data, without explicit permission of the owner. Only interact with your own accounts or test accounts for security research purposes;&lt;br /&gt;
* Contact Moodle HQ (or the instance admin) immediately if you do inadvertently encounter user data. Do not view, alter, save, store, transfer, or otherwise access the data, and immediately purge any local information upon reporting the vulnerability;&lt;br /&gt;
* Give us time to correct the issue before disclosing it to other parties (if after waiting a reasonable amount of time, we seem clearly unable or unwilling to do anything about it, please do hold us accountable!)&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/Beta_testing&amp;diff=55241</id>
		<title>MoodleNet/Beta testing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/Beta_testing&amp;diff=55241"/>
		<updated>2018-12-06T11:34:07Z</updated>

		<summary type="html">&lt;p&gt;Mayel: /* Checklist */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[File:moodlenet-testing-approach.png|thumb|400px]]&lt;br /&gt;
&lt;br /&gt;
== Timeline ==&lt;br /&gt;
&lt;br /&gt;
Right now, the plan for 2019 is: &lt;br /&gt;
&lt;br /&gt;
* January&lt;br /&gt;
** Open applications to the beta testing programme&lt;br /&gt;
** Create two HQ-run MoodleNet instances (English and Spanish)&lt;br /&gt;
** Invite 100 people to take part in the testing, based on meeting certain criteria (language, location, experience, etc.) &lt;br /&gt;
* February&lt;br /&gt;
** Receive daily/regular feedback from these 100 testers, and improve MoodleNet iteratively&lt;br /&gt;
** Once we&#039;re happy with progress, give 10 invites to each test user, increasing the number of people using MoodleNet to 1,000&lt;br /&gt;
* March&lt;br /&gt;
** Test federation between HQ-run instances&lt;br /&gt;
** Continue iteration based on feedback&lt;br /&gt;
** Start developing Moodle Core plugin&lt;br /&gt;
* April&lt;br /&gt;
** Test Moodle Core plugin&lt;br /&gt;
** Test federation with non-HQ instances&lt;br /&gt;
* May&lt;br /&gt;
** Integrate Moodle Core plugin in 3.7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Approach to testing ==&lt;br /&gt;
&lt;br /&gt;
=== Why? ===&lt;br /&gt;
&#039;&#039;Why does MoodleNet exist?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
MoodleNet exists to better connect the existing Moodle community, and also to attract new educators. To date, the only Moodle-provided way for educators and other users to share content has been within their Moodle Core installation, backing up and importing activities, or by sharing entire courses. MoodleNet will be an upgrade to this, connecting educators via a Moodle-provided open social media platform which focuses on professional development and open content.&lt;br /&gt;
&lt;br /&gt;
=== What? ===&lt;br /&gt;
&#039;&#039;What is the value proposition we&#039;re testing?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We have done some [https://docs.moodle.org/dev/MoodleNet/VPD Value Proposition Design] for different groups using MoodleNet and have decided that it will begin life as a place for educators to curate and share collections of resources. Our hypothesis is that the problem of discovery for educators cannot be solved by simply providing a more powerful search engine for the millions of resources already available. This is for at least three reasons: &lt;br /&gt;
&lt;br /&gt;
* Learning is a &#039;&#039;social&#039;&#039; activity - and likewise teaching should be something that is not done entirely on one&#039;s own&lt;br /&gt;
* Search engines rely on &#039;&#039;already knowing&#039;&#039; what you&#039;re looking for - which is not always the case when planning a lesson, scheme of work, or course&lt;br /&gt;
* Individual resources exist in a wider context - including their relation to other resources, the educator&#039;s approach to learning, and where the &#039;classroom&#039; is located&lt;br /&gt;
&lt;br /&gt;
Initially, then, MoodleNet will be a simple web-based application allowing educators to form communities that curate collections of resources. Most of these, we imagine, will be free and openly-licensed, although MoodleNet will be resource-agnostic. Uploading resources directly to MoodleNet is out of scope for the first phase of testing, as we need to decide our approach to file hosting.&lt;br /&gt;
&lt;br /&gt;
=== How? ===&lt;br /&gt;
&#039;&#039;How are we going to test MoodleNet?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In early January 2019, we&#039;ll put out a call for educators to be involved in MoodleNet testing. We can use something simple such as a Google Form for this, ensuring that there is a privacy notice that they have to agree to on the application. &lt;br /&gt;
&lt;br /&gt;
We&#039;re looking for a diverse mix of educators, with our only limiting factor being their ability to speak English and/or Spanish. The kind of information we&#039;re looking to capture to make a selection includes:&lt;br /&gt;
&lt;br /&gt;
* Name&lt;br /&gt;
* Location (country)&lt;br /&gt;
* Languages(s) spoken&lt;br /&gt;
* Current role&lt;br /&gt;
* Subject area(s)&lt;br /&gt;
* Teaching experience (years)&lt;br /&gt;
* Moodle experience (years)&lt;br /&gt;
* Resource-sharing sites currently used&lt;br /&gt;
* Social networks currently used&lt;br /&gt;
* Reason(s) for wanting to be involved in testing&lt;br /&gt;
&lt;br /&gt;
We&#039;re interested in every aspect of how they decide to use MoodleNet, including:&lt;br /&gt;
&lt;br /&gt;
* The communities and collections they decide to create&lt;br /&gt;
* What type of collections they create &#039;&#039;(subject-based? topic-based? other?)&#039;&#039;&lt;br /&gt;
* The number and type of communities they decide to join&lt;br /&gt;
* How and when they use tags&lt;br /&gt;
* What kind of comments they add in collections&lt;br /&gt;
* How they respond to a 10-item limit on resource collections&lt;br /&gt;
&lt;br /&gt;
=== Who? ===&lt;br /&gt;
&#039;&#039;Who is going to be involved in the testing?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The plan is to recruit 100 people to test MoodleNet. Although we need learning technologists, system administrators, and other techies to test it eventually, our initial focus should be on early-adopter educators. These will agree our [http://bit.ly/2FvqrM0 Guidelines for Contributors] and agree to give us regular feedback.&lt;br /&gt;
&lt;br /&gt;
We should aim to have 50 people on the English-speaking HQ MoodleNet instance, and 50 people on the Spanish-speaking instance. On both, we need a mix of:&lt;br /&gt;
&lt;br /&gt;
* Moodlers / non-Moodlers&lt;br /&gt;
* Experienced / inexperienced teachers&lt;br /&gt;
* Genders&lt;br /&gt;
* Experience with other social networks and OER repositories&lt;br /&gt;
* Educational sectors&lt;br /&gt;
&lt;br /&gt;
=== When? === &lt;br /&gt;
&#039;&#039;When will the testing take place? what comes next?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The first phase of testing MoodleNet is scheduled to begin week beginning January 21st. We need to have a testing period long enough that allows us to observe behaviours and make changes, but short enough so that it&#039;s a focused effort. Therefore, we&#039;re proposing a three-week period from Monday 21st January to Monday 11th February. &lt;br /&gt;
&lt;br /&gt;
After this, we need to test at least three more things:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Inviting a new cohort of users&#039;&#039;&#039; - we&#039;re envisaging that this will be done by giving every existing (active) user 10 invites. That theoretically takes us from 100 to 1,000 users of MoodleNet. &lt;br /&gt;
* &#039;&#039;&#039;Federation&#039;&#039;&#039; - first of all we can test this between HQ-run instances, but we then need to allow users and organisations to set up their own MoodleNet instances&lt;br /&gt;
* &#039;&#039;&#039;Moodle plugin&#039;&#039;&#039; - users should be able to send MoodleNet collections to their Moodle Core installation, and resources from Moodle Core to MoodleNet&lt;br /&gt;
&lt;br /&gt;
The last of these is not well-scoped yet, for a variety of reasons. However, we&#039;re aiming for the Moodle plugin to be integrated into Moodle Core 3.7 in May 2019. The major blocker is a decision to be made about how to deal with uploaded resources. Previous proposals around Moodle Core installations hosting files have been rejected, as this was based on initial testing with MoodleCloud.&lt;br /&gt;
&lt;br /&gt;
=== Where? === &lt;br /&gt;
&#039;&#039;Where will users go to test MoodleNet and give their feedback?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
There will be two HQ-run MoodleNet instances that beta testers can sign up to. We are planning for feedback to be captured in several ways:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;In-situ&#039;&#039;&#039; - when testers perform an action such as create a community, add a resource, or make a comment, they will have the opportunity to give feedback on the experience (including suggestions to improve it). This is for tweaks to the existing functionality and interface.&lt;br /&gt;
* &#039;&#039;&#039;[https://changemap.co/moodle/moodlenet/ Changemap]&#039;&#039;&#039; - when testers have requests around new functionality, integrations, or approach, they can use this tool.&lt;br /&gt;
* &#039;&#039;&#039;[https://moodle.org/mod/forum/view.php?id=8352 Forum]&#039;&#039;&#039; - more public feedback and wider philosophical speculations can be posted to the existing MoodleNet forum&lt;br /&gt;
&lt;br /&gt;
=== Checklist ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;[TO COMPLETE]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We need to ensure that the following things are complete by week beginning January 7th:&lt;br /&gt;
&lt;br /&gt;
* Beta tester application form&lt;br /&gt;
* Privacy statement&lt;br /&gt;
* Contribution guidelines&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
The following needs to be complete by week beginning January 14th:&lt;br /&gt;
&lt;br /&gt;
* Front-end and backend functionality for [https://gitlab.com/moodlenet/project/meta/wikis/List-of-intentions-of-MoodleNet-users-(verb-based) list of verb-based user intentions] (not including federation and Moodle Core integration)&lt;br /&gt;
* Decisions about which applicants to invite to beta testing&lt;br /&gt;
* Moderation &amp;amp; Administration tools &lt;br /&gt;
*&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/Beta_testing&amp;diff=55240</id>
		<title>MoodleNet/Beta testing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/Beta_testing&amp;diff=55240"/>
		<updated>2018-12-06T11:32:58Z</updated>

		<summary type="html">&lt;p&gt;Mayel: /* When? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[File:moodlenet-testing-approach.png|thumb|400px]]&lt;br /&gt;
&lt;br /&gt;
== Timeline ==&lt;br /&gt;
&lt;br /&gt;
Right now, the plan for 2019 is: &lt;br /&gt;
&lt;br /&gt;
* January&lt;br /&gt;
** Open applications to the beta testing programme&lt;br /&gt;
** Create two HQ-run MoodleNet instances (English and Spanish)&lt;br /&gt;
** Invite 100 people to take part in the testing, based on meeting certain criteria (language, location, experience, etc.) &lt;br /&gt;
* February&lt;br /&gt;
** Receive daily/regular feedback from these 100 testers, and improve MoodleNet iteratively&lt;br /&gt;
** Once we&#039;re happy with progress, give 10 invites to each test user, increasing the number of people using MoodleNet to 1,000&lt;br /&gt;
* March&lt;br /&gt;
** Test federation between HQ-run instances&lt;br /&gt;
** Continue iteration based on feedback&lt;br /&gt;
** Start developing Moodle Core plugin&lt;br /&gt;
* April&lt;br /&gt;
** Test Moodle Core plugin&lt;br /&gt;
** Test federation with non-HQ instances&lt;br /&gt;
* May&lt;br /&gt;
** Integrate Moodle Core plugin in 3.7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Approach to testing ==&lt;br /&gt;
&lt;br /&gt;
=== Why? ===&lt;br /&gt;
&#039;&#039;Why does MoodleNet exist?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
MoodleNet exists to better connect the existing Moodle community, and also to attract new educators. To date, the only Moodle-provided way for educators and other users to share content has been within their Moodle Core installation, backing up and importing activities, or by sharing entire courses. MoodleNet will be an upgrade to this, connecting educators via a Moodle-provided open social media platform which focuses on professional development and open content.&lt;br /&gt;
&lt;br /&gt;
=== What? ===&lt;br /&gt;
&#039;&#039;What is the value proposition we&#039;re testing?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We have done some [https://docs.moodle.org/dev/MoodleNet/VPD Value Proposition Design] for different groups using MoodleNet and have decided that it will begin life as a place for educators to curate and share collections of resources. Our hypothesis is that the problem of discovery for educators cannot be solved by simply providing a more powerful search engine for the millions of resources already available. This is for at least three reasons: &lt;br /&gt;
&lt;br /&gt;
* Learning is a &#039;&#039;social&#039;&#039; activity - and likewise teaching should be something that is not done entirely on one&#039;s own&lt;br /&gt;
* Search engines rely on &#039;&#039;already knowing&#039;&#039; what you&#039;re looking for - which is not always the case when planning a lesson, scheme of work, or course&lt;br /&gt;
* Individual resources exist in a wider context - including their relation to other resources, the educator&#039;s approach to learning, and where the &#039;classroom&#039; is located&lt;br /&gt;
&lt;br /&gt;
Initially, then, MoodleNet will be a simple web-based application allowing educators to form communities that curate collections of resources. Most of these, we imagine, will be free and openly-licensed, although MoodleNet will be resource-agnostic. Uploading resources directly to MoodleNet is out of scope for the first phase of testing, as we need to decide our approach to file hosting.&lt;br /&gt;
&lt;br /&gt;
=== How? ===&lt;br /&gt;
&#039;&#039;How are we going to test MoodleNet?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In early January 2019, we&#039;ll put out a call for educators to be involved in MoodleNet testing. We can use something simple such as a Google Form for this, ensuring that there is a privacy notice that they have to agree to on the application. &lt;br /&gt;
&lt;br /&gt;
We&#039;re looking for a diverse mix of educators, with our only limiting factor being their ability to speak English and/or Spanish. The kind of information we&#039;re looking to capture to make a selection includes:&lt;br /&gt;
&lt;br /&gt;
* Name&lt;br /&gt;
* Location (country)&lt;br /&gt;
* Languages(s) spoken&lt;br /&gt;
* Current role&lt;br /&gt;
* Subject area(s)&lt;br /&gt;
* Teaching experience (years)&lt;br /&gt;
* Moodle experience (years)&lt;br /&gt;
* Resource-sharing sites currently used&lt;br /&gt;
* Social networks currently used&lt;br /&gt;
* Reason(s) for wanting to be involved in testing&lt;br /&gt;
&lt;br /&gt;
We&#039;re interested in every aspect of how they decide to use MoodleNet, including:&lt;br /&gt;
&lt;br /&gt;
* The communities and collections they decide to create&lt;br /&gt;
* What type of collections they create &#039;&#039;(subject-based? topic-based? other?)&#039;&#039;&lt;br /&gt;
* The number and type of communities they decide to join&lt;br /&gt;
* How and when they use tags&lt;br /&gt;
* What kind of comments they add in collections&lt;br /&gt;
* How they respond to a 10-item limit on resource collections&lt;br /&gt;
&lt;br /&gt;
=== Who? ===&lt;br /&gt;
&#039;&#039;Who is going to be involved in the testing?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The plan is to recruit 100 people to test MoodleNet. Although we need learning technologists, system administrators, and other techies to test it eventually, our initial focus should be on early-adopter educators. These will agree our [http://bit.ly/2FvqrM0 Guidelines for Contributors] and agree to give us regular feedback.&lt;br /&gt;
&lt;br /&gt;
We should aim to have 50 people on the English-speaking HQ MoodleNet instance, and 50 people on the Spanish-speaking instance. On both, we need a mix of:&lt;br /&gt;
&lt;br /&gt;
* Moodlers / non-Moodlers&lt;br /&gt;
* Experienced / inexperienced teachers&lt;br /&gt;
* Genders&lt;br /&gt;
* Experience with other social networks and OER repositories&lt;br /&gt;
* Educational sectors&lt;br /&gt;
&lt;br /&gt;
=== When? === &lt;br /&gt;
&#039;&#039;When will the testing take place? what comes next?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The first phase of testing MoodleNet is scheduled to begin week beginning January 21st. We need to have a testing period long enough that allows us to observe behaviours and make changes, but short enough so that it&#039;s a focused effort. Therefore, we&#039;re proposing a three-week period from Monday 21st January to Monday 11th February. &lt;br /&gt;
&lt;br /&gt;
After this, we need to test at least three more things:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Inviting a new cohort of users&#039;&#039;&#039; - we&#039;re envisaging that this will be done by giving every existing (active) user 10 invites. That theoretically takes us from 100 to 1,000 users of MoodleNet. &lt;br /&gt;
* &#039;&#039;&#039;Federation&#039;&#039;&#039; - first of all we can test this between HQ-run instances, but we then need to allow users and organisations to set up their own MoodleNet instances&lt;br /&gt;
* &#039;&#039;&#039;Moodle plugin&#039;&#039;&#039; - users should be able to send MoodleNet collections to their Moodle Core installation, and resources from Moodle Core to MoodleNet&lt;br /&gt;
&lt;br /&gt;
The last of these is not well-scoped yet, for a variety of reasons. However, we&#039;re aiming for the Moodle plugin to be integrated into Moodle Core 3.7 in May 2019. The major blocker is a decision to be made about how to deal with uploaded resources. Previous proposals around Moodle Core installations hosting files have been rejected, as this was based on initial testing with MoodleCloud.&lt;br /&gt;
&lt;br /&gt;
=== Where? === &lt;br /&gt;
&#039;&#039;Where will users go to test MoodleNet and give their feedback?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
There will be two HQ-run MoodleNet instances that beta testers can sign up to. We are planning for feedback to be captured in several ways:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;In-situ&#039;&#039;&#039; - when testers perform an action such as create a community, add a resource, or make a comment, they will have the opportunity to give feedback on the experience (including suggestions to improve it). This is for tweaks to the existing functionality and interface.&lt;br /&gt;
* &#039;&#039;&#039;[https://changemap.co/moodle/moodlenet/ Changemap]&#039;&#039;&#039; - when testers have requests around new functionality, integrations, or approach, they can use this tool.&lt;br /&gt;
* &#039;&#039;&#039;[https://moodle.org/mod/forum/view.php?id=8352 Forum]&#039;&#039;&#039; - more public feedback and wider philosophical speculations can be posted to the existing MoodleNet forum&lt;br /&gt;
&lt;br /&gt;
=== Checklist ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;[TO COMPLETE]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We need to ensure that the following things are complete by week beginning January 7th:&lt;br /&gt;
&lt;br /&gt;
* Beta tester application form&lt;br /&gt;
* Privacy statement&lt;br /&gt;
* Contribution guidelines&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
The following needs to be complete by week beginning January 14th:&lt;br /&gt;
&lt;br /&gt;
* Front-end and backend functionality for [https://gitlab.com/moodlenet/project/meta/wikis/List-of-intentions-of-MoodleNet-users-(verb-based) list of verb-based user intentions] (not including federation and Moodle Core integration)&lt;br /&gt;
* Decisions about which applicants to invite to beta testing&lt;br /&gt;
* Administration tools &lt;br /&gt;
*&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/Beta_testing&amp;diff=55239</id>
		<title>MoodleNet/Beta testing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/Beta_testing&amp;diff=55239"/>
		<updated>2018-12-06T11:29:23Z</updated>

		<summary type="html">&lt;p&gt;Mayel: /* How? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[File:moodlenet-testing-approach.png|thumb|400px]]&lt;br /&gt;
&lt;br /&gt;
== Timeline ==&lt;br /&gt;
&lt;br /&gt;
Right now, the plan for 2019 is: &lt;br /&gt;
&lt;br /&gt;
* January&lt;br /&gt;
** Open applications to the beta testing programme&lt;br /&gt;
** Create two HQ-run MoodleNet instances (English and Spanish)&lt;br /&gt;
** Invite 100 people to take part in the testing, based on meeting certain criteria (language, location, experience, etc.) &lt;br /&gt;
* February&lt;br /&gt;
** Receive daily/regular feedback from these 100 testers, and improve MoodleNet iteratively&lt;br /&gt;
** Once we&#039;re happy with progress, give 10 invites to each test user, increasing the number of people using MoodleNet to 1,000&lt;br /&gt;
* March&lt;br /&gt;
** Test federation between HQ-run instances&lt;br /&gt;
** Continue iteration based on feedback&lt;br /&gt;
** Start developing Moodle Core plugin&lt;br /&gt;
* April&lt;br /&gt;
** Test Moodle Core plugin&lt;br /&gt;
** Test federation with non-HQ instances&lt;br /&gt;
* May&lt;br /&gt;
** Integrate Moodle Core plugin in 3.7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Approach to testing ==&lt;br /&gt;
&lt;br /&gt;
=== Why? ===&lt;br /&gt;
&#039;&#039;Why does MoodleNet exist?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
MoodleNet exists to better connect the existing Moodle community, and also to attract new educators. To date, the only Moodle-provided way for educators and other users to share content has been within their Moodle Core installation, backing up and importing activities, or by sharing entire courses. MoodleNet will be an upgrade to this, connecting educators via a Moodle-provided open social media platform which focuses on professional development and open content.&lt;br /&gt;
&lt;br /&gt;
=== What? ===&lt;br /&gt;
&#039;&#039;What is the value proposition we&#039;re testing?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We have done some [https://docs.moodle.org/dev/MoodleNet/VPD Value Proposition Design] for different groups using MoodleNet and have decided that it will begin life as a place for educators to curate and share collections of resources. Our hypothesis is that the problem of discovery for educators cannot be solved by simply providing a more powerful search engine for the millions of resources already available. This is for at least three reasons: &lt;br /&gt;
&lt;br /&gt;
* Learning is a &#039;&#039;social&#039;&#039; activity - and likewise teaching should be something that is not done entirely on one&#039;s own&lt;br /&gt;
* Search engines rely on &#039;&#039;already knowing&#039;&#039; what you&#039;re looking for - which is not always the case when planning a lesson, scheme of work, or course&lt;br /&gt;
* Individual resources exist in a wider context - including their relation to other resources, the educator&#039;s approach to learning, and where the &#039;classroom&#039; is located&lt;br /&gt;
&lt;br /&gt;
Initially, then, MoodleNet will be a simple web-based application allowing educators to form communities that curate collections of resources. Most of these, we imagine, will be free and openly-licensed, although MoodleNet will be resource-agnostic. Uploading resources directly to MoodleNet is out of scope for the first phase of testing, as we need to decide our approach to file hosting.&lt;br /&gt;
&lt;br /&gt;
=== How? ===&lt;br /&gt;
&#039;&#039;How are we going to test MoodleNet?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In early January 2019, we&#039;ll put out a call for educators to be involved in MoodleNet testing. We can use something simple such as a Google Form for this, ensuring that there is a privacy notice that they have to agree to on the application. &lt;br /&gt;
&lt;br /&gt;
We&#039;re looking for a diverse mix of educators, with our only limiting factor being their ability to speak English and/or Spanish. The kind of information we&#039;re looking to capture to make a selection includes:&lt;br /&gt;
&lt;br /&gt;
* Name&lt;br /&gt;
* Location (country)&lt;br /&gt;
* Languages(s) spoken&lt;br /&gt;
* Current role&lt;br /&gt;
* Subject area(s)&lt;br /&gt;
* Teaching experience (years)&lt;br /&gt;
* Moodle experience (years)&lt;br /&gt;
* Resource-sharing sites currently used&lt;br /&gt;
* Social networks currently used&lt;br /&gt;
* Reason(s) for wanting to be involved in testing&lt;br /&gt;
&lt;br /&gt;
We&#039;re interested in every aspect of how they decide to use MoodleNet, including:&lt;br /&gt;
&lt;br /&gt;
* The communities and collections they decide to create&lt;br /&gt;
* What type of collections they create &#039;&#039;(subject-based? topic-based? other?)&#039;&#039;&lt;br /&gt;
* The number and type of communities they decide to join&lt;br /&gt;
* How and when they use tags&lt;br /&gt;
* What kind of comments they add in collections&lt;br /&gt;
* How they respond to a 10-item limit on resource collections&lt;br /&gt;
&lt;br /&gt;
=== Who? ===&lt;br /&gt;
&#039;&#039;Who is going to be involved in the testing?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The plan is to recruit 100 people to test MoodleNet. Although we need learning technologists, system administrators, and other techies to test it eventually, our initial focus should be on early-adopter educators. These will agree our [http://bit.ly/2FvqrM0 Guidelines for Contributors] and agree to give us regular feedback.&lt;br /&gt;
&lt;br /&gt;
We should aim to have 50 people on the English-speaking HQ MoodleNet instance, and 50 people on the Spanish-speaking instance. On both, we need a mix of:&lt;br /&gt;
&lt;br /&gt;
* Moodlers / non-Moodlers&lt;br /&gt;
* Experienced / inexperienced teachers&lt;br /&gt;
* Genders&lt;br /&gt;
* Experience with other social networks and OER repositories&lt;br /&gt;
* Educational sectors&lt;br /&gt;
&lt;br /&gt;
=== When? === &lt;br /&gt;
&#039;&#039;When will the testing take place? what comes next?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The first phase of testing MoodleNet is scheduled to begin week beginning January 21st. We need to have a testing period long enough that allows us to observe behaviours and make changes, but short enough so that it&#039;s a focused effort. Therefore, we&#039;re proposing a three-week period from Monday 21st January to Monday 11th February. &lt;br /&gt;
&lt;br /&gt;
After this, we need to test at least three more things:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Inviting a new cohort of users&#039;&#039;&#039; - we&#039;re envisaging that this will be done by giving every existing (active) user 10 invites. That theoretically takes us from 100 to 1,000 users of MoodleNet. &lt;br /&gt;
* &#039;&#039;&#039;Federation&#039;&#039;&#039; - first of all we can test this between HQ-run instances, but we then need to allow users and organisations to set up their own MoodleNet instances&lt;br /&gt;
* &#039;&#039;&#039;Moodle plugin&#039;&#039;&#039; - users should be able to send MoodleNet collections to their Moodle Core installation, and resources from Moodle Core to MoodleNet&lt;br /&gt;
&lt;br /&gt;
The last of these is not well-scoped yet, for a variety of reasons. However, we&#039;re aiming for the Moodle plugin to be integrated into Moodle Core 3.7 in May 2019. The major blocker is a decision to be made about how to deal with uploaded resources. Previous proposals around Moodle Core installations hosting files have been rejected, as has basing initial testing on MoodleCloud.&lt;br /&gt;
&lt;br /&gt;
=== Where? === &lt;br /&gt;
&#039;&#039;Where will users go to test MoodleNet and give their feedback?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
There will be two HQ-run MoodleNet instances that beta testers can sign up to. We are planning for feedback to be captured in several ways:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;In-situ&#039;&#039;&#039; - when testers perform an action such as create a community, add a resource, or make a comment, they will have the opportunity to give feedback on the experience (including suggestions to improve it). This is for tweaks to the existing functionality and interface.&lt;br /&gt;
* &#039;&#039;&#039;[https://changemap.co/moodle/moodlenet/ Changemap]&#039;&#039;&#039; - when testers have requests around new functionality, integrations, or approach, they can use this tool.&lt;br /&gt;
* &#039;&#039;&#039;[https://moodle.org/mod/forum/view.php?id=8352 Forum]&#039;&#039;&#039; - more public feedback and wider philosophical speculations can be posted to the existing MoodleNet forum&lt;br /&gt;
&lt;br /&gt;
=== Checklist ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;[TO COMPLETE]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We need to ensure that the following things are complete by week beginning January 7th:&lt;br /&gt;
&lt;br /&gt;
* Beta tester application form&lt;br /&gt;
* Privacy statement&lt;br /&gt;
* Contribution guidelines&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
The following needs to be complete by week beginning January 14th:&lt;br /&gt;
&lt;br /&gt;
* Front-end and backend functionality for [https://gitlab.com/moodlenet/project/meta/wikis/List-of-intentions-of-MoodleNet-users-(verb-based) list of verb-based user intentions] (not including federation and Moodle Core integration)&lt;br /&gt;
* Decisions about which applicants to invite to beta testing&lt;br /&gt;
* Administration tools &lt;br /&gt;
*&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/Beta_testing&amp;diff=55238</id>
		<title>MoodleNet/Beta testing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/Beta_testing&amp;diff=55238"/>
		<updated>2018-12-06T11:26:11Z</updated>

		<summary type="html">&lt;p&gt;Mayel: /* Why? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[File:moodlenet-testing-approach.png|thumb|400px]]&lt;br /&gt;
&lt;br /&gt;
== Timeline ==&lt;br /&gt;
&lt;br /&gt;
Right now, the plan for 2019 is: &lt;br /&gt;
&lt;br /&gt;
* January&lt;br /&gt;
** Open applications to the beta testing programme&lt;br /&gt;
** Create two HQ-run MoodleNet instances (English and Spanish)&lt;br /&gt;
** Invite 100 people to take part in the testing, based on meeting certain criteria (language, location, experience, etc.) &lt;br /&gt;
* February&lt;br /&gt;
** Receive daily/regular feedback from these 100 testers, and improve MoodleNet iteratively&lt;br /&gt;
** Once we&#039;re happy with progress, give 10 invites to each test user, increasing the number of people using MoodleNet to 1,000&lt;br /&gt;
* March&lt;br /&gt;
** Test federation between HQ-run instances&lt;br /&gt;
** Continue iteration based on feedback&lt;br /&gt;
** Start developing Moodle Core plugin&lt;br /&gt;
* April&lt;br /&gt;
** Test Moodle Core plugin&lt;br /&gt;
** Test federation with non-HQ instances&lt;br /&gt;
* May&lt;br /&gt;
** Integrate Moodle Core plugin in 3.7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Approach to testing ==&lt;br /&gt;
&lt;br /&gt;
=== Why? ===&lt;br /&gt;
&#039;&#039;Why does MoodleNet exist?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
MoodleNet exists to better connect the existing Moodle community, and also to attract new educators. To date, the only Moodle-provided way for educators and other users to share content has been within their Moodle Core installation, backing up and importing activities, or by sharing entire courses. MoodleNet will be an upgrade to this, connecting educators via a Moodle-provided open social media platform which focuses on professional development and open content.&lt;br /&gt;
&lt;br /&gt;
=== What? ===&lt;br /&gt;
&#039;&#039;What is the value proposition we&#039;re testing?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We have done some [https://docs.moodle.org/dev/MoodleNet/VPD Value Proposition Design] for different groups using MoodleNet and have decided that it will begin life as a place for educators to curate and share collections of resources. Our hypothesis is that the problem of discovery for educators cannot be solved by simply providing a more powerful search engine for the millions of resources already available. This is for at least three reasons: &lt;br /&gt;
&lt;br /&gt;
* Learning is a &#039;&#039;social&#039;&#039; activity - and likewise teaching should be something that is not done entirely on one&#039;s own&lt;br /&gt;
* Search engines rely on &#039;&#039;already knowing&#039;&#039; what you&#039;re looking for - which is not always the case when planning a lesson, scheme of work, or course&lt;br /&gt;
* Individual resources exist in a wider context - including their relation to other resources, the educator&#039;s approach to learning, and where the &#039;classroom&#039; is located&lt;br /&gt;
&lt;br /&gt;
Initially, then, MoodleNet will be a simple web-based application allowing educators to form communities that curate collections of resources. Most of these, we imagine, will be free and openly-licensed, although MoodleNet will be resource-agnostic. Uploading resources directly to MoodleNet is out of scope for the first phase of testing, as we need to decide our approach to file hosting.&lt;br /&gt;
&lt;br /&gt;
=== How? ===&lt;br /&gt;
&#039;&#039;How are we going to test MoodleNet?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In early January 2019, we&#039;ll put out a call for educators to be involved in MoodleNet testing. We can use something simple such as a Google Form for this, ensuring that there is a privacy notice that they have to agree to on the application. &lt;br /&gt;
&lt;br /&gt;
We&#039;re looking for a diverse mix of educators, with our only limiting factor being their ability to speak English and/or Spanish. The kind of information we&#039;re looking to capture to make a selection includes:&lt;br /&gt;
&lt;br /&gt;
* Name&lt;br /&gt;
* Location (country)&lt;br /&gt;
* Languages(s) spoken&lt;br /&gt;
* Current role&lt;br /&gt;
* Subject area(s)&lt;br /&gt;
* Teaching experience (years)&lt;br /&gt;
* Moodle experience (years)&lt;br /&gt;
* Resource-sharing sites currently used&lt;br /&gt;
* Social networks currently used&lt;br /&gt;
* Reason(s) for wanting to be involved in testing&lt;br /&gt;
&lt;br /&gt;
We&#039;re interested in every aspect of how they decide to use MoodleNet, including:&lt;br /&gt;
&lt;br /&gt;
* The communities and collections they decide to create&lt;br /&gt;
* What type of collections they create &#039;&#039;(subject-based? topic-based? other?)&#039;&#039;&lt;br /&gt;
* The number and type of communities they decide to join&lt;br /&gt;
* How and when they use tags&lt;br /&gt;
* What kind of comments they add to resources&lt;br /&gt;
* How they respond to a 10-item limit on resource collections&lt;br /&gt;
&lt;br /&gt;
=== Who? ===&lt;br /&gt;
&#039;&#039;Who is going to be involved in the testing?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The plan is to recruit 100 people to test MoodleNet. Although we need learning technologists, system administrators, and other techies to test it eventually, our initial focus should be on early-adopter educators. These will agree our [http://bit.ly/2FvqrM0 Guidelines for Contributors] and agree to give us regular feedback.&lt;br /&gt;
&lt;br /&gt;
We should aim to have 50 people on the English-speaking HQ MoodleNet instance, and 50 people on the Spanish-speaking instance. On both, we need a mix of:&lt;br /&gt;
&lt;br /&gt;
* Moodlers / non-Moodlers&lt;br /&gt;
* Experienced / inexperienced teachers&lt;br /&gt;
* Genders&lt;br /&gt;
* Experience with other social networks and OER repositories&lt;br /&gt;
* Educational sectors&lt;br /&gt;
&lt;br /&gt;
=== When? === &lt;br /&gt;
&#039;&#039;When will the testing take place? what comes next?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The first phase of testing MoodleNet is scheduled to begin week beginning January 21st. We need to have a testing period long enough that allows us to observe behaviours and make changes, but short enough so that it&#039;s a focused effort. Therefore, we&#039;re proposing a three-week period from Monday 21st January to Monday 11th February. &lt;br /&gt;
&lt;br /&gt;
After this, we need to test at least three more things:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Inviting a new cohort of users&#039;&#039;&#039; - we&#039;re envisaging that this will be done by giving every existing (active) user 10 invites. That theoretically takes us from 100 to 1,000 users of MoodleNet. &lt;br /&gt;
* &#039;&#039;&#039;Federation&#039;&#039;&#039; - first of all we can test this between HQ-run instances, but we then need to allow users and organisations to set up their own MoodleNet instances&lt;br /&gt;
* &#039;&#039;&#039;Moodle plugin&#039;&#039;&#039; - users should be able to send MoodleNet collections to their Moodle Core installation, and resources from Moodle Core to MoodleNet&lt;br /&gt;
&lt;br /&gt;
The last of these is not well-scoped yet, for a variety of reasons. However, we&#039;re aiming for the Moodle plugin to be integrated into Moodle Core 3.7 in May 2019. The major blocker is a decision to be made about how to deal with uploaded resources. Previous proposals around Moodle Core installations hosting files have been rejected, as has basing initial testing on MoodleCloud.&lt;br /&gt;
&lt;br /&gt;
=== Where? === &lt;br /&gt;
&#039;&#039;Where will users go to test MoodleNet and give their feedback?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
There will be two HQ-run MoodleNet instances that beta testers can sign up to. We are planning for feedback to be captured in several ways:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;In-situ&#039;&#039;&#039; - when testers perform an action such as create a community, add a resource, or make a comment, they will have the opportunity to give feedback on the experience (including suggestions to improve it). This is for tweaks to the existing functionality and interface.&lt;br /&gt;
* &#039;&#039;&#039;[https://changemap.co/moodle/moodlenet/ Changemap]&#039;&#039;&#039; - when testers have requests around new functionality, integrations, or approach, they can use this tool.&lt;br /&gt;
* &#039;&#039;&#039;[https://moodle.org/mod/forum/view.php?id=8352 Forum]&#039;&#039;&#039; - more public feedback and wider philosophical speculations can be posted to the existing MoodleNet forum&lt;br /&gt;
&lt;br /&gt;
=== Checklist ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;[TO COMPLETE]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We need to ensure that the following things are complete by week beginning January 7th:&lt;br /&gt;
&lt;br /&gt;
* Beta tester application form&lt;br /&gt;
* Privacy statement&lt;br /&gt;
* Contribution guidelines&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
The following needs to be complete by week beginning January 14th:&lt;br /&gt;
&lt;br /&gt;
* Front-end and backend functionality for [https://gitlab.com/moodlenet/project/meta/wikis/List-of-intentions-of-MoodleNet-users-(verb-based) list of verb-based user intentions] (not including federation and Moodle Core integration)&lt;br /&gt;
* Decisions about which applicants to invite to beta testing&lt;br /&gt;
* Administration tools &lt;br /&gt;
*&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54945</id>
		<title>MoodleNet/tech</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54945"/>
		<updated>2018-11-05T16:03:56Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
An area to document the tech decisions we&#039;ve made, and our approaches (mostly work in progress) to current or future problems.&lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb|link=https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL]]&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/architecture Technical architecture] - how is the platform going to be set up?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/stack Tech stack] - why did we choose Elixir?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/Moodle_integration MoodleNet integrations with Moodle]&lt;br /&gt;
* How to have a [https://gitlab.com/moodlenet/contacts-import &amp;quot;find my friends&amp;quot; feature without compromising privacy]&lt;br /&gt;
* [https://gitlab.com/moodlenet/project/meta/wikis/activitypub-and-activitystreams ActivityStreams-based metadata schemas]&lt;br /&gt;
* [https://gitlab.com/moodlenet/project/meta/wikis/databases-and-models Database schema] for the federated server&lt;br /&gt;
* [https://gitlab.com/moodlenet/project/meta/wikis Various notes (messy!)]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54722</id>
		<title>MoodleNet/tech</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54722"/>
		<updated>2018-09-06T09:30:08Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
An area to document the tech decisions we&#039;ve made, and our approaches (mostly work in progress) to current or future problems.&lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb|link=https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL]]&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/architecture Technical architecture] - how is the platform going to be set up?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/stack Tech stack] - why did we choose Elixir?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/Moodle_integration MoodleNet integrations with Moodle]&lt;br /&gt;
* How to have a [https://gitlab.com/moodlenet/contacts-import &amp;quot;find my friends&amp;quot; feature without compromising privacy]&lt;br /&gt;
* [https://gitlab.com/moodlenet/architecture/issues/1#note_94925974 Database schema] for the federated server&lt;br /&gt;
* [https://gitlab.com/moodlenet/architecture/issues/1#note_95144351 ActivityStreams-based metadata schemas]&lt;br /&gt;
* [https://gitlab.com/moodlenet/meta/wikis/home Various notes (messy!)]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54721</id>
		<title>MoodleNet/tech</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54721"/>
		<updated>2018-09-06T09:28:46Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
An area to document the tech choices and decisions we&#039;ve made.&lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb|link=https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL]]&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/architecture Technical architecture] - how is the platform going to be set up?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/stack Tech stack] - why did we choose Elixir?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/Moodle_integration MoodleNet integrations with Moodle]&lt;br /&gt;
* How to have a [https://gitlab.com/moodlenet/contacts-import &amp;quot;find my friends&amp;quot; feature without compromising privacy]&lt;br /&gt;
* [https://gitlab.com/moodlenet/architecture/issues/1#note_94925974 Database schema] for the federated server&lt;br /&gt;
* [https://gitlab.com/moodlenet/architecture/issues/1#note_95144351 ActivityStreams-based metadata schemas]&lt;br /&gt;
* [https://gitlab.com/moodlenet/meta/wikis/home Various notes (messy!)]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54720</id>
		<title>MoodleNet/tech</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54720"/>
		<updated>2018-09-06T09:27:03Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
An area to document the tech choices and decisions we&#039;ve made.&lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb|link=https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL]]&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/architecture Technical architecture] - how is the platform going to be set up?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/stack Tech stack] - why did we choose Elixir?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/Moodle_integration MoodleNet integrations with Moodle]&lt;br /&gt;
* How to have a [https://gitlab.com/moodlenet/contacts-import &amp;quot;find my friends&amp;quot; feature without compromising privacy]&lt;br /&gt;
* [https://gitlab.com/moodlenet/architecture/issues/1#note_94925974 Database schema] for the federated server&lt;br /&gt;
* [https://gitlab.com/moodlenet/architecture/issues/1#note_95144351 ActivityStreams-based metadata schemas]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54719</id>
		<title>MoodleNet/tech</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54719"/>
		<updated>2018-09-06T09:26:52Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
An area to document the tech choices and decisions we&#039;ve made.&lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb|link=https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL]]&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/architecture Technical architecture] - how is the platform going to be set up?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/stack Tech stack] - why did we choose Elixir?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/Moodle_integration MoodleNet integrations with Moodle]&lt;br /&gt;
* How to have a [https://gitlab.com/moodlenet/contacts-import &amp;quot;find my friends&amp;quot; feature without compromising privacy]&lt;br /&gt;
* [https://gitlab.com/moodlenet/architecture/issues/1#note_94925974 Database schema] for the federated server&lt;br /&gt;
* [https://gitlab.com/moodlenet/architecture/issues/1#note_94925974 Database schema] for the federated server&lt;br /&gt;
* [https://gitlab.com/moodlenet/architecture/issues/1#note_95144351 ActivityStreams-based metadata schemas]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54718</id>
		<title>MoodleNet/tech</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54718"/>
		<updated>2018-09-06T09:24:24Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
An area to document the tech choices and decisions we&#039;ve made.&lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb|link=https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL]]&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/architecture Technical architecture] - how is the platform going to be set up?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/stack Tech stack] - why did we choose Elixir?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/Moodle_integration MoodleNet integrations with Moodle]&lt;br /&gt;
* How to have a [https://gitlab.com/moodlenet/contacts-import &amp;quot;find my friends&amp;quot; feature without compromising privacy]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/architecture&amp;diff=54717</id>
		<title>MoodleNet/tech/architecture</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/architecture&amp;diff=54717"/>
		<updated>2018-09-06T09:20:06Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet/tech Back to MoodleNet Tech index]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: terms in bold are defined in the glossary at the end of the document.&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
There are broadly three approaches we can take to building out MoodleNet’s platform architecture. These are:&lt;br /&gt;
&lt;br /&gt;
# Fully peer-to-peer &lt;br /&gt;
# Fully federated &lt;br /&gt;
# Federated with HQ API-as-a-service&lt;br /&gt;
# Centralised SaaS &lt;br /&gt;
&lt;br /&gt;
This page explains why we have chosen to focus on the federated with HQ API-as-a-service option. A document outlining three of the potential architectural approaches is also available at http://bit.ly/2yjF8y6. We believe that creating MoodleNet with a federated architecture combined with a HQ API-as-a-service will balance an open approach with a sustainable way of managing the project. &lt;br /&gt;
&lt;br /&gt;
Irrespective of architectural decision, we plan for MoodleNet to be consistent with Moodle’s philosophy of libre software. Moodle Core is licensed under the GNU General Public License (GNU GPL), which is compatible with the GNU Affero General Public License (GNU AGPL) that we intend to use for MoodleNet. The latter is recommended for software being run over a network. Like Moodle Core, MoodleNet is an open source platform, meaning that anyone can adapt, extend or modify the software for both commercial and non-commercial projects without any licensing fees.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Federated with HQ API service ==&lt;br /&gt;
Moodle HQ will run a MoodleNet HQ &#039;&#039;&#039;API-as-a-service&#039;&#039;&#039; serving as a central index of information across the network. This enables consistent discovery and search experiences across all MoodleNet &#039;&#039;&#039;instances&#039;&#039;&#039; (including the one provided by Moodle HQ). &lt;br /&gt;
&lt;br /&gt;
Each &#039;&#039;&#039;MoodleNet instance&#039;&#039;&#039; stores the full data of local users, communities, and collections (including personal information, private messages, and public comments/discussions). &lt;br /&gt;
&lt;br /&gt;
The database of the MoodleNet HQ API service contains lists of all public communities, collections, resources, and users across the network, along with a copy of some metadata. A search index also sits behind the API to enable fast and accurate search results. Each item always refers back to the originating MoodleNet instance for the full data (e.g. membership, permissions, comments/discussions). &lt;br /&gt;
&lt;br /&gt;
In practice, this means that the MoodleNet network, while &#039;&#039;&#039;federated&#039;&#039;&#039;, is reliant upon the MoodleNet HQ API service for search and discovery. This provides users with a better and more consistent experience, reducing fragmentation and spreading the shared content more widely, and also gives Moodle HQ more control over the overall network. &lt;br /&gt;
&lt;br /&gt;
Another HQ API service, the Moodle resources repository, could also provides hosting for Moodle course content that users share on MoodleNet. This could later be facilitated with P2P file sharing protocols like &#039;&#039;&#039;IPFS&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
This network can also be based on existing &#039;&#039;&#039;protocols&#039;&#039;&#039; and &#039;&#039;&#039;standards&#039;&#039;&#039; to form a &#039;&#039;&#039;decentralised&#039;&#039;&#039; collection of nodes that send, receive, and store data. The data handling module can be based on an extended ActivityStreams data format and at least some of the APIs on the ActivityPub protocol to ensure compatibility between systems. &lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb|link=https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL]]&lt;br /&gt;
&lt;br /&gt;
Interactive diagram: https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL &lt;br /&gt;
&lt;br /&gt;
Advantages of a federated network:&lt;br /&gt;
* Robust and resilient&lt;br /&gt;
* Scales horizontally&lt;br /&gt;
* Private data stays on each user’s home instance&lt;br /&gt;
* Each instance is responsible for its content (moderation of discussions, etc)&lt;br /&gt;
* Standards-based but also extensible&lt;br /&gt;
* Open&lt;br /&gt;
&lt;br /&gt;
Advantages of HQ API service:&lt;br /&gt;
* Some Moodle HQ influence over the network &lt;br /&gt;
* Consistent network-wide search and discovery experiences&lt;br /&gt;
* No duplication of resources for core functions like the indexing of resources from OER APIs, global search indexing, and Moodle resource hosting&lt;br /&gt;
* Each instance is still responsible for its content (moderation of discussions, etc)&lt;br /&gt;
* Moodle HQ controls the evolution/standardisation of content/metadata types and formats&lt;br /&gt;
&lt;br /&gt;
Disadvantages of HQ API service:&lt;br /&gt;
* Single point of failure (HQ API service operated by Moodle HQ).  &lt;br /&gt;
* Moodle HQ may be responsible for the content that shows up in search / discovery &lt;br /&gt;
* Some infrastructure costs for Moodle HQ &lt;br /&gt;
* Slightly higher number of components &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Glossary ==&lt;br /&gt;
&lt;br /&gt;
ActivityPub - a standard decentralised social networking protocol based on ActivityStreams.&lt;br /&gt;
&lt;br /&gt;
ActivityStreams - a standard format for syndicating social activities.&lt;br /&gt;
&lt;br /&gt;
API - Application Programming Interface. A set of definitions, protocols, and tools for building application software, to enable communication between various components.&lt;br /&gt;
&lt;br /&gt;
API-as-a-service - Software as a Service (SaaS) primarily exposed as an API.&lt;br /&gt;
&lt;br /&gt;
Canonical - the main or reference location for something (eg. canonical URL)&lt;br /&gt;
&lt;br /&gt;
Data handling module - a database abstraction library, using an ORM approach, which would have added support for caching and federation (when applicable).&lt;br /&gt;
&lt;br /&gt;
Decentralisation - the process by which the activities of a network are distributed or delegated away from a central, authoritative location or group.&lt;br /&gt;
&lt;br /&gt;
Federation - the ability for decentralised systems to send data to one another in a standardised way, to prevent fragmentation of the network. Email is a great example of a federated system.&lt;br /&gt;
&lt;br /&gt;
GNU AGPL - a free, copyleft license published by the Free Software Foundation, and based on version 3 of the GNU General Public License (GPL) and the Affero General Public License. This license is compatible with the GPL and is recommended for any software that will commonly be run over a network.&lt;br /&gt;
&lt;br /&gt;
GNU GPL - a widely used free software license guaranteeing end users the freedom to run, study, share and modify the libre software. &lt;br /&gt;
&lt;br /&gt;
Instance - See also node. Can refer to an independently-hosted version of a software package.&lt;br /&gt;
&lt;br /&gt;
IPFS - the InterPlanetary File System is a new hypermedia distribution protocol, addressed by content and identities. IPFS enables the creation of completely distributed applications. It aims to make the web faster, safer, and more open.&lt;br /&gt;
&lt;br /&gt;
Libre software - software that is distributed under terms that allow users to run the software for any purpose as well as to study, change, and distribute it (and any adapted versions).&lt;br /&gt;
&lt;br /&gt;
Metadata - data that provides information about other data. For educational resources, it could describe various aspects of the material, including grade level, subject area, and content type or format. &lt;br /&gt;
&lt;br /&gt;
MoodleNet instance - an independently-hosted version of MoodleNet.&lt;br /&gt;
&lt;br /&gt;
Moodle instance - an independently-hosted version of Moodle Core.&lt;br /&gt;
&lt;br /&gt;
Node - a member of a decentralised network, which can sometimes serve as client, sometimes as server. See also instance.&lt;br /&gt;
&lt;br /&gt;
Open Source -  a decentralized software-development model that encourages open collaboration, with products such as source code, blueprints, and documentation freely available to the public.&lt;br /&gt;
&lt;br /&gt;
ORM - Object-relational mapping, used to create a ‘virtual object database’ which can then be referenced programmatically (with less code and more flexibility as to the underlying data storage). &lt;br /&gt;
&lt;br /&gt;
Protocol - a defined set of rules and formats that determine how data is transmitted.&lt;br /&gt;
&lt;br /&gt;
SaaS - Software as a Service. Web-based software that’s centrally hosted and made available to use (free or by subscription).&lt;br /&gt;
&lt;br /&gt;
Scaling horizontally - implies adding more nodes to a system to support its growth, for example installing copies of the same software on three web servers instead of just one. &lt;br /&gt;
&lt;br /&gt;
Scaling vertically - implies adding resources (like CPUs or memory) to a single server in a system to support its growth.&lt;br /&gt;
&lt;br /&gt;
Search index - a component of search engines which collects, parses, and stores data to facilitate fast and accurate search and information retrieval. Index design incorporates interdisciplinary concepts from linguistics, cognitive psychology, mathematics, informatics, and computer science. &lt;br /&gt;
&lt;br /&gt;
Standard - a collection of agreed specifications, usually organised by a standards body such as the W3C.&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/architecture&amp;diff=54716</id>
		<title>MoodleNet/tech/architecture</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/architecture&amp;diff=54716"/>
		<updated>2018-09-06T09:17:45Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet/tech Back to MoodleNet Tech index]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: terms in bold are defined in the glossary at the end of the document.&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
There are broadly three approaches we can take to building out MoodleNet’s platform architecture. These are:&lt;br /&gt;
&lt;br /&gt;
# Fully peer-to-peer &lt;br /&gt;
# Fully federated &lt;br /&gt;
# Federated with HQ API-as-a-service [Note: this is the architecture approach that was selected] &lt;br /&gt;
# Centralised SaaS &lt;br /&gt;
&lt;br /&gt;
This document outlines three of the potential architectural approaches, and explains why we have chosen to focus on the second option. We believe that creating MoodleNet with a federated architecture combined with a HQ API-as-a-service will balance an open approach with a sustainable way of managing the project. &lt;br /&gt;
&lt;br /&gt;
Irrespective of architectural decision, we plan for MoodleNet to be consistent with Moodle’s philosophy of libre software. Moodle Core is licensed under the GNU General Public License (GNU GPL), which is compatible with the GNU Affero General Public License (GNU AGPL) that we intend to use for MoodleNet. The latter is recommended for software being run over a network. Like Moodle Core, MoodleNet is an open source platform, meaning that anyone can adapt, extend or modify the software for both commercial and non-commercial projects without any licensing fees.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Federated with HQ API service ==&lt;br /&gt;
Moodle HQ will run a MoodleNet HQ &#039;&#039;&#039;API-as-a-service&#039;&#039;&#039; serving as a central index of information across the network. This enables consistent discovery and search experiences across all MoodleNet &#039;&#039;&#039;instances&#039;&#039;&#039; (including the one provided by Moodle HQ). &lt;br /&gt;
&lt;br /&gt;
Each &#039;&#039;&#039;MoodleNet instance&#039;&#039;&#039; stores the full data of local users, communities, and collections (including personal information, private messages, and public comments/discussions). &lt;br /&gt;
&lt;br /&gt;
The database of the MoodleNet HQ API service contains lists of all public communities, collections, resources, and users across the network, along with a copy of some metadata. A search index also sits behind the API to enable fast and accurate search results. Each item always refers back to the originating MoodleNet instance for the full data (e.g. membership, permissions, comments/discussions). &lt;br /&gt;
&lt;br /&gt;
In practice, this means that the MoodleNet network, while &#039;&#039;&#039;federated&#039;&#039;&#039;, is reliant upon the MoodleNet HQ API service for search and discovery. This provides users with a better and more consistent experience, reducing fragmentation and spreading the shared content more widely, and also gives Moodle HQ more control over the overall network. &lt;br /&gt;
&lt;br /&gt;
Another HQ API service, the Moodle resources repository, could also provides hosting for Moodle course content that users share on MoodleNet. This could later be facilitated with P2P file sharing protocols like &#039;&#039;&#039;IPFS&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
This network can also be based on existing &#039;&#039;&#039;protocols&#039;&#039;&#039; and &#039;&#039;&#039;standards&#039;&#039;&#039; to form a &#039;&#039;&#039;decentralised&#039;&#039;&#039; collection of nodes that send, receive, and store data. The data handling module can be based on an extended ActivityStreams data format and at least some of the APIs on the ActivityPub protocol to ensure compatibility between systems. &lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb|link=https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL]]&lt;br /&gt;
&lt;br /&gt;
Interactive diagram: https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL &lt;br /&gt;
&lt;br /&gt;
Advantages of a federated network:&lt;br /&gt;
* Robust and resilient&lt;br /&gt;
* Scales horizontally&lt;br /&gt;
* Private data stays on each user’s home instance&lt;br /&gt;
* Each instance is responsible for its content (moderation of discussions, etc)&lt;br /&gt;
* Standards-based but also extensible&lt;br /&gt;
* Open&lt;br /&gt;
&lt;br /&gt;
Advantages of HQ API service:&lt;br /&gt;
* Some Moodle HQ influence over the network &lt;br /&gt;
* Consistent network-wide search and discovery experiences&lt;br /&gt;
* No duplication of resources for core functions like the indexing of resources from OER APIs, global search indexing, and Moodle resource hosting&lt;br /&gt;
* Each instance is still responsible for its content (moderation of discussions, etc)&lt;br /&gt;
* Moodle HQ controls the evolution/standardisation of content/metadata types and formats&lt;br /&gt;
&lt;br /&gt;
Disadvantages of HQ API service:&lt;br /&gt;
* Single point of failure (HQ API service operated by Moodle HQ).  &lt;br /&gt;
* Moodle HQ may be responsible for the content that shows up in search / discovery &lt;br /&gt;
* Some infrastructure costs for Moodle HQ &lt;br /&gt;
* Slightly higher number of components &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Glossary ==&lt;br /&gt;
&lt;br /&gt;
ActivityPub - a standard decentralised social networking protocol based on ActivityStreams.&lt;br /&gt;
&lt;br /&gt;
ActivityStreams - a standard format for syndicating social activities.&lt;br /&gt;
&lt;br /&gt;
API - Application Programming Interface. A set of definitions, protocols, and tools for building application software, to enable communication between various components.&lt;br /&gt;
&lt;br /&gt;
API-as-a-service - Software as a Service (SaaS) primarily exposed as an API.&lt;br /&gt;
&lt;br /&gt;
Canonical - the main or reference location for something (eg. canonical URL)&lt;br /&gt;
&lt;br /&gt;
Data handling module - a database abstraction library, using an ORM approach, which would have added support for caching and federation (when applicable).&lt;br /&gt;
&lt;br /&gt;
Decentralisation - the process by which the activities of a network are distributed or delegated away from a central, authoritative location or group.&lt;br /&gt;
&lt;br /&gt;
Federation - the ability for decentralised systems to send data to one another in a standardised way, to prevent fragmentation of the network. Email is a great example of a federated system.&lt;br /&gt;
&lt;br /&gt;
GNU AGPL - a free, copyleft license published by the Free Software Foundation, and based on version 3 of the GNU General Public License (GPL) and the Affero General Public License. This license is compatible with the GPL and is recommended for any software that will commonly be run over a network.&lt;br /&gt;
&lt;br /&gt;
GNU GPL - a widely used free software license guaranteeing end users the freedom to run, study, share and modify the libre software. &lt;br /&gt;
&lt;br /&gt;
Instance - See also node. Can refer to an independently-hosted version of a software package.&lt;br /&gt;
&lt;br /&gt;
IPFS - the InterPlanetary File System is a new hypermedia distribution protocol, addressed by content and identities. IPFS enables the creation of completely distributed applications. It aims to make the web faster, safer, and more open.&lt;br /&gt;
&lt;br /&gt;
Libre software - software that is distributed under terms that allow users to run the software for any purpose as well as to study, change, and distribute it (and any adapted versions).&lt;br /&gt;
&lt;br /&gt;
Metadata - data that provides information about other data. For educational resources, it could describe various aspects of the material, including grade level, subject area, and content type or format. &lt;br /&gt;
&lt;br /&gt;
MoodleNet instance - an independently-hosted version of MoodleNet.&lt;br /&gt;
&lt;br /&gt;
Moodle instance - an independently-hosted version of Moodle Core.&lt;br /&gt;
&lt;br /&gt;
Node - a member of a decentralised network, which can sometimes serve as client, sometimes as server. See also instance.&lt;br /&gt;
&lt;br /&gt;
Open Source -  a decentralized software-development model that encourages open collaboration, with products such as source code, blueprints, and documentation freely available to the public.&lt;br /&gt;
&lt;br /&gt;
ORM - Object-relational mapping, used to create a ‘virtual object database’ which can then be referenced programmatically (with less code and more flexibility as to the underlying data storage). &lt;br /&gt;
&lt;br /&gt;
Protocol - a defined set of rules and formats that determine how data is transmitted.&lt;br /&gt;
&lt;br /&gt;
SaaS - Software as a Service. Web-based software that’s centrally hosted and made available to use (free or by subscription).&lt;br /&gt;
&lt;br /&gt;
Scaling horizontally - implies adding more nodes to a system to support its growth, for example installing copies of the same software on three web servers instead of just one. &lt;br /&gt;
&lt;br /&gt;
Scaling vertically - implies adding resources (like CPUs or memory) to a single server in a system to support its growth.&lt;br /&gt;
&lt;br /&gt;
Search index - a component of search engines which collects, parses, and stores data to facilitate fast and accurate search and information retrieval. Index design incorporates interdisciplinary concepts from linguistics, cognitive psychology, mathematics, informatics, and computer science. &lt;br /&gt;
&lt;br /&gt;
Standard - a collection of agreed specifications, usually organised by a standards body such as the W3C.&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/Moodle_integration&amp;diff=54715</id>
		<title>MoodleNet/tech/Moodle integration</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/Moodle_integration&amp;diff=54715"/>
		<updated>2018-09-06T09:16:06Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet/tech Back to MoodleNet tech index]&lt;br /&gt;
&lt;br /&gt;
= &amp;lt;span class=&amp;quot;c20&amp;quot;&amp;gt;MoodleNet integration with Moodle core&amp;lt;/span&amp;gt; =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Note: This document is available with extra screenshots at: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=http://bit.ly/2mBAZgq&amp;amp;sa=D&amp;amp;ust=1536228177969000 http://bit.ly/2mBAZgq]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;c10&amp;quot;&amp;gt;What we&#039;re trying to achieve&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Users &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;need&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; to be able to easily: &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Share content from their Moodle (entire courses or specific activities) to MoodleNet&amp;lt;/span&amp;gt;&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Search and import any type of MoodleNet resources from within their Moodle&amp;lt;/span&amp;gt;&lt;br /&gt;
# &amp;lt;span&amp;gt;Import any &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;type of resources&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt1|[a]]][[#cmnt2|[b]]]&amp;lt;/sup&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; they come across when browsing MoodleNet into their Moodle&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;It would be nice if users could:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Preview Moodle-specific resources on MoodleNet, without/before having to import them into their Moodle&amp;lt;/span&amp;gt;&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Sign into MoodleNet with their existing Moodle account&amp;lt;/span&amp;gt;&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Sign into their Moodle with their MoodleNet account&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;Where in Moodle could MoodleNet be integrated?&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Login / Registration (sign in to your Moodle with your MoodleNet account, and vice versa)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Global search&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Create new course&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Add an activity or resource&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Rich text editors -&amp;amp;gt; Insert media -&amp;amp;gt; Browse repositories&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Share course&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Share activity&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span&amp;gt;Options for previewing Moodle-specific content&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt3|[c]]]&amp;lt;/sup&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;The most challenging functionality to implement is allowing users to &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;preview&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Moodle-specific content (resources/activities) from MoodleNet&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; before importing content into their Moodle course &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Because of all the different types of data possible, it seems obvious that we should leverage Moodle Core for this, with dedicated plugin(s). Here are options we’ve identified:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Temporary course on user’s Moodle site&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; - Add a &amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;preview&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;&amp;amp;quot; UX flow to &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Moodle&#039;s import functionality&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;, so that when a user clicks “preview” the content is seamlessly (1 step only) imported &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;as a new course&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; into&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt; their Moodle site&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;, so the user can browse the content and if they’re satisfied they can then actually “import” (copy) the sections/activities they want into their existing course, or &amp;amp;quot;delete the preview&amp;amp;quot;.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Mostly involves tweaking some Moodle UX and plugins.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Users (or admins) might not feel comfortable importing random content from the web into their production Moodle instance.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Slower, more friction.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;        Option 1 is most likely what we’re implementing for the MoodleNet MVP.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;2&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Moodle HQ-run preview site - Auto-import&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; the content to &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;one big dedicated preview site&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; (powered by Moodle).&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: The content could be imported in the background as soon as it’s shared, and always be instantly accessible for previewing.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Educators would have read-only access.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: The preview site would get massive and probably slow over time (solution could be to split the content between several sites).&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Requires adding an automatic mode (controllable by command line) to the import plugin.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;3&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Temporary Moodle site at subdomain of moodle.net - Auto-&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;import&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;the content on a&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;temporary Moodle site&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; (similar to &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://demo.moodle.net&amp;amp;sa=D&amp;amp;ust=1536228177979000 https://demo.moodle.net]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;) which gets deleted after X hours/days.&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Educators can get read-write access.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: There’s already a system in place to do this.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Slower, more friction.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;: Requires adding an automatic mode (controllable by command line) to the import plugin.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Import&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt; to user’s MoodleCloud site&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt4|[d]]]&amp;lt;/sup&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt; - &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Import&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; the content to the &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;user&#039;s personal MoodleCloud site&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; (or a separate personal test site?)&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: User is in full control.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;: Could make this a premium &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;feature&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Requires the user to sign up for a MoodleCould site (solution could be to add an opt-in option that automatically does that when they join MoodleNet).&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Slower, more friction.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;c10&amp;quot;&amp;gt;Options for importing content from around the web&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;TBD depending on the type content and where it’s coming from.&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; Some examples:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;YouTube or Vimeo video: embedded in Page module&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Video file: linked (URL module) from original source?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;PDF: linked (URL module) from original source, or copied (File module)?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Word document: linked (URL module) from original source, or copied (File module), or converted to HTML (Page module)?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;etc...&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;c10&amp;quot;&amp;gt;Where the current Moodle.net is integrated with Moodle&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;Context&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;The existing Moodle.net allows users to share Moodle courses with the community. These courses are shared and, after moderation, appear via a searchable interface at &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://moodle.net&amp;amp;sa=D&amp;amp;ust=1536228177983000 https://moodle.net]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; and in Moodle Core’s ‘Community Finder’ functionality.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;1. Moodle.net registration&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;To submit a course to Moodle.net, the user’s Moodle site must be registered. &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;An admin of the Moodle instance first needs to fill in Moodle.net registration form, which is main source of &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://moodle.net/stats/&amp;amp;sa=D&amp;amp;ust=1536228177983000 Moodle usage stats]&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;. Users are blocked from sharing content to Moodle.net before this is done (but they can search &amp;amp;amp; import content). Note that sites that are not publicly-accessible on the internet, or using a non-standard port are &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/35/en/error/local_hub/cannotregisterbadport&amp;amp;sa=D&amp;amp;ust=1536228177984000 not able to register]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Admins are told that by registering:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;You&#039;ll be one of the first to find out about important notifications such as security alerts and new Moodle releases.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;You can access and activate mobile push notifications from your Moodle site through our free Moodle Mobile app.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;You are contributing to our Moodle statistics of the worldwide community, which help us improve Moodle and our community sites.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;If you wish, your site can be included in the list of registered Moodle sites in your country.&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; [Unlisted / Name only / Name + URL]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Required fields: &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Country&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Admin email address&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Optional fields:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Name&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Site listing in directory?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Description&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Language&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Notifications about important security and technical issues?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Updates about Moodle news and features?&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;The following information will be sent to contribute to overall statistics only. It will not be made public on any site listing.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Moodle release (3.5)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of courses (3)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of users (3)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of role assignments (3)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of posts (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of questions (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of resources (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of badges (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of issued badges (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Average number of participants (1.00)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Average number of course modules (5.00)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Mobile services enabled (Yes)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Mobile notifications enabled (No)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of users with registered mobile devices (1)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of active users with registered mobile devices which are receiving notifications (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;span class=&amp;quot;c15&amp;quot;&amp;gt;Next steps regarding registration&amp;lt;/span&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Check structure of API and code that handles registration between Moodle &amp;amp;amp; Moodle.net (both sides)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Check if we can override this functionality with a plugin (for backward compatibility with old Moodle versions)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Decide what changes (if any) need to be made to the data collected&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Decide if registration could be done by any teacher-level account instead of just admins (i.e. registering with the MoodleNet core API service, to collect stats &amp;amp;amp; enable MoodleNet search)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Add new sign-in functionality (&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/35/en/OAuth_2_services&amp;amp;sa=D&amp;amp;ust=1536228177989000 OAuth]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; client) for users to connect their Moodle account to their MoodleNet account (i.e. authenticating with their MoodleNet instance&#039;s API, to enable personalised MoodleNet search, and sharing &amp;amp;amp; importing of resources). An OAuth client is available as a core part of Moodle.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Potentially &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://github.com/projectestac/moodle-local_oauth&amp;amp;sa=D&amp;amp;ust=1536228177989000 turn Moodle into an OAuth server]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; so that users can sign into MoodleNet with their existing Moodle accounts (especially useful for on-boarding, to avoid having to re-enter personal details). This would mean adding a plugin. &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;2. Search &amp;amp;amp; import courses&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;The &#039;Community Finder&#039; function allows searching for resources on Moodle.net and is currently available as a &#039;block&#039; that needs to be added manually (not ideal).&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt5|[e]]][[#cmnt6|[f]]]&amp;lt;/sup&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;It can be used with simple keyword search, or with advanced filtering.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;‘Visit Demo&#039; function for resources currently is just an optional link to a public course that needs to be hosted somewhere (submitted as part of &#039;sharing&#039;, not ideal).&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;‘Install’ function has 8 steps/screens.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;span class=&amp;quot;c15&amp;quot;&amp;gt;Next steps regarding search &amp;amp;amp; import&amp;lt;/span&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Create new Moodle plugin(s) to handle search of MoodleNet content, in these places:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Global search&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Create course&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Add an activity or resource&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Rich text editors -&amp;amp;gt; Insert media -&amp;amp;gt; Browse repositories&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span&amp;gt;Unless MoodleNet provides ‘preview’ functionality for Moodle content&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt7|[g]]][[#cmnt8|[h]]][[#cmnt9|[i]]]&amp;lt;/sup&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;, decide if instead of the user selecting which sections/resources to import before seeing them, they all get imported into a new course so the user can afterwards delete those they don’t need (or copy/move only those they need into an existing course).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;In any case, create new import plugin with simplified UX (1 or 2 steps max) and make it explicitly about ‘importing’ rather than ‘restoring’.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;If the import plugin doesn’t already, make it check upfront for compatibility with the Moodle version and list of plugins, and if necessary tell the user what they need to ask their admin before they can import that content. (Only admins can install plugins, and MoodleCloud doesn&#039;t allow extra plugins, but fortunately only a minority of content seems to depend on 3rd party activity plugins).&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;3. Share &amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 1&amp;lt;/span&amp;gt; is for choosing if you want to export or just open up your course to the public.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 2 is pre-filled with metadata from the course and includes list of subjects from Australian standard (used to be hierarchical, only allows selecting on subject), and some other fields which contain the same options as seen in the search filters above.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 3 has the following toggles:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Anonymize user information&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include user role assignments&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include activities and resources&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include blocks&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include filters&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include comments&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include badges&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include calendar events&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include user completion details&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include course logs&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include grade history&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include question bank&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include groups and groupings&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include competencies&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 4 allows selecting/deselecting which activities to share (this should be moved to before step 2).&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Step 5 is a review of previous options (backup options, not incl. course metadata weirdly). The main button here says ‘Perform backup’ rather than ‘Share to MoodleNet’.&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt10|[j]]]&amp;lt;/sup&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 6 contents are packaged as an mbz file and uploaded to moodle.net&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;The mbz is a zip with xml files and other content (including subfolders for plugin content). The format doesn&#039;t seem to be documented but should contain all the info we need (eg. what Moodle version it came from, and the list of required plugins).&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Step 7 - the upload then goes in moderation queue (Mary) before being published.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;After sharing, there’s a status screen available&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;span class=&amp;quot;c15&amp;quot;&amp;gt;Next steps regarding sharing&amp;lt;/span&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Add sharing function at section &amp;amp;amp; activity level (currently only available at course level).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Simplify UX (1 or 2 steps max) and make it explicitly about ‘sharing’ rather than ‘backup’.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Possibly move all metadata input to a screen on MoodleNet (where it can also be edited later) rather than it being part of Moodle.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Review all metadata fields.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;‘Publisher’ will be the MoodleNet user who is doing the sharing.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;‘Creator’ could be prefilled with the MoodleNet accounts of the Moodle users who created the course (or activities therein), if known.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Decide on list of licensing options, and what should be the default.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;c10&amp;quot;&amp;gt;References&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;Relevant Documentation&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span&amp;gt;General docs: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Main_Page&amp;amp;sa=D&amp;amp;ust=1536228178000000 https://docs.moodle.org/dev/Main_Page]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Plugin diff. types: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Plugin_types&amp;amp;sa=D&amp;amp;ust=1536228178001000 https://docs.moodle.org/dev/Plugin_types]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;E&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;xisting plugins: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://moodle.org/plugins/&amp;amp;sa=D&amp;amp;ust=1536228178001000 https://moodle.org/plugins/]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;T&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;utorial: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Tutorial&amp;amp;sa=D&amp;amp;ust=1536228178002000 https://docs.moodle.org/dev/Tutorial]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;API: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Web_services&amp;amp;sa=D&amp;amp;ust=1536228178002000 https://docs.moodle.org/dev/Web_services]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;This tool might be useful for command-line ops: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=http://moosh-online.com&amp;amp;sa=D&amp;amp;ust=1536228178003000 http://moosh-online.com]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;Relevant Moodle plugin types&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Other than modifying Moodle Core (which would make our integration not be backwards compatible with older Moodle versions), this is the plugin architecture that is available for us to plug into Moodle:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span&amp;gt;Simple HTML/PHP block: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Blocks&amp;amp;sa=D&amp;amp;ust=1536228178003000 https://docs.moodle.org/dev/Blocks]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Repository (allow Moodle to bring contents in from external repositories): &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Repository_plugins&amp;amp;sa=D&amp;amp;ust=1536228178004000 https://docs.moodle.org/dev/Repository_plugins]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Portfolio (allow to publish files to all kinds of external document repository systems) &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Portfolio_plugins&amp;amp;sa=D&amp;amp;ust=1536228178004000 https://docs.moodle.org/dev/Portfolio_plugins]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;G&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;lobal search: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Search_engines&amp;amp;sa=D&amp;amp;ust=1536228178005000 https://docs.moodle.org/dev/Search_engines]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Authentication / OAuth: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Authentication_plugins&amp;amp;sa=D&amp;amp;ust=1536228178005000 https://docs.moodle.org/dev/Authentication_plugins]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/35/en/OAuth_2_authentication&amp;amp;sa=D&amp;amp;ust=1536228178006000 https://docs.moodle.org/35/en/OAuth_2_authentication]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;External tool source / LTI &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/External_tool_source&amp;amp;sa=D&amp;amp;ust=1536228178006000 https://docs.moodle.org/dev/External_tool_source]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://en.wikipedia.org/wiki/Learning_Tools_Interoperability&amp;amp;sa=D&amp;amp;ust=1536228178006000 https://en.wikipedia.org/wiki/Learning_Tools_Interoperability]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Adding protocols to the API: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Webservice_protocols&amp;amp;sa=D&amp;amp;ust=1536228178007000 https://docs.moodle.org/dev/Webservice_protocols]&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54714</id>
		<title>MoodleNet/tech</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54714"/>
		<updated>2018-09-06T09:15:46Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
An area to document the tech choices and decisions we&#039;ve made.&lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb|link=https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL]]&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/architecture Technical architecture] - how is the platform going to be set up?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/stack Tech stack] - why did we choose Elixir?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/Moodle_integration MoodleNet integrations with Moodle]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/Moodle_integration&amp;diff=54713</id>
		<title>MoodleNet/tech/Moodle integration</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/Moodle_integration&amp;diff=54713"/>
		<updated>2018-09-06T09:14:37Z</updated>

		<summary type="html">&lt;p&gt;Mayel: /* Options for previewing Moodle-specific content[c] */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &amp;lt;span class=&amp;quot;c20&amp;quot;&amp;gt;MoodleNet integration with Moodle core&amp;lt;/span&amp;gt; =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Note: This document is available with extra screenshots at: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=http://bit.ly/2mBAZgq&amp;amp;sa=D&amp;amp;ust=1536228177969000 http://bit.ly/2mBAZgq]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;c10&amp;quot;&amp;gt;What we&#039;re trying to achieve&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Users &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;need&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; to be able to easily: &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Share content from their Moodle (entire courses or specific activities) to MoodleNet&amp;lt;/span&amp;gt;&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Search and import any type of MoodleNet resources from within their Moodle&amp;lt;/span&amp;gt;&lt;br /&gt;
# &amp;lt;span&amp;gt;Import any &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;type of resources&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt1|[a]]][[#cmnt2|[b]]]&amp;lt;/sup&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; they come across when browsing MoodleNet into their Moodle&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;It would be nice if users could:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Preview Moodle-specific resources on MoodleNet, without/before having to import them into their Moodle&amp;lt;/span&amp;gt;&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Sign into MoodleNet with their existing Moodle account&amp;lt;/span&amp;gt;&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Sign into their Moodle with their MoodleNet account&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;Where in Moodle could MoodleNet be integrated?&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Login / Registration (sign in to your Moodle with your MoodleNet account, and vice versa)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Global search&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Create new course&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Add an activity or resource&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Rich text editors -&amp;amp;gt; Insert media -&amp;amp;gt; Browse repositories&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Share course&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Share activity&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span&amp;gt;Options for previewing Moodle-specific content&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt3|[c]]]&amp;lt;/sup&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;The most challenging functionality to implement is allowing users to &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;preview&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Moodle-specific content (resources/activities) from MoodleNet&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; before importing content into their Moodle course &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Because of all the different types of data possible, it seems obvious that we should leverage Moodle Core for this, with dedicated plugin(s). Here are options we’ve identified:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Temporary course on user’s Moodle site&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; - Add a &amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;preview&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;&amp;amp;quot; UX flow to &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Moodle&#039;s import functionality&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;, so that when a user clicks “preview” the content is seamlessly (1 step only) imported &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;as a new course&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; into&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt; their Moodle site&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;, so the user can browse the content and if they’re satisfied they can then actually “import” (copy) the sections/activities they want into their existing course, or &amp;amp;quot;delete the preview&amp;amp;quot;.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Mostly involves tweaking some Moodle UX and plugins.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Users (or admins) might not feel comfortable importing random content from the web into their production Moodle instance.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Slower, more friction.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;        Option 1 is most likely what we’re implementing for the MoodleNet MVP.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;2&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Moodle HQ-run preview site - Auto-import&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; the content to &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;one big dedicated preview site&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; (powered by Moodle).&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: The content could be imported in the background as soon as it’s shared, and always be instantly accessible for previewing.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Educators would have read-only access.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: The preview site would get massive and probably slow over time (solution could be to split the content between several sites).&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Requires adding an automatic mode (controllable by command line) to the import plugin.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;3&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Temporary Moodle site at subdomain of moodle.net - Auto-&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;import&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;the content on a&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;temporary Moodle site&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; (similar to &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://demo.moodle.net&amp;amp;sa=D&amp;amp;ust=1536228177979000 https://demo.moodle.net]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;) which gets deleted after X hours/days.&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Educators can get read-write access.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: There’s already a system in place to do this.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Slower, more friction.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;: Requires adding an automatic mode (controllable by command line) to the import plugin.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Import&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt; to user’s MoodleCloud site&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt4|[d]]]&amp;lt;/sup&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt; - &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Import&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; the content to the &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;user&#039;s personal MoodleCloud site&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; (or a separate personal test site?)&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: User is in full control.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;: Could make this a premium &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;feature&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;.&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Requires the user to sign up for a MoodleCould site (solution could be to add an opt-in option that automatically does that when they join MoodleNet).&amp;lt;/span&amp;gt;&lt;br /&gt;
  * &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Slower, more friction.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;c10&amp;quot;&amp;gt;Options for importing content from around the web&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;TBD depending on the type content and where it’s coming from.&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; Some examples:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;YouTube or Vimeo video: embedded in Page module&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Video file: linked (URL module) from original source?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;PDF: linked (URL module) from original source, or copied (File module)?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Word document: linked (URL module) from original source, or copied (File module), or converted to HTML (Page module)?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;etc...&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;c10&amp;quot;&amp;gt;Where the current Moodle.net is integrated with Moodle&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;Context&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;The existing Moodle.net allows users to share Moodle courses with the community. These courses are shared and, after moderation, appear via a searchable interface at &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://moodle.net&amp;amp;sa=D&amp;amp;ust=1536228177983000 https://moodle.net]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; and in Moodle Core’s ‘Community Finder’ functionality.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;1. Moodle.net registration&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;To submit a course to Moodle.net, the user’s Moodle site must be registered. &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;An admin of the Moodle instance first needs to fill in Moodle.net registration form, which is main source of &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://moodle.net/stats/&amp;amp;sa=D&amp;amp;ust=1536228177983000 Moodle usage stats]&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;. Users are blocked from sharing content to Moodle.net before this is done (but they can search &amp;amp;amp; import content). Note that sites that are not publicly-accessible on the internet, or using a non-standard port are &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/35/en/error/local_hub/cannotregisterbadport&amp;amp;sa=D&amp;amp;ust=1536228177984000 not able to register]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Admins are told that by registering:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;You&#039;ll be one of the first to find out about important notifications such as security alerts and new Moodle releases.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;You can access and activate mobile push notifications from your Moodle site through our free Moodle Mobile app.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;You are contributing to our Moodle statistics of the worldwide community, which help us improve Moodle and our community sites.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;If you wish, your site can be included in the list of registered Moodle sites in your country.&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; [Unlisted / Name only / Name + URL]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Required fields: &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Country&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Admin email address&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Optional fields:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Name&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Site listing in directory?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Description&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Language&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Notifications about important security and technical issues?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Updates about Moodle news and features?&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;The following information will be sent to contribute to overall statistics only. It will not be made public on any site listing.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Moodle release (3.5)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of courses (3)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of users (3)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of role assignments (3)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of posts (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of questions (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of resources (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of badges (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of issued badges (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Average number of participants (1.00)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Average number of course modules (5.00)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Mobile services enabled (Yes)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Mobile notifications enabled (No)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of users with registered mobile devices (1)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of active users with registered mobile devices which are receiving notifications (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;span class=&amp;quot;c15&amp;quot;&amp;gt;Next steps regarding registration&amp;lt;/span&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Check structure of API and code that handles registration between Moodle &amp;amp;amp; Moodle.net (both sides)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Check if we can override this functionality with a plugin (for backward compatibility with old Moodle versions)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Decide what changes (if any) need to be made to the data collected&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Decide if registration could be done by any teacher-level account instead of just admins (i.e. registering with the MoodleNet core API service, to collect stats &amp;amp;amp; enable MoodleNet search)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Add new sign-in functionality (&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/35/en/OAuth_2_services&amp;amp;sa=D&amp;amp;ust=1536228177989000 OAuth]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; client) for users to connect their Moodle account to their MoodleNet account (i.e. authenticating with their MoodleNet instance&#039;s API, to enable personalised MoodleNet search, and sharing &amp;amp;amp; importing of resources). An OAuth client is available as a core part of Moodle.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Potentially &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://github.com/projectestac/moodle-local_oauth&amp;amp;sa=D&amp;amp;ust=1536228177989000 turn Moodle into an OAuth server]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; so that users can sign into MoodleNet with their existing Moodle accounts (especially useful for on-boarding, to avoid having to re-enter personal details). This would mean adding a plugin. &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;2. Search &amp;amp;amp; import courses&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;The &#039;Community Finder&#039; function allows searching for resources on Moodle.net and is currently available as a &#039;block&#039; that needs to be added manually (not ideal).&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt5|[e]]][[#cmnt6|[f]]]&amp;lt;/sup&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;It can be used with simple keyword search, or with advanced filtering.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;‘Visit Demo&#039; function for resources currently is just an optional link to a public course that needs to be hosted somewhere (submitted as part of &#039;sharing&#039;, not ideal).&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;‘Install’ function has 8 steps/screens.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;span class=&amp;quot;c15&amp;quot;&amp;gt;Next steps regarding search &amp;amp;amp; import&amp;lt;/span&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Create new Moodle plugin(s) to handle search of MoodleNet content, in these places:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Global search&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Create course&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Add an activity or resource&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Rich text editors -&amp;amp;gt; Insert media -&amp;amp;gt; Browse repositories&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span&amp;gt;Unless MoodleNet provides ‘preview’ functionality for Moodle content&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt7|[g]]][[#cmnt8|[h]]][[#cmnt9|[i]]]&amp;lt;/sup&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;, decide if instead of the user selecting which sections/resources to import before seeing them, they all get imported into a new course so the user can afterwards delete those they don’t need (or copy/move only those they need into an existing course).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;In any case, create new import plugin with simplified UX (1 or 2 steps max) and make it explicitly about ‘importing’ rather than ‘restoring’.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;If the import plugin doesn’t already, make it check upfront for compatibility with the Moodle version and list of plugins, and if necessary tell the user what they need to ask their admin before they can import that content. (Only admins can install plugins, and MoodleCloud doesn&#039;t allow extra plugins, but fortunately only a minority of content seems to depend on 3rd party activity plugins).&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;3. Share &amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 1&amp;lt;/span&amp;gt; is for choosing if you want to export or just open up your course to the public.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 2 is pre-filled with metadata from the course and includes list of subjects from Australian standard (used to be hierarchical, only allows selecting on subject), and some other fields which contain the same options as seen in the search filters above.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 3 has the following toggles:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Anonymize user information&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include user role assignments&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include activities and resources&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include blocks&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include filters&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include comments&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include badges&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include calendar events&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include user completion details&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include course logs&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include grade history&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include question bank&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include groups and groupings&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include competencies&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 4 allows selecting/deselecting which activities to share (this should be moved to before step 2).&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Step 5 is a review of previous options (backup options, not incl. course metadata weirdly). The main button here says ‘Perform backup’ rather than ‘Share to MoodleNet’.&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt10|[j]]]&amp;lt;/sup&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 6 contents are packaged as an mbz file and uploaded to moodle.net&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;The mbz is a zip with xml files and other content (including subfolders for plugin content). The format doesn&#039;t seem to be documented but should contain all the info we need (eg. what Moodle version it came from, and the list of required plugins).&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Step 7 - the upload then goes in moderation queue (Mary) before being published.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;After sharing, there’s a status screen available&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;span class=&amp;quot;c15&amp;quot;&amp;gt;Next steps regarding sharing&amp;lt;/span&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Add sharing function at section &amp;amp;amp; activity level (currently only available at course level).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Simplify UX (1 or 2 steps max) and make it explicitly about ‘sharing’ rather than ‘backup’.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Possibly move all metadata input to a screen on MoodleNet (where it can also be edited later) rather than it being part of Moodle.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Review all metadata fields.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;‘Publisher’ will be the MoodleNet user who is doing the sharing.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;‘Creator’ could be prefilled with the MoodleNet accounts of the Moodle users who created the course (or activities therein), if known.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Decide on list of licensing options, and what should be the default.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;c10&amp;quot;&amp;gt;References&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;Relevant Documentation&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span&amp;gt;General docs: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Main_Page&amp;amp;sa=D&amp;amp;ust=1536228178000000 https://docs.moodle.org/dev/Main_Page]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Plugin diff. types: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Plugin_types&amp;amp;sa=D&amp;amp;ust=1536228178001000 https://docs.moodle.org/dev/Plugin_types]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;E&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;xisting plugins: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://moodle.org/plugins/&amp;amp;sa=D&amp;amp;ust=1536228178001000 https://moodle.org/plugins/]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;T&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;utorial: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Tutorial&amp;amp;sa=D&amp;amp;ust=1536228178002000 https://docs.moodle.org/dev/Tutorial]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;API: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Web_services&amp;amp;sa=D&amp;amp;ust=1536228178002000 https://docs.moodle.org/dev/Web_services]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;This tool might be useful for command-line ops: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=http://moosh-online.com&amp;amp;sa=D&amp;amp;ust=1536228178003000 http://moosh-online.com]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;Relevant Moodle plugin types&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Other than modifying Moodle Core (which would make our integration not be backwards compatible with older Moodle versions), this is the plugin architecture that is available for us to plug into Moodle:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span&amp;gt;Simple HTML/PHP block: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Blocks&amp;amp;sa=D&amp;amp;ust=1536228178003000 https://docs.moodle.org/dev/Blocks]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Repository (allow Moodle to bring contents in from external repositories): &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Repository_plugins&amp;amp;sa=D&amp;amp;ust=1536228178004000 https://docs.moodle.org/dev/Repository_plugins]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Portfolio (allow to publish files to all kinds of external document repository systems) &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Portfolio_plugins&amp;amp;sa=D&amp;amp;ust=1536228178004000 https://docs.moodle.org/dev/Portfolio_plugins]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;G&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;lobal search: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Search_engines&amp;amp;sa=D&amp;amp;ust=1536228178005000 https://docs.moodle.org/dev/Search_engines]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Authentication / OAuth: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Authentication_plugins&amp;amp;sa=D&amp;amp;ust=1536228178005000 https://docs.moodle.org/dev/Authentication_plugins]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/35/en/OAuth_2_authentication&amp;amp;sa=D&amp;amp;ust=1536228178006000 https://docs.moodle.org/35/en/OAuth_2_authentication]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;External tool source / LTI &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/External_tool_source&amp;amp;sa=D&amp;amp;ust=1536228178006000 https://docs.moodle.org/dev/External_tool_source]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://en.wikipedia.org/wiki/Learning_Tools_Interoperability&amp;amp;sa=D&amp;amp;ust=1536228178006000 https://en.wikipedia.org/wiki/Learning_Tools_Interoperability]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Adding protocols to the API: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Webservice_protocols&amp;amp;sa=D&amp;amp;ust=1536228178007000 https://docs.moodle.org/dev/Webservice_protocols]&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/Moodle_integration&amp;diff=54712</id>
		<title>MoodleNet/tech/Moodle integration</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/Moodle_integration&amp;diff=54712"/>
		<updated>2018-09-06T09:12:43Z</updated>

		<summary type="html">&lt;p&gt;Mayel: /* MoodleNet integration with Moodle core */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &amp;lt;span class=&amp;quot;c20&amp;quot;&amp;gt;MoodleNet integration with Moodle core&amp;lt;/span&amp;gt; =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Note: This document is available with extra screenshots at: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=http://bit.ly/2mBAZgq&amp;amp;sa=D&amp;amp;ust=1536228177969000 http://bit.ly/2mBAZgq]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;c10&amp;quot;&amp;gt;What we&#039;re trying to achieve&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Users &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;need&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; to be able to easily: &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Share content from their Moodle (entire courses or specific activities) to MoodleNet&amp;lt;/span&amp;gt;&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Search and import any type of MoodleNet resources from within their Moodle&amp;lt;/span&amp;gt;&lt;br /&gt;
# &amp;lt;span&amp;gt;Import any &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;type of resources&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt1|[a]]][[#cmnt2|[b]]]&amp;lt;/sup&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; they come across when browsing MoodleNet into their Moodle&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;It would be nice if users could:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Preview Moodle-specific resources on MoodleNet, without/before having to import them into their Moodle&amp;lt;/span&amp;gt;&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Sign into MoodleNet with their existing Moodle account&amp;lt;/span&amp;gt;&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Sign into their Moodle with their MoodleNet account&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;Where in Moodle could MoodleNet be integrated?&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Login / Registration (sign in to your Moodle with your MoodleNet account, and vice versa)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Global search&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Create new course&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Add an activity or resource&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Rich text editors -&amp;amp;gt; Insert media -&amp;amp;gt; Browse repositories&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Share course&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Share activity&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span&amp;gt;Options for previewing Moodle-specific content&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt3|[c]]]&amp;lt;/sup&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;The most challenging functionality to implement is allowing users to &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;preview&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Moodle-specific content (resources/activities) from MoodleNet&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; before importing content into their Moodle course &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Because of all the different types of data possible, it seems obvious that we should leverage Moodle Core for this, with dedicated plugin(s). Here are options we’ve identified:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Temporary course on user’s Moodle site&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; - Add a &amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;preview&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;&amp;amp;quot; UX flow to &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Moodle&#039;s import functionality&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;, so that when a user clicks “preview” the content is seamlessly (1 step only) imported &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;as a new course&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; into&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt; their Moodle site&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;, so the user can browse the content and if they’re satisfied they can then actually “import” (copy) the sections/activities they want into their existing course, or &amp;amp;quot;delete the preview&amp;amp;quot;.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Mostly involves tweaking some Moodle UX and plugins.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Users (or admins) might not feel comfortable importing random content from the web into their production Moodle instance.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Slower, more friction.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;        Option 1 is most likely what we’re implementing for the MoodleNet MVP.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;2&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Moodle HQ-run preview site - Auto-import&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; the content to &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;one big dedicated preview site&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; (powered by Moodle).&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: The content could be imported in the background as soon as it’s shared, and always be instantly accessible for previewing.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Educators would have read-only access.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: The preview site would get massive and probably slow over time (solution could be to split the content between several sites).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Requires adding an automatic mode (controllable by command line) to the import plugin.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;3&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Temporary Moodle site at subdomain of moodle.net - Auto-&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;import&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;the content on a&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;temporary Moodle site&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; (similar to &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://demo.moodle.net&amp;amp;sa=D&amp;amp;ust=1536228177979000 https://demo.moodle.net]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;) which gets deleted after X hours/days.&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Educators can get read-write access.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: There’s already a system in place to do this.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Slower, more friction.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;: Requires adding an automatic mode (controllable by command line) to the import plugin.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Import&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt; to user’s MoodleCloud site&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt4|[d]]]&amp;lt;/sup&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt; - &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Import&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; the content to the &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;user&#039;s personal MoodleCloud site&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; (or a separate personal test site?)&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: User is in full control.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;: Could make this a premium &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;feature&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Requires the user to sign up for a MoodleCould site (solution could be to add an opt-in option that automatically does that when they join MoodleNet).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Slower, more friction.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;c10&amp;quot;&amp;gt;Options for importing content from around the web&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;TBD depending on the type content and where it’s coming from.&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; Some examples:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;YouTube or Vimeo video: embedded in Page module&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Video file: linked (URL module) from original source?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;PDF: linked (URL module) from original source, or copied (File module)?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Word document: linked (URL module) from original source, or copied (File module), or converted to HTML (Page module)?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;etc...&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;c10&amp;quot;&amp;gt;Where the current Moodle.net is integrated with Moodle&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;Context&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;The existing Moodle.net allows users to share Moodle courses with the community. These courses are shared and, after moderation, appear via a searchable interface at &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://moodle.net&amp;amp;sa=D&amp;amp;ust=1536228177983000 https://moodle.net]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; and in Moodle Core’s ‘Community Finder’ functionality.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;1. Moodle.net registration&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;To submit a course to Moodle.net, the user’s Moodle site must be registered. &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;An admin of the Moodle instance first needs to fill in Moodle.net registration form, which is main source of &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://moodle.net/stats/&amp;amp;sa=D&amp;amp;ust=1536228177983000 Moodle usage stats]&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;. Users are blocked from sharing content to Moodle.net before this is done (but they can search &amp;amp;amp; import content). Note that sites that are not publicly-accessible on the internet, or using a non-standard port are &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/35/en/error/local_hub/cannotregisterbadport&amp;amp;sa=D&amp;amp;ust=1536228177984000 not able to register]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Admins are told that by registering:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;You&#039;ll be one of the first to find out about important notifications such as security alerts and new Moodle releases.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;You can access and activate mobile push notifications from your Moodle site through our free Moodle Mobile app.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;You are contributing to our Moodle statistics of the worldwide community, which help us improve Moodle and our community sites.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;If you wish, your site can be included in the list of registered Moodle sites in your country.&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; [Unlisted / Name only / Name + URL]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Required fields: &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Country&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Admin email address&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Optional fields:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Name&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Site listing in directory?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Description&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Language&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Notifications about important security and technical issues?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Updates about Moodle news and features?&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;The following information will be sent to contribute to overall statistics only. It will not be made public on any site listing.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Moodle release (3.5)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of courses (3)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of users (3)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of role assignments (3)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of posts (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of questions (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of resources (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of badges (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of issued badges (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Average number of participants (1.00)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Average number of course modules (5.00)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Mobile services enabled (Yes)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Mobile notifications enabled (No)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of users with registered mobile devices (1)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of active users with registered mobile devices which are receiving notifications (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;span class=&amp;quot;c15&amp;quot;&amp;gt;Next steps regarding registration&amp;lt;/span&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Check structure of API and code that handles registration between Moodle &amp;amp;amp; Moodle.net (both sides)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Check if we can override this functionality with a plugin (for backward compatibility with old Moodle versions)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Decide what changes (if any) need to be made to the data collected&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Decide if registration could be done by any teacher-level account instead of just admins (i.e. registering with the MoodleNet core API service, to collect stats &amp;amp;amp; enable MoodleNet search)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Add new sign-in functionality (&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/35/en/OAuth_2_services&amp;amp;sa=D&amp;amp;ust=1536228177989000 OAuth]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; client) for users to connect their Moodle account to their MoodleNet account (i.e. authenticating with their MoodleNet instance&#039;s API, to enable personalised MoodleNet search, and sharing &amp;amp;amp; importing of resources). An OAuth client is available as a core part of Moodle.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Potentially &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://github.com/projectestac/moodle-local_oauth&amp;amp;sa=D&amp;amp;ust=1536228177989000 turn Moodle into an OAuth server]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; so that users can sign into MoodleNet with their existing Moodle accounts (especially useful for on-boarding, to avoid having to re-enter personal details). This would mean adding a plugin. &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;2. Search &amp;amp;amp; import courses&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;The &#039;Community Finder&#039; function allows searching for resources on Moodle.net and is currently available as a &#039;block&#039; that needs to be added manually (not ideal).&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt5|[e]]][[#cmnt6|[f]]]&amp;lt;/sup&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;It can be used with simple keyword search, or with advanced filtering.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;‘Visit Demo&#039; function for resources currently is just an optional link to a public course that needs to be hosted somewhere (submitted as part of &#039;sharing&#039;, not ideal).&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;‘Install’ function has 8 steps/screens.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;span class=&amp;quot;c15&amp;quot;&amp;gt;Next steps regarding search &amp;amp;amp; import&amp;lt;/span&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Create new Moodle plugin(s) to handle search of MoodleNet content, in these places:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Global search&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Create course&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Add an activity or resource&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Rich text editors -&amp;amp;gt; Insert media -&amp;amp;gt; Browse repositories&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span&amp;gt;Unless MoodleNet provides ‘preview’ functionality for Moodle content&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt7|[g]]][[#cmnt8|[h]]][[#cmnt9|[i]]]&amp;lt;/sup&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;, decide if instead of the user selecting which sections/resources to import before seeing them, they all get imported into a new course so the user can afterwards delete those they don’t need (or copy/move only those they need into an existing course).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;In any case, create new import plugin with simplified UX (1 or 2 steps max) and make it explicitly about ‘importing’ rather than ‘restoring’.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;If the import plugin doesn’t already, make it check upfront for compatibility with the Moodle version and list of plugins, and if necessary tell the user what they need to ask their admin before they can import that content. (Only admins can install plugins, and MoodleCloud doesn&#039;t allow extra plugins, but fortunately only a minority of content seems to depend on 3rd party activity plugins).&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;3. Share &amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 1&amp;lt;/span&amp;gt; is for choosing if you want to export or just open up your course to the public.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 2 is pre-filled with metadata from the course and includes list of subjects from Australian standard (used to be hierarchical, only allows selecting on subject), and some other fields which contain the same options as seen in the search filters above.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 3 has the following toggles:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Anonymize user information&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include user role assignments&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include activities and resources&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include blocks&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include filters&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include comments&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include badges&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include calendar events&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include user completion details&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include course logs&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include grade history&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include question bank&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include groups and groupings&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include competencies&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 4 allows selecting/deselecting which activities to share (this should be moved to before step 2).&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Step 5 is a review of previous options (backup options, not incl. course metadata weirdly). The main button here says ‘Perform backup’ rather than ‘Share to MoodleNet’.&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt10|[j]]]&amp;lt;/sup&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 6 contents are packaged as an mbz file and uploaded to moodle.net&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;The mbz is a zip with xml files and other content (including subfolders for plugin content). The format doesn&#039;t seem to be documented but should contain all the info we need (eg. what Moodle version it came from, and the list of required plugins).&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Step 7 - the upload then goes in moderation queue (Mary) before being published.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;After sharing, there’s a status screen available&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;span class=&amp;quot;c15&amp;quot;&amp;gt;Next steps regarding sharing&amp;lt;/span&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Add sharing function at section &amp;amp;amp; activity level (currently only available at course level).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Simplify UX (1 or 2 steps max) and make it explicitly about ‘sharing’ rather than ‘backup’.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Possibly move all metadata input to a screen on MoodleNet (where it can also be edited later) rather than it being part of Moodle.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Review all metadata fields.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;‘Publisher’ will be the MoodleNet user who is doing the sharing.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;‘Creator’ could be prefilled with the MoodleNet accounts of the Moodle users who created the course (or activities therein), if known.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Decide on list of licensing options, and what should be the default.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;c10&amp;quot;&amp;gt;References&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;Relevant Documentation&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span&amp;gt;General docs: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Main_Page&amp;amp;sa=D&amp;amp;ust=1536228178000000 https://docs.moodle.org/dev/Main_Page]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Plugin diff. types: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Plugin_types&amp;amp;sa=D&amp;amp;ust=1536228178001000 https://docs.moodle.org/dev/Plugin_types]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;E&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;xisting plugins: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://moodle.org/plugins/&amp;amp;sa=D&amp;amp;ust=1536228178001000 https://moodle.org/plugins/]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;T&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;utorial: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Tutorial&amp;amp;sa=D&amp;amp;ust=1536228178002000 https://docs.moodle.org/dev/Tutorial]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;API: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Web_services&amp;amp;sa=D&amp;amp;ust=1536228178002000 https://docs.moodle.org/dev/Web_services]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;This tool might be useful for command-line ops: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=http://moosh-online.com&amp;amp;sa=D&amp;amp;ust=1536228178003000 http://moosh-online.com]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;Relevant Moodle plugin types&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Other than modifying Moodle Core (which would make our integration not be backwards compatible with older Moodle versions), this is the plugin architecture that is available for us to plug into Moodle:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span&amp;gt;Simple HTML/PHP block: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Blocks&amp;amp;sa=D&amp;amp;ust=1536228178003000 https://docs.moodle.org/dev/Blocks]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Repository (allow Moodle to bring contents in from external repositories): &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Repository_plugins&amp;amp;sa=D&amp;amp;ust=1536228178004000 https://docs.moodle.org/dev/Repository_plugins]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Portfolio (allow to publish files to all kinds of external document repository systems) &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Portfolio_plugins&amp;amp;sa=D&amp;amp;ust=1536228178004000 https://docs.moodle.org/dev/Portfolio_plugins]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;G&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;lobal search: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Search_engines&amp;amp;sa=D&amp;amp;ust=1536228178005000 https://docs.moodle.org/dev/Search_engines]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Authentication / OAuth: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Authentication_plugins&amp;amp;sa=D&amp;amp;ust=1536228178005000 https://docs.moodle.org/dev/Authentication_plugins]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/35/en/OAuth_2_authentication&amp;amp;sa=D&amp;amp;ust=1536228178006000 https://docs.moodle.org/35/en/OAuth_2_authentication]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;External tool source / LTI &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/External_tool_source&amp;amp;sa=D&amp;amp;ust=1536228178006000 https://docs.moodle.org/dev/External_tool_source]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://en.wikipedia.org/wiki/Learning_Tools_Interoperability&amp;amp;sa=D&amp;amp;ust=1536228178006000 https://en.wikipedia.org/wiki/Learning_Tools_Interoperability]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Adding protocols to the API: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Webservice_protocols&amp;amp;sa=D&amp;amp;ust=1536228178007000 https://docs.moodle.org/dev/Webservice_protocols]&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/Moodle_integration&amp;diff=54711</id>
		<title>MoodleNet/tech/Moodle integration</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/Moodle_integration&amp;diff=54711"/>
		<updated>2018-09-06T09:11:53Z</updated>

		<summary type="html">&lt;p&gt;Mayel: create&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &amp;lt;span class=&amp;quot;c20&amp;quot;&amp;gt;MoodleNet integration with Moodle core&amp;lt;/span&amp;gt; =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Document about issue &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://tracker.moodle.org/browse/MDLNET-10&amp;amp;sa=D&amp;amp;ust=1536228177968000 MDLNET-10]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Short URL: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=http://bit.ly/2mBAZgq&amp;amp;sa=D&amp;amp;ust=1536228177969000 http://bit.ly/2mBAZgq]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;c10&amp;quot;&amp;gt;What we&#039;re trying to achieve&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Users &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;need&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; to be able to easily: &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Share content from their Moodle (entire courses or specific activities) to MoodleNet&amp;lt;/span&amp;gt;&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Search and import any type of MoodleNet resources from within their Moodle&amp;lt;/span&amp;gt;&lt;br /&gt;
# &amp;lt;span&amp;gt;Import any &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;type of resources&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt1|[a]]][[#cmnt2|[b]]]&amp;lt;/sup&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; they come across when browsing MoodleNet into their Moodle&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;It would be nice if users could:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Preview Moodle-specific resources on MoodleNet, without/before having to import them into their Moodle&amp;lt;/span&amp;gt;&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Sign into MoodleNet with their existing Moodle account&amp;lt;/span&amp;gt;&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Sign into their Moodle with their MoodleNet account&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;Where in Moodle could MoodleNet be integrated?&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Login / Registration (sign in to your Moodle with your MoodleNet account, and vice versa)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Global search&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Create new course&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Add an activity or resource&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Rich text editors -&amp;amp;gt; Insert media -&amp;amp;gt; Browse repositories&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Share course&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Share activity&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span&amp;gt;Options for previewing Moodle-specific content&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt3|[c]]]&amp;lt;/sup&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;The most challenging functionality to implement is allowing users to &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;preview&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Moodle-specific content (resources/activities) from MoodleNet&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; before importing content into their Moodle course &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Because of all the different types of data possible, it seems obvious that we should leverage Moodle Core for this, with dedicated plugin(s). Here are options we’ve identified:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Temporary course on user’s Moodle site&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; - Add a &amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;preview&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;&amp;amp;quot; UX flow to &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Moodle&#039;s import functionality&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;, so that when a user clicks “preview” the content is seamlessly (1 step only) imported &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;as a new course&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; into&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt; their Moodle site&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;, so the user can browse the content and if they’re satisfied they can then actually “import” (copy) the sections/activities they want into their existing course, or &amp;amp;quot;delete the preview&amp;amp;quot;.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Mostly involves tweaking some Moodle UX and plugins.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Users (or admins) might not feel comfortable importing random content from the web into their production Moodle instance.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Slower, more friction.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;        Option 1 is most likely what we’re implementing for the MoodleNet MVP.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;2&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Moodle HQ-run preview site - Auto-import&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; the content to &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;one big dedicated preview site&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; (powered by Moodle).&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: The content could be imported in the background as soon as it’s shared, and always be instantly accessible for previewing.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Educators would have read-only access.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: The preview site would get massive and probably slow over time (solution could be to split the content between several sites).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Requires adding an automatic mode (controllable by command line) to the import plugin.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;3&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Temporary Moodle site at subdomain of moodle.net - Auto-&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;import&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;the content on a&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;temporary Moodle site&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; (similar to &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://demo.moodle.net&amp;amp;sa=D&amp;amp;ust=1536228177979000 https://demo.moodle.net]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;) which gets deleted after X hours/days.&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Educators can get read-write access.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: There’s already a system in place to do this.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Slower, more friction.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;: Requires adding an automatic mode (controllable by command line) to the import plugin.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Import&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt; to user’s MoodleCloud site&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt4|[d]]]&amp;lt;/sup&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt; - &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;Import&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt; the content to the &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c21&amp;quot;&amp;gt;user&#039;s personal MoodleCloud site&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; (or a separate personal test site?)&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: User is in full control.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Pro&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;: Could make this a premium &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;feature&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Requires the user to sign up for a MoodleCould site (solution could be to add an opt-in option that automatically does that when they join MoodleNet).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;Con&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;: Slower, more friction.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;c10&amp;quot;&amp;gt;Options for importing content from around the web&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;TBD depending on the type content and where it’s coming from.&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; Some examples:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;YouTube or Vimeo video: embedded in Page module&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Video file: linked (URL module) from original source?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;PDF: linked (URL module) from original source, or copied (File module)?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Word document: linked (URL module) from original source, or copied (File module), or converted to HTML (Page module)?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;etc...&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;c10&amp;quot;&amp;gt;Where the current Moodle.net is integrated with Moodle&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;Context&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;The existing Moodle.net allows users to share Moodle courses with the community. These courses are shared and, after moderation, appear via a searchable interface at &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://moodle.net&amp;amp;sa=D&amp;amp;ust=1536228177983000 https://moodle.net]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; and in Moodle Core’s ‘Community Finder’ functionality.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;1. Moodle.net registration&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;To submit a course to Moodle.net, the user’s Moodle site must be registered. &amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;An admin of the Moodle instance first needs to fill in Moodle.net registration form, which is main source of &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://moodle.net/stats/&amp;amp;sa=D&amp;amp;ust=1536228177983000 Moodle usage stats]&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;. Users are blocked from sharing content to Moodle.net before this is done (but they can search &amp;amp;amp; import content). Note that sites that are not publicly-accessible on the internet, or using a non-standard port are &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/35/en/error/local_hub/cannotregisterbadport&amp;amp;sa=D&amp;amp;ust=1536228177984000 not able to register]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Admins are told that by registering:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;You&#039;ll be one of the first to find out about important notifications such as security alerts and new Moodle releases.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;You can access and activate mobile push notifications from your Moodle site through our free Moodle Mobile app.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;You are contributing to our Moodle statistics of the worldwide community, which help us improve Moodle and our community sites.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c7&amp;quot;&amp;gt;If you wish, your site can be included in the list of registered Moodle sites in your country.&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; [Unlisted / Name only / Name + URL]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Required fields: &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Country&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Admin email address&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Optional fields:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Name&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Site listing in directory?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Description&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Language&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Notifications about important security and technical issues?&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Updates about Moodle news and features?&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;The following information will be sent to contribute to overall statistics only. It will not be made public on any site listing.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Moodle release (3.5)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of courses (3)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of users (3)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of role assignments (3)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of posts (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of questions (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of resources (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of badges (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of issued badges (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Average number of participants (1.00)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Average number of course modules (5.00)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Mobile services enabled (Yes)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Mobile notifications enabled (No)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of users with registered mobile devices (1)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c1&amp;quot;&amp;gt;Number of active users with registered mobile devices which are receiving notifications (0)&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;span class=&amp;quot;c15&amp;quot;&amp;gt;Next steps regarding registration&amp;lt;/span&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Check structure of API and code that handles registration between Moodle &amp;amp;amp; Moodle.net (both sides)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Check if we can override this functionality with a plugin (for backward compatibility with old Moodle versions)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Decide what changes (if any) need to be made to the data collected&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Decide if registration could be done by any teacher-level account instead of just admins (i.e. registering with the MoodleNet core API service, to collect stats &amp;amp;amp; enable MoodleNet search)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Add new sign-in functionality (&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/35/en/OAuth_2_services&amp;amp;sa=D&amp;amp;ust=1536228177989000 OAuth]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; client) for users to connect their Moodle account to their MoodleNet account (i.e. authenticating with their MoodleNet instance&#039;s API, to enable personalised MoodleNet search, and sharing &amp;amp;amp; importing of resources). An OAuth client is available as a core part of Moodle.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Potentially &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://github.com/projectestac/moodle-local_oauth&amp;amp;sa=D&amp;amp;ust=1536228177989000 turn Moodle into an OAuth server]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; so that users can sign into MoodleNet with their existing Moodle accounts (especially useful for on-boarding, to avoid having to re-enter personal details). This would mean adding a plugin. &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;2. Search &amp;amp;amp; import courses&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;The &#039;Community Finder&#039; function allows searching for resources on Moodle.net and is currently available as a &#039;block&#039; that needs to be added manually (not ideal).&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt5|[e]]][[#cmnt6|[f]]]&amp;lt;/sup&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;It can be used with simple keyword search, or with advanced filtering.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;‘Visit Demo&#039; function for resources currently is just an optional link to a public course that needs to be hosted somewhere (submitted as part of &#039;sharing&#039;, not ideal).&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;‘Install’ function has 8 steps/screens.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;span class=&amp;quot;c15&amp;quot;&amp;gt;Next steps regarding search &amp;amp;amp; import&amp;lt;/span&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Create new Moodle plugin(s) to handle search of MoodleNet content, in these places:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Global search&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Create course&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Add an activity or resource&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Rich text editors -&amp;amp;gt; Insert media -&amp;amp;gt; Browse repositories&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span&amp;gt;Unless MoodleNet provides ‘preview’ functionality for Moodle content&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt7|[g]]][[#cmnt8|[h]]][[#cmnt9|[i]]]&amp;lt;/sup&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;, decide if instead of the user selecting which sections/resources to import before seeing them, they all get imported into a new course so the user can afterwards delete those they don’t need (or copy/move only those they need into an existing course).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;In any case, create new import plugin with simplified UX (1 or 2 steps max) and make it explicitly about ‘importing’ rather than ‘restoring’.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;If the import plugin doesn’t already, make it check upfront for compatibility with the Moodle version and list of plugins, and if necessary tell the user what they need to ask their admin before they can import that content. (Only admins can install plugins, and MoodleCloud doesn&#039;t allow extra plugins, but fortunately only a minority of content seems to depend on 3rd party activity plugins).&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;3. Share &amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 1&amp;lt;/span&amp;gt; is for choosing if you want to export or just open up your course to the public.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 2 is pre-filled with metadata from the course and includes list of subjects from Australian standard (used to be hierarchical, only allows selecting on subject), and some other fields which contain the same options as seen in the search filters above.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 3 has the following toggles:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Anonymize user information&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include user role assignments&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include activities and resources&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include blocks&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include filters&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include comments&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include badges&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include calendar events&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include user completion details&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include course logs&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include grade history&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include question bank&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include groups and groupings&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Include competencies&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 4 allows selecting/deselecting which activities to share (this should be moved to before step 2).&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Step 5 is a review of previous options (backup options, not incl. course metadata weirdly). The main button here says ‘Perform backup’ rather than ‘Share to MoodleNet’.&amp;lt;/span&amp;gt;&amp;lt;sup&amp;gt;[[#cmnt10|[j]]]&amp;lt;/sup&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Step 6 contents are packaged as an mbz file and uploaded to moodle.net&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;The mbz is a zip with xml files and other content (including subfolders for plugin content). The format doesn&#039;t seem to be documented but should contain all the info we need (eg. what Moodle version it came from, and the list of required plugins).&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span&amp;gt;Step 7 - the upload then goes in moderation queue (Mary) before being published.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;After sharing, there’s a status screen available&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;span class=&amp;quot;c15&amp;quot;&amp;gt;Next steps regarding sharing&amp;lt;/span&amp;gt; ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Add sharing function at section &amp;amp;amp; activity level (currently only available at course level).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Simplify UX (1 or 2 steps max) and make it explicitly about ‘sharing’ rather than ‘backup’.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Possibly move all metadata input to a screen on MoodleNet (where it can also be edited later) rather than it being part of Moodle.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Review all metadata fields.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;‘Publisher’ will be the MoodleNet user who is doing the sharing.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;‘Creator’ could be prefilled with the MoodleNet accounts of the Moodle users who created the course (or activities therein), if known.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Decide on list of licensing options, and what should be the default.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;c10&amp;quot;&amp;gt;References&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;Relevant Documentation&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span&amp;gt;General docs: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Main_Page&amp;amp;sa=D&amp;amp;ust=1536228178000000 https://docs.moodle.org/dev/Main_Page]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt; &amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Plugin diff. types: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Plugin_types&amp;amp;sa=D&amp;amp;ust=1536228178001000 https://docs.moodle.org/dev/Plugin_types]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;E&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;xisting plugins: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://moodle.org/plugins/&amp;amp;sa=D&amp;amp;ust=1536228178001000 https://moodle.org/plugins/]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;T&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;utorial: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Tutorial&amp;amp;sa=D&amp;amp;ust=1536228178002000 https://docs.moodle.org/dev/Tutorial]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;API: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Web_services&amp;amp;sa=D&amp;amp;ust=1536228178002000 https://docs.moodle.org/dev/Web_services]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;This tool might be useful for command-line ops: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=http://moosh-online.com&amp;amp;sa=D&amp;amp;ust=1536228178003000 http://moosh-online.com]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span class=&amp;quot;c9&amp;quot;&amp;gt;Relevant Moodle plugin types&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;c0&amp;quot;&amp;gt;Other than modifying Moodle Core (which would make our integration not be backwards compatible with older Moodle versions), this is the plugin architecture that is available for us to plug into Moodle:&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span&amp;gt;Simple HTML/PHP block: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Blocks&amp;amp;sa=D&amp;amp;ust=1536228178003000 https://docs.moodle.org/dev/Blocks]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Repository (allow Moodle to bring contents in from external repositories): &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Repository_plugins&amp;amp;sa=D&amp;amp;ust=1536228178004000 https://docs.moodle.org/dev/Repository_plugins]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Portfolio (allow to publish files to all kinds of external document repository systems) &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Portfolio_plugins&amp;amp;sa=D&amp;amp;ust=1536228178004000 https://docs.moodle.org/dev/Portfolio_plugins]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;G&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;lobal search: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Search_engines&amp;amp;sa=D&amp;amp;ust=1536228178005000 https://docs.moodle.org/dev/Search_engines]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Authentication / OAuth: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Authentication_plugins&amp;amp;sa=D&amp;amp;ust=1536228178005000 https://docs.moodle.org/dev/Authentication_plugins]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/35/en/OAuth_2_authentication&amp;amp;sa=D&amp;amp;ust=1536228178006000 https://docs.moodle.org/35/en/OAuth_2_authentication]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;External tool source / LTI &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/External_tool_source&amp;amp;sa=D&amp;amp;ust=1536228178006000 https://docs.moodle.org/dev/External_tool_source]&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://en.wikipedia.org/wiki/Learning_Tools_Interoperability&amp;amp;sa=D&amp;amp;ust=1536228178006000 https://en.wikipedia.org/wiki/Learning_Tools_Interoperability]&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span&amp;gt;Adding protocols to the API: &amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;c16 c6&amp;quot;&amp;gt;[https://www.google.com/url?q=https://docs.moodle.org/dev/Webservice_protocols&amp;amp;sa=D&amp;amp;ust=1536228178007000 https://docs.moodle.org/dev/Webservice_protocols]&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/architecture&amp;diff=54709</id>
		<title>MoodleNet/tech/architecture</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/architecture&amp;diff=54709"/>
		<updated>2018-09-05T11:08:21Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet/tech Back to MoodleNet Tech index]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: terms in bold are defined in the glossary at the end of the document.&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
There are broadly three approaches we can take to building out MoodleNet’s platform architecture. These are:&lt;br /&gt;
&lt;br /&gt;
# Fully federated &lt;br /&gt;
# Federated with HQ API-as-a-service [Note: this is the architecture approach that was selected] &lt;br /&gt;
# Centralised SaaS &lt;br /&gt;
&lt;br /&gt;
This document outlines each of these three potential architectural approaches, and explains why we have chosen to focus on the second option. We believe that creating MoodleNet with a federated architecture combined with a HQ API-as-a-service will balance an open approach with a sustainable way of managing the project. &lt;br /&gt;
&lt;br /&gt;
Irrespective of architectural decision, we plan for MoodleNet to be consistent with Moodle’s philosophy of libre software. Moodle Core is licensed under the GNU General Public License (GNU GPL), which is compatible with the GNU Affero General Public License (GNU AGPL) that we intend to use for MoodleNet. The latter is recommended for software being run over a network. Like Moodle Core, MoodleNet is an open source platform, meaning that anyone can adapt, extend or modify the software for both commercial and non-commercial projects without any licensing fees.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Federated with HQ API service ==&lt;br /&gt;
Moodle HQ will run a MoodleNet HQ &#039;&#039;&#039;API-as-a-service&#039;&#039;&#039; serving as a central index of information across the network. This enables consistent discovery and search experiences across all MoodleNet &#039;&#039;&#039;instances&#039;&#039;&#039; (including the one provided by Moodle HQ). &lt;br /&gt;
&lt;br /&gt;
Each &#039;&#039;&#039;MoodleNet instance&#039;&#039;&#039; stores the full data of local users, communities, and collections (including personal information, private messages, and public comments/discussions). &lt;br /&gt;
&lt;br /&gt;
The database of the MoodleNet HQ API service contains lists of all public communities, collections, resources, and users across the network, along with a copy of some metadata. A search index also sits behind the API to enable fast and accurate search results. Each item always refers back to the originating MoodleNet instance for the full data (e.g. membership, permissions, comments/discussions). &lt;br /&gt;
&lt;br /&gt;
In practice, this means that the MoodleNet network, while &#039;&#039;&#039;federated&#039;&#039;&#039;, is reliant upon the MoodleNet HQ API service for search and discovery. This provides users with a better and more consistent experience, reducing fragmentation and spreading the shared content more widely, and also gives Moodle HQ more control over the overall network. &lt;br /&gt;
&lt;br /&gt;
Another HQ API service, the Moodle resources repository, could also provides hosting for Moodle course content that users share on MoodleNet. This could later be facilitated with P2P file sharing protocols like &#039;&#039;&#039;IPFS&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
This network can also be based on existing &#039;&#039;&#039;protocols&#039;&#039;&#039; and &#039;&#039;&#039;standards&#039;&#039;&#039; to form a &#039;&#039;&#039;decentralised&#039;&#039;&#039; collection of nodes that send, receive, and store data. The data handling module can be based on an extended ActivityStreams data format and at least some of the APIs on the ActivityPub protocol to ensure compatibility between systems. &lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb|link=https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL]]&lt;br /&gt;
&lt;br /&gt;
Interactive diagram: https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL &lt;br /&gt;
&lt;br /&gt;
Advantages of a federated network:&lt;br /&gt;
* Robust and resilient&lt;br /&gt;
* Scales horizontally&lt;br /&gt;
* Private data stays on each user’s home instance&lt;br /&gt;
* Each instance is responsible for its content (moderation of discussions, etc)&lt;br /&gt;
* Standards-based but also extensible&lt;br /&gt;
* Open&lt;br /&gt;
&lt;br /&gt;
Advantages of HQ API service:&lt;br /&gt;
* Some Moodle HQ influence over the network &lt;br /&gt;
* Consistent network-wide search and discovery experiences&lt;br /&gt;
* No duplication of resources for core functions like the indexing of resources from OER APIs, global search indexing, and Moodle resource hosting&lt;br /&gt;
* Each instance is still responsible for its content (moderation of discussions, etc)&lt;br /&gt;
* Moodle HQ controls the evolution/standardisation of content/metadata types and formats&lt;br /&gt;
&lt;br /&gt;
Disadvantages of HQ API service:&lt;br /&gt;
* Single point of failure (HQ API service operated by Moodle HQ).  &lt;br /&gt;
* Moodle HQ may be responsible for the content that shows up in search / discovery &lt;br /&gt;
* Some infrastructure costs for Moodle HQ &lt;br /&gt;
* Slightly higher number of components &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Glossary ==&lt;br /&gt;
&lt;br /&gt;
ActivityPub - a standard decentralised social networking protocol based on ActivityStreams.&lt;br /&gt;
&lt;br /&gt;
ActivityStreams - a standard format for syndicating social activities.&lt;br /&gt;
&lt;br /&gt;
API - Application Programming Interface. A set of definitions, protocols, and tools for building application software, to enable communication between various components.&lt;br /&gt;
&lt;br /&gt;
API-as-a-service - Software as a Service (SaaS) primarily exposed as an API.&lt;br /&gt;
&lt;br /&gt;
Canonical - the main or reference location for something (eg. canonical URL)&lt;br /&gt;
&lt;br /&gt;
Data handling module - a database abstraction library, using an ORM approach, which would have added support for caching and federation (when applicable).&lt;br /&gt;
&lt;br /&gt;
Decentralisation - the process by which the activities of a network are distributed or delegated away from a central, authoritative location or group.&lt;br /&gt;
&lt;br /&gt;
Federation - the ability for decentralised systems to send data to one another in a standardised way, to prevent fragmentation of the network. Email is a great example of a federated system.&lt;br /&gt;
&lt;br /&gt;
GNU AGPL - a free, copyleft license published by the Free Software Foundation, and based on version 3 of the GNU General Public License (GPL) and the Affero General Public License. This license is compatible with the GPL and is recommended for any software that will commonly be run over a network.&lt;br /&gt;
&lt;br /&gt;
GNU GPL - a widely used free software license guaranteeing end users the freedom to run, study, share and modify the libre software. &lt;br /&gt;
&lt;br /&gt;
Instance - See also node. Can refer to an independently-hosted version of a software package.&lt;br /&gt;
&lt;br /&gt;
IPFS - the InterPlanetary File System is a new hypermedia distribution protocol, addressed by content and identities. IPFS enables the creation of completely distributed applications. It aims to make the web faster, safer, and more open.&lt;br /&gt;
&lt;br /&gt;
Libre software - software that is distributed under terms that allow users to run the software for any purpose as well as to study, change, and distribute it (and any adapted versions).&lt;br /&gt;
&lt;br /&gt;
Metadata - data that provides information about other data. For educational resources, it could describe various aspects of the material, including grade level, subject area, and content type or format. &lt;br /&gt;
&lt;br /&gt;
MoodleNet instance - an independently-hosted version of MoodleNet.&lt;br /&gt;
&lt;br /&gt;
Moodle instance - an independently-hosted version of Moodle Core.&lt;br /&gt;
&lt;br /&gt;
Node - a member of a decentralised network, which can sometimes serve as client, sometimes as server. See also instance.&lt;br /&gt;
&lt;br /&gt;
Open Source -  a decentralized software-development model that encourages open collaboration, with products such as source code, blueprints, and documentation freely available to the public.&lt;br /&gt;
&lt;br /&gt;
ORM - Object-relational mapping, used to create a ‘virtual object database’ which can then be referenced programmatically (with less code and more flexibility as to the underlying data storage). &lt;br /&gt;
&lt;br /&gt;
Protocol - a defined set of rules and formats that determine how data is transmitted.&lt;br /&gt;
&lt;br /&gt;
SaaS - Software as a Service. Web-based software that’s centrally hosted and made available to use (free or by subscription).&lt;br /&gt;
&lt;br /&gt;
Scaling horizontally - implies adding more nodes to a system to support its growth, for example installing copies of the same software on three web servers instead of just one. &lt;br /&gt;
&lt;br /&gt;
Scaling vertically - implies adding resources (like CPUs or memory) to a single server in a system to support its growth.&lt;br /&gt;
&lt;br /&gt;
Search index - a component of search engines which collects, parses, and stores data to facilitate fast and accurate search and information retrieval. Index design incorporates interdisciplinary concepts from linguistics, cognitive psychology, mathematics, informatics, and computer science. &lt;br /&gt;
&lt;br /&gt;
Standard - a collection of agreed specifications, usually organised by a standards body such as the W3C.&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54708</id>
		<title>MoodleNet/tech</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54708"/>
		<updated>2018-09-05T11:07:39Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
An area to document the tech choices and decisions we&#039;ve made.&lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb|link=https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL]]&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/architecture Technical architecture] - how is the platform going to be set up?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/stack Tech stack] - why did we choose Elixir?&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/architecture&amp;diff=54675</id>
		<title>MoodleNet/tech/architecture</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/architecture&amp;diff=54675"/>
		<updated>2018-08-27T10:54:21Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet/tech Back to MoodleNet Tech index]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: terms in bold are defined in the glossary at the end of the document.&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
There are broadly three approaches we can take to building out MoodleNet’s platform architecture. These are:&lt;br /&gt;
&lt;br /&gt;
# Fully federated &lt;br /&gt;
# Federated with HQ API-as-a-service [Note: this is the architecture approach that was selected] &lt;br /&gt;
# Centralised SaaS &lt;br /&gt;
&lt;br /&gt;
This document outlines each of these three potential architectural approaches, and explains why we have chosen to focus on the second option. We believe that creating MoodleNet with a federated architecture combined with a HQ API-as-a-service will balance an open approach with a sustainable way of managing the project. &lt;br /&gt;
&lt;br /&gt;
Irrespective of architectural decision, we plan for MoodleNet to be consistent with Moodle’s philosophy of libre software. Moodle Core is licensed under the GNU General Public License (GNU GPL), which is compatible with the GNU Affero General Public License (GNU AGPL) that we intend to use for MoodleNet. The latter is recommended for software being run over a network. Like Moodle Core, MoodleNet is an open source platform, meaning that anyone can adapt, extend or modify the software for both commercial and non-commercial projects without any licensing fees.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Federated with HQ API service ==&lt;br /&gt;
Moodle HQ will run a MoodleNet HQ &#039;&#039;&#039;API-as-a-service&#039;&#039;&#039; serving as a central index of information across the network. This enables consistent discovery and search experiences across all MoodleNet &#039;&#039;&#039;instances&#039;&#039;&#039; (including the one provided by Moodle HQ). &lt;br /&gt;
&lt;br /&gt;
Each &#039;&#039;&#039;MoodleNet instance&#039;&#039;&#039; stores the full data of local users, communities, and collections (including personal information, private messages, and public comments/discussions). &lt;br /&gt;
&lt;br /&gt;
The database of the MoodleNet HQ API service contains lists of all public communities, collections, resources, and users across the network, along with a copy of some metadata. A search index also sits behind the API to enable fast and accurate search results. Each item always refers back to the originating MoodleNet instance for the full data (e.g. membership, permissions, comments/discussions). &lt;br /&gt;
&lt;br /&gt;
In practice, this means that the MoodleNet network, while &#039;&#039;&#039;federated&#039;&#039;&#039;, is reliant upon the MoodleNet HQ API service for search and discovery. This provides users with a better and more consistent experience, reducing fragmentation and spreading the shared content more widely, and also gives Moodle HQ more control over the overall network. &lt;br /&gt;
&lt;br /&gt;
Another HQ API service, the Moodle resources repository, could also provides hosting for Moodle course content that users share on MoodleNet. This could later be facilitated with P2P file sharing protocols like &#039;&#039;&#039;IPFS&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
This network can also be based on existing &#039;&#039;&#039;protocols&#039;&#039;&#039; and &#039;&#039;&#039;standards&#039;&#039;&#039; to form a &#039;&#039;&#039;decentralised&#039;&#039;&#039; collection of nodes that send, receive, and store data. The data handling module can be based on an extended ActivityStreams data format and at least some of the APIs on the ActivityPub protocol to ensure compatibility between systems. &lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
Interactive diagram: https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL &lt;br /&gt;
&lt;br /&gt;
Advantages of a federated network:&lt;br /&gt;
* Robust and resilient&lt;br /&gt;
* Scales horizontally&lt;br /&gt;
* Private data stays on each user’s home instance&lt;br /&gt;
* Each instance is responsible for its content (moderation of discussions, etc)&lt;br /&gt;
* Standards-based but also extensible&lt;br /&gt;
* Open&lt;br /&gt;
&lt;br /&gt;
Advantages of HQ API service:&lt;br /&gt;
* Some Moodle HQ influence over the network &lt;br /&gt;
* Consistent network-wide search and discovery experiences&lt;br /&gt;
* No duplication of resources for core functions like the indexing of resources from OER APIs, global search indexing, and Moodle resource hosting&lt;br /&gt;
* Each instance is still responsible for its content (moderation of discussions, etc)&lt;br /&gt;
* Moodle HQ controls the evolution/standardisation of content/metadata types and formats&lt;br /&gt;
&lt;br /&gt;
Disadvantages of HQ API service:&lt;br /&gt;
* Single point of failure (HQ API service operated by Moodle HQ).  &lt;br /&gt;
* Moodle HQ may be responsible for the content that shows up in search / discovery &lt;br /&gt;
* Some infrastructure costs for Moodle HQ &lt;br /&gt;
* Slightly higher number of components &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Glossary ==&lt;br /&gt;
&lt;br /&gt;
ActivityPub - a standard decentralised social networking protocol based on ActivityStreams.&lt;br /&gt;
&lt;br /&gt;
ActivityStreams - a standard format for syndicating social activities.&lt;br /&gt;
&lt;br /&gt;
API - Application Programming Interface. A set of definitions, protocols, and tools for building application software, to enable communication between various components.&lt;br /&gt;
&lt;br /&gt;
API-as-a-service - Software as a Service (SaaS) primarily exposed as an API.&lt;br /&gt;
&lt;br /&gt;
Canonical - the main or reference location for something (eg. canonical URL)&lt;br /&gt;
&lt;br /&gt;
Data handling module - a database abstraction library, using an ORM approach, which would have added support for caching and federation (when applicable).&lt;br /&gt;
&lt;br /&gt;
Decentralisation - the process by which the activities of a network are distributed or delegated away from a central, authoritative location or group.&lt;br /&gt;
&lt;br /&gt;
Federation - the ability for decentralised systems to send data to one another in a standardised way, to prevent fragmentation of the network. Email is a great example of a federated system.&lt;br /&gt;
&lt;br /&gt;
GNU AGPL - a free, copyleft license published by the Free Software Foundation, and based on version 3 of the GNU General Public License (GPL) and the Affero General Public License. This license is compatible with the GPL and is recommended for any software that will commonly be run over a network.&lt;br /&gt;
&lt;br /&gt;
GNU GPL - a widely used free software license guaranteeing end users the freedom to run, study, share and modify the libre software. &lt;br /&gt;
&lt;br /&gt;
Instance - See also node. Can refer to an independently-hosted version of a software package.&lt;br /&gt;
&lt;br /&gt;
IPFS - the InterPlanetary File System is a new hypermedia distribution protocol, addressed by content and identities. IPFS enables the creation of completely distributed applications. It aims to make the web faster, safer, and more open.&lt;br /&gt;
&lt;br /&gt;
Libre software - software that is distributed under terms that allow users to run the software for any purpose as well as to study, change, and distribute it (and any adapted versions).&lt;br /&gt;
&lt;br /&gt;
Metadata - data that provides information about other data. For educational resources, it could describe various aspects of the material, including grade level, subject area, and content type or format. &lt;br /&gt;
&lt;br /&gt;
MoodleNet instance - an independently-hosted version of MoodleNet.&lt;br /&gt;
&lt;br /&gt;
Moodle instance - an independently-hosted version of Moodle Core.&lt;br /&gt;
&lt;br /&gt;
Node - a member of a decentralised network, which can sometimes serve as client, sometimes as server. See also instance.&lt;br /&gt;
&lt;br /&gt;
Open Source -  a decentralized software-development model that encourages open collaboration, with products such as source code, blueprints, and documentation freely available to the public.&lt;br /&gt;
&lt;br /&gt;
ORM - Object-relational mapping, used to create a ‘virtual object database’ which can then be referenced programmatically (with less code and more flexibility as to the underlying data storage). &lt;br /&gt;
&lt;br /&gt;
Protocol - a defined set of rules and formats that determine how data is transmitted.&lt;br /&gt;
&lt;br /&gt;
SaaS - Software as a Service. Web-based software that’s centrally hosted and made available to use (free or by subscription).&lt;br /&gt;
&lt;br /&gt;
Scaling horizontally - implies adding more nodes to a system to support its growth, for example installing copies of the same software on three web servers instead of just one. &lt;br /&gt;
&lt;br /&gt;
Scaling vertically - implies adding resources (like CPUs or memory) to a single server in a system to support its growth.&lt;br /&gt;
&lt;br /&gt;
Search index - a component of search engines which collects, parses, and stores data to facilitate fast and accurate search and information retrieval. Index design incorporates interdisciplinary concepts from linguistics, cognitive psychology, mathematics, informatics, and computer science. &lt;br /&gt;
&lt;br /&gt;
Standard - a collection of agreed specifications, usually organised by a standards body such as the W3C.&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/architecture&amp;diff=54674</id>
		<title>MoodleNet/tech/architecture</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/architecture&amp;diff=54674"/>
		<updated>2018-08-27T10:53:47Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet/tech Back to MoodleNet Tech index]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: terms in bold are defined in the glossary at the end of the document.&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
There are broadly three approaches we can take to building out MoodleNet’s platform architecture. These are:&lt;br /&gt;
&lt;br /&gt;
# Fully federated &lt;br /&gt;
# Federated with HQ API-as-a-service [Note: this is the architecture approach that was selected] &lt;br /&gt;
# Centralised SaaS &lt;br /&gt;
&lt;br /&gt;
This document outlines each of these three potential architectural approaches, and explains why we have chosen to focus on the second option. We believe that creating MoodleNet with a federated architecture combined with a HQ API-as-a-service will balance an open approach with a sustainable way of managing the project. &lt;br /&gt;
&lt;br /&gt;
Irrespective of architectural decision, we plan for MoodleNet to be consistent with Moodle’s philosophy of libre software. Moodle Core is licensed under the GNU General Public License (GNU GPL), which is compatible with the GNU Affero General Public License (GNU AGPL) that we intend to use for MoodleNet. The latter is recommended for software being run over a network. Like Moodle Core, MoodleNet is an open source platform, meaning that anyone can adapt, extend or modify the software for both commercial and non-commercial projects without any licensing fees.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Federated with HQ API service ==&lt;br /&gt;
Moodle HQ will run a MoodleNet HQ &#039;&#039;&#039;API-as-a-service&#039;&#039;&#039; serving as a central index of information across the network. This enables consistent discovery and search experiences across all MoodleNet &#039;&#039;&#039;instances&#039;&#039;&#039; (including the one provided by Moodle HQ). &lt;br /&gt;
&lt;br /&gt;
Each &#039;&#039;&#039;MoodleNet instance&#039;&#039;&#039; stores the full data of local users, communities, and collections (including personal information, private messages, and public comments/discussions). &lt;br /&gt;
&lt;br /&gt;
The database of the MoodleNet HQ API service contains lists of all public communities, collections, resources, and users across the network, along with a copy of some metadata. A search index also sits behind the API to enable fast and accurate search results. Each item always refers back to the originating MoodleNet instance for the full data (e.g. membership, permissions, comments/discussions). &lt;br /&gt;
&lt;br /&gt;
In practice, this means that the MoodleNet network, while &#039;&#039;&#039;federated&#039;&#039;&#039;, is reliant upon the MoodleNet HQ API service for search and discovery. This provides users with a better and more consistent experience, reducing fragmentation and spreading the shared content more widely, and also gives Moodle HQ more control over the overall network. &lt;br /&gt;
&lt;br /&gt;
Another HQ API service, the Moodle resources repository, could also provides hosting for Moodle course content that users share on MoodleNet. This could later be facilitated with P2P file sharing protocols like &#039;&#039;&#039;IPFS&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
This network can also be based on existing &#039;&#039;&#039;protocols&#039;&#039;&#039; and &#039;&#039;&#039;standards&#039;&#039;&#039; to form a &#039;&#039;&#039;decentralised&#039;&#039;&#039; collection of nodes that send, receive, and store data. The data handling module can be based on an extended ActivityStreams data format and at least some of the APIs on the ActivityPub protocol to ensure compatibility between systems. &lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
Interactive diagram: https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL &lt;br /&gt;
&lt;br /&gt;
Advantages of a federated network:&lt;br /&gt;
* Robust and resilient&lt;br /&gt;
* Scales horizontally&lt;br /&gt;
* Private data stays on each user’s home instance&lt;br /&gt;
* Each instance is responsible for its content (moderation of discussions, etc)&lt;br /&gt;
* Standards-based but also extensible&lt;br /&gt;
* Open&lt;br /&gt;
&lt;br /&gt;
Advantages of HQ API service:&lt;br /&gt;
* Some Moodle HQ influence over the network &lt;br /&gt;
* Consistent network-wide search and discovery experiences&lt;br /&gt;
* No duplication of resources for core functions like the indexing of resources from OER APIs, global search indexing, and Moodle resource hosting&lt;br /&gt;
* Each instance is still responsible for its content (moderation of discussions, etc)&lt;br /&gt;
* Moodle HQ controls the evolution/standardisation of content/metadata types and formats&lt;br /&gt;
&lt;br /&gt;
Disadvantages:&lt;br /&gt;
* Single point of failure (HQ API service operated by Moodle HQ).  &lt;br /&gt;
* Moodle HQ may be responsible for the content that shows up in search / discovery &lt;br /&gt;
* Some infrastructure costs for Moodle HQ &lt;br /&gt;
* Slightly higher number of components &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Glossary ==&lt;br /&gt;
&lt;br /&gt;
ActivityPub - a standard decentralised social networking protocol based on ActivityStreams.&lt;br /&gt;
&lt;br /&gt;
ActivityStreams - a standard format for syndicating social activities.&lt;br /&gt;
&lt;br /&gt;
API - Application Programming Interface. A set of definitions, protocols, and tools for building application software, to enable communication between various components.&lt;br /&gt;
&lt;br /&gt;
API-as-a-service - Software as a Service (SaaS) primarily exposed as an API.&lt;br /&gt;
&lt;br /&gt;
Canonical - the main or reference location for something (eg. canonical URL)&lt;br /&gt;
&lt;br /&gt;
Data handling module - a database abstraction library, using an ORM approach, which would have added support for caching and federation (when applicable).&lt;br /&gt;
&lt;br /&gt;
Decentralisation - the process by which the activities of a network are distributed or delegated away from a central, authoritative location or group.&lt;br /&gt;
&lt;br /&gt;
Federation - the ability for decentralised systems to send data to one another in a standardised way, to prevent fragmentation of the network. Email is a great example of a federated system.&lt;br /&gt;
&lt;br /&gt;
GNU AGPL - a free, copyleft license published by the Free Software Foundation, and based on version 3 of the GNU General Public License (GPL) and the Affero General Public License. This license is compatible with the GPL and is recommended for any software that will commonly be run over a network.&lt;br /&gt;
&lt;br /&gt;
GNU GPL - a widely used free software license guaranteeing end users the freedom to run, study, share and modify the libre software. &lt;br /&gt;
&lt;br /&gt;
Instance - See also node. Can refer to an independently-hosted version of a software package.&lt;br /&gt;
&lt;br /&gt;
IPFS - the InterPlanetary File System is a new hypermedia distribution protocol, addressed by content and identities. IPFS enables the creation of completely distributed applications. It aims to make the web faster, safer, and more open.&lt;br /&gt;
&lt;br /&gt;
Libre software - software that is distributed under terms that allow users to run the software for any purpose as well as to study, change, and distribute it (and any adapted versions).&lt;br /&gt;
&lt;br /&gt;
Metadata - data that provides information about other data. For educational resources, it could describe various aspects of the material, including grade level, subject area, and content type or format. &lt;br /&gt;
&lt;br /&gt;
MoodleNet instance - an independently-hosted version of MoodleNet.&lt;br /&gt;
&lt;br /&gt;
Moodle instance - an independently-hosted version of Moodle Core.&lt;br /&gt;
&lt;br /&gt;
Node - a member of a decentralised network, which can sometimes serve as client, sometimes as server. See also instance.&lt;br /&gt;
&lt;br /&gt;
Open Source -  a decentralized software-development model that encourages open collaboration, with products such as source code, blueprints, and documentation freely available to the public.&lt;br /&gt;
&lt;br /&gt;
ORM - Object-relational mapping, used to create a ‘virtual object database’ which can then be referenced programmatically (with less code and more flexibility as to the underlying data storage). &lt;br /&gt;
&lt;br /&gt;
Protocol - a defined set of rules and formats that determine how data is transmitted.&lt;br /&gt;
&lt;br /&gt;
SaaS - Software as a Service. Web-based software that’s centrally hosted and made available to use (free or by subscription).&lt;br /&gt;
&lt;br /&gt;
Scaling horizontally - implies adding more nodes to a system to support its growth, for example installing copies of the same software on three web servers instead of just one. &lt;br /&gt;
&lt;br /&gt;
Scaling vertically - implies adding resources (like CPUs or memory) to a single server in a system to support its growth.&lt;br /&gt;
&lt;br /&gt;
Search index - a component of search engines which collects, parses, and stores data to facilitate fast and accurate search and information retrieval. Index design incorporates interdisciplinary concepts from linguistics, cognitive psychology, mathematics, informatics, and computer science. &lt;br /&gt;
&lt;br /&gt;
Standard - a collection of agreed specifications, usually organised by a standards body such as the W3C.&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54673</id>
		<title>MoodleNet/tech</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54673"/>
		<updated>2018-08-27T10:51:54Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
An area to document the tech choices and decisions we&#039;ve made.&lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/architecture Technical architecture] - how is the platform going to be set up?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/stack Tech stack] - why did we choose Elixir?&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/stack&amp;diff=54672</id>
		<title>MoodleNet/tech/stack</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/stack&amp;diff=54672"/>
		<updated>2018-08-27T10:51:39Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet/tech Back to MoodleNet Tech index]&lt;br /&gt;
&lt;br /&gt;
= Rationale for choosing Elixir for the MoodleNet back-end =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Author:&#039;&#039;&#039; Mayel de Borniol (Technical Architect)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Date:&#039;&#039;&#039; 6 August 2018&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
MoodleNet is a new open social media platform for educators, focused on professional development and open content. It will be an integral part of the Moodle ecosystem.&lt;br /&gt;
&lt;br /&gt;
Just like the ~7,000 languages that are spoken in the world today, there are many different types of programming languages that allow humans to communicate with computers (and tell them nicely what to do). An important decision for our team was what technical language(s) Moodlenet should speak, and this document highlights the decision-making process which ended up with choosing the ‘Elixir’ language.&lt;br /&gt;
&lt;br /&gt;
== Research process ==&lt;br /&gt;
&lt;br /&gt;
The process began with an extensive review of web application programming languages. More specifically, the technologies used for apps based on [https://en.wikipedia.org/wiki/ActivityPub ActivityPub federation standard] - which will enable MoodleNet to be a &#039;&#039;&#039;decentralised platform, you will be able self-host an instance&#039;&#039;&#039; (just like you can install Moodle on a server, and customise it) but all the instances will be &#039;&#039;&#039;interconnected&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;[https://ethercalc.org/fediverse-stacks spreadsheet of fediverse apps and their stacks]&#039;&#039;&#039; (and [https://social.coop/@mayel/100469319126679591 crowdsourced extra information via the fediverse]) was compiled. This showed that besides Ruby on Rails, there were a few ActivityPub projects using Python (and a couple intending to use PHP) and some other languages, however, most projects are still in early development and many are not yet federated. Considering that &#039;&#039;&#039;ActivityPub is still relatively new it is understandable that there are limited examples of full implementations&#039;&#039;&#039;, let alone ones that are proven to work and be interoperable.&lt;br /&gt;
&lt;br /&gt;
One of the first languages that stood out was Go, one of the only a few to actually have an [https://github.com/go-fed/activity ActivityPub library]. The developer was contacted and offered his assistance for future collaboration (although in full-time employment and developing the Go library in his spare time). What this meant was that the MoodleNet team would have to modify the library in order to tailor it to the project’s needs. The main obstacle to this, however, is that Go is a ‘statically typed’ language which means every ActivityStreams extension would have to be hard coded pre-compilation. This would make things less flexible, so this option was set aside.&lt;br /&gt;
&lt;br /&gt;
Alongside researching the documentations, codebases, issue trackers and communicating with developers of the apps in the spreadsheet, many of them were installed and tested (including Mastodon, Pleroma, and Prismo). The latter, while having some functionality that MoodleNet will need, confirmed an earlier impression from running a Mastodon instance: &#039;&#039;&#039;Rails apps tend to not be lightweight and often rely on many external dependencies&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
After comparing the possible language candidates, the focus shifted on detailing the pros and cons for each, finally focusing on the following:&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;[https://en.wikipedia.org/wiki/BEAM_(Erlang_virtual_machine) Erlang VM]&#039;&#039;&#039; is time tested (more than 20 years old), very fast and has good concurrency and inter-process communication (called OTP).&lt;br /&gt;
* &#039;&#039;&#039;[https://elixir-lang.org Elixir]&#039;&#039;&#039; is a new (7+ years) functional language designed for productivity and maintainability that runs on the Erlang VM.&lt;br /&gt;
* &#039;&#039;&#039;[https://phoenixframework.org Phoenix]&#039;&#039;&#039; is a modern web framework that makes building APIs and web applications easy. Since it’s built with Elixir and runs on Erlang VM, it is very fast and has excellent support for handling very large numbers of simultaneous users.&lt;br /&gt;
&lt;br /&gt;
= Benefits of Elixir =&lt;br /&gt;
&lt;br /&gt;
A list of reasons to use Elixir in our context:&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
The Phoenix web framework has been found to perform better than Rails, PHP, and Python. [https://github.com/mroth/phoenix-showdown/blob/master/README.md#benchmarking One benchmark] showed Phoenix handling over 10x more requests than Rails in a given period. Phoenix was also much more consistent under load - Rails was more prone to have some requests bog down. This can cause a “chain reaction”, because Rails apps are configured with a fixed number of application processes, so if some of them are slow, it can mean that others have to wait in line, which dramatically increases the app’s response time.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Phoenix apps &#039;&#039;&#039;without caching&#039;&#039;&#039; drastically outperform Rails apps &#039;&#039;&#039;with caching&#039;&#039;&#039;. This is important because caching is notorious for being a source of complexity and bugs, and because caching can’t be used for moment-by-moment, personalised content. The [https://youtu.be/AdY5AfXs7aw?t=3m14s Bleacher Report] for example went from over 100 AWS servers to 5, with CPU usage rarely going above 10%, and saw a 10x performance improvement over their Rails app.&lt;br /&gt;
&lt;br /&gt;
There are a growing number of software projects using Elixir - e.g. Pinterest [https://github.com/bignerdranch/why_elixir who say]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“We like Elixir and have seen some pretty big wins with it. The system that manages rate limits for both the Pinterest API and Ads API is built in Elixir. Its 50 percent response time is around 500 microseconds with a 90 percent response time of 800 microseconds. Yes, microseconds.”&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And an [https://blog.carbonfive.com/2016/04/19/elixir-and-phoenix-the-future-of-web-apis-and-apps/ adopter of the Phoenix framework] says: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“A rather large JSON request was taking about 1.5-2.0s against our Rails backend (no caching). That same request (same h/w, database queries and data) takes about 400ms with Phoenix. Our entire application went from using just shy of 1 GB across 2 dynos to a single dyno using less than 100 MB. That single dyno is notably faster and can handle higher concurrency (about 10x). Importantly, Phoenix (without caching) performs better than Rails (with caching).”&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One thing that makes Erlang/Elixir so efficient is [https://www.brianstorti.com/the-actor-model/ the actor model], which ActivityPub seems to have taken inspiration from.&lt;br /&gt;
&lt;br /&gt;
== Scalability ==&lt;br /&gt;
&lt;br /&gt;
The Erlang VM’s model of concurrency is great for multi-core CPUs, but it was created before they existed. Its original purpose was to support concurrency and fault-tolerance via the use of many different machines. This makes it an excellent tool for building systems that can handle more load by simply adding more servers.&lt;br /&gt;
&lt;br /&gt;
As the [http://ninenines.eu/docs/en/cowboy/2.0/guide/erlang_web/ docs for an Erlang web server] put it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“At the time of writing there are application servers written in Erlang that can handle more than two million connections on a single server in a real production application, with spare memory and CPU! The Web is concurrent, and Erlang is a language designed for concurrency, so it is a perfect match. &amp;lt;br&amp;gt;&amp;lt;br&amp;gt; Of course, various platforms need to scale beyond a few million connections. This is where Erlang’s built-in distribution mechanisms come in. If one server isn’t enough, add more! Erlang allows you to use the same code for talking to local processes or to processes in other parts of your cluster, which means you can scale very quickly if the need arises.”&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Developer Productivity &amp;amp;amp; Happiness ==&lt;br /&gt;
&lt;br /&gt;
When people argue about programming languages, often the performance card is pulled (“this language is so much faster in these benchmarks”). But performance isn’t the only consideration: while it’s possible to just add more servers, developer time often costs more than servers.&lt;br /&gt;
&lt;br /&gt;
More important then is which framework helps write software faster, of a better quality, and which benefits the programmer’s wellbeing.&lt;br /&gt;
&lt;br /&gt;
As Pinterest concluded from using Elixir:  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“We’ve also seen an improvement in code clarity. We’re converting our notifications system from Java to Elixir. The Java version used an Actor system and weighed in at around 10,000 lines of code. The new Elixir system has shrunk this to around 1000 lines. The Elixir based system is also faster and more consistent than the Java one and runs on half the number of servers.”&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And [http://www.techworld.com/apps-wearables/how-elixir-helped-bleacher-report-handle-8x-more-traffic-3653957/ Bleacher Report], who went from 150 servers to 5 using Elixir: &amp;amp;gt; &amp;amp;quot;The new language has led to cleaner code base and much less technical debt. It has also increased the speed of development.&lt;br /&gt;
&lt;br /&gt;
Some [https://pragtob.wordpress.com/2017/07/26/choosing-elixir-for-the-code-not-the-performance/ advantages of Elixir for programmers] include:&lt;br /&gt;
&lt;br /&gt;
* No extra engineering spent on “making it faster” (if the runtime is already fast enough they don’t need to bother with caching for example).&lt;br /&gt;
* All the goodies of modern day programming, like a package manager.&lt;br /&gt;
* Pattern Matching: you can make assertions on the structure and can get values directly out of a deeply nested map (or list) and put their value into a variable. You also have method overloading and Elixir will try to match the functions from top to bottom which means you can have different function definitions based on the structure of your input data.&lt;br /&gt;
* Immutable data structures &amp;amp;amp; pure functions: Everything that the function depends on is a parameter, and the only thing that “happens” is the return value of the function. There are no instance variables that are difficult to debug.&lt;br /&gt;
* Explicit code: For example, you explicitly specify a template by name, and pass the values you’ll need from the controller. Ecto also gives you more control over what data will be loaded from the DB.&lt;br /&gt;
* [https://hexdocs.pm/ecto/Ecto.Changeset.html Ecto Changesets]: filtering, casting, validation and definition of constraints when manipulating DB data.&lt;br /&gt;
* Optional type-checking: use [https://github.com/jeremyjh/dialyxir typing only when you want to].&lt;br /&gt;
* Parallelism: it’s not just about performance! Parallelism in the Erlang VM low cost and seamless. Spawning a new process (not like an OS process, they are more like actors) is easy and has a very low overhead, unlike starting a new thread. You can have millions of them on one machine. And thanks to immutability guarantees and every process being isolated you don’t have to worry about processes messing with each other.&lt;br /&gt;
* Doc tests: It is possible to write code examples directly in the documentation of a method. These will be executed during test runs and check if they still return the same values/still pass. They are also included in the generated documentation.&lt;br /&gt;
&lt;br /&gt;
== Reliability ==&lt;br /&gt;
&lt;br /&gt;
While Elixir is a fairly new language, it is mostly a friendly interface to the Erlang virtual machine, which has been used since the 80s to build some of the most reliable systems in the world: telephone systems.&lt;br /&gt;
&lt;br /&gt;
It is made for running a complex system with almost no downtime, like having multiple levels of “supervising” processes in a system to reboot parts that have errors. Basically, microservices before microservices were cool.&lt;br /&gt;
&lt;br /&gt;
== Concurrency ==&lt;br /&gt;
&lt;br /&gt;
CPUs are no longer getting dramatically faster each year. Instead, we get machines with more cores. Our code can run faster, but only if it can run concurrently - meaning, different bits of code run simultaneously on different cores.&lt;br /&gt;
&lt;br /&gt;
The main problem with concurrent code is having two pieces of code mess with the same data at the same time, creating unexpected results. Object-oriented languages like Ruby don’t provide great tools for avoiding such problems. But functional languages, like Elixir, do.&lt;br /&gt;
&lt;br /&gt;
Writing concurrent code in Elixir is extremely easy, and it’s nearly impossible to accidentally interfere with other code that is running at the time.&lt;br /&gt;
&lt;br /&gt;
== Simplicity ==&lt;br /&gt;
&lt;br /&gt;
For modern web applications (written in languages like PHP or Ruby on Rails) to do everything we require of them, they depend on a lot of other pieces running on the server, for example: &lt;br /&gt;
&lt;br /&gt;
* Only one web request can be handled at a time, and it is not possible to spin up new processes as needed, so tools are needed to spawn multiple application servers up front and put a web server like Nginx in front of them to hand off requests. &lt;br /&gt;
* It is not possible to do slow background tasks without blocking web requests, so something like [http://resque.github.io Resque] needs to be added to take care of running background jobs. &lt;br /&gt;
* It is not advisable to use a precious process to maintain a websocket connection with a user, so something like Pusher needs to be added to get realtime functionality (meaning extra costs). &lt;br /&gt;
* It is not possible to keep a big process running all the time to do scheduled tasks, so a dependency on cron needs to be added. &lt;br /&gt;
* No built-in tool for managing multiple parts of a running system currently exists, so tools like [https://www.theforeman.org foreman] are used to start and monitor them.&lt;br /&gt;
&lt;br /&gt;
In Elixir on the other hand, it is possible to spin up a nearly limitless number of processes as needed, so it is possible (in theory) to forego all those tools above.&lt;br /&gt;
&lt;br /&gt;
Elixir code is also simpler to understand than object-oriented code because it has explicitness as a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“Functional programming is associated with concurrency but it was not by design. It just happens that, by making the complex parts of our system explicit, solving more complicated issues like concurrency becomes much simpler.” - [http://www.sitepoint.com/an-interview-with-elixir-creator-jose-valim/ Jose Valim]&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flexibility ==&lt;br /&gt;
&lt;br /&gt;
Using Phoenix and Elixir opens the door to building applications that are not possible with other web frameworks.&lt;br /&gt;
&lt;br /&gt;
The Phoenix framework has first-class support for realtime communication via websockets (with polling as a fallback). In benchmarks, the creators have been able to[http://www.phoenixframework.org/blog/the-road-to-2-million-websocket-connections serve 2 million simultaneously-connected clients]. Additionally, they already have native channel clients for iOS, Android, and Windows devices. With that kind of support, you can confidently build servers to support chat, networked games, and more.&lt;br /&gt;
&lt;br /&gt;
== Correctness ==&lt;br /&gt;
&lt;br /&gt;
In Rails, ActiveRecord encourages developers to do all data validation in application code. However, validations that depend on the state of the database can only be reliably done by the database, using constraints or locks. This includes things like:&lt;br /&gt;
&lt;br /&gt;
* Does any user have this username right now? (uniqueness constraint)&lt;br /&gt;
* Does post 5 exist still right now, before I comment on it? (foreign key constraint)&lt;br /&gt;
* Does this user’s account have enough money to cover this purchase right now? (CHECK constraint)&lt;br /&gt;
* Is this rental property reserved for June 8 right now? (EXCLUDE constraint on date ranges)&lt;br /&gt;
&lt;br /&gt;
It is possible to use such constraints with a Rails application, but it is not typical to do so, and the tools do not encourage it.&lt;br /&gt;
&lt;br /&gt;
Elixir’s [https://hexdocs.pm/ecto/Ecto.html Ecto] database library embraces database constraints, with built-in support for adding them, catching constraint violations, and turning them back into friendly user-facing error messages.&lt;br /&gt;
&lt;br /&gt;
== Where Elixir is especially suited ==&lt;br /&gt;
&lt;br /&gt;
Any project that is a good fit for Rails or Python is something that could be done in Phoenix, especially if the project involves any or multiple of the following:&lt;br /&gt;
&lt;br /&gt;
* System expecting high traffic or requiring very fast / consistent response times&lt;br /&gt;
* Minimal downtime being crucial&lt;br /&gt;
* Realtime updates (eg, stock ticker, social media)&lt;br /&gt;
* Bidirectional realtime communication with websockets (eg, chat, games)&lt;br /&gt;
&lt;br /&gt;
= Drawbacks of Elixir =&lt;br /&gt;
&lt;br /&gt;
Some potential downsides of using Elixir, along with mitigating actions:&lt;br /&gt;
&lt;br /&gt;
* Fewer Elixir developers available. However:&lt;br /&gt;
** There are also significantly fewer projects competing for those people.&lt;br /&gt;
** There is a trend in Ruby developers wanting to cross over to Elixir.&lt;br /&gt;
** Developers with Erlang experience are also well suited.&lt;br /&gt;
** Elixir is a shiny new thing with real promise, which helps attract very enthusiastic developers.&lt;br /&gt;
* While Phoenix is productive, it is not as productive as older frameworks like Rails… yet. Reasons include:&lt;br /&gt;
** Lack of developer experience with Elixir.&lt;br /&gt;
** The relative newness of its open source ecosystem (documentation, forums, example code available).&lt;br /&gt;
** There are fewer libraries in Elixir than in older languages, so there are more times when you’d have to write something yourself. However:&lt;br /&gt;
*** You can use the many existing Erlang libraries.&lt;br /&gt;
*** New Elixir libraries are being added quickly.&lt;br /&gt;
*** Any remaining gaps are a chance to contribute to the community by creating a great open source tool.&lt;br /&gt;
* It may be harder to convince people to use Elixir, given that it’s currently obscure - not in the top [https://www.tiobe.com/tiobe-index/ 50 TIOBE index]. However:&lt;br /&gt;
** Erlang is better-known. Elixir compiles to Erlang bytecode, runs on the Erlang VM and can use or be used by Erlang code. It’s basically “Erlang made friendlier”.&lt;br /&gt;
** Joe Armstrong, co-creator of Erlang, said of pre-1.0 Elixir in 2013 that it was &amp;amp;quot;good s**t&amp;amp;quot;.&lt;br /&gt;
** Therefore, if we can convince someone on Erlang, Elixir is a no-brainer.&lt;br /&gt;
&lt;br /&gt;
= What’s next for MoodleNet’s development =&lt;br /&gt;
&lt;br /&gt;
== A generic agent-centric approach to federation? ==&lt;br /&gt;
&lt;br /&gt;
Another fediverse app being developed in Elixir ([https://github.com/beta-phenylethylamine/fontina Fontina], for photo sharing - although it has been put on hiatus) is now working on a [https://github.com/fontina-project/pubstomp generic ActivityPub server] to serve as back-end (there may be a good opportunity to join efforts…) Here is how the developer describes it: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“I’m working on pubstomp, a generic AP server that is intended for services like mastodon/pixelfed/peertube to work as frontends to it and would indeed support single account [per person, versus having an account on an instance of each of those apps]. &amp;amp;gt; That said, one of my goals down the road is to build”api adaptors&amp;amp;quot; that would basically plug into pubstomp and adapt to, say, the mastoAPI, pleromaAPI, etc.”&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a good example of an &#039;&#039;&#039;agent-centric approach&#039;&#039;&#039;, where instead of having one &#039;&#039;&#039;monolithic app per use-case&#039;&#039;&#039; it is possible instead to separate out federation logic and custom app logic (both back-ends could still share a database on the same server, and share a JavaScript-based front-end app that talks to both APIs).&lt;br /&gt;
&lt;br /&gt;
I started a [https://social.coop/@mayel/100469525067581562 thread about this on the fediverse] (please join the conversation!): &lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;There’s need for a generic agent-centric #ActivityPub server, so that instead of signing up to a bunch of different servers, a user could have their identity and data all in one place, and all the apps they use (clients, but if necessary server-side “plugins” as well) would interact with the activity/objects types that they support.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The plan for Moodlenet (so far) ==&lt;br /&gt;
&lt;br /&gt;
# Fork the Pleroma back-end to create a set of ActivityPub libraries (or a generic ActivityPub server)&lt;br /&gt;
# Add suport for authenticating as OAuth client&lt;br /&gt;
# Add support for group accounts (agents that represent a several users)&lt;br /&gt;
# Create ActivityStreams extensions&lt;br /&gt;
# Test federation&lt;br /&gt;
# Possibly add [https://graphql.org GraphQL] client-server API&lt;br /&gt;
# Create front-end app with React.js (web and mobile)&lt;br /&gt;
&lt;br /&gt;
We are planning to fork the [https://git.pleroma.social/pleroma/pleroma Pleroma back-end] to &#039;&#039;&#039;create a set of ActivityPub/ActivityStreams libraries&#039;&#039;&#039;. If that proves to not be feasible, we will turn it into a generic ActivityPub server back-end that can support any type of activity and object (including extensions to ActivityStreams) and is easily extensible which doesn’t ship with any frontend (possible name: &#039;&#039;Pub of the Commons&#039;&#039;). Pleroma is written with [https://elixir-lang.org Elixir]’s [https://phoenixframework.org Phoenix Framework], and licensed as AGPL (which is also being used for MoodleNet) so the upstream project will be able to use any improvements we make.&lt;br /&gt;
&lt;br /&gt;
Firstly, any parts of the code coming from Pleroma that we don’t needed will be removed (like support for the deprecated OStatus protocol, and the two front-ends which ship with Pleroma - its own Vue.js interface and Mastodon’s React.js interface), and we’ll add some things that can be &#039;&#039;&#039;universally useful&#039;&#039;&#039; like &#039;&#039;&#039;support for groups&#039;&#039;&#039; (actors made of several users), a basic HTML registration/authentication interface (and &#039;&#039;&#039;OAuth client&#039;&#039;&#039; functionality, so users can sign in using their existing accounts elsewhere) so that at least those things can be done without relying on a front-end app.&lt;br /&gt;
&lt;br /&gt;
While we work on creating models/vocabulary for MoodleNet, we can use this generic ActivityPub server to test our ActivityStreams extensions and make sure federation works well in real time (using the API only). Only once that is ready, will we start plugging in custom MoodleNet logic and developing the front-end app (which is the reverse from many fediverse app projects, who have first implemented MVPs of their use case, and then often find it challenging to add federation on top).&lt;br /&gt;
&lt;br /&gt;
Regarding the connection between the back-end and front-end app, the ActivityPub standard comes with a suggested [https://www.w3.org/TR/activitypub/#client-to-server-interactions client-server REST API specification], but for some reason Mastodon and many other fediverse apps have created their own custom REST APIs (and Pleroma implemented Mastodon’s so that it can share front-end apps). So an interesting option at this point for MoodleNet (and &#039;&#039;Pub of the Commons&#039;&#039;), may be to still support Mastodon’s client REST API (for compatibility with existing front-ends like [https://github.com/nolanlawson/pinafore Pinafore]) and additionally to &#039;&#039;&#039;implement a new GraphQL-based API that would allow more flexibility and extensibility between the server and front-end apps&#039;&#039;&#039; (any functionality/activities/objects not supported by Mastodon would only have to be implemented in the server-to-server REST API and the [https://graphql.org GraphQL] API).&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&lt;br /&gt;
* [https://ethercalc.org/fediverse-stacks Spreadsheet of fediverse apps and their stacks]&lt;br /&gt;
* [https://www.w3.org/TR/activitypub/ ActivityPub] standard (for federation)&lt;br /&gt;
* [https://www.w3.org/TR/activitystreams-core/ ActivityStreams] &amp;amp;amp; its [https://www.w3.org/TR/activitystreams-vocabulary/ vocabulary] (which ActivityPub uses as a data format)&lt;br /&gt;
* [https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/ How to implement a basic Mastodon-compatible server]&lt;br /&gt;
* [https://github.com/bignerdranch/why_elixir Why elixir] (big tanks to Big Nerd Ranch for some of the great material used in this doc!)&lt;br /&gt;
* [https://pragtob.wordpress.com/2017/07/26/choosing-elixir-for-the-code-not-the-performance/ Choosing Elixir for the Code, not the Performance]&lt;br /&gt;
* [https://git.pleroma.social/pleroma/pleroma/wikis/Hacking-Pleroma:-Elixir,-Phoenix-and-a-bit-of-ActivityPub Pleroma’s architecture]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/&amp;diff=54671</id>
		<title>MoodleNet/tech/</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/&amp;diff=54671"/>
		<updated>2018-08-27T10:50:38Z</updated>

		<summary type="html">&lt;p&gt;Mayel: redir&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[MoodleNet/tech]]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54670</id>
		<title>MoodleNet/tech</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech&amp;diff=54670"/>
		<updated>2018-08-27T10:49:45Z</updated>

		<summary type="html">&lt;p&gt;Mayel: Created page with &amp;quot;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet/tech Back to MoodleNet index]  ----  An area to document the tech choices and decisions we&amp;#039;ve made.  File:MoodleNet-technical-diagr...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet/tech Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
An area to document the tech choices and decisions we&#039;ve made.&lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/architecture Technical architecture] - how is the platform going to be set up?&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/tech/stack Tech stack] - why did we choose Elixir?&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/architecture&amp;diff=54669</id>
		<title>MoodleNet/tech/architecture</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/architecture&amp;diff=54669"/>
		<updated>2018-08-27T10:48:03Z</updated>

		<summary type="html">&lt;p&gt;Mayel: copied from Google doc&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet/tech Back to MoodleNet Tech index]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: terms in bold are defined in the glossary at the end of the document.&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
There are broadly three approaches we can take to building out MoodleNet’s platform architecture. These are:&lt;br /&gt;
&lt;br /&gt;
# Fully federated &lt;br /&gt;
# Federated with HQ API-as-a-service [Note: this is the architecture approach that was selected] &lt;br /&gt;
# Centralised SaaS &lt;br /&gt;
&lt;br /&gt;
This document outlines each of these three potential architectural approaches, and explains why we have chosen to focus on the second option. We believe that creating MoodleNet with a federated architecture combined with a HQ API-as-a-service will balance an open approach with a sustainable way of managing the project. &lt;br /&gt;
&lt;br /&gt;
Irrespective of architectural decision, we plan for MoodleNet to be consistent with Moodle’s philosophy of libre software. Moodle Core is licensed under the GNU General Public License (GNU GPL), which is compatible with the GNU Affero General Public License (GNU AGPL) that we intend to use for MoodleNet. The latter is recommended for software being run over a network. Like Moodle Core, MoodleNet is an open source platform, meaning that anyone can adapt, extend or modify the software for both commercial and non-commercial projects without any licensing fees.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Federated with HQ API service ==&lt;br /&gt;
Moodle HQ will run a MoodleNet HQ &#039;&#039;&#039;API-as-a-service&#039;&#039;&#039; serving as a central index of information across the network. This enables consistent discovery and search experiences across all MoodleNet &#039;&#039;&#039;instances&#039;&#039;&#039; (including the one provided by Moodle HQ). &lt;br /&gt;
&lt;br /&gt;
Each &#039;&#039;&#039;MoodleNet instance&#039;&#039;&#039; stores the full data of local users, communities, and collections (including personal information, private messages, and public comments/discussions). &lt;br /&gt;
&lt;br /&gt;
The database of the MoodleNet HQ API service contains lists of all public communities, collections, resources, and users across the network, along with a copy of some metadata. A search index also sits behind the API to enable fast and accurate search results. Each item always refers back to the originating MoodleNet instance for the full data (e.g. membership, permissions, comments/discussions). &lt;br /&gt;
&lt;br /&gt;
In practice, this means that the MoodleNet network, while &#039;&#039;&#039;federated&#039;&#039;&#039;, is reliant upon the MoodleNet HQ API service for search and discovery. This provides users with a better and more consistent experience, reducing fragmentation and spreading the shared content more widely, and also gives Moodle HQ more control over the overall network. &lt;br /&gt;
&lt;br /&gt;
Another HQ API service, the Moodle resources repository, could also provides hosting for Moodle course content that users share on MoodleNet. This could later be facilitated with P2P file sharing protocols like &#039;&#039;&#039;IPFS&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
This network can also be based on existing &#039;&#039;&#039;protocols&#039;&#039;&#039; and &#039;&#039;&#039;standards&#039;&#039;&#039; to form a &#039;&#039;&#039;decentralised&#039;&#039;&#039; collection of nodes that send, receive, and store data. The data handling module can be based on an extended ActivityStreams data format and at least some of the APIs on the ActivityPub protocol to ensure compatibility between systems. &lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet-technical-diagram.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
Interactive diagram: https://whimsical.co/Xh45SHnfdAuNAJgGqQu8hL &lt;br /&gt;
&lt;br /&gt;
Advantages:&lt;br /&gt;
* Robust and resilient&lt;br /&gt;
* Scales horizontally&lt;br /&gt;
* Private data stays on each user’s home instance&lt;br /&gt;
* Each instance is responsible for its content (moderation of discussions, etc)&lt;br /&gt;
* Standards-based but also extensible&lt;br /&gt;
* Open&lt;br /&gt;
* Some Moodle HQ influence over the network &lt;br /&gt;
* Consistent network-wide search and discovery experiences&lt;br /&gt;
* No duplication of resources for core functions like the indexing of resources from OER APIs, global search indexing, and Moodle resource hosting&lt;br /&gt;
* Each instance is still responsible for its content (moderation of discussions, etc)&lt;br /&gt;
* Moodle HQ controls the evolution/standardisation of content/metadata types and formats&lt;br /&gt;
&lt;br /&gt;
Disadvantages:&lt;br /&gt;
* Single point of failure (HQ API service operated by Moodle HQ).  &lt;br /&gt;
* Moodle HQ may be responsible for the content that shows up in search / discovery &lt;br /&gt;
* Some infrastructure costs for Moodle HQ &lt;br /&gt;
* Slightly higher number of components &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Glossary ==&lt;br /&gt;
&lt;br /&gt;
ActivityPub - a standard decentralised social networking protocol based on ActivityStreams.&lt;br /&gt;
&lt;br /&gt;
ActivityStreams - a standard format for syndicating social activities.&lt;br /&gt;
&lt;br /&gt;
API - Application Programming Interface. A set of definitions, protocols, and tools for building application software, to enable communication between various components.&lt;br /&gt;
&lt;br /&gt;
API-as-a-service - Software as a Service (SaaS) primarily exposed as an API.&lt;br /&gt;
&lt;br /&gt;
Canonical - the main or reference location for something (eg. canonical URL)&lt;br /&gt;
&lt;br /&gt;
Data handling module - a database abstraction library, using an ORM approach, which would have added support for caching and federation (when applicable).&lt;br /&gt;
&lt;br /&gt;
Decentralisation - the process by which the activities of a network are distributed or delegated away from a central, authoritative location or group.&lt;br /&gt;
&lt;br /&gt;
Federation - the ability for decentralised systems to send data to one another in a standardised way, to prevent fragmentation of the network. Email is a great example of a federated system.&lt;br /&gt;
&lt;br /&gt;
GNU AGPL - a free, copyleft license published by the Free Software Foundation, and based on version 3 of the GNU General Public License (GPL) and the Affero General Public License. This license is compatible with the GPL and is recommended for any software that will commonly be run over a network.&lt;br /&gt;
&lt;br /&gt;
GNU GPL - a widely used free software license guaranteeing end users the freedom to run, study, share and modify the libre software. &lt;br /&gt;
&lt;br /&gt;
Instance - See also node. Can refer to an independently-hosted version of a software package.&lt;br /&gt;
&lt;br /&gt;
IPFS - the InterPlanetary File System is a new hypermedia distribution protocol, addressed by content and identities. IPFS enables the creation of completely distributed applications. It aims to make the web faster, safer, and more open.&lt;br /&gt;
&lt;br /&gt;
Libre software - software that is distributed under terms that allow users to run the software for any purpose as well as to study, change, and distribute it (and any adapted versions).&lt;br /&gt;
&lt;br /&gt;
Metadata - data that provides information about other data. For educational resources, it could describe various aspects of the material, including grade level, subject area, and content type or format. &lt;br /&gt;
&lt;br /&gt;
MoodleNet instance - an independently-hosted version of MoodleNet.&lt;br /&gt;
&lt;br /&gt;
Moodle instance - an independently-hosted version of Moodle Core.&lt;br /&gt;
&lt;br /&gt;
Node - a member of a decentralised network, which can sometimes serve as client, sometimes as server. See also instance.&lt;br /&gt;
&lt;br /&gt;
Open Source -  a decentralized software-development model that encourages open collaboration, with products such as source code, blueprints, and documentation freely available to the public.&lt;br /&gt;
&lt;br /&gt;
ORM - Object-relational mapping, used to create a ‘virtual object database’ which can then be referenced programmatically (with less code and more flexibility as to the underlying data storage). &lt;br /&gt;
&lt;br /&gt;
Protocol - a defined set of rules and formats that determine how data is transmitted.&lt;br /&gt;
&lt;br /&gt;
SaaS - Software as a Service. Web-based software that’s centrally hosted and made available to use (free or by subscription).&lt;br /&gt;
&lt;br /&gt;
Scaling horizontally - implies adding more nodes to a system to support its growth, for example installing copies of the same software on three web servers instead of just one. &lt;br /&gt;
&lt;br /&gt;
Scaling vertically - implies adding resources (like CPUs or memory) to a single server in a system to support its growth.&lt;br /&gt;
&lt;br /&gt;
Search index - a component of search engines which collects, parses, and stores data to facilitate fast and accurate search and information retrieval. Index design incorporates interdisciplinary concepts from linguistics, cognitive psychology, mathematics, informatics, and computer science. &lt;br /&gt;
&lt;br /&gt;
Standard - a collection of agreed specifications, usually organised by a standards body such as the W3C.&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/stack&amp;diff=54610</id>
		<title>MoodleNet/tech/stack</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/stack&amp;diff=54610"/>
		<updated>2018-08-06T16:01:59Z</updated>

		<summary type="html">&lt;p&gt;Mayel: /* Research process */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Rationale for choosing Elixir for the MoodleNet back-end =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Author:&#039;&#039;&#039; Mayel de Borniol (Technical Architect)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Date:&#039;&#039;&#039; 6 August 2018&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
MoodleNet is a new open social media platform for educators, focused on professional development and open content. It will be an integral part of the Moodle ecosystem.&lt;br /&gt;
&lt;br /&gt;
Just like the ~7,000 languages that are spoken in the world today, there are many different types of programming languages that allow humans to communicate with computers (and tell them nicely what to do). An important decision for our team was what technical language(s) Moodlenet should speak, and this document highlights the decision-making process which ended up with choosing the ‘Elixir’ language.&lt;br /&gt;
&lt;br /&gt;
== Research process ==&lt;br /&gt;
&lt;br /&gt;
The process began with an extensive review of web application programming languages. More specifically, the technologies used for apps based on [https://en.wikipedia.org/wiki/ActivityPub ActivityPub federation standard] - which will enable MoodleNet to be a &#039;&#039;&#039;decentralised platform, you will be able self-host an instance&#039;&#039;&#039; (just like you can install Moodle on a server, and customise it) but all the instances will be &#039;&#039;&#039;interconnected&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;[https://ethercalc.org/fediverse-stacks spreadsheet of fediverse apps and their stacks]&#039;&#039;&#039; (and [https://social.coop/@mayel/100469319126679591 crowdsourced extra information via the fediverse]) was compiled. This showed that besides Ruby on Rails, there were a few ActivityPub projects using Python (and a couple intending to use PHP) and some other languages, however, most projects are still in early development and many are not yet federated. Considering that &#039;&#039;&#039;ActivityPub is still relatively new it is understandable that there are limited examples of full implementations&#039;&#039;&#039;, let alone ones that are proven to work and be interoperable.&lt;br /&gt;
&lt;br /&gt;
One of the first languages that stood out was Go, one of the only a few to actually have an [https://github.com/go-fed/activity ActivityPub library]. The developer was contacted and offered his assistance for future collaboration (although in full-time employment and developing the Go library in his spare time). What this meant was that the MoodleNet team would have to modify the library in order to tailor it to the project’s needs. The main obstacle to this, however, is that Go is a ‘statically typed’ language which means every ActivityStreams extension would have to be hard coded pre-compilation. This would make things less flexible, so this option was set aside.&lt;br /&gt;
&lt;br /&gt;
Alongside researching the documentations, codebases, issue trackers and communicating with developers of the apps in the spreadsheet, many of them were installed and tested (including Mastodon, Pleroma, and Prismo). The latter, while having some functionality that MoodleNet will need, confirmed an earlier impression from running a Mastodon instance: &#039;&#039;&#039;Rails apps tend to not be lightweight and often rely on many external dependencies&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
After comparing the possible language candidates, the focus shifted on detailing the pros and cons for each, finally focusing on the following:&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;[https://en.wikipedia.org/wiki/BEAM_(Erlang_virtual_machine) Erlang VM]&#039;&#039;&#039; is time tested (more than 20 years old), very fast and has good concurrency and inter-process communication (called OTP).&lt;br /&gt;
* &#039;&#039;&#039;[https://elixir-lang.org Elixir]&#039;&#039;&#039; is a new (7+ years) functional language designed for productivity and maintainability that runs on the Erlang VM.&lt;br /&gt;
* &#039;&#039;&#039;[https://phoenixframework.org Phoenix]&#039;&#039;&#039; is a modern web framework that makes building APIs and web applications easy. Since it’s built with Elixir and runs on Erlang VM, it is very fast and has excellent support for handling very large numbers of simultaneous users.&lt;br /&gt;
&lt;br /&gt;
= Benefits of Elixir =&lt;br /&gt;
&lt;br /&gt;
A list of reasons to use Elixir in our context:&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
The Phoenix web framework has been found to perform better than Rails, PHP, and Python. [https://github.com/mroth/phoenix-showdown/blob/master/README.md#benchmarking One benchmark] showed Phoenix handling over 10x more requests than Rails in a given period. Phoenix was also much more consistent under load - Rails was more prone to have some requests bog down. This can cause a “chain reaction”, because Rails apps are configured with a fixed number of application processes, so if some of them are slow, it can mean that others have to wait in line, which dramatically increases the app’s response time.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Phoenix apps &#039;&#039;&#039;without caching&#039;&#039;&#039; drastically outperform Rails apps &#039;&#039;&#039;with caching&#039;&#039;&#039;. This is important because caching is notorious for being a source of complexity and bugs, and because caching can’t be used for moment-by-moment, personalised content. The [https://youtu.be/AdY5AfXs7aw?t=3m14s Bleacher Report] for example went from over 100 AWS servers to 5, with CPU usage rarely going above 10%, and saw a 10x performance improvement over their Rails app.&lt;br /&gt;
&lt;br /&gt;
There are a growing number of software projects using Elixir - e.g. Pinterest [https://github.com/bignerdranch/why_elixir who say]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“We like Elixir and have seen some pretty big wins with it. The system that manages rate limits for both the Pinterest API and Ads API is built in Elixir. Its 50 percent response time is around 500 microseconds with a 90 percent response time of 800 microseconds. Yes, microseconds.”&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And an [https://blog.carbonfive.com/2016/04/19/elixir-and-phoenix-the-future-of-web-apis-and-apps/ adopter of the Phoenix framework] says: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“A rather large JSON request was taking about 1.5-2.0s against our Rails backend (no caching). That same request (same h/w, database queries and data) takes about 400ms with Phoenix. Our entire application went from using just shy of 1 GB across 2 dynos to a single dyno using less than 100 MB. That single dyno is notably faster and can handle higher concurrency (about 10x). Importantly, Phoenix (without caching) performs better than Rails (with caching).”&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One thing that makes Erlang/Elixir so efficient is [https://www.brianstorti.com/the-actor-model/ the actor model], which ActivityPub seems to have taken inspiration from.&lt;br /&gt;
&lt;br /&gt;
== Scalability ==&lt;br /&gt;
&lt;br /&gt;
The Erlang VM’s model of concurrency is great for multi-core CPUs, but it was created before they existed. Its original purpose was to support concurrency and fault-tolerance via the use of many different machines. This makes it an excellent tool for building systems that can handle more load by simply adding more servers.&lt;br /&gt;
&lt;br /&gt;
As the [http://ninenines.eu/docs/en/cowboy/2.0/guide/erlang_web/ docs for an Erlang web server] put it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“At the time of writing there are application servers written in Erlang that can handle more than two million connections on a single server in a real production application, with spare memory and CPU! The Web is concurrent, and Erlang is a language designed for concurrency, so it is a perfect match. &amp;lt;br&amp;gt;&amp;lt;br&amp;gt; Of course, various platforms need to scale beyond a few million connections. This is where Erlang’s built-in distribution mechanisms come in. If one server isn’t enough, add more! Erlang allows you to use the same code for talking to local processes or to processes in other parts of your cluster, which means you can scale very quickly if the need arises.”&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Developer Productivity &amp;amp;amp; Happiness ==&lt;br /&gt;
&lt;br /&gt;
When people argue about programming languages, often the performance card is pulled (“this language is so much faster in these benchmarks”). But performance isn’t the only consideration: while it’s possible to just add more servers, developer time often costs more than servers.&lt;br /&gt;
&lt;br /&gt;
More important then is which framework helps write software faster, of a better quality, and which benefits the programmer’s wellbeing.&lt;br /&gt;
&lt;br /&gt;
As Pinterest concluded from using Elixir:  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“We’ve also seen an improvement in code clarity. We’re converting our notifications system from Java to Elixir. The Java version used an Actor system and weighed in at around 10,000 lines of code. The new Elixir system has shrunk this to around 1000 lines. The Elixir based system is also faster and more consistent than the Java one and runs on half the number of servers.”&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And [http://www.techworld.com/apps-wearables/how-elixir-helped-bleacher-report-handle-8x-more-traffic-3653957/ Bleacher Report], who went from 150 servers to 5 using Elixir: &amp;amp;gt; &amp;amp;quot;The new language has led to cleaner code base and much less technical debt. It has also increased the speed of development.&lt;br /&gt;
&lt;br /&gt;
Some [https://pragtob.wordpress.com/2017/07/26/choosing-elixir-for-the-code-not-the-performance/ advantages of Elixir for programmers] include:&lt;br /&gt;
&lt;br /&gt;
* No extra engineering spent on “making it faster” (if the runtime is already fast enough they don’t need to bother with caching for example).&lt;br /&gt;
* All the goodies of modern day programming, like a package manager.&lt;br /&gt;
* Pattern Matching: you can make assertions on the structure and can get values directly out of a deeply nested map (or list) and put their value into a variable. You also have method overloading and Elixir will try to match the functions from top to bottom which means you can have different function definitions based on the structure of your input data.&lt;br /&gt;
* Immutable data structures &amp;amp;amp; pure functions: Everything that the function depends on is a parameter, and the only thing that “happens” is the return value of the function. There are no instance variables that are difficult to debug.&lt;br /&gt;
* Explicit code: For example, you explicitly specify a template by name, and pass the values you’ll need from the controller. Ecto also gives you more control over what data will be loaded from the DB.&lt;br /&gt;
* [https://hexdocs.pm/ecto/Ecto.Changeset.html Ecto Changesets]: filtering, casting, validation and definition of constraints when manipulating DB data.&lt;br /&gt;
* Optional type-checking: use [https://github.com/jeremyjh/dialyxir typing only when you want to].&lt;br /&gt;
* Parallelism: it’s not just about performance! Parallelism in the Erlang VM low cost and seamless. Spawning a new process (not like an OS process, they are more like actors) is easy and has a very low overhead, unlike starting a new thread. You can have millions of them on one machine. And thanks to immutability guarantees and every process being isolated you don’t have to worry about processes messing with each other.&lt;br /&gt;
* Doc tests: It is possible to write code examples directly in the documentation of a method. These will be executed during test runs and check if they still return the same values/still pass. They are also included in the generated documentation.&lt;br /&gt;
&lt;br /&gt;
== Reliability ==&lt;br /&gt;
&lt;br /&gt;
While Elixir is a fairly new language, it is mostly a friendly interface to the Erlang virtual machine, which has been used since the 80s to build some of the most reliable systems in the world: telephone systems.&lt;br /&gt;
&lt;br /&gt;
It is made for running a complex system with almost no downtime, like having multiple levels of “supervising” processes in a system to reboot parts that have errors. Basically, microservices before microservices were cool.&lt;br /&gt;
&lt;br /&gt;
== Concurrency ==&lt;br /&gt;
&lt;br /&gt;
CPUs are no longer getting dramatically faster each year. Instead, we get machines with more cores. Our code can run faster, but only if it can run concurrently - meaning, different bits of code run simultaneously on different cores.&lt;br /&gt;
&lt;br /&gt;
The main problem with concurrent code is having two pieces of code mess with the same data at the same time, creating unexpected results. Object-oriented languages like Ruby don’t provide great tools for avoiding such problems. But functional languages, like Elixir, do.&lt;br /&gt;
&lt;br /&gt;
Writing concurrent code in Elixir is extremely easy, and it’s nearly impossible to accidentally interfere with other code that is running at the time.&lt;br /&gt;
&lt;br /&gt;
== Simplicity ==&lt;br /&gt;
&lt;br /&gt;
For modern web applications (written in languages like PHP or Ruby on Rails) to do everything we require of them, they depend on a lot of other pieces running on the server, for example: &lt;br /&gt;
&lt;br /&gt;
* Only one web request can be handled at a time, and it is not possible to spin up new processes as needed, so tools are needed to spawn multiple application servers up front and put a web server like Nginx in front of them to hand off requests. &lt;br /&gt;
* It is not possible to do slow background tasks without blocking web requests, so something like [http://resque.github.io Resque] needs to be added to take care of running background jobs. &lt;br /&gt;
* It is not advisable to use a precious process to maintain a websocket connection with a user, so something like Pusher needs to be added to get realtime functionality (meaning extra costs). &lt;br /&gt;
* It is not possible to keep a big process running all the time to do scheduled tasks, so a dependency on cron needs to be added. &lt;br /&gt;
* No built-in tool for managing multiple parts of a running system currently exists, so tools like [https://www.theforeman.org foreman] are used to start and monitor them.&lt;br /&gt;
&lt;br /&gt;
In Elixir on the other hand, it is possible to spin up a nearly limitless number of processes as needed, so it is possible (in theory) to forego all those tools above.&lt;br /&gt;
&lt;br /&gt;
Elixir code is also simpler to understand than object-oriented code because it has explicitness as a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“Functional programming is associated with concurrency but it was not by design. It just happens that, by making the complex parts of our system explicit, solving more complicated issues like concurrency becomes much simpler.” - [http://www.sitepoint.com/an-interview-with-elixir-creator-jose-valim/ Jose Valim]&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flexibility ==&lt;br /&gt;
&lt;br /&gt;
Using Phoenix and Elixir opens the door to building applications that are not possible with other web frameworks.&lt;br /&gt;
&lt;br /&gt;
The Phoenix framework has first-class support for realtime communication via websockets (with polling as a fallback). In benchmarks, the creators have been able to[http://www.phoenixframework.org/blog/the-road-to-2-million-websocket-connections serve 2 million simultaneously-connected clients]. Additionally, they already have native channel clients for iOS, Android, and Windows devices. With that kind of support, you can confidently build servers to support chat, networked games, and more.&lt;br /&gt;
&lt;br /&gt;
== Correctness ==&lt;br /&gt;
&lt;br /&gt;
In Rails, ActiveRecord encourages developers to do all data validation in application code. However, validations that depend on the state of the database can only be reliably done by the database, using constraints or locks. This includes things like:&lt;br /&gt;
&lt;br /&gt;
* Does any user have this username right now? (uniqueness constraint)&lt;br /&gt;
* Does post 5 exist still right now, before I comment on it? (foreign key constraint)&lt;br /&gt;
* Does this user’s account have enough money to cover this purchase right now? (CHECK constraint)&lt;br /&gt;
* Is this rental property reserved for June 8 right now? (EXCLUDE constraint on date ranges)&lt;br /&gt;
&lt;br /&gt;
It is possible to use such constraints with a Rails application, but it is not typical to do so, and the tools do not encourage it.&lt;br /&gt;
&lt;br /&gt;
Elixir’s [https://hexdocs.pm/ecto/Ecto.html Ecto] database library embraces database constraints, with built-in support for adding them, catching constraint violations, and turning them back into friendly user-facing error messages.&lt;br /&gt;
&lt;br /&gt;
== Where Elixir is especially suited ==&lt;br /&gt;
&lt;br /&gt;
Any project that is a good fit for Rails or Python is something that could be done in Phoenix, especially if the project involves any or multiple of the following:&lt;br /&gt;
&lt;br /&gt;
* System expecting high traffic or requiring very fast / consistent response times&lt;br /&gt;
* Minimal downtime being crucial&lt;br /&gt;
* Realtime updates (eg, stock ticker, social media)&lt;br /&gt;
* Bidirectional realtime communication with websockets (eg, chat, games)&lt;br /&gt;
&lt;br /&gt;
= Drawbacks of Elixir =&lt;br /&gt;
&lt;br /&gt;
Some potential downsides of using Elixir, along with mitigating actions:&lt;br /&gt;
&lt;br /&gt;
* Fewer Elixir developers available. However:&lt;br /&gt;
** There are also significantly fewer projects competing for those people.&lt;br /&gt;
** There is a trend in Ruby developers wanting to cross over to Elixir.&lt;br /&gt;
** Developers with Erlang experience are also well suited.&lt;br /&gt;
** Elixir is a shiny new thing with real promise, which helps attract very enthusiastic developers.&lt;br /&gt;
* While Phoenix is productive, it is not as productive as older frameworks like Rails… yet. Reasons include:&lt;br /&gt;
** Lack of developer experience with Elixir.&lt;br /&gt;
** The relative newness of its open source ecosystem (documentation, forums, example code available).&lt;br /&gt;
** There are fewer libraries in Elixir than in older languages, so there are more times when you’d have to write something yourself. However:&lt;br /&gt;
*** You can use the many existing Erlang libraries.&lt;br /&gt;
*** New Elixir libraries are being added quickly.&lt;br /&gt;
*** Any remaining gaps are a chance to contribute to the community by creating a great open source tool.&lt;br /&gt;
* It may be harder to convince people to use Elixir, given that it’s currently obscure - not in the top [https://www.tiobe.com/tiobe-index/ 50 TIOBE index]. However:&lt;br /&gt;
** Erlang is better-known. Elixir compiles to Erlang bytecode, runs on the Erlang VM and can use or be used by Erlang code. It’s basically “Erlang made friendlier”.&lt;br /&gt;
** Joe Armstrong, co-creator of Erlang, said of pre-1.0 Elixir in 2013 that it was &amp;amp;quot;good s**t&amp;amp;quot;.&lt;br /&gt;
** Therefore, if we can convince someone on Erlang, Elixir is a no-brainer.&lt;br /&gt;
&lt;br /&gt;
= What’s next for MoodleNet’s development =&lt;br /&gt;
&lt;br /&gt;
== A generic agent-centric approach to federation? ==&lt;br /&gt;
&lt;br /&gt;
Another fediverse app being developed in Elixir ([https://github.com/beta-phenylethylamine/fontina Fontina], for photo sharing - although it has been put on hiatus) is now working on a [https://github.com/fontina-project/pubstomp generic ActivityPub server] to serve as back-end (there may be a good opportunity to join efforts…) Here is how the developer describes it: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“I’m working on pubstomp, a generic AP server that is intended for services like mastodon/pixelfed/peertube to work as frontends to it and would indeed support single account [per person, versus having an account on an instance of each of those apps]. &amp;amp;gt; That said, one of my goals down the road is to build”api adaptors&amp;amp;quot; that would basically plug into pubstomp and adapt to, say, the mastoAPI, pleromaAPI, etc.”&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a good example of an &#039;&#039;&#039;agent-centric approach&#039;&#039;&#039;, where instead of having one &#039;&#039;&#039;monolithic app per use-case&#039;&#039;&#039; it is possible instead to separate out federation logic and custom app logic (both back-ends could still share a database on the same server, and share a JavaScript-based front-end app that talks to both APIs).&lt;br /&gt;
&lt;br /&gt;
I started a [https://social.coop/@mayel/100469525067581562 thread about this on the fediverse] (please join the conversation!): &lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;There’s need for a generic agent-centric #ActivityPub server, so that instead of signing up to a bunch of different servers, a user could have their identity and data all in one place, and all the apps they use (clients, but if necessary server-side “plugins” as well) would interact with the activity/objects types that they support.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The plan for Moodlenet (so far) ==&lt;br /&gt;
&lt;br /&gt;
# Fork the Pleroma back-end to create a set of ActivityPub libraries (or a generic ActivityPub server)&lt;br /&gt;
# Add suport for authenticating as OAuth client&lt;br /&gt;
# Add support for group accounts (agents that represent a several users)&lt;br /&gt;
# Create ActivityStreams extensions&lt;br /&gt;
# Test federation&lt;br /&gt;
# Possibly add [https://graphql.org GraphQL] client-server API&lt;br /&gt;
# Create front-end app with React.js (web and mobile)&lt;br /&gt;
&lt;br /&gt;
We are planning to fork the [https://git.pleroma.social/pleroma/pleroma Pleroma back-end] to &#039;&#039;&#039;create a set of ActivityPub/ActivityStreams libraries&#039;&#039;&#039;. If that proves to not be feasible, we will turn it into a generic ActivityPub server back-end that can support any type of activity and object (including extensions to ActivityStreams) and is easily extensible which doesn’t ship with any frontend (possible name: &#039;&#039;Pub of the Commons&#039;&#039;). Pleroma is written with [https://elixir-lang.org Elixir]’s [https://phoenixframework.org Phoenix Framework], and licensed as AGPL (which is also being used for MoodleNet) so the upstream project will be able to use any improvements we make.&lt;br /&gt;
&lt;br /&gt;
Firstly, any parts of the code coming from Pleroma that we don’t needed will be removed (like support for the deprecated OStatus protocol, and the two front-ends which ship with Pleroma - its own Vue.js interface and Mastodon’s React.js interface), and we’ll add some things that can be &#039;&#039;&#039;universally useful&#039;&#039;&#039; like &#039;&#039;&#039;support for groups&#039;&#039;&#039; (actors made of several users), a basic HTML registration/authentication interface (and &#039;&#039;&#039;OAuth client&#039;&#039;&#039; functionality, so users can sign in using their existing accounts elsewhere) so that at least those things can be done without relying on a front-end app.&lt;br /&gt;
&lt;br /&gt;
While we work on creating models/vocabulary for MoodleNet, we can use this generic ActivityPub server to test our ActivityStreams extensions and make sure federation works well in real time (using the API only). Only once that is ready, will we start plugging in custom MoodleNet logic and developing the front-end app (which is the reverse from many fediverse app projects, who have first implemented MVPs of their use case, and then often find it challenging to add federation on top).&lt;br /&gt;
&lt;br /&gt;
Regarding the connection between the back-end and front-end app, the ActivityPub standard comes with a suggested [https://www.w3.org/TR/activitypub/#client-to-server-interactions client-server REST API specification], but for some reason Mastodon and many other fediverse apps have created their own custom REST APIs (and Pleroma implemented Mastodon’s so that it can share front-end apps). So an interesting option at this point for MoodleNet (and &#039;&#039;Pub of the Commons&#039;&#039;), may be to still support Mastodon’s client REST API (for compatibility with existing front-ends like [https://github.com/nolanlawson/pinafore Pinafore]) and additionally to &#039;&#039;&#039;implement a new GraphQL-based API that would allow more flexibility and extensibility between the server and front-end apps&#039;&#039;&#039; (any functionality/activities/objects not supported by Mastodon would only have to be implemented in the server-to-server REST API and the [https://graphql.org GraphQL] API).&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&lt;br /&gt;
* [https://ethercalc.org/fediverse-stacks Spreadsheet of fediverse apps and their stacks]&lt;br /&gt;
* [https://www.w3.org/TR/activitypub/ ActivityPub] standard (for federation)&lt;br /&gt;
* [https://www.w3.org/TR/activitystreams-core/ ActivityStreams] &amp;amp;amp; its [https://www.w3.org/TR/activitystreams-vocabulary/ vocabulary] (which ActivityPub uses as a data format)&lt;br /&gt;
* [https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/ How to implement a basic Mastodon-compatible server]&lt;br /&gt;
* [https://github.com/bignerdranch/why_elixir Why elixir] (big tanks to Big Nerd Ranch for some of the great material used in this doc!)&lt;br /&gt;
* [https://pragtob.wordpress.com/2017/07/26/choosing-elixir-for-the-code-not-the-performance/ Choosing Elixir for the Code, not the Performance]&lt;br /&gt;
* [https://git.pleroma.social/pleroma/pleroma/wikis/Hacking-Pleroma:-Elixir,-Phoenix-and-a-bit-of-ActivityPub Pleroma’s architecture]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/1.0/Decision_Log&amp;diff=54609</id>
		<title>MoodleNet/1.0/Decision Log</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/1.0/Decision_Log&amp;diff=54609"/>
		<updated>2018-08-06T15:41:04Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
This page serves as a log of decisions made during the development of Project MoodleNet, along with a brief justification.&lt;br /&gt;
&lt;br /&gt;
* 6 Aug 18 - [https://docs.moodle.org/dev/MoodleNet/tech/stack Elixir will be the main programming language] used by MoodleNet&#039;s back-end &lt;br /&gt;
* 13th June 18 - Initial integration will be with MoodleCloud, as that makes it easier in terms of versioning and tightly controlling data flows.&lt;br /&gt;
* 6th June 18 - We&#039;re going to use GitLab now that Microsoft has acquired GitHub.&lt;br /&gt;
* 23rd Apr 18 - Martin has decided we are going with the name &#039;MoodleNet&#039;.&lt;br /&gt;
* Feb 18 - the MVP should be focused on resource curation so that we&#039;re not just dropping people into a social network that doesn&#039;t have a particular purpose&lt;br /&gt;
* 9th Jan 18 - Renaming &#039;News feed&#039; component of project to &#039;Activity feed&#039; to more accurately describe what we&#039;re developing.&lt;br /&gt;
* 3rd Jan 18 - Social sign-in shouldn&#039;t be the &#039;&#039;only&#039;&#039; way to log in to Project MoodleNet ([http://dougbelshaw.com/blog/2018/01/03/identity-on-the-web/ rationale])&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/stack&amp;diff=54608</id>
		<title>MoodleNet/tech/stack</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/stack&amp;diff=54608"/>
		<updated>2018-08-06T15:38:58Z</updated>

		<summary type="html">&lt;p&gt;Mayel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Rationale for choosing Elixir for the MoodleNet back-end =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Author:&#039;&#039;&#039; Mayel de Borniol (Technical Architect)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Date:&#039;&#039;&#039; 6 August 2018&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
MoodleNet is a new open social media platform for educators, focused on professional development and open content. It will be an integral part of the Moodle ecosystem.&lt;br /&gt;
&lt;br /&gt;
Just like the ~7,000 languages that are spoken in the world today, there are many different types of programming languages that allow humans to communicate with computers (and tell them nicely what to do). An important decision for our team was what technical language(s) Moodlenet should speak, and this document highlights the decision-making process which ended up with choosing the ‘Elixir’ language.&lt;br /&gt;
&lt;br /&gt;
== Research process ==&lt;br /&gt;
&lt;br /&gt;
The process began with an extensive review of web application programming languages. More specifically, the technologies used for apps based on [https://en.wikipedia.org/wiki/ActivityPub ActivityPub federation standard] - which will enable MoodleNet to be a &#039;&#039;&#039;decentralised platform, you will be able self-host an instance&#039;&#039;&#039; (just like you can install Moodle on a server, and customise it) but all the instances will be &#039;&#039;&#039;interconnected&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A [https://ethercalc.org/fediverse-stacks spreadsheet of fediverse apps and their stacks] (and [https://social.coop/@mayel/100469319126679591 crowdsourced extra information via the fediverse]) was compiled. This showed that besides Ruby on Rails, there were a few ActivityPub projects using Python (and a couple intending to use PHP) and some other languages, however, most projects are still in early development and many are not yet federated. Considering that &#039;&#039;&#039;ActivityPub is still relatively new it is understandable that there are limited examples of full implementations&#039;&#039;&#039;, let alone ones that are proven to work and be interoperable.&lt;br /&gt;
&lt;br /&gt;
One of the first languages that stood out was Go, one of the only a few to actually have an [https://github.com/go-fed/activity ActivityPub library]. The developer was contacted and offered his assistance for future collaboration (although in full-time employment and developing the Go library in his spare time). What this meant was that the MoodleNet team would have to modify the library in order to tailor it to the project’s needs. The main obstacle to this, however, is that Go is a ‘statically typed’ language which means every ActivityStreams extension would have to be hard coded pre-compilation. This would make things less flexible, so this option was set aside.&lt;br /&gt;
&lt;br /&gt;
Alongside researching the documentations, codebases, issue trackers and communicating with developers of the apps in the spreadsheet, many of them were installed and tested (including Mastodon, Pleroma, and Prismo). The latter, while having some functionality that MoodleNet will need, confirmed an earlier impression from running a Mastodon instance: &#039;&#039;&#039;Rails apps tend to not be lightweight and often rely on many external dependencies&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
After comparing the possible language candidates, the focus shifted on detailing the pros and cons for each, finally focusing on the following:&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;[https://en.wikipedia.org/wiki/BEAM_(Erlang_virtual_machine) Erlang VM]&#039;&#039;&#039; is time tested (more than 20 years old), very fast and has good concurrency and inter-process communication (called OTP).&lt;br /&gt;
* &#039;&#039;&#039;[https://elixir-lang.org Elixir]&#039;&#039;&#039; is a new (7+ years) functional language designed for productivity and maintainability that runs on the Erlang VM.&lt;br /&gt;
* &#039;&#039;&#039;[https://phoenixframework.org Phoenix]&#039;&#039;&#039; is a modern web framework that makes building APIs and web applications easy. Since it’s built with Elixir and runs on Erlang VM, it is very fast and has excellent support for handling very large numbers of simultaneous users.&lt;br /&gt;
&lt;br /&gt;
= Benefits of Elixir =&lt;br /&gt;
&lt;br /&gt;
A list of reasons to use Elixir in our context:&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
The Phoenix web framework has been found to perform better than Rails, PHP, and Python. [https://github.com/mroth/phoenix-showdown/blob/master/README.md#benchmarking One benchmark] showed Phoenix handling over 10x more requests than Rails in a given period. Phoenix was also much more consistent under load - Rails was more prone to have some requests bog down. This can cause a “chain reaction”, because Rails apps are configured with a fixed number of application processes, so if some of them are slow, it can mean that others have to wait in line, which dramatically increases the app’s response time.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Phoenix apps &#039;&#039;&#039;without caching&#039;&#039;&#039; drastically outperform Rails apps &#039;&#039;&#039;with caching&#039;&#039;&#039;. This is important because caching is notorious for being a source of complexity and bugs, and because caching can’t be used for moment-by-moment, personalised content. The [https://youtu.be/AdY5AfXs7aw?t=3m14s Bleacher Report] for example went from over 100 AWS servers to 5, with CPU usage rarely going above 10%, and saw a 10x performance improvement over their Rails app.&lt;br /&gt;
&lt;br /&gt;
There are a growing number of software projects using Elixir - e.g. Pinterest [https://github.com/bignerdranch/why_elixir who say]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“We like Elixir and have seen some pretty big wins with it. The system that manages rate limits for both the Pinterest API and Ads API is built in Elixir. Its 50 percent response time is around 500 microseconds with a 90 percent response time of 800 microseconds. Yes, microseconds.”&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And an [https://blog.carbonfive.com/2016/04/19/elixir-and-phoenix-the-future-of-web-apis-and-apps/ adopter of the Phoenix framework] says: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“A rather large JSON request was taking about 1.5-2.0s against our Rails backend (no caching). That same request (same h/w, database queries and data) takes about 400ms with Phoenix. Our entire application went from using just shy of 1 GB across 2 dynos to a single dyno using less than 100 MB. That single dyno is notably faster and can handle higher concurrency (about 10x). Importantly, Phoenix (without caching) performs better than Rails (with caching).”&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One thing that makes Erlang/Elixir so efficient is [https://www.brianstorti.com/the-actor-model/ the actor model], which ActivityPub seems to have taken inspiration from.&lt;br /&gt;
&lt;br /&gt;
== Scalability ==&lt;br /&gt;
&lt;br /&gt;
The Erlang VM’s model of concurrency is great for multi-core CPUs, but it was created before they existed. Its original purpose was to support concurrency and fault-tolerance via the use of many different machines. This makes it an excellent tool for building systems that can handle more load by simply adding more servers.&lt;br /&gt;
&lt;br /&gt;
As the [http://ninenines.eu/docs/en/cowboy/2.0/guide/erlang_web/ docs for an Erlang web server] put it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“At the time of writing there are application servers written in Erlang that can handle more than two million connections on a single server in a real production application, with spare memory and CPU! The Web is concurrent, and Erlang is a language designed for concurrency, so it is a perfect match. &amp;lt;br&amp;gt;&amp;lt;br&amp;gt; Of course, various platforms need to scale beyond a few million connections. This is where Erlang’s built-in distribution mechanisms come in. If one server isn’t enough, add more! Erlang allows you to use the same code for talking to local processes or to processes in other parts of your cluster, which means you can scale very quickly if the need arises.”&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Developer Productivity &amp;amp;amp; Happiness ==&lt;br /&gt;
&lt;br /&gt;
When people argue about programming languages, often the performance card is pulled (“this language is so much faster in these benchmarks”). But performance isn’t the only consideration: while it’s possible to just add more servers, developer time often costs more than servers.&lt;br /&gt;
&lt;br /&gt;
More important then is which framework helps write software faster, of a better quality, and which benefits the programmer’s wellbeing.&lt;br /&gt;
&lt;br /&gt;
As Pinterest concluded from using Elixir:  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“We’ve also seen an improvement in code clarity. We’re converting our notifications system from Java to Elixir. The Java version used an Actor system and weighed in at around 10,000 lines of code. The new Elixir system has shrunk this to around 1000 lines. The Elixir based system is also faster and more consistent than the Java one and runs on half the number of servers.”&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And [http://www.techworld.com/apps-wearables/how-elixir-helped-bleacher-report-handle-8x-more-traffic-3653957/ Bleacher Report], who went from 150 servers to 5 using Elixir: &amp;amp;gt; &amp;amp;quot;The new language has led to cleaner code base and much less technical debt. It has also increased the speed of development.&lt;br /&gt;
&lt;br /&gt;
Some [https://pragtob.wordpress.com/2017/07/26/choosing-elixir-for-the-code-not-the-performance/ advantages of Elixir for programmers] include:&lt;br /&gt;
&lt;br /&gt;
* No extra engineering spent on “making it faster” (if the runtime is already fast enough they don’t need to bother with caching for example).&lt;br /&gt;
* All the goodies of modern day programming, like a package manager.&lt;br /&gt;
* Pattern Matching: you can make assertions on the structure and can get values directly out of a deeply nested map (or list) and put their value into a variable. You also have method overloading and Elixir will try to match the functions from top to bottom which means you can have different function definitions based on the structure of your input data.&lt;br /&gt;
* Immutable data structures &amp;amp;amp; pure functions: Everything that the function depends on is a parameter, and the only thing that “happens” is the return value of the function. There are no instance variables that are difficult to debug.&lt;br /&gt;
* Explicit code: For example, you explicitly specify a template by name, and pass the values you’ll need from the controller. Ecto also gives you more control over what data will be loaded from the DB.&lt;br /&gt;
* [https://hexdocs.pm/ecto/Ecto.Changeset.html Ecto Changesets]: filtering, casting, validation and definition of constraints when manipulating DB data.&lt;br /&gt;
* Optional type-checking: use [https://github.com/jeremyjh/dialyxir typing only when you want to].&lt;br /&gt;
* Parallelism: it’s not just about performance! Parallelism in the Erlang VM low cost and seamless. Spawning a new process (not like an OS process, they are more like actors) is easy and has a very low overhead, unlike starting a new thread. You can have millions of them on one machine. And thanks to immutability guarantees and every process being isolated you don’t have to worry about processes messing with each other.&lt;br /&gt;
* Doc tests: It is possible to write code examples directly in the documentation of a method. These will be executed during test runs and check if they still return the same values/still pass. They are also included in the generated documentation.&lt;br /&gt;
&lt;br /&gt;
== Reliability ==&lt;br /&gt;
&lt;br /&gt;
While Elixir is a fairly new language, it is mostly a friendly interface to the Erlang virtual machine, which has been used since the 80s to build some of the most reliable systems in the world: telephone systems.&lt;br /&gt;
&lt;br /&gt;
It is made for running a complex system with almost no downtime, like having multiple levels of “supervising” processes in a system to reboot parts that have errors. Basically, microservices before microservices were cool.&lt;br /&gt;
&lt;br /&gt;
== Concurrency ==&lt;br /&gt;
&lt;br /&gt;
CPUs are no longer getting dramatically faster each year. Instead, we get machines with more cores. Our code can run faster, but only if it can run concurrently - meaning, different bits of code run simultaneously on different cores.&lt;br /&gt;
&lt;br /&gt;
The main problem with concurrent code is having two pieces of code mess with the same data at the same time, creating unexpected results. Object-oriented languages like Ruby don’t provide great tools for avoiding such problems. But functional languages, like Elixir, do.&lt;br /&gt;
&lt;br /&gt;
Writing concurrent code in Elixir is extremely easy, and it’s nearly impossible to accidentally interfere with other code that is running at the time.&lt;br /&gt;
&lt;br /&gt;
== Simplicity ==&lt;br /&gt;
&lt;br /&gt;
For modern web applications (written in languages like PHP or Ruby on Rails) to do everything we require of them, they depend on a lot of other pieces running on the server, for example: &lt;br /&gt;
&lt;br /&gt;
* Only one web request can be handled at a time, and it is not possible to spin up new processes as needed, so tools are needed to spawn multiple application servers up front and put a web server like Nginx in front of them to hand off requests. &lt;br /&gt;
* It is not possible to do slow background tasks without blocking web requests, so something like [http://resque.github.io Resque] needs to be added to take care of running background jobs. &lt;br /&gt;
* It is not advisable to use a precious process to maintain a websocket connection with a user, so something like Pusher needs to be added to get realtime functionality (meaning extra costs). &lt;br /&gt;
* It is not possible to keep a big process running all the time to do scheduled tasks, so a dependency on cron needs to be added. &lt;br /&gt;
* No built-in tool for managing multiple parts of a running system currently exists, so tools like [https://www.theforeman.org foreman] are used to start and monitor them.&lt;br /&gt;
&lt;br /&gt;
In Elixir on the other hand, it is possible to spin up a nearly limitless number of processes as needed, so it is possible (in theory) to forego all those tools above.&lt;br /&gt;
&lt;br /&gt;
Elixir code is also simpler to understand than object-oriented code because it has explicitness as a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“Functional programming is associated with concurrency but it was not by design. It just happens that, by making the complex parts of our system explicit, solving more complicated issues like concurrency becomes much simpler.” - [http://www.sitepoint.com/an-interview-with-elixir-creator-jose-valim/ Jose Valim]&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flexibility ==&lt;br /&gt;
&lt;br /&gt;
Using Phoenix and Elixir opens the door to building applications that are not possible with other web frameworks.&lt;br /&gt;
&lt;br /&gt;
The Phoenix framework has first-class support for realtime communication via websockets (with polling as a fallback). In benchmarks, the creators have been able to[http://www.phoenixframework.org/blog/the-road-to-2-million-websocket-connections serve 2 million simultaneously-connected clients]. Additionally, they already have native channel clients for iOS, Android, and Windows devices. With that kind of support, you can confidently build servers to support chat, networked games, and more.&lt;br /&gt;
&lt;br /&gt;
== Correctness ==&lt;br /&gt;
&lt;br /&gt;
In Rails, ActiveRecord encourages developers to do all data validation in application code. However, validations that depend on the state of the database can only be reliably done by the database, using constraints or locks. This includes things like:&lt;br /&gt;
&lt;br /&gt;
* Does any user have this username right now? (uniqueness constraint)&lt;br /&gt;
* Does post 5 exist still right now, before I comment on it? (foreign key constraint)&lt;br /&gt;
* Does this user’s account have enough money to cover this purchase right now? (CHECK constraint)&lt;br /&gt;
* Is this rental property reserved for June 8 right now? (EXCLUDE constraint on date ranges)&lt;br /&gt;
&lt;br /&gt;
It is possible to use such constraints with a Rails application, but it is not typical to do so, and the tools do not encourage it.&lt;br /&gt;
&lt;br /&gt;
Elixir’s [https://hexdocs.pm/ecto/Ecto.html Ecto] database library embraces database constraints, with built-in support for adding them, catching constraint violations, and turning them back into friendly user-facing error messages.&lt;br /&gt;
&lt;br /&gt;
== Where Elixir is especially suited ==&lt;br /&gt;
&lt;br /&gt;
Any project that is a good fit for Rails or Python is something that could be done in Phoenix, especially if the project involves any or multiple of the following:&lt;br /&gt;
&lt;br /&gt;
* System expecting high traffic or requiring very fast / consistent response times&lt;br /&gt;
* Minimal downtime being crucial&lt;br /&gt;
* Realtime updates (eg, stock ticker, social media)&lt;br /&gt;
* Bidirectional realtime communication with websockets (eg, chat, games)&lt;br /&gt;
&lt;br /&gt;
= Drawbacks of Elixir =&lt;br /&gt;
&lt;br /&gt;
Some potential downsides of using Elixir, along with mitigating actions:&lt;br /&gt;
&lt;br /&gt;
* Fewer Elixir developers available. However:&lt;br /&gt;
** There are also significantly fewer projects competing for those people.&lt;br /&gt;
** There is a trend in Ruby developers wanting to cross over to Elixir.&lt;br /&gt;
** Developers with Erlang experience are also well suited.&lt;br /&gt;
** Elixir is a shiny new thing with real promise, which helps attract very enthusiastic developers.&lt;br /&gt;
* While Phoenix is productive, it is not as productive as older frameworks like Rails… yet. Reasons include:&lt;br /&gt;
** Lack of developer experience with Elixir.&lt;br /&gt;
** The relative newness of its open source ecosystem (documentation, forums, example code available).&lt;br /&gt;
** There are fewer libraries in Elixir than in older languages, so there are more times when you’d have to write something yourself. However:&lt;br /&gt;
*** You can use the many existing Erlang libraries.&lt;br /&gt;
*** New Elixir libraries are being added quickly.&lt;br /&gt;
*** Any remaining gaps are a chance to contribute to the community by creating a great open source tool.&lt;br /&gt;
* It may be harder to convince people to use Elixir, given that it’s currently obscure - not in the top [https://www.tiobe.com/tiobe-index/ 50 TIOBE index]. However:&lt;br /&gt;
** Erlang is better-known. Elixir compiles to Erlang bytecode, runs on the Erlang VM and can use or be used by Erlang code. It’s basically “Erlang made friendlier”.&lt;br /&gt;
** Joe Armstrong, co-creator of Erlang, said of pre-1.0 Elixir in 2013 that it was &amp;amp;quot;good s**t&amp;amp;quot;.&lt;br /&gt;
** Therefore, if we can convince someone on Erlang, Elixir is a no-brainer.&lt;br /&gt;
&lt;br /&gt;
= What’s next for MoodleNet’s development =&lt;br /&gt;
&lt;br /&gt;
== A generic agent-centric approach to federation? ==&lt;br /&gt;
&lt;br /&gt;
Another fediverse app being developed in Elixir ([https://github.com/beta-phenylethylamine/fontina Fontina], for photo sharing - although it has been put on hiatus) is now working on a [https://github.com/fontina-project/pubstomp generic ActivityPub server] to serve as back-end (there may be a good opportunity to join efforts…) Here is how the developer describes it: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“I’m working on pubstomp, a generic AP server that is intended for services like mastodon/pixelfed/peertube to work as frontends to it and would indeed support single account [per person, versus having an account on an instance of each of those apps]. &amp;amp;gt; That said, one of my goals down the road is to build”api adaptors&amp;amp;quot; that would basically plug into pubstomp and adapt to, say, the mastoAPI, pleromaAPI, etc.”&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a good example of an &#039;&#039;&#039;agent-centric approach&#039;&#039;&#039;, where instead of having one &#039;&#039;&#039;monolithic app per use-case&#039;&#039;&#039; it is possible instead to separate out federation logic and custom app logic (both back-ends could still share a database on the same server, and share a JavaScript-based front-end app that talks to both APIs).&lt;br /&gt;
&lt;br /&gt;
I started a [https://social.coop/@mayel/100469525067581562 thread about this on the fediverse] (please join the conversation!): &lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;There’s need for a generic agent-centric #ActivityPub server, so that instead of signing up to a bunch of different servers, a user could have their identity and data all in one place, and all the apps they use (clients, but if necessary server-side “plugins” as well) would interact with the activity/objects types that they support.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The plan for Moodlenet (so far) ==&lt;br /&gt;
&lt;br /&gt;
# Fork the Pleroma back-end to create a set of ActivityPub libraries (or a generic ActivityPub server)&lt;br /&gt;
# Add suport for authenticating as OAuth client&lt;br /&gt;
# Add support for group accounts (agents that represent a several users)&lt;br /&gt;
# Create ActivityStreams extensions&lt;br /&gt;
# Test federation&lt;br /&gt;
# Possibly add [https://graphql.org GraphQL] client-server API&lt;br /&gt;
# Create front-end app with React.js (web and mobile)&lt;br /&gt;
&lt;br /&gt;
We are planning to fork the [https://git.pleroma.social/pleroma/pleroma Pleroma back-end] to &#039;&#039;&#039;create a set of ActivityPub/ActivityStreams libraries&#039;&#039;&#039;. If that proves to not be feasible, we will turn it into a generic ActivityPub server back-end that can support any type of activity and object (including extensions to ActivityStreams) and is easily extensible which doesn’t ship with any frontend (possible name: &#039;&#039;Pub of the Commons&#039;&#039;). Pleroma is written with [https://elixir-lang.org Elixir]’s [https://phoenixframework.org Phoenix Framework], and licensed as AGPL (which is also being used for MoodleNet) so the upstream project will be able to use any improvements we make.&lt;br /&gt;
&lt;br /&gt;
Firstly, any parts of the code coming from Pleroma that we don’t needed will be removed (like support for the deprecated OStatus protocol, and the two front-ends which ship with Pleroma - its own Vue.js interface and Mastodon’s React.js interface), and we’ll add some things that can be &#039;&#039;&#039;universally useful&#039;&#039;&#039; like &#039;&#039;&#039;support for groups&#039;&#039;&#039; (actors made of several users), a basic HTML registration/authentication interface (and &#039;&#039;&#039;OAuth client&#039;&#039;&#039; functionality, so users can sign in using their existing accounts elsewhere) so that at least those things can be done without relying on a front-end app.&lt;br /&gt;
&lt;br /&gt;
While we work on creating models/vocabulary for MoodleNet, we can use this generic ActivityPub server to test our ActivityStreams extensions and make sure federation works well in real time (using the API only). Only once that is ready, will we start plugging in custom MoodleNet logic and developing the front-end app (which is the reverse from many fediverse app projects, who have first implemented MVPs of their use case, and then often find it challenging to add federation on top).&lt;br /&gt;
&lt;br /&gt;
Regarding the connection between the back-end and front-end app, the ActivityPub standard comes with a suggested [https://www.w3.org/TR/activitypub/#client-to-server-interactions client-server REST API specification], but for some reason Mastodon and many other fediverse apps have created their own custom REST APIs (and Pleroma implemented Mastodon’s so that it can share front-end apps). So an interesting option at this point for MoodleNet (and &#039;&#039;Pub of the Commons&#039;&#039;), may be to still support Mastodon’s client REST API (for compatibility with existing front-ends like [https://github.com/nolanlawson/pinafore Pinafore]) and additionally to &#039;&#039;&#039;implement a new GraphQL-based API that would allow more flexibility and extensibility between the server and front-end apps&#039;&#039;&#039; (any functionality/activities/objects not supported by Mastodon would only have to be implemented in the server-to-server REST API and the [https://graphql.org GraphQL] API).&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&lt;br /&gt;
* [https://ethercalc.org/fediverse-stacks Spreadsheet of fediverse apps and their stacks]&lt;br /&gt;
* [https://www.w3.org/TR/activitypub/ ActivityPub] standard (for federation)&lt;br /&gt;
* [https://www.w3.org/TR/activitystreams-core/ ActivityStreams] &amp;amp;amp; its [https://www.w3.org/TR/activitystreams-vocabulary/ vocabulary] (which ActivityPub uses as a data format)&lt;br /&gt;
* [https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/ How to implement a basic Mastodon-compatible server]&lt;br /&gt;
* [https://github.com/bignerdranch/why_elixir Why elixir] (big tanks to Big Nerd Ranch for some of the great material used in this doc!)&lt;br /&gt;
* [https://pragtob.wordpress.com/2017/07/26/choosing-elixir-for-the-code-not-the-performance/ Choosing Elixir for the Code, not the Performance]&lt;br /&gt;
* [https://git.pleroma.social/pleroma/pleroma/wikis/Hacking-Pleroma:-Elixir,-Phoenix-and-a-bit-of-ActivityPub Pleroma’s architecture]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/stack&amp;diff=54598</id>
		<title>MoodleNet/tech/stack</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/tech/stack&amp;diff=54598"/>
		<updated>2018-08-06T14:42:07Z</updated>

		<summary type="html">&lt;p&gt;Mayel: Created page with &amp;quot;= Rationale for choosing Elixir for the MoodleNet back-end =  &amp;#039;&amp;#039;&amp;#039;Author:&amp;#039;&amp;#039;&amp;#039; Mayel de Borniol (Technical Architect)  &amp;#039;&amp;#039;&amp;#039;Date:&amp;#039;&amp;#039;&amp;#039; 6 August 2018   -----  == Introduction ==  Mood...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Rationale for choosing Elixir for the MoodleNet back-end =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Author:&#039;&#039;&#039; Mayel de Borniol (Technical Architect)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Date:&#039;&#039;&#039; 6 August 2018&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
MoodleNet is a new open social media platform for educators, focussed on professional development and open content. It will be an integral part of the Moodle ecosystem.&lt;br /&gt;
&lt;br /&gt;
Just like the ~7,000 languages that are spoken in the world today, there many different types of programming languages that allow humans to communicate with computers (and tell them nicely what to do). An important decision for our team was what technical language(s) Moodlenet should speak, and this document highlights the decision-making process which ended up with choosing the ‘Elixir’ language.&lt;br /&gt;
&lt;br /&gt;
== Research process ==&lt;br /&gt;
&lt;br /&gt;
The process began with an extensive review of web application appprogramming languages. More specifically, the technologies used for apps based on [https://en.wikipedia.org/wiki/ActivityPub ActivityPub federation standard] - which will enable MoodleNet to be a &#039;&#039;&#039;decentralised platform, you will be able self-host an instance&#039;&#039;&#039; (just like you can install Moodle on a server, and customise it) but all the instances will be &#039;&#039;&#039;interconnected&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A [https://ethercalc.org/fediverse-stacks spreadsheet of fediverse apps and their stacks] (and [https://social.coop/@mayel/100469319126679591 crowdsourced extra information via the fediverse]) was compiled. This showed that besides Ruby on Rails, there were a few ActivityPub projects using Python (and a couple intending to use PHP) and some other languages, however, most projects are still in early development and many are not yet federated. Considering that &#039;&#039;&#039;ActivityPub is still relatively new it is understandable that there are limited examples of full implementations&#039;&#039;&#039;, let alone ones that are proven to work and be interoperable.&lt;br /&gt;
&lt;br /&gt;
One of the first languages that stood out was Go, one of the only a few to actually have an [https://github.com/go-fed/activity ActivityPub library]. The developer was contacted and offered his assistance for future collaboration (although in full-time employment and developing the Go library in his spare time). What this meant was that the MoodleNet team would have to modify the library in order to tailor it to the project’s needs. The main obstacle to this, however, is that Go is a ‘statically typed’ language which means every ActivityStreams extension would have to be hard coded pre-compilation. This would make things less flexible, so this option was set aside.&lt;br /&gt;
&lt;br /&gt;
Alongside researching the documentations, codebases, issue trackers and communicating with developers of the apps in the spreadsheet, many of them were installed and tested (including Mastodon, Pleroma, and Prismo). The latter, while having some functionality that MoodleNet will need, confirmed an earlier impression from running a Mastodon instance: &#039;&#039;&#039;Rails apps tend to not be lightweight and often rely on many external dependencies&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
After comparing the possible language candidates, the focus shifted on detailing the pros and cons for each, finaly focusing on the following:&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;[https://en.wikipedia.org/wiki/BEAM_(Erlang_virtual_machine) Erlang VM]&#039;&#039;&#039; is time tested (more than 20 years old), very fast and has good concurrency and inter-process communication (called OTP).&lt;br /&gt;
* &#039;&#039;&#039;[https://elixir-lang.org Elixir]&#039;&#039;&#039; is a new (7+ years) functional language designed for productivity and maintainability that runs on the Erlang VM.&lt;br /&gt;
* &#039;&#039;&#039;[https://phoenixframework.org Phoenix]&#039;&#039;&#039; is a modern web framework that makes building APIs and web applications easy. Since it’s built with Elixir and runs on Erlang VM, it is very fast and has excellent support for handling very large numbers of simultaneous users.&lt;br /&gt;
&lt;br /&gt;
= Benefits of Elixir =&lt;br /&gt;
&lt;br /&gt;
A list of reasons to use Elixir in our context:&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
The Phoenix web framework has been found to perform better than Rails, PHP, and Python. [https://github.com/mroth/phoenix-showdown/blob/master/README.md#benchmarking One benchmark] showed Phoenix handling over 10x more requests than Rails in a given period. Phoenix was also much more consistent under load - Rails was more prone to have some requests bog down. This can cause a “chain reaction”, because Rails apps are configured with a fixed number of application processes, so if some of them are slow, it can mean that others have to wait in line, which dramatically increases the app’s response time.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Phoenix apps &#039;&#039;&#039;without caching&#039;&#039;&#039; drastically outperform Rails apps &#039;&#039;&#039;with caching&#039;&#039;&#039;. This is important because caching is notorious for being a source of complexity and bugs, and because caching can’t be used for moment-by-moment, personalized content. The [https://youtu.be/AdY5AfXs7aw?t=3m14s Bleacher Report] for example went from over 100 AWS servers to 5, with CPU usage rarely going above 10%, and saw a 10x performance improvement over their Rails app.&lt;br /&gt;
&lt;br /&gt;
There are a growing number of software projects using Elixir - e.g. Pinterest [https://github.com/bignerdranch/why_elixir who say]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“We like Elixir and have seen some pretty big wins with it. The system that manages rate limits for both the Pinterest API and Ads API is built in Elixir. Its 50 percent response time is around 500 microseconds with a 90 percent response time of 800 microseconds. Yes, microseconds.”&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
And an [https://blog.carbonfive.com/2016/04/19/elixir-and-phoenix-the-future-of-web-apis-and-apps/ adopter of the Phoenix framework] says: &amp;amp;gt; “A rather large JSON request was taking about 1.5-2.0s against our Rails backend (no caching). That same request (same h/w, database queries and data) takes about 400ms with Phoenix. Our entire application went from using just shy of 1 GB across 2 dynos to a single dyno using less than 100 MB. That single dyno is notably faster and can handle higher concurrency (about 10x). Importantly, Phoenix (without caching) performs better than Rails (with caching).”&lt;br /&gt;
&lt;br /&gt;
One thing that makes Erlang/Elixir so efficient is [https://www.brianstorti.com/the-actor-model/ the actor model], which ActivityPub seems to have taken inspiration from.&lt;br /&gt;
&lt;br /&gt;
== Scalability ==&lt;br /&gt;
&lt;br /&gt;
The Erlang VM’s model of concurrency is great for multi-core CPUs, but it was created before they existed. Its original purpose was to support concurrency and fault-tolerance via the use of many different machines. This makes it an excellent tool for building systems that can handle more load by simply adding more servers.&lt;br /&gt;
&lt;br /&gt;
As the [http://ninenines.eu/docs/en/cowboy/2.0/guide/erlang_web/ docs for an Erlang web server] put it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“At the time of writing there are application servers written in Erlang that can handle more than two million connections on a single server in a real production application, with spare memory and CPU! The Web is concurrent, and Erlang is a language designed for concurrency, so it is a perfect match. &amp;lt;br&amp;gt;&amp;lt;br&amp;gt; Of course, various platforms need to scale beyond a few million connections. This is where Erlang’s built-in distribution mechanisms come in. If one server isn’t enough, add more! Erlang allows you to use the same code for talking to local processes or to processes in other parts of your cluster, which means you can scale very quickly if the need arises.”&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
== Developer Productivity &amp;amp;amp; Happiness ==&lt;br /&gt;
&lt;br /&gt;
When people argue about programming languages, often the performance card is pulled (“this language is so much faster in these benchmarks”). But performance isn’t the only consideration: while it’s possible to just add more servers, developer time often costs more than servers.&lt;br /&gt;
&lt;br /&gt;
More important then is which framework helps write software faster, of a better quality, and which benefits the programmer’s wellbeing.&lt;br /&gt;
&lt;br /&gt;
As Pinterest concluded from using Elixir: &amp;amp;gt; “We’ve also seen an improvement in code clarity. We’re converting our notifications system from Java to Elixir. The Java version used an Actor system and weighed in at around 10,000 lines of code. The new Elixir system has shrunk this to around 1000 lines. The Elixir based system is also faster and more consistent than the Java one and runs on half the number of servers.”&lt;br /&gt;
&lt;br /&gt;
And [http://www.techworld.com/apps-wearables/how-elixir-helped-bleacher-report-handle-8x-more-traffic-3653957/ Bleacher Report], who went from 150 servers to 5 using Elixir: &amp;amp;gt; &amp;amp;quot;The new language has led to cleaner code base and much less technical debt. It has also increased the speed of development.&lt;br /&gt;
&lt;br /&gt;
Some [https://pragtob.wordpress.com/2017/07/26/choosing-elixir-for-the-code-not-the-performance/ advantages of Elixir for programmers] include:&lt;br /&gt;
&lt;br /&gt;
* No extra engineering spent on “making it faster” (if the runtime is already fast enough they don’t need to bother with caching for example).&lt;br /&gt;
* All the goodies of modern day programming, like a package manager.&lt;br /&gt;
* Pattern Matching: you can make assertions on the structure and can get values directly out of a deeply nested map (or list) and put their value into a variable. You also have method overloading and Elixir will try to match the functions from top to bottom which means you can have different function definitions based on the structure of your input data.&lt;br /&gt;
* Immutable data structures &amp;amp;amp; pure functions: Everything that the function depends on is a parameter, and the only thing that “happens” is the return value of the function. There are no instance variables that are difficult to debug.&lt;br /&gt;
* Explicit code: For example, you explicitly specify a template by name, and pass the values you’ll need from the controller. Ecto also gives you more control over what data will be loaded from the DB.&lt;br /&gt;
* [https://hexdocs.pm/ecto/Ecto.Changeset.html Ecto Changesets]: filtering, casting, validation and definition of constraints when manipulating DB data.&lt;br /&gt;
* Optional type-checking: use [https://github.com/jeremyjh/dialyxir typing only when you want to].&lt;br /&gt;
* Parallelism: it’s not just about performance! Parallelism in the Erlang VM low cost and seamless. Spawning a new process (not like an OS process, they are more like actors) is easy and has a very low overhead, unlike starting a new thread. You can have millions of them on one machine. And thanks to immutability guarantees and every process being isolated you don’t have to worry about processes messing with each other.&lt;br /&gt;
* Doc tests: It is possible to write code examples directly in the documentation of a method. These will be executed during test runs and check if they still return the same values/still pass. They are also included in the generated documentation.&lt;br /&gt;
&lt;br /&gt;
== Reliability ==&lt;br /&gt;
&lt;br /&gt;
While Elixir is a fairly new language, it is mostly a friendly interface to the Erlang virtual machine, which has been used since the 80s to build some of the most reliable systems in the world: telephone systems.&lt;br /&gt;
&lt;br /&gt;
It is made for running a complex system with almost no downtime, like having multiple levels of “supervising” processes in a system to reboot parts that have errors. Basically, microservices before microservices were cool.&lt;br /&gt;
&lt;br /&gt;
== Concurrency ==&lt;br /&gt;
&lt;br /&gt;
CPUs are no longer getting dramatically faster each year. Instead, we get machines with more cores. Our code can run faster, but only if it can run concurrently - meaning, different bits of code run simultaneously on different cores.&lt;br /&gt;
&lt;br /&gt;
The main problem with concurrent code is having two pieces of code mess with the same data at the same time, creating unexpected results. Object-oriented languages like Ruby don’t provide great tools for avoiding such problems. But functional languages, like Elixir, do.&lt;br /&gt;
&lt;br /&gt;
Writing concurrent code in Elixir is extremely easy, and it’s nearly impossible to accidentally interfere with other code that is running at the time.&lt;br /&gt;
&lt;br /&gt;
== Simplicity ==&lt;br /&gt;
&lt;br /&gt;
For modern web applications (written in languages like PHP or Ruby on Rails) to do everything we require of them, they depend on a lot of other pieces running on the server, for example: * Only one web request can be handled at a time, and it is not possible to spin up new processes as needed, so tools are needed to spawn multiple application servers up front and put a web server like Nginx in front of them to hand off requests. * It is not possible to do slow background tasks without blocking web requests, so something like [http://resque.github.io Resque] needs to be added to take care of running background jobs. * It is not advisable to use a precious process to maintain a websocket connection with a user, so something like Pusher needs to be added to get realtime functionality (meaning extra costs). * It is not possible to keep a big process running all the time to do scheduled tasks, so a dependency on cron needs to be added. * No built-in tool for managing multiple parts of a running system currently exists, so tools like [https://www.theforeman.org foreman] are used to start and monitor them.&lt;br /&gt;
&lt;br /&gt;
In Elixir on the other hand, it is possible to spin up a nearly limitless number of processes as needed, so it is possible (in theory) to forego all those tools above.&lt;br /&gt;
&lt;br /&gt;
Elixir code is also simpler to understand than object-oriented code because it has explicitness as a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“Functional programming is associated with concurrency but it was not by design. It just happens that, by making the complex parts of our system explicit, solving more complicated issues like concurrency becomes much simpler.” - [http://www.sitepoint.com/an-interview-with-elixir-creator-jose-valim/ Jose Valim]&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
== Flexibility ==&lt;br /&gt;
&lt;br /&gt;
Using Phoenix and Elixir opens the door to building applications that are not possible with other web frameworks.&lt;br /&gt;
&lt;br /&gt;
The Phoenix framework has first-class support for realtime communication via websockets (with polling as a fallback). In benchmarks, the creators have been able to[http://www.phoenixframework.org/blog/the-road-to-2-million-websocket-connections serve 2 million simultaneously-connected clients]. Additionally, they already have native channel clients for iOS, Android, and Windows devices. With that kind of support, you can confidently build servers to support chat, networked games, and more.&lt;br /&gt;
&lt;br /&gt;
== Correctness ==&lt;br /&gt;
&lt;br /&gt;
In Rails, ActiveRecord encourages developers to do all data validation in application code. However, validations that depend on the state of the database can only be reliably done by the database, using constraints or locks. This includes things like:&lt;br /&gt;
&lt;br /&gt;
* Does any user have this username right now? (uniqueness constraint)&lt;br /&gt;
* Does post 5 exist still right now, before I comment on it? (foreign key constraint)&lt;br /&gt;
* Does this user’s account have enough money to cover this purchase right now? (CHECK constraint)&lt;br /&gt;
* Is this rental property reserved for June 8 right now? (EXCLUDE constraint on date ranges)&lt;br /&gt;
&lt;br /&gt;
It is possible to use such constraints with a Rails application, but it is not typical to do so, and the tools do not encourage it.&lt;br /&gt;
&lt;br /&gt;
Elixir’s [https://hexdocs.pm/ecto/Ecto.html Ecto] database library embraces database constraints, with built-in support for adding them, catching constraint violations, and turning them back into friendly user-facing error messages.&lt;br /&gt;
&lt;br /&gt;
== Where Elixir is especially suited ==&lt;br /&gt;
&lt;br /&gt;
Any project that is a good fit for Rails or Python is something that could be done in Phoenix, especially if the project involves any or multiple of the following:&lt;br /&gt;
&lt;br /&gt;
* System expecting high traffic or requiring very fast / consistent response times&lt;br /&gt;
* Minimal downtime being crucial&lt;br /&gt;
* Realtime updates (eg, stock ticker, social media)&lt;br /&gt;
* Bidirectional realtime communication with websockets (eg, chat, games)&lt;br /&gt;
&lt;br /&gt;
= Drawbacks of Elixir =&lt;br /&gt;
&lt;br /&gt;
Some potential downsides of using Elixir, along with mitigating actions:&lt;br /&gt;
&lt;br /&gt;
* Fewer Elixir developers available. However:&lt;br /&gt;
** There are also significantly fewer projects competing for those people.&lt;br /&gt;
** There is a trend in Ruby developers wanting to cross over to Elixir.&lt;br /&gt;
** Developers with Erlang experience are also well suited.&lt;br /&gt;
** Elixir is a shiny new thing with real promise, which helps attract very enthusiastic developers.&lt;br /&gt;
* While Phoenix is productive, it is not as productive as older frameworks like Rails… yet. Reasons include:&lt;br /&gt;
** Lack of developer experience with Elixir.&lt;br /&gt;
** The relative newness of its open source ecosystem (documentation, forums, example code available).&lt;br /&gt;
** There are fewer libraries in Elixir than in older languages, so there are more times when you’d have to write something yourself. However:&lt;br /&gt;
*** You can use the many existing Erlang libraries.&lt;br /&gt;
*** New Elixir libraries are being added quickly.&lt;br /&gt;
*** Any remaining gaps are a chance to contribute to the community by creating a great open source tool.&lt;br /&gt;
* It may be harder to convince people to use Elixir, given that it’s currently obscure - not in the top [https://www.tiobe.com/tiobe-index/ 50 TIOBE index]. However:&lt;br /&gt;
** Erlang is better-known. Elixir compiles to Erlang bytecode, runs on the Erlang VM and can use or be used by Erlang code. It’s basically “Erlang made friendlier”.&lt;br /&gt;
** Joe Armstrong, co-creator of Erlang, said of pre-1.0 Elixir in 2013 that it was &amp;amp;quot;good s**t&amp;amp;quot;.&lt;br /&gt;
** Therefore, if we can convince someone on Erlang, Elixir is a no-brainer.&lt;br /&gt;
&lt;br /&gt;
= What’s next for MoodleNet’s development =&lt;br /&gt;
&lt;br /&gt;
== A generic agent-centric approach to federation? ==&lt;br /&gt;
&lt;br /&gt;
Another fediverse app being developed in Elixir ([https://github.com/beta-phenylethylamine/fontina Fontina], for photo sharing - although it has been put on hiatus) is now working on a [https://github.com/fontina-project/pubstomp generic ActivityPub server] to serve as back-end (there may be a good opportunity to join efforts…) Here is how the developer describes it: &amp;amp;gt; “I’m working on pubstomp, a generic AP server that is intended for services like mastodon/pixelfed/peertube to work as frontends to it and would indeed support single account [per person, versus having an account on an instance of each of those apps]. &amp;amp;gt; That said, one of my goals down the road is to build”api adaptors&amp;amp;quot; that would basically plug into pubstomp and adapt to, say, the mastoAPI, pleromaAPI, etc.”&lt;br /&gt;
&lt;br /&gt;
This is a good example of an &#039;&#039;&#039;agent-centric approach&#039;&#039;&#039;, where instead of having one &#039;&#039;&#039;monolithic app per use-case&#039;&#039;&#039; it is possible instead to seperate out federation logic and custom app logic (both back-ends could still share a database on the same server, and share a JavaScript-based front-end app that talks to both APIs).&lt;br /&gt;
&lt;br /&gt;
I started a [https://social.coop/@mayel/100469525067581562 thread about this on the fediverse] (please join the conversation!): &amp;amp;gt; There’s need for a generic agent-centric #ActivityPub server, so that instead of signing up to a bunch of different servers, a user could have their indentity and data all in one place, and all the apps they use (clients, but if necessary server-side “plugins” as well) would interact with the activity/objects types that they support.&lt;br /&gt;
&lt;br /&gt;
== The plan for Moodlenet (so far) ==&lt;br /&gt;
&lt;br /&gt;
# Fork the Pleroma back-end to create a set of ActivityPub libraries (or a generic ActivityPub server)&lt;br /&gt;
# Add suport for authenticating as OAuth client&lt;br /&gt;
# Add support for group accounts (agents that represent a severa users)&lt;br /&gt;
# Create ActivityStreams extensions&lt;br /&gt;
# Test federation&lt;br /&gt;
# Possibly add [https://graphql.org GraphQL] client-server API&lt;br /&gt;
# Create front-end app with React.js (web and mobile)&lt;br /&gt;
&lt;br /&gt;
We are planning to fork the [https://git.pleroma.social/pleroma/pleroma Pleroma back-end] to &#039;&#039;&#039;create a set of ActivityPub/ActivityStreams libraries&#039;&#039;&#039;. If that proves to not be feasible, we will turn it into a generic ActivityPub server back-end that can support any type of activity and object (including extensions to ActivityStreams) and is easily extensible which doesn’t ship with any frontend (possible name: &#039;&#039;Pub of the Commons&#039;&#039;). Pleroma is written with [https://elixir-lang.org Elixir]’s [https://phoenixframework.org Phoenix Framework], and licenced as AGPL (which is also being used for MoodleNet) so the upstream project will be able to use any improvements we make.&lt;br /&gt;
&lt;br /&gt;
Firstly, any parts of the code coming from Pleroma that we don’t needed will be removed (like support for the deprecated OStatus protocol, and the two front-ends which ship with Pleroma - its own Vue.js interface and Mastodon’s React.js interface), and we’ll add some things that can be &#039;&#039;&#039;universally useful&#039;&#039;&#039; like &#039;&#039;&#039;support for groups&#039;&#039;&#039; (actors made of several users), a basic HTML registration/authentication interface (and &#039;&#039;&#039;OAuth client&#039;&#039;&#039; functionality, so users can sign in using their existing accounts elsewhere) so that at least those things can be done without relying on a front-end app.&lt;br /&gt;
&lt;br /&gt;
While we work on creating models/vocabulary for MoodleNet, we can use this generic ActivityPub server to test our ActivityStreams extensions and make sure federation works well in real time (using the API only). Only once that is ready, will we start plugging in custom MoodleNet logic and developing the front-end app (which is the reverse from many fediverse app projects, who have first implemented MVPs of their use case, and then often find it challenging to add federation on top).&lt;br /&gt;
&lt;br /&gt;
Regarding the connection between the back-end and front-end app, the ActivityPub standard comes with a suggested [https://www.w3.org/TR/activitypub/#client-to-server-interactions client-server REST API specification], but for some reason Mastodon and many other fediverse apps have created their own custom REST APIs (and Pleroma implemented Mastodon’s so that it can share front-end apps). So an interesting option at this point for MoodleNet (and &#039;&#039;Pub of the Commons&#039;&#039;), may be to still support Mastodon’s client REST API (for compatibillity with existing front-ends like [https://github.com/nolanlawson/pinafore Pinafore]) and additionally to &#039;&#039;&#039;implement a new GraphQL-based API that would allow more flexibility and extensiblity between the server and front-end apps&#039;&#039;&#039; (any functionality/activities/objects not supported by Mastodon would only have to be implemented in the server-to-server REST API and the [https://graphql.org GraphQL] API).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;References&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [https://ethercalc.org/fediverse-stacks Spreadsheet of fediverse apps and their stacks]&lt;br /&gt;
* [https://www.w3.org/TR/activitypub/ ActivityPub] standard (for federation)&lt;br /&gt;
* [https://www.w3.org/TR/activitystreams-core/ ActivityStreams] &amp;amp;amp; its [https://www.w3.org/TR/activitystreams-vocabulary/ vocabulary] (which ActivityPub uses as a data format)&lt;br /&gt;
* [https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/ How to implement a basic Mastodon-compatible server]&lt;br /&gt;
* [https://github.com/bignerdranch/why_elixir Why elixir] (big tanks to Big Nerd Ranch for some of the great material used in this doc!)&lt;br /&gt;
* [https://pragtob.wordpress.com/2017/07/26/choosing-elixir-for-the-code-not-the-performance/ Choosing Elixir for the Code, not the Performance]&lt;br /&gt;
* [https://git.pleroma.social/pleroma/pleroma/wikis/Hacking-Pleroma:-Elixir,-Phoenix-and-a-bit-of-ActivityPub Pleroma’s architecture]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet_stack_choice&amp;diff=54597</id>
		<title>MoodleNet stack choice</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet_stack_choice&amp;diff=54597"/>
		<updated>2018-08-06T14:32:45Z</updated>

		<summary type="html">&lt;p&gt;Mayel: page created&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Rationale for choosing Elixir for the MoodleNet back-end =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Author:&#039;&#039;&#039; Mayel de Borniol (Technical Architect)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Date:&#039;&#039;&#039; 6 August 2018&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
MoodleNet is a new open social media platform for educators, focussed on professional development and open content. It will be an integral part of the Moodle ecosystem.&lt;br /&gt;
&lt;br /&gt;
Just like the ~7,000 languages that are spoken in the world today, there many different types of programming languages that allow humans to communicate with computers (and tell them nicely what to do). An important decision for our team was what technical language(s) Moodlenet should speak, and this document highlights the decision-making process which ended up with choosing the ‘Elixir’ language.&lt;br /&gt;
&lt;br /&gt;
== Research process ==&lt;br /&gt;
&lt;br /&gt;
The process began with an extensive review of web application appprogramming languages. More specifically, the technologies used for apps based on [https://en.wikipedia.org/wiki/ActivityPub ActivityPub federation standard] - which will enable MoodleNet to be a &#039;&#039;&#039;decentralised platform, you will be able self-host an instance&#039;&#039;&#039; (just like you can install Moodle on a server, and customise it) but all the instances will be &#039;&#039;&#039;interconnected&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A [https://ethercalc.org/fediverse-stacks spreadsheet of fediverse apps and their stacks] (and [https://social.coop/@mayel/100469319126679591 crowdsourced extra information via the fediverse]) was compiled. This showed that besides Ruby on Rails, there were a few ActivityPub projects using Python (and a couple intending to use PHP) and some other languages, however, most projects are still in early development and many are not yet federated. Considering that &#039;&#039;&#039;ActivityPub is still relatively new it is understandable that there are limited examples of full implementations&#039;&#039;&#039;, let alone ones that are proven to work and be interoperable.&lt;br /&gt;
&lt;br /&gt;
One of the first languages that stood out was Go, one of the only a few to actually have an [https://github.com/go-fed/activity ActivityPub library]. The developer was contacted and offered his assistance for future collaboration (although in full-time employment and developing the Go library in his spare time). What this meant was that the MoodleNet team would have to modify the library in order to tailor it to the project’s needs. The main obstacle to this, however, is that Go is a ‘statically typed’ language which means every ActivityStreams extension would have to be hard coded pre-compilation. This would make things less flexible, so this option was set aside.&lt;br /&gt;
&lt;br /&gt;
Alongside researching the documentations, codebases, issue trackers and communicating with developers of the apps in the spreadsheet, many of them were installed and tested (including Mastodon, Pleroma, and Prismo). The latter, while having some functionality that MoodleNet will need, confirmed an earlier impression from running a Mastodon instance: &#039;&#039;&#039;Rails apps tend to not be lightweight and often rely on many external dependencies&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
After comparing the possible language candidates, the focus shifted on detailing the pros and cons for each, finaly focusing on the following:&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;[https://en.wikipedia.org/wiki/BEAM_(Erlang_virtual_machine) Erlang VM]&#039;&#039;&#039; is time tested (more than 20 years old), very fast and has good concurrency and inter-process communication (called OTP).&lt;br /&gt;
* &#039;&#039;&#039;[https://elixir-lang.org Elixir]&#039;&#039;&#039; is a new (7+ years) functional language designed for productivity and maintainability that runs on the Erlang VM.&lt;br /&gt;
* &#039;&#039;&#039;[https://phoenixframework.org Phoenix]&#039;&#039;&#039; is a modern web framework that makes building APIs and web applications easy. Since it’s built with Elixir and runs on Erlang VM, it is very fast and has excellent support for handling very large numbers of simultaneous users.&lt;br /&gt;
&lt;br /&gt;
= Benefits of Elixir =&lt;br /&gt;
&lt;br /&gt;
A list of reasons to use Elixir in our context:&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
The Phoenix web framework has been found to perform better than Rails, PHP, and Python. [https://github.com/mroth/phoenix-showdown/blob/master/README.md#benchmarking One benchmark] showed Phoenix handling over 10x more requests than Rails in a given period. Phoenix was also much more consistent under load - Rails was more prone to have some requests bog down. This can cause a “chain reaction”, because Rails apps are configured with a fixed number of application processes, so if some of them are slow, it can mean that others have to wait in line, which dramatically increases the app’s response time.&lt;br /&gt;
&lt;br /&gt;
Furthermore, Phoenix apps &#039;&#039;&#039;without caching&#039;&#039;&#039; drastically outperform Rails apps &#039;&#039;&#039;with caching&#039;&#039;&#039;. This is important because caching is notorious for being a source of complexity and bugs, and because caching can’t be used for moment-by-moment, personalized content. The [https://youtu.be/AdY5AfXs7aw?t=3m14s Bleacher Report] for example went from over 100 AWS servers to 5, with CPU usage rarely going above 10%, and saw a 10x performance improvement over their Rails app.&lt;br /&gt;
&lt;br /&gt;
There are a growing number of software projects using Elixir - e.g. Pinterest [https://github.com/bignerdranch/why_elixir who say]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“We like Elixir and have seen some pretty big wins with it. The system that manages rate limits for both the Pinterest API and Ads API is built in Elixir. Its 50 percent response time is around 500 microseconds with a 90 percent response time of 800 microseconds. Yes, microseconds.”&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
And an [https://blog.carbonfive.com/2016/04/19/elixir-and-phoenix-the-future-of-web-apis-and-apps/ adopter of the Phoenix framework] says: &amp;amp;gt; “A rather large JSON request was taking about 1.5-2.0s against our Rails backend (no caching). That same request (same h/w, database queries and data) takes about 400ms with Phoenix. Our entire application went from using just shy of 1 GB across 2 dynos to a single dyno using less than 100 MB. That single dyno is notably faster and can handle higher concurrency (about 10x). Importantly, Phoenix (without caching) performs better than Rails (with caching).”&lt;br /&gt;
&lt;br /&gt;
One thing that makes Erlang/Elixir so efficient is [https://www.brianstorti.com/the-actor-model/ the actor model], which ActivityPub seems to have taken inspiration from.&lt;br /&gt;
&lt;br /&gt;
== Scalability ==&lt;br /&gt;
&lt;br /&gt;
The Erlang VM’s model of concurrency is great for multi-core CPUs, but it was created before they existed. Its original purpose was to support concurrency and fault-tolerance via the use of many different machines. This makes it an excellent tool for building systems that can handle more load by simply adding more servers.&lt;br /&gt;
&lt;br /&gt;
As the [http://ninenines.eu/docs/en/cowboy/2.0/guide/erlang_web/ docs for an Erlang web server] put it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“At the time of writing there are application servers written in Erlang that can handle more than two million connections on a single server in a real production application, with spare memory and CPU! The Web is concurrent, and Erlang is a language designed for concurrency, so it is a perfect match. &amp;lt;br&amp;gt;&amp;lt;br&amp;gt; Of course, various platforms need to scale beyond a few million connections. This is where Erlang’s built-in distribution mechanisms come in. If one server isn’t enough, add more! Erlang allows you to use the same code for talking to local processes or to processes in other parts of your cluster, which means you can scale very quickly if the need arises.”&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
== Developer Productivity &amp;amp;amp; Happiness ==&lt;br /&gt;
&lt;br /&gt;
When people argue about programming languages, often the performance card is pulled (“this language is so much faster in these benchmarks”). But performance isn’t the only consideration: while it’s possible to just add more servers, developer time often costs more than servers.&lt;br /&gt;
&lt;br /&gt;
More important then is which framework helps write software faster, of a better quality, and which benefits the programmer’s wellbeing.&lt;br /&gt;
&lt;br /&gt;
As Pinterest concluded from using Elixir: &amp;amp;gt; “We’ve also seen an improvement in code clarity. We’re converting our notifications system from Java to Elixir. The Java version used an Actor system and weighed in at around 10,000 lines of code. The new Elixir system has shrunk this to around 1000 lines. The Elixir based system is also faster and more consistent than the Java one and runs on half the number of servers.”&lt;br /&gt;
&lt;br /&gt;
And [http://www.techworld.com/apps-wearables/how-elixir-helped-bleacher-report-handle-8x-more-traffic-3653957/ Bleacher Report], who went from 150 servers to 5 using Elixir: &amp;amp;gt; &amp;amp;quot;The new language has led to cleaner code base and much less technical debt. It has also increased the speed of development.&lt;br /&gt;
&lt;br /&gt;
Some [https://pragtob.wordpress.com/2017/07/26/choosing-elixir-for-the-code-not-the-performance/ advantages of Elixir for programmers] include:&lt;br /&gt;
&lt;br /&gt;
* No extra engineering spent on “making it faster” (if the runtime is already fast enough they don’t need to bother with caching for example).&lt;br /&gt;
* All the goodies of modern day programming, like a package manager.&lt;br /&gt;
* Pattern Matching: you can make assertions on the structure and can get values directly out of a deeply nested map (or list) and put their value into a variable. You also have method overloading and Elixir will try to match the functions from top to bottom which means you can have different function definitions based on the structure of your input data.&lt;br /&gt;
* Immutable data structures &amp;amp;amp; pure functions: Everything that the function depends on is a parameter, and the only thing that “happens” is the return value of the function. There are no instance variables that are difficult to debug.&lt;br /&gt;
* Explicit code: For example, you explicitly specify a template by name, and pass the values you’ll need from the controller. Ecto also gives you more control over what data will be loaded from the DB.&lt;br /&gt;
* [https://hexdocs.pm/ecto/Ecto.Changeset.html Ecto Changesets]: filtering, casting, validation and definition of constraints when manipulating DB data.&lt;br /&gt;
* Optional type-checking: use [https://github.com/jeremyjh/dialyxir typing only when you want to].&lt;br /&gt;
* Parallelism: it’s not just about performance! Parallelism in the Erlang VM low cost and seamless. Spawning a new process (not like an OS process, they are more like actors) is easy and has a very low overhead, unlike starting a new thread. You can have millions of them on one machine. And thanks to immutability guarantees and every process being isolated you don’t have to worry about processes messing with each other.&lt;br /&gt;
* Doc tests: It is possible to write code examples directly in the documentation of a method. These will be executed during test runs and check if they still return the same values/still pass. They are also included in the generated documentation.&lt;br /&gt;
&lt;br /&gt;
== Reliability ==&lt;br /&gt;
&lt;br /&gt;
While Elixir is a fairly new language, it is mostly a friendly interface to the Erlang virtual machine, which has been used since the 80s to build some of the most reliable systems in the world: telephone systems.&lt;br /&gt;
&lt;br /&gt;
It is made for running a complex system with almost no downtime, like having multiple levels of “supervising” processes in a system to reboot parts that have errors. Basically, microservices before microservices were cool.&lt;br /&gt;
&lt;br /&gt;
== Concurrency ==&lt;br /&gt;
&lt;br /&gt;
CPUs are no longer getting dramatically faster each year. Instead, we get machines with more cores. Our code can run faster, but only if it can run concurrently - meaning, different bits of code run simultaneously on different cores.&lt;br /&gt;
&lt;br /&gt;
The main problem with concurrent code is having two pieces of code mess with the same data at the same time, creating unexpected results. Object-oriented languages like Ruby don’t provide great tools for avoiding such problems. But functional languages, like Elixir, do.&lt;br /&gt;
&lt;br /&gt;
Writing concurrent code in Elixir is extremely easy, and it’s nearly impossible to accidentally interfere with other code that is running at the time.&lt;br /&gt;
&lt;br /&gt;
== Simplicity ==&lt;br /&gt;
&lt;br /&gt;
For modern web applications (written in languages like PHP or Ruby on Rails) to do everything we require of them, they depend on a lot of other pieces running on the server, for example: * Only one web request can be handled at a time, and it is not possible to spin up new processes as needed, so tools are needed to spawn multiple application servers up front and put a web server like Nginx in front of them to hand off requests. * It is not possible to do slow background tasks without blocking web requests, so something like [http://resque.github.io Resque] needs to be added to take care of running background jobs. * It is not advisable to use a precious process to maintain a websocket connection with a user, so something like Pusher needs to be added to get realtime functionality (meaning extra costs). * It is not possible to keep a big process running all the time to do scheduled tasks, so a dependency on cron needs to be added. * No built-in tool for managing multiple parts of a running system currently exists, so tools like [https://www.theforeman.org foreman] are used to start and monitor them.&lt;br /&gt;
&lt;br /&gt;
In Elixir on the other hand, it is possible to spin up a nearly limitless number of processes as needed, so it is possible (in theory) to forego all those tools above.&lt;br /&gt;
&lt;br /&gt;
Elixir code is also simpler to understand than object-oriented code because it has explicitness as a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;“Functional programming is associated with concurrency but it was not by design. It just happens that, by making the complex parts of our system explicit, solving more complicated issues like concurrency becomes much simpler.” - [http://www.sitepoint.com/an-interview-with-elixir-creator-jose-valim/ Jose Valim]&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
== Flexibility ==&lt;br /&gt;
&lt;br /&gt;
Using Phoenix and Elixir opens the door to building applications that are not possible with other web frameworks.&lt;br /&gt;
&lt;br /&gt;
The Phoenix framework has first-class support for realtime communication via websockets (with polling as a fallback). In benchmarks, the creators have been able to[http://www.phoenixframework.org/blog/the-road-to-2-million-websocket-connections serve 2 million simultaneously-connected clients]. Additionally, they already have native channel clients for iOS, Android, and Windows devices. With that kind of support, you can confidently build servers to support chat, networked games, and more.&lt;br /&gt;
&lt;br /&gt;
== Correctness ==&lt;br /&gt;
&lt;br /&gt;
In Rails, ActiveRecord encourages developers to do all data validation in application code. However, validations that depend on the state of the database can only be reliably done by the database, using constraints or locks. This includes things like:&lt;br /&gt;
&lt;br /&gt;
* Does any user have this username right now? (uniqueness constraint)&lt;br /&gt;
* Does post 5 exist still right now, before I comment on it? (foreign key constraint)&lt;br /&gt;
* Does this user’s account have enough money to cover this purchase right now? (CHECK constraint)&lt;br /&gt;
* Is this rental property reserved for June 8 right now? (EXCLUDE constraint on date ranges)&lt;br /&gt;
&lt;br /&gt;
It is possible to use such constraints with a Rails application, but it is not typical to do so, and the tools do not encourage it.&lt;br /&gt;
&lt;br /&gt;
Elixir’s [https://hexdocs.pm/ecto/Ecto.html Ecto] database library embraces database constraints, with built-in support for adding them, catching constraint violations, and turning them back into friendly user-facing error messages.&lt;br /&gt;
&lt;br /&gt;
== Where Elixir is especially suited ==&lt;br /&gt;
&lt;br /&gt;
Any project that is a good fit for Rails or Python is something that could be done in Phoenix, especially if the project involves any or multiple of the following:&lt;br /&gt;
&lt;br /&gt;
* System expecting high traffic or requiring very fast / consistent response times&lt;br /&gt;
* Minimal downtime being crucial&lt;br /&gt;
* Realtime updates (eg, stock ticker, social media)&lt;br /&gt;
* Bidirectional realtime communication with websockets (eg, chat, games)&lt;br /&gt;
&lt;br /&gt;
= Drawbacks of Elixir =&lt;br /&gt;
&lt;br /&gt;
Some potential downsides of using Elixir, along with mitigating actions:&lt;br /&gt;
&lt;br /&gt;
* Fewer Elixir developers available. However:&lt;br /&gt;
** There are also significantly fewer projects competing for those people.&lt;br /&gt;
** There is a trend in Ruby developers wanting to cross over to Elixir.&lt;br /&gt;
** Developers with Erlang experience are also well suited.&lt;br /&gt;
** Elixir is a shiny new thing with real promise, which helps attract very enthusiastic developers.&lt;br /&gt;
* While Phoenix is productive, it is not as productive as older frameworks like Rails… yet. Reasons include:&lt;br /&gt;
** Lack of developer experience with Elixir.&lt;br /&gt;
** The relative newness of its open source ecosystem (documentation, forums, example code available).&lt;br /&gt;
** There are fewer libraries in Elixir than in older languages, so there are more times when you’d have to write something yourself. However:&lt;br /&gt;
*** You can use the many existing Erlang libraries.&lt;br /&gt;
*** New Elixir libraries are being added quickly.&lt;br /&gt;
*** Any remaining gaps are a chance to contribute to the community by creating a great open source tool.&lt;br /&gt;
* It may be harder to convince people to use Elixir, given that it’s currently obscure - not in the top [https://www.tiobe.com/tiobe-index/ 50 TIOBE index]. However:&lt;br /&gt;
** Erlang is better-known. Elixir compiles to Erlang bytecode, runs on the Erlang VM and can use or be used by Erlang code. It’s basically “Erlang made friendlier”.&lt;br /&gt;
** Joe Armstrong, co-creator of Erlang, said of pre-1.0 Elixir in 2013 that it was &amp;amp;quot;good s**t&amp;amp;quot;.&lt;br /&gt;
** Therefore, if we can convince someone on Erlang, Elixir is a no-brainer.&lt;br /&gt;
&lt;br /&gt;
= What’s next for MoodleNet’s development =&lt;br /&gt;
&lt;br /&gt;
== A generic agent-centric approach to federation? ==&lt;br /&gt;
&lt;br /&gt;
Another fediverse app being developed in Elixir ([https://github.com/beta-phenylethylamine/fontina Fontina], for photo sharing - although it has been put on hiatus) is now working on a [https://github.com/fontina-project/pubstomp generic ActivityPub server] to serve as back-end (there may be a good opportunity to join efforts…) Here is how the developer describes it: &amp;amp;gt; “I’m working on pubstomp, a generic AP server that is intended for services like mastodon/pixelfed/peertube to work as frontends to it and would indeed support single account [per person, versus having an account on an instance of each of those apps]. &amp;amp;gt; That said, one of my goals down the road is to build”api adaptors&amp;amp;quot; that would basically plug into pubstomp and adapt to, say, the mastoAPI, pleromaAPI, etc.”&lt;br /&gt;
&lt;br /&gt;
This is a good example of an &#039;&#039;&#039;agent-centric approach&#039;&#039;&#039;, where instead of having one &#039;&#039;&#039;monolithic app per use-case&#039;&#039;&#039; it is possible instead to seperate out federation logic and custom app logic (both back-ends could still share a database on the same server, and share a JavaScript-based front-end app that talks to both APIs).&lt;br /&gt;
&lt;br /&gt;
I started a [https://social.coop/@mayel/100469525067581562 thread about this on the fediverse] (please join the conversation!): &amp;amp;gt; There’s need for a generic agent-centric #ActivityPub server, so that instead of signing up to a bunch of different servers, a user could have their indentity and data all in one place, and all the apps they use (clients, but if necessary server-side “plugins” as well) would interact with the activity/objects types that they support.&lt;br /&gt;
&lt;br /&gt;
== The plan for Moodlenet (so far) ==&lt;br /&gt;
&lt;br /&gt;
# Fork the Pleroma back-end to create a set of ActivityPub libraries (or a generic ActivityPub server)&lt;br /&gt;
# Add suport for authenticating as OAuth client&lt;br /&gt;
# Add support for group accounts (agents that represent a severa users)&lt;br /&gt;
# Create ActivityStreams extensions&lt;br /&gt;
# Test federation&lt;br /&gt;
# Possibly add [https://graphql.org GraphQL] client-server API&lt;br /&gt;
# Create front-end app with React.js (web and mobile)&lt;br /&gt;
&lt;br /&gt;
We are planning to fork the [https://git.pleroma.social/pleroma/pleroma Pleroma back-end] to &#039;&#039;&#039;create a set of ActivityPub/ActivityStreams libraries&#039;&#039;&#039;. If that proves to not be feasible, we will turn it into a generic ActivityPub server back-end that can support any type of activity and object (including extensions to ActivityStreams) and is easily extensible which doesn’t ship with any frontend (possible name: &#039;&#039;Pub of the Commons&#039;&#039;). Pleroma is written with [https://elixir-lang.org Elixir]’s [https://phoenixframework.org Phoenix Framework], and licenced as AGPL (which is also being used for MoodleNet) so the upstream project will be able to use any improvements we make.&lt;br /&gt;
&lt;br /&gt;
Firstly, any parts of the code coming from Pleroma that we don’t needed will be removed (like support for the deprecated OStatus protocol, and the two front-ends which ship with Pleroma - its own Vue.js interface and Mastodon’s React.js interface), and we’ll add some things that can be &#039;&#039;&#039;universally useful&#039;&#039;&#039; like &#039;&#039;&#039;support for groups&#039;&#039;&#039; (actors made of several users), a basic HTML registration/authentication interface (and &#039;&#039;&#039;OAuth client&#039;&#039;&#039; functionality, so users can sign in using their existing accounts elsewhere) so that at least those things can be done without relying on a front-end app.&lt;br /&gt;
&lt;br /&gt;
While we work on creating models/vocabulary for MoodleNet, we can use this generic ActivityPub server to test our ActivityStreams extensions and make sure federation works well in real time (using the API only). Only once that is ready, will we start plugging in custom MoodleNet logic and developing the front-end app (which is the reverse from many fediverse app projects, who have first implemented MVPs of their use case, and then often find it challenging to add federation on top).&lt;br /&gt;
&lt;br /&gt;
Regarding the connection between the back-end and front-end app, the ActivityPub standard comes with a suggested [https://www.w3.org/TR/activitypub/#client-to-server-interactions client-server REST API specification], but for some reason Mastodon and many other fediverse apps have created their own custom REST APIs (and Pleroma implemented Mastodon’s so that it can share front-end apps). So an interesting option at this point for MoodleNet (and &#039;&#039;Pub of the Commons&#039;&#039;), may be to still support Mastodon’s client REST API (for compatibillity with existing front-ends like [https://github.com/nolanlawson/pinafore Pinafore]) and additionally to &#039;&#039;&#039;implement a new GraphQL-based API that would allow more flexibility and extensiblity between the server and front-end apps&#039;&#039;&#039; (any functionality/activities/objects not supported by Mastodon would only have to be implemented in the server-to-server REST API and the [https://graphql.org GraphQL] API).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;References&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [https://ethercalc.org/fediverse-stacks Spreadsheet of fediverse apps and their stacks]&lt;br /&gt;
* [https://www.w3.org/TR/activitypub/ ActivityPub] standard (for federation)&lt;br /&gt;
* [https://www.w3.org/TR/activitystreams-core/ ActivityStreams] &amp;amp;amp; its [https://www.w3.org/TR/activitystreams-vocabulary/ vocabulary] (which ActivityPub uses as a data format)&lt;br /&gt;
* [https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/ How to implement a basic Mastodon-compatible server]&lt;br /&gt;
* [https://github.com/bignerdranch/why_elixir Why elixir] (big tanks to Big Nerd Ranch for some of the great material used in this doc!)&lt;br /&gt;
* [https://pragtob.wordpress.com/2017/07/26/choosing-elixir-for-the-code-not-the-performance/ Choosing Elixir for the Code, not the Performance]&lt;br /&gt;
* [https://git.pleroma.social/pleroma/pleroma/wikis/Hacking-Pleroma:-Elixir,-Phoenix-and-a-bit-of-ActivityPub Pleroma’s architecture]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_App_Plugins_Development_Guide&amp;diff=54437</id>
		<title>Moodle App Plugins Development Guide</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_App_Plugins_Development_Guide&amp;diff=54437"/>
		<updated>2018-06-25T15:39:43Z</updated>

		<summary type="html">&lt;p&gt;Mayel: purge cache&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle Mobile}}&lt;br /&gt;
&lt;br /&gt;
==Context==&lt;br /&gt;
Since Moodle 3.1 it is possible to support different types of Moodle plugins in the Mobile app via the [[Moodle Mobile Remote add-ons|Remote add-ons]] functionality.&lt;br /&gt;
&lt;br /&gt;
Remote add-ons allow a developer to add complete support to their plugins in the Mobile app, but they have some disadvantages:&lt;br /&gt;
* Remote add-ons are not easy to develop and test since they are required to be developed as an Angular JS/Ionic module.&lt;br /&gt;
* A zip file containing the plugin must be downloaded from the server to be lazy-loaded.&lt;br /&gt;
* It is not easy to maintain or upgrade them.&lt;br /&gt;
* Developers had to set up a local Mobile development environment&lt;br /&gt;
&lt;br /&gt;
In order to allow plugin developers to make their plugins compatible with the app, the Mobile team has been thinking in a new way to extend the mobile app features following these premises:&lt;br /&gt;
* It has to be easy to develop&lt;br /&gt;
* It should work without developing Angular/Ionic code&lt;br /&gt;
* It has to be easy to maintain&lt;br /&gt;
* It has to be supported since Moodle 3.1 at least&lt;br /&gt;
* Should support all the different types of Moodle plugins supported by the app&lt;br /&gt;
* Should work in any type of device&lt;br /&gt;
* Should not require JavaScript at all, although in some cases it will be needed. In the latter case, we’ll try to simplify the required JavaScript&lt;br /&gt;
&lt;br /&gt;
==New approach==&lt;br /&gt;
&lt;br /&gt;
We published an initial draft specification, and last month we started its implementation. During the implementation process we decided to make the following changes to the initial plans in order to make developers life easier:&lt;br /&gt;
&lt;br /&gt;
* There will be just one way to support plugins in the app.&lt;br /&gt;
* This new way will allow developers to support plugins using PHP code, templates and Ionic markup (html components).&lt;br /&gt;
* The use of JavaScript will be optional (but some type of advanced plugins may require it)&lt;br /&gt;
* Developers won’t need to set up a Mobile development environment, they will be able to test using the latest version of the official app (although setting up a local Mobile environment is recommended for complex plugins).&lt;br /&gt;
&lt;br /&gt;
This means that remote add-ons won’t be necessary anymore, and developers won’t have to learn Ionic 3 / Angular and set up a new mobile development environment to migrate them.&lt;br /&gt;
&lt;br /&gt;
Important notes:&lt;br /&gt;
* Moodle Mobile 3.5 (to be released June 2018) will be the first version of the Mobile app supporting this new type of plugins.&lt;br /&gt;
* Remote add-ons will have to be migrated to the new simpler way (following this documentation)&lt;br /&gt;
* These features are natively supported in Moodle 3.5, but for previous versions you will need to install the Moodle Mobile Additional Features plugin.&lt;br /&gt;
&lt;br /&gt;
==How it works==&lt;br /&gt;
&lt;br /&gt;
The overall idea is to allow Moodle plugins to extend different areas in the app with &#039;&#039;just PHP server side&#039;&#039; code and Ionic 3 markup (custom html elements that are called components) using a set of custom Ionic directives and components.&lt;br /&gt;
&lt;br /&gt;
Developers will have to:&lt;br /&gt;
# Create a db/mobile.php file in their plugins. In this file developers will be able to indicate which areas of the app they want to extend, for example, adding a new option in the main menu, implementing an activity module not supported, including a new option in the course menu, including a new option in the user profile, etc. All the areas supported are described further in this document.&lt;br /&gt;
# Create new functions in a reserved namespace that will return the content of the new options. The content should be returned rendered (html). The template should use [https://ionicframework.com/docs/components/ Ionic components] so that it looks native (custom html elements) but it can be generated using mustache templates. &lt;br /&gt;
&lt;br /&gt;
Let’s clarify some points:&lt;br /&gt;
&lt;br /&gt;
* You don’t need to create new Web Service functions (although you will be able to use them for advanced features). You just need plain php functions that will be placed in a reserved namespace.&lt;br /&gt;
* Those functions will be exported via the Web Service function tool_mobile_get_content&lt;br /&gt;
* As arguments of your functions you will always receive the userid, some relevant details of the app (app version, current language in the app, etc…) and some specific data depending on the type of plugin (courseid, cmid, …).&lt;br /&gt;
* We provide a list of custom Ionic components and directives (html tags) that will provide dynamic behaviour, like indicating that you are linking a file that can be downloaded, or to allow a transition to new pages into the app calling a specific function in the server, submit form data to the server  etc..&lt;br /&gt;
&lt;br /&gt;
==Step by step example==&lt;br /&gt;
&lt;br /&gt;
In this example, we are going to update an existing plugin ([https://github.com/markn86/moodle-mod_certificate Certificate activity module]) that currently uses a Remote add-on.&lt;br /&gt;
This is a simple activity module that displays the certificate issued for the current user along with the list of the dates of previously issued certificates. It also stores in the course log that the user viewed a certificate. This module also works offline: when the user downloads the course or activity, the data is pre-fetched and can be viewed offline.&lt;br /&gt;
&lt;br /&gt;
The example code can be downloaded from here (see last commit) https://github.com/jleyva/moodle-mod_certificate/commits/MOBILE-2363&lt;br /&gt;
&lt;br /&gt;
TIP: Make sure to ([https://docs.moodle.org/35/en/Developer_tools#Purge_all_caches purge all cache]) after making an edit to one of the following files for your changes to be taken into account.&lt;br /&gt;
&lt;br /&gt;
===Step 1. Update the db/mobile.php file===&lt;br /&gt;
In this case, we are updating an existing file but for new plugins, you should create this new file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$addons = array(&lt;br /&gt;
    &amp;quot;mod_certificate&amp;quot; =&amp;gt; array( // Plugin identifier&lt;br /&gt;
    	&#039;handlers&#039; =&amp;gt; array( // Different places where the plugin will display content.&lt;br /&gt;
            &#039;coursecertificate&#039; =&amp;gt; array( // Handler unique name (alphanumeric).&lt;br /&gt;
            	&#039;displaydata&#039; =&amp;gt; array(&lt;br /&gt;
                	&#039;icon&#039; =&amp;gt; $CFG-&amp;gt;wwwroot . &#039;/mod/certificate/pix/icon.gif&#039;,&lt;br /&gt;
                	&#039;class&#039; =&amp;gt; &#039;&#039;,&lt;br /&gt;
            	),&lt;br /&gt;
       &lt;br /&gt;
            	&#039;delegate&#039; =&amp;gt; &#039;CoreCourseModuleDelegate&#039;, // Delegate (where to display the link to the plugin)&lt;br /&gt;
            	&#039;method&#039; =&amp;gt; &#039;mobile_course_view&#039;, // Main function in \mod_certificate\output\mobile&lt;br /&gt;
            	&#039;offlinefunctions&#039; =&amp;gt; array(&lt;br /&gt;
                    &#039;mobile_course_view&#039; =&amp;gt; array(),&lt;br /&gt;
                    &#039;mobile_issues_view&#039; =&amp;gt; array()&lt;br /&gt;
                 )       // Function that needs to be downloaded for offline.&lt;br /&gt;
            )&lt;br /&gt;
    	),&lt;br /&gt;
	&#039;lang&#039; =&amp;gt; array(	// Language strings that are used in all the handlers.&lt;br /&gt;
                array(&#039;pluginname&#039;, &#039;certificate&#039;),&lt;br /&gt;
                array(&#039;summaryofattempts&#039;, &#039;certificate&#039;),&lt;br /&gt;
                array(&#039;getcertificate&#039;, &#039;certificate&#039;),&lt;br /&gt;
                array(&#039;requiredtimenotmet&#039;, &#039;certificate&#039;),&lt;br /&gt;
		 array(&#039;viewcertificateviews&#039;, &#039;certificate&#039;)&lt;br /&gt;
        ),&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Plugin identifier:&lt;br /&gt;
: A unique name for the plugin, it can be anything (there’s no need to match the module name).&lt;br /&gt;
 &lt;br /&gt;
;Handlers  (Different places where the plugin will display content):&lt;br /&gt;
: A plugin can be displayed in different views in the app. Each view should have a unique name inside the plugin scope (alphanumeric).&lt;br /&gt;
&lt;br /&gt;
; Display data:&lt;br /&gt;
: This is only needed for certain types of plugins. Also, depending on the type of delegate it may require additional (or less fields), in this case we are indicating the module icon.&lt;br /&gt;
	&lt;br /&gt;
; Delegate&lt;br /&gt;
: Where to display the link to the plugin, see the Delegates chapter in this documentation for all the possible options.&lt;br /&gt;
&lt;br /&gt;
; Method:&lt;br /&gt;
: This is the function in the Moodle component/lib.php file to be executed the first time the user clicks in the new option displayed in the app. The function should be a method of a Mobile class under the output/mobile namespace.	&lt;br /&gt;
&lt;br /&gt;
; Offlinefunctions&lt;br /&gt;
: These are the functions that need to be downloaded for offline usage. This is the list of functions that need to be called and stored when the user downloads a course for offline usage. Please note that you can add functions here that are not even listed in the mobile.php file. &lt;br /&gt;
: In our example, downloading for offline access will mean that we&#039;ll execute the functions for getting the certificate and issued certificates passing as parameters the current userid (and courseid when we are using the mod or course delegate). If we have the result of those functions stored in the app, we&#039;ll be able to display the certificate information even if the user is offline.&lt;br /&gt;
: Offline functions will be mostly used to display information for final users, any further interaction with the view won’t be supported offline (for example, trying to send information when the user is offline).&lt;br /&gt;
: You can indicate here other Web Services functions, indicating the parameters that they might need from a defined subset (currently userid and courseid)&lt;br /&gt;
: Prefetching the module will also download all the files returned by the methods in these offline functions (in the &#039;&#039;files&#039;&#039; array).&lt;br /&gt;
&lt;br /&gt;
;Lang:&lt;br /&gt;
: The language pack string ids used in the plugin by all the handlers. Please note that you should avoid adding all the plugin string ids (including those unused) because the Web Service that returns the plugin information will include the translation of each string id for every language installed in the platform.&lt;br /&gt;
&lt;br /&gt;
There are additional attributes supported by the mobile.php list, see “Mobile.php supported options” section below.&lt;br /&gt;
&lt;br /&gt;
===Step 2. Creating the main function===&lt;br /&gt;
&lt;br /&gt;
The main function displays the current issued certificate (or several warnings if it’s not possible to issue a certificate). It also displays a link to view the dates of previously issued certificates.&lt;br /&gt;
&lt;br /&gt;
All the functions must be created in the plugin or subsystem classes/output directory, the name of the class must be mobile.&lt;br /&gt;
&lt;br /&gt;
For this example (mod_certificate plugin) the namespace name will be mod_certificate\output.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;File contents: mod/certificate/classes/output/mobile.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
namespace mod_certificate\output;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use context_module;&lt;br /&gt;
use mod_certificate_external;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Mobile output class for certificate&lt;br /&gt;
 *&lt;br /&gt;
 * @package	mod_certificate&lt;br /&gt;
 * @copyright  2018 Juan Leyva&lt;br /&gt;
 * @license	http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
class mobile {&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
 	* Returns the certificate course view for the mobile app.&lt;br /&gt;
 	* @param  array $args Arguments from tool_mobile_get_content WS&lt;br /&gt;
 	*&lt;br /&gt;
 	* @return array   	HTML, javascript and otherdata&lt;br /&gt;
 	*/&lt;br /&gt;
    public static function mobile_course_view($args) {&lt;br /&gt;
    	global $OUTPUT, $USER, $DB;&lt;br /&gt;
&lt;br /&gt;
    	$args = (object) $args;&lt;br /&gt;
    	$cm = get_coursemodule_from_id(&#039;certificate&#039;, $args-&amp;gt;cmid);&lt;br /&gt;
&lt;br /&gt;
    	// Capabilities check.&lt;br /&gt;
    	require_login($args-&amp;gt;courseid , false , $cm, true, true);&lt;br /&gt;
&lt;br /&gt;
    	$context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    	require_capability (&#039;mod/certificate:view&#039;, $context);&lt;br /&gt;
    	if ($args-&amp;gt;userid != $USER-&amp;gt;id) {&lt;br /&gt;
        	require_capability(&#039;mod/certificate:manage&#039;, $context);&lt;br /&gt;
    	}&lt;br /&gt;
    	$certificate = $DB-&amp;gt;get_record(&#039;certificate&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;instance));&lt;br /&gt;
&lt;br /&gt;
    	// Get certificates from external (taking care of exceptions).&lt;br /&gt;
    	try {&lt;br /&gt;
        	$issued = mod_certificate_external::issue_certificate($cm-&amp;gt;instance);&lt;br /&gt;
        	$certificates = mod_certificate_external::get_issued_certificates($cm-&amp;gt;instance);&lt;br /&gt;
        	$issues = array_values($certificates[&#039;issues&#039;]); // Make it mustache compatible.&lt;br /&gt;
    	} catch (Exception $e) {&lt;br /&gt;
        	$issues = array();&lt;br /&gt;
    	}&lt;br /&gt;
&lt;br /&gt;
    	// Set timemodified for each certificate.&lt;br /&gt;
    	foreach ($issues as $issue) {&lt;br /&gt;
        	if (empty($issue-&amp;gt;timemodified)) {&lt;br /&gt;
            		$issue-&amp;gt;timemodified = $issue-&amp;gt;timecreated;&lt;br /&gt;
        	}&lt;br /&gt;
    	}&lt;br /&gt;
&lt;br /&gt;
    	$showget = true;&lt;br /&gt;
    	if ($certificate-&amp;gt;requiredtime &amp;amp;&amp;amp; !has_capability(&#039;mod/certificate:manage&#039;, $context)) {&lt;br /&gt;
        	if (certificate_get_course_time($certificate-&amp;gt;course) &amp;lt; ($certificate-&amp;gt;requiredtime * 60)) {&lt;br /&gt;
            		$showget = false;&lt;br /&gt;
        	}&lt;br /&gt;
    	}&lt;br /&gt;
&lt;br /&gt;
    	$certificate-&amp;gt;name = format_string($certificate-&amp;gt;name);&lt;br /&gt;
    	list($certificate-&amp;gt;intro, $certificate-&amp;gt;introformat) =&lt;br /&gt;
                    	external_format_text($certificate-&amp;gt;intro, $certificate-&amp;gt;introformat, $context-&amp;gt;id,&#039;mod_certificate&#039;, &#039;intro&#039;);&lt;br /&gt;
    	$data = array(&lt;br /&gt;
        	&#039;certificate&#039; =&amp;gt; $certificate,&lt;br /&gt;
        	&#039;showget&#039; =&amp;gt; $showget &amp;amp;&amp;amp; count($issues) &amp;gt; 0,&lt;br /&gt;
        	&#039;issues&#039; =&amp;gt; $issues,&lt;br /&gt;
        	&#039;issue&#039; =&amp;gt; $issues[0],&lt;br /&gt;
&#039;numissues&#039; =&amp;gt; count($issues),&lt;br /&gt;
        	&#039;cmid&#039; =&amp;gt; $cm-&amp;gt;id,&lt;br /&gt;
        	&#039;courseid&#039; =&amp;gt; $args-&amp;gt;courseid&lt;br /&gt;
    	);&lt;br /&gt;
&lt;br /&gt;
    	return array(&lt;br /&gt;
        	&#039;templates&#039; =&amp;gt; array(&lt;br /&gt;
            	array(&lt;br /&gt;
                	&#039;id&#039; =&amp;gt; &#039;main&#039;,&lt;br /&gt;
                	&#039;html&#039; =&amp;gt; $OUTPUT-&amp;gt;render_from_template(&#039;mod_certificate/mobile_view_page&#039;, $data),&lt;br /&gt;
            	),&lt;br /&gt;
        	),&lt;br /&gt;
        	&#039;javascript&#039; =&amp;gt; &#039;&#039;,&lt;br /&gt;
        	&#039;otherdata&#039; =&amp;gt; &#039;&#039;,&lt;br /&gt;
        	&#039;files&#039; =&amp;gt; $issues&lt;br /&gt;
    	);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let’s go through the function code to analyse the different parts.&lt;br /&gt;
&lt;br /&gt;
;Function declaration: &lt;br /&gt;
: The function name is the same as the one used in the mobile.php file (method field). There is only one argument “$args” which is an array containing all the information sent by the mobile app (the courseid, userid, appid, appversionname, appversioncode, applang, appcustomurlscheme…)&lt;br /&gt;
&lt;br /&gt;
; Function implementation:&lt;br /&gt;
: In the first part of the function, we check permissions and capabilities (like a view.php script would do normally). Then we retrieve the certificate information that’s necessary to display the template.&lt;br /&gt;
&lt;br /&gt;
Finally, we return:&lt;br /&gt;
* The rendered template (notice that we could return more than one template but we usually would only need one). By default the app will always render the first template received, the rest of the templates can be used if the plugin defines some Javascript code.&lt;br /&gt;
* JavaScript: Empty, because we don’t need any in this case&lt;br /&gt;
* Other data: Empty as well, because we don’t need any additional data to be used by directives or components in the template. This field will be published as an object supporting 2-way-data-bind to the template.&lt;br /&gt;
* Files: A list of files that the app should be able to download (for offline usage mostly)&lt;br /&gt;
&lt;br /&gt;
===Step 3. Creating the template for the main function===&lt;br /&gt;
&lt;br /&gt;
This is the most important part of your plugin because it contains the code that will be rendered on the mobile app.&lt;br /&gt;
&lt;br /&gt;
In this template we’ll be using Ionic and custom directives and components available in the Mobile app.&lt;br /&gt;
&lt;br /&gt;
All the HTML attributes starting with ion- are ionic components. Most of the time the component name is self-explanatory but you may refer to a detailed guide here: https://ionicframework.com/docs/components/ &lt;br /&gt;
&lt;br /&gt;
All the HTML attributes starting with &#039;&#039;core-&#039;&#039; are custom components of the Mobile app.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;File contents: mod/certificate/templates/mobile_view_page.mustache&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
{{=&amp;lt;% %&amp;gt;=}}&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
	&amp;lt;core-course-module-description description=&amp;quot;&amp;lt;% certificate.intro %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; componentId=&amp;quot;&amp;lt;% cmid %&amp;gt;&amp;quot;&amp;gt;&amp;lt;/core-course-module-description&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;ion-list&amp;gt;&lt;br /&gt;
    	&amp;lt;ion-list-header&amp;gt;&lt;br /&gt;
        	&amp;lt;p class=&amp;quot;item-heading&amp;quot;&amp;gt;{{ &#039;plugin.mod_certificate.summaryofattempts&#039; | translate }}&amp;lt;/p&amp;gt;&lt;br /&gt;
    	&amp;lt;/ion-list-header&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    	&amp;lt;%#issues%&amp;gt;&lt;br /&gt;
        	&amp;lt;ion-item&amp;gt;&lt;br /&gt;
            	&amp;lt;button ion-button block color=&amp;quot;light&amp;quot; core-site-plugins-new-content title=&amp;quot;&amp;lt;% certificate.name %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; method=&amp;quot;mobile_issues_view&amp;quot; [args]=&amp;quot;{cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;}&amp;quot;&amp;gt;&lt;br /&gt;
                	{{ &#039;plugin.mod_certificate.viewcertificateviews&#039; | translate: {$a: &amp;lt;% numissues %&amp;gt;} }}&lt;br /&gt;
            	&amp;lt;/button&amp;gt;&lt;br /&gt;
        	&amp;lt;/ion-item&amp;gt;&lt;br /&gt;
    	&amp;lt;%/issues%&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    	&amp;lt;%#showget%&amp;gt;&lt;br /&gt;
    	&amp;lt;ion-item&amp;gt;&lt;br /&gt;
        	&amp;lt;button ion-button block core-course-download-module-main-file moduleId=&amp;quot;&amp;lt;% cmid %&amp;gt;&amp;quot; courseId=&amp;quot;&amp;lt;% certificate.course %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; [files]=&amp;quot;[{fileurl: &#039;&amp;lt;% issue.fileurl %&amp;gt;&#039;, filename: &#039;&amp;lt;% issue.filename %&amp;gt;&#039;, timemodified: &#039;&amp;lt;% issue.timemodified %&amp;gt;&#039;, mimetype: &#039;&amp;lt;% issue.mimetype %&amp;gt;&#039;}]&amp;quot;&amp;gt;&lt;br /&gt;
            	&amp;lt;ion-icon name=&amp;quot;cloud-download&amp;quot; item-start&amp;gt;&amp;lt;/ion-icon&amp;gt;&lt;br /&gt;
            	{{ &#039;plugin.mod_certificate.getcertificate&#039; | translate }}&lt;br /&gt;
        	&amp;lt;/button&amp;gt;&lt;br /&gt;
    	&amp;lt;/ion-item&amp;gt;&lt;br /&gt;
    	&amp;lt;%/showget%&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    	&amp;lt;%^showget%&amp;gt;&lt;br /&gt;
    	&amp;lt;ion-item&amp;gt;&lt;br /&gt;
        	&amp;lt;p&amp;gt;{{ &#039;plugin.mod_certificate.requiredtimenotmet&#039; | translate }}&amp;lt;/p&amp;gt;&lt;br /&gt;
    	&amp;lt;/ion-item&amp;gt;&lt;br /&gt;
    	&amp;lt;%/showget%&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    	&amp;lt;!-- Call log WS when the template is loaded. --&amp;gt;&lt;br /&gt;
    	&amp;lt;span core-site-plugins-call-ws-on-load name=&amp;quot;mod_certificate_view_certificate&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; [preSets]=&amp;quot;{getFromCache: 0, saveToCache: 0}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
	&amp;lt;/ion-list&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the first line of the template we switch delimiters to avoid conflicting with Ionic delimiters (that are curly brackets like mustache). &lt;br /&gt;
&lt;br /&gt;
Then we display the module description using &amp;lt;code&amp;gt;&amp;lt;core-course-module-description&amp;lt;/code&amp;gt; that is a component used to include the course module description.&lt;br /&gt;
&lt;br /&gt;
For displaying the certificate information we create a list of elements, adding a header on top.&lt;br /&gt;
The following line &amp;lt;code&amp;gt;{{ &#039;plugin.mod_certificate.summaryofattempts&#039; | translate }}&amp;lt;/code&amp;gt; indicates that the Mobile app will translate the &#039;&#039;summaryofattempts&#039;&#039; string id (here we could’ve used mustache translation but it is usually better to delegate the strings translations to the app). The string id has this format: &lt;br /&gt;
&lt;br /&gt;
“plugin” + plugin identifier (from mobile.php) +  string id (the string must be indicated in the lang field in mobile.php). &lt;br /&gt;
&lt;br /&gt;
Then we display a button to transition to another page if there are certificates issued. The attribute (directive) &amp;lt;code&amp;gt;core-site-plugins-new-content&amp;lt;/code&amp;gt; indicates that if the user clicks the button, we need to call the function “mobile_issues_view” in the component “mod_certificate” passing as arguments the cmid and courseid. The content returned by this function will be displayed in a new page (see Step 4 for the code of this new page).&lt;br /&gt;
&lt;br /&gt;
Just after this button we display another one but this time for downloading an issued certificate. The &amp;lt;code&amp;gt;core-course-download-module-main-file&amp;lt;/code&amp;gt; directive indicates that clicking this button is for downloading the whole activity and opening the main file. This means that, when the user clicks this button, the whole certificate activity will be available in offline.&lt;br /&gt;
&lt;br /&gt;
Finally, just before the ion-list is closed, we use the &amp;lt;code&amp;gt;core-site-plugins-call-ws-on-load&amp;lt;/code&amp;gt; directive to indicate that once the page is loaded, we need to call to a Web Service function in the server, in this case we are calling the &#039;&#039;mod_certificate_view_certificate&#039;&#039; that will log that the user viewed this page.&lt;br /&gt;
&lt;br /&gt;
As you can see, no JavaScript was necessary at all. We used plain HTML elements and attributes that did all the complex dynamic logic (like calling a Web Service) behind the scenes.&lt;br /&gt;
&lt;br /&gt;
===Step 4. Adding an additional page===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Partial file contents: mod/certificate/classes/output/mobile.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
     * Returns the certificate issues view for the mobile app.&lt;br /&gt;
     * @param  array $args Arguments from tool_mobile_get_content WS&lt;br /&gt;
     *&lt;br /&gt;
     * @return array   	HTML, javascript and otherdata&lt;br /&gt;
     */&lt;br /&gt;
    public static function mobile_issues_view($args) {&lt;br /&gt;
    	global $OUTPUT, $USER, $DB;&lt;br /&gt;
&lt;br /&gt;
    	$args = (object) $args;&lt;br /&gt;
    	$cm = get_coursemodule_from_id(&#039;certificate&#039;, $args-&amp;gt;cmid);&lt;br /&gt;
&lt;br /&gt;
    	// Capabilities check.&lt;br /&gt;
    	require_login($args-&amp;gt;courseid , false , $cm, true, true);&lt;br /&gt;
&lt;br /&gt;
    	$context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    	require_capability (&#039;mod/certificate:view&#039;, $context);&lt;br /&gt;
    	if ($args-&amp;gt;userid != $USER-&amp;gt;id) {&lt;br /&gt;
        	require_capability(&#039;mod/certificate:manage&#039;, $context);&lt;br /&gt;
    	}&lt;br /&gt;
    	$certificate = $DB-&amp;gt;get_record(&#039;certificate&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;instance));&lt;br /&gt;
&lt;br /&gt;
    	// Get certificates from external (taking care of exceptions).&lt;br /&gt;
    	try {&lt;br /&gt;
        	$issued = mod_certificate_external::issue_certificate($cm-&amp;gt;instance);&lt;br /&gt;
        	$certificates = mod_certificate_external::get_issued_certificates($cm-&amp;gt;instance);&lt;br /&gt;
        	$issues = array_values($certificates[&#039;issues&#039;]); // Make it mustache compatible.&lt;br /&gt;
    	} catch (Exception $e) {&lt;br /&gt;
        	$issues = array();&lt;br /&gt;
    	}&lt;br /&gt;
&lt;br /&gt;
    	$data = array(&lt;br /&gt;
        	&#039;issues&#039; =&amp;gt; $issues&lt;br /&gt;
    	);&lt;br /&gt;
&lt;br /&gt;
    	return array(&lt;br /&gt;
        	&#039;templates&#039; =&amp;gt; array(&lt;br /&gt;
            	array(&lt;br /&gt;
                	&#039;id&#039; =&amp;gt; &#039;main&#039;,&lt;br /&gt;
                	&#039;html&#039; =&amp;gt; $OUTPUT-&amp;gt;render_from_template(&#039;mod_certificate/mobile_view_issues&#039;, $data),&lt;br /&gt;
            	),&lt;br /&gt;
        	),&lt;br /&gt;
        	&#039;javascript&#039; =&amp;gt; &#039;&#039;,&lt;br /&gt;
        	&#039;otherdata&#039; =&amp;gt; &#039;&#039;&lt;br /&gt;
    	);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function for the new page was added just after the mobile_course_view function, the code is quite similar: Capabilities checks, retrieves the information required for the template and returns the template rendered.&lt;br /&gt;
&lt;br /&gt;
The code of the mustache template is also very simple:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;File contents: mod/certificate/templates/mobile_view_issues.mustache&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
{{=&amp;lt;% %&amp;gt;=}}&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
	&amp;lt;ion-list&amp;gt;&lt;br /&gt;
    	&amp;lt;%#issues%&amp;gt;&lt;br /&gt;
        	&amp;lt;ion-item&amp;gt;&lt;br /&gt;
            	&amp;lt;p class=&amp;quot;item-heading&amp;quot;&amp;gt;{{ &amp;lt;%timecreated%&amp;gt; | coreToLocaleString }}&amp;lt;/p&amp;gt;&lt;br /&gt;
            	&amp;lt;p&amp;gt;&amp;lt;%grade%&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
        	&amp;lt;/ion-item&amp;gt;&lt;br /&gt;
    	&amp;lt;%/issues%&amp;gt;&lt;br /&gt;
	&amp;lt;/ion-list&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As we did in the previous template, in the first line of the template we switch delimiters to avoid conflicting with Ionic delimiters (that are curly brackets like mustache). &lt;br /&gt;
&lt;br /&gt;
Here we are creating an ionic list that will display a new item in the list per each issued certificated.&lt;br /&gt;
&lt;br /&gt;
For the issued certificated we’ll display the time when it was created (using the app filter &#039;&#039;coreToLocaleString&#039;&#039;). We are also displaying the grade displayed in the certificate (if any). &lt;br /&gt;
&lt;br /&gt;
===Step 5. Plugin webservices, if included===&lt;br /&gt;
&lt;br /&gt;
If your plugin uses its own web services, they will also need to be enabled for mobile access in your db/services.php file.&lt;br /&gt;
&lt;br /&gt;
The following line &amp;lt;code&amp;gt;&#039;services&#039;      =&amp;gt; array(MOODLE_OFFICIAL_MOBILE_SERVICE, &#039;local_mobile&#039;),&amp;lt;/code&amp;gt; should be included in each webservice definition.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;File contents: mod/certificate/db/services.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$functions = array(&lt;br /&gt;
&lt;br /&gt;
    &#039;mod_certificate_get_certificates_by_courses&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;classname&#039;     =&amp;gt; &#039;mod_certificate_external&#039;,&lt;br /&gt;
        &#039;methodname&#039;    =&amp;gt; &#039;get_certificates_by_courses&#039;,&lt;br /&gt;
        &#039;description&#039;   =&amp;gt; &#039;Returns a list of certificate instances...&#039;,&lt;br /&gt;
        &#039;type&#039;          =&amp;gt; &#039;read&#039;,&lt;br /&gt;
        &#039;capabilities&#039;  =&amp;gt; &#039;mod/certificate:view&#039;,&lt;br /&gt;
        &#039;services&#039;      =&amp;gt; array(MOODLE_OFFICIAL_MOBILE_SERVICE, &#039;local_mobile&#039;),&lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
This extra services definition is the reason why you will need to have the local_mobile plugin installed for Moodle versions 3.4 and lower, so that your Moodle site will have all the additional webservices included to deal with all these mobile access calls. This is explained further in the [https://docs.moodle.org/dev/Mobile_support_for_plugins#Moodle_version_requirements Moodle version requirements section] below.&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
The first and most important thing to know is that you don’t need a local mobile environment, you can just use the Chrome or Chromium browser to add mobile support to your plugins!&lt;br /&gt;
&lt;br /&gt;
Open this URL (with Chrome or Chromium browser): https://mobileapp.moodledemo.net/ and you will see a web version of the mobile app completely functional (except for some native features). This URL is updated with the latest integration version of the app.&lt;br /&gt;
&lt;br /&gt;
Please test that your site works correctly in the web version before starting any development.&lt;br /&gt;
&lt;br /&gt;
===Moodle version requirements===&lt;br /&gt;
&lt;br /&gt;
If your Moodle version is lower than 3.5 (to be released in May) you will need to install the [https://docs.moodle.org/en/Moodle_Mobile_additional_features Moodle Mobile additional features plugin]. &lt;br /&gt;
&lt;br /&gt;
Please use this development version for now: https://github.com/moodlehq/moodle-local_mobile/commits/MOODLE_31_STABLE (if your Moodle version is 3.2, 3.3 or 3.4) you will have to use the specific branch for your version but applying manually the [https://github.com/moodlehq/moodle-local_mobile/commits/MOODLE_31_STABLE last commit from the 3.1 branch] (the one with number MOBILE-2362).&lt;br /&gt;
&lt;br /&gt;
Also, when installing the Moodle Mobile Additional features plugin you must follow the installation instructions so the service is set up properly.&lt;br /&gt;
&lt;br /&gt;
Remember to update your plugin documentation to reflect that this plugin is mandatory for Mobile support. We don’t recommend to indicate in your plugin version.php a dependency to local_mobile though.&lt;br /&gt;
&lt;br /&gt;
===Development workflow===&lt;br /&gt;
&lt;br /&gt;
First of all, we recommend creating a simple &#039;&#039;mobile.php&#039;&#039; for displaying a new main menu option (even if your plugin won’t be in the main menu, just to verify that you are able to extend the app plugins). Then open the webapp (https://mobileapp.moodledemo.net/) or refresh the browser if it was already open. Check that you can correctly  see the new menu option you included.&lt;br /&gt;
&lt;br /&gt;
Then, develop the main function of the app returning a “Hello world” or basic code (without using templates) to see that everything works together. After adding the classes/output/mobile.php file it is very important to “Purge all caches” to avoid problems with the auto-loading cache.&lt;br /&gt;
&lt;br /&gt;
It is important to remember that:&lt;br /&gt;
* Any change in the mobile.php file will require you to refresh the web app page in the browser (remember to disable the cache in the Chrome developer options).&lt;br /&gt;
* Any change in an existing template or function won’t require to refresh the browser page. In most cases you should just do a PTR (Pull down To Refresh) in the page that displays the view returned by the function. Be aware that PTR will work only when using the “device” emulation in the browser (see following section).&lt;br /&gt;
&lt;br /&gt;
===Testing and debugging===&lt;br /&gt;
&lt;br /&gt;
To learn how to debug with the web version of the app, please read the following documents:&lt;br /&gt;
* [[Moodle Mobile debugging WS requests]] AND&lt;br /&gt;
* [[Moodle Mobile development using Chrome or Chromium]] (please, omit the installation section)&lt;br /&gt;
&lt;br /&gt;
For plugins using the Javascript API you may develop making use of the console.log function to add trace messages in your code that will be displayed in the browser console.&lt;br /&gt;
&lt;br /&gt;
==Mobile.php supported options==&lt;br /&gt;
&lt;br /&gt;
In the Step by Step section we learned about some of the existing options for handlers configuration. This is the full list of supported options:&lt;br /&gt;
&lt;br /&gt;
===Common options===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;displaydata&#039;&#039;&#039; (mandatory for certain types): Data used to display the handler. It will vary depending on the delegate, and some delegates won’t need it at all (like course format). Attributes usually required in the &#039;&#039;displaydata&#039;&#039;: title, icon, class.&lt;br /&gt;
* &#039;&#039;&#039;delegate&#039;&#039;&#039; (mandatory): Name of the delegate to register the handler in.&lt;br /&gt;
* &#039;&#039;&#039;method&#039;&#039;&#039; (mandatory): The function to call to retrieve the main page content.&lt;br /&gt;
* &#039;&#039;&#039;priority&#039;&#039;&#039; (optional): Priority of the handler. Only for certain delegates. Higher priority is displayed first. &lt;br /&gt;
* &#039;&#039;&#039;lang&#039;&#039;&#039; (optional): List of language strings.&lt;br /&gt;
* &#039;&#039;&#039;init&#039;&#039;&#039; (optional): A function to call to retrieve the initialization JS and the &amp;quot;restrict&amp;quot; to apply to the whole handler. It can also return templates that can be used from the Javascript of the init method or the Javascript of the handler’s method.&lt;br /&gt;
* &#039;&#039;&#039;restricttocurrentuser&#039;&#039;&#039; (optional) Only used if the delegate has a isEnabledForUser function. If true, the handler will only be shown for current user. For more info about displaying the plugin only for certain users, please see [[Mobile_support_for_plugins#Display_the_plugin_only_if_certain_conditions_are_met|Display the plugin only if certain conditions are met]].&lt;br /&gt;
* &#039;&#039;&#039;restricttoenrolledcourses&#039;&#039;&#039; (optional): Only used if the delegate has a isEnabledForCourse function. If true or not defined, the handler will only be shown for courses the user is enrolled in. For more info about displaying the plugin only for certain courses, please see [[Mobile_support_for_plugins#Display_the_plugin_only_if_certain_conditions_are_met|Display the plugin only if certain conditions are met]].&lt;br /&gt;
* &#039;&#039;&#039;styles&#039;&#039;&#039; (optional): An array with two properties: &#039;&#039;url&#039;&#039; and &#039;&#039;version&#039;&#039;. The URL should point to a CSS file, either using an absolute URL or a relative URL. This file will be downloaded and applied by the app. It&#039;s recommended to include styles that will only affect your plugin templates. The version number is used to determine if the file needs to be downloaded again, you should change the version number everytime you change the CSS file.&lt;br /&gt;
&lt;br /&gt;
===Options only for CoreCourseModuleDelegate===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;offlinefunctions&#039;&#039;&#039;: (optional) List of functions to call when prefetching the module. It can be a get_content method or a WS. You can filter the params received by the WS. By default, WS will receive these params: courseid, cmid, userid. Other valid values that will be added if they are present in the list of params: courseids (it will receive a list with the courses the user is enrolled in), component + &#039;id&#039; (e.g. certificateid).&lt;br /&gt;
* &#039;&#039;&#039;downloadbutton&#039;&#039;&#039;: (optional) Whether to display download button in the module. If not defined, the button will be shown if there is any offlinefunction.&lt;br /&gt;
* &#039;&#039;&#039;isresource&#039;&#039;&#039;: (optional) Whether the module is a resource or an activity. Only used if there is any offlinefunction. If your module relies on the &amp;quot;contents&amp;quot; field, then it should be true.&lt;br /&gt;
* &#039;&#039;&#039;updatesnames&#039;&#039;&#039;: (optional) Only used if there is any offlinefunction. A Regular Expression to check if there&#039;s any update in the module. It will be compared to the result of &#039;&#039;core_course_check_updates&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Options only for CoreCourseFormatDelegate===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;canviewallsections&#039;&#039;&#039;: (optional) Whether the course format allows seeing all sections in a single page. Defaults to true.&lt;br /&gt;
* &#039;&#039;&#039;displayenabledownload&#039;&#039;&#039;: (optional) Whether the option to enable section/module download should be displayed. Defaults to true.&lt;br /&gt;
* &#039;&#039;&#039;displaysectionselector&#039;&#039;&#039;: (optional) Whether the default section selector should be displayed. Defaults to true.&lt;br /&gt;
&lt;br /&gt;
===Options only for CoreUserDelegate===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;type&#039;&#039;&#039;: The type of the addon. Values accepted: &#039;newpage&#039; (default) or  &#039;communication&#039;. &lt;br /&gt;
&lt;br /&gt;
==Delegates==&lt;br /&gt;
&lt;br /&gt;
===CoreMainMenuDelegate===&lt;br /&gt;
&lt;br /&gt;
You must use this delegate when you want to add new items to the main menu (currently displayed at the bottom of the app). &lt;br /&gt;
&lt;br /&gt;
===CoreCourseOptionsDelegate===&lt;br /&gt;
&lt;br /&gt;
You must use this delegate when you want to add new options in a course (Participants or Grades are examples of this type of delegate).&lt;br /&gt;
&lt;br /&gt;
===CoreCourseModuleDelegate===&lt;br /&gt;
&lt;br /&gt;
You must use this delegate for supporting activity modules or resources, please review the specific options for this delegate in the “Options only for CoreCourseModuleDelegate” section.&lt;br /&gt;
&lt;br /&gt;
===CoreUserDelegate===&lt;br /&gt;
&lt;br /&gt;
You must use this delegate when you want to add additional options in the user profile page in the app. Options can be of different types (newpage, communication or action).&lt;br /&gt;
&lt;br /&gt;
===CoreCourseFormatDelegate===&lt;br /&gt;
&lt;br /&gt;
You must use this delegate for supporting course formats, please review the specific options for this delegate in the “Options only for CoreCourseFormatDelegate” section.&lt;br /&gt;
&lt;br /&gt;
===Other advanced delegates===&lt;br /&gt;
&lt;br /&gt;
This delegates require JavaScript to be supported. See [[Mobile_support_for_plugins#Initialization|Initialization]] for more information.&lt;br /&gt;
&lt;br /&gt;
* CoreContentLinksDelegate&lt;br /&gt;
* CoreUserProfileFieldDelegate&lt;br /&gt;
* CoreCourseModulePrefetchDelegate&lt;br /&gt;
* CoreFileUploaderDelegate&lt;br /&gt;
* CorePluginFileDelegate&lt;br /&gt;
&lt;br /&gt;
==Available components and directives==&lt;br /&gt;
&lt;br /&gt;
===Difference between component and directives===&lt;br /&gt;
&lt;br /&gt;
A component (represented as an HTML tag) is used to add custom elements to the app.&lt;br /&gt;
Example of components are: ion-list, ion-item, core-search-box&lt;br /&gt;
&lt;br /&gt;
A directive (represented as an HTML attribute) allows you to extend a piece of HTML with additional information or functionality.&lt;br /&gt;
Example of directives are: core-auto-focus, *ngIf, ng-repeat&lt;br /&gt;
&lt;br /&gt;
The Mobile app uses Angular, Ionic and custom components and directives, for a full reference of:&lt;br /&gt;
* Angular directives, please check: https://angular.io/api?type=directive&lt;br /&gt;
* Ionic components, please check: https://ionicframework.com/docs/&lt;br /&gt;
&lt;br /&gt;
===Custom core components and directives===&lt;br /&gt;
&lt;br /&gt;
These are some useful custom components and directives (only available in the mobile app). Please notice that this isn’t the full list of components and directives of the app, it’s just an extract of the most common ones.&lt;br /&gt;
&lt;br /&gt;
====core-format-text====&lt;br /&gt;
&lt;br /&gt;
This directive formats the text and adds some directives needed for the app to work as it should. For example, it treats all links and all the embedded media so they work fine in the app. If some content in your template includes links or embedded media, please use this directive.&lt;br /&gt;
&lt;br /&gt;
This directive automatically applies core-external-content and core-link to all the links and embedded media.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;text&#039;&#039;&#039; (string): The text to format.&lt;br /&gt;
* &#039;&#039;&#039;siteId&#039;&#039;&#039; (string): Optional. Site ID to use. If not defined, current site.&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): Optional. Component to use when downloading embedded files.&lt;br /&gt;
* &#039;&#039;&#039;componentId&#039;&#039;&#039; (string|number): Optional. ID to use in conjunction with the component.&lt;br /&gt;
* &#039;&#039;&#039;adaptImg&#039;&#039;&#039; (boolean): Optional. Whether to adapt images to screen width. Defaults to true.&lt;br /&gt;
* &#039;&#039;&#039;clean&#039;&#039;&#039; (boolean): Optional. Whether all the HTML tags should be removed. Defaults to false.&lt;br /&gt;
* &#039;&#039;&#039;singleLine&#039;&#039;&#039; (boolean): Optional. Whether new lines should be removed (all text in single line). Only if clean=true. Defaults to false.&lt;br /&gt;
* &#039;&#039;&#039;maxHeight&#039;&#039;&#039; (number): Optional. Max height in pixels to render the content box. It should be 50 at least to make sense. Using this parameter will force display: block to calculate height better. If you want to avoid this use class=&amp;quot;inline&amp;quot; at the same time to use display: inline-block.&lt;br /&gt;
* &#039;&#039;&#039;fullOnClick&#039;&#039;&#039; (boolean): Optional. Whether it should open a new page with the full contents on click. Only if maxHeight is set and the content has been collapsed. Defaults to false.&lt;br /&gt;
* &#039;&#039;&#039;fullTitle&#039;&#039;&#039; (string): Optional. Title to use in full view. Defaults to &amp;quot;Description&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;core-format-text text=&amp;quot;&amp;lt;% cm.description %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; componentId=&amp;quot;&amp;lt;% cm.id %&amp;gt;&amp;quot;&amp;gt;&amp;lt;/core-format-text&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-link====&lt;br /&gt;
&lt;br /&gt;
Directive to handle a link. It performs several checks, like checking if the link needs to be opened in the app, and opens the link as it should (without overriding the app).&lt;br /&gt;
&lt;br /&gt;
This directive is automatically applied to all the links and media inside core-format-text.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;capture&#039;&#039;&#039; (boolean): Optional. Whether the link needs to be captured by the app (check if the link can be handled by the app instead of opening it in a browser).&lt;br /&gt;
* &#039;&#039;&#039;inApp&#039;&#039;&#039; (boolean): Optional. True to open in embedded browser, false to open in system browser.&lt;br /&gt;
* &#039;&#039;&#039;autoLogin&#039;&#039;&#039; (string): Optional. If the link should be open with auto-login. Accepts the following values:&lt;br /&gt;
** &amp;quot;yes&amp;quot; -&amp;gt; Always auto-login.&lt;br /&gt;
** &amp;quot;no&amp;quot; -&amp;gt; Never auto-login.&lt;br /&gt;
** &amp;quot;check&amp;quot; -&amp;gt; Auto-login only if it points to the current site. Default value.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;&amp;lt;% cm.url %&amp;gt;&amp;quot; core-link&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-external-content====&lt;br /&gt;
&lt;br /&gt;
Directive to handle links to files and embedded files. This directive should be used in any link to a file or any embedded file that you want to have available when the app is offline. &lt;br /&gt;
&lt;br /&gt;
If a file is downloaded, its URL will be replaced by the local file URL.&lt;br /&gt;
&lt;br /&gt;
This directive is automatically applied to all the links and media inside core-format-text.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;siteId&#039;&#039;&#039; (string): Optional. Site ID to use. If not defined, current site.&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): Optional. Component to use when downloading embedded files.&lt;br /&gt;
* &#039;&#039;&#039;componentId&#039;&#039;&#039; (string|number): Optional. ID to use in conjunction with the component.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;img src=&amp;quot;&amp;lt;% event.iconurl %&amp;gt;&amp;quot; core-external-content component=&amp;quot;mod_certificate&amp;quot; componentId=&amp;quot;&amp;lt;% event.id %&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-user-link====&lt;br /&gt;
&lt;br /&gt;
Directive to go to user profile on click. When the user clicks the element where this directive is attached, the right user profile will be opened.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;userId&#039;&#039;&#039; (number): User id to open the profile.&lt;br /&gt;
* &#039;&#039;&#039;courseId&#039;&#039;&#039; (number): Optional. Course id to show the user info related to that course.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;a ion-item core-user-link userId=&amp;quot;&amp;lt;% userid %&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-file====&lt;br /&gt;
&lt;br /&gt;
Component to handle a remote file. It shows the file name, icon (depending on mimetype) and a button to download/refresh it. The user can identify if the file is downloaded or not based on the button.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* file (object): The file. Must have a property &#039;filename&#039; and a &#039;fileurl&#039; or &#039;url&#039;&lt;br /&gt;
* component (string): Optional. Component the file belongs to.&lt;br /&gt;
* componentId (string|number): Optional. ID to use in conjunction with the component.&lt;br /&gt;
* canDelete (boolean): Optional. Whether file can be deleted.&lt;br /&gt;
* alwaysDownload (boolean): Optional. Whether it should always display the refresh button when the file is downloaded. Use it for files that you cannot determine if they&#039;re outdated or not.&lt;br /&gt;
* canDownload (boolean): Optional. Whether file can be downloaded. Defaults to true.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;core-file [file]=&amp;quot;{fileurl: &amp;lt;% issue.url %&amp;gt;, filename: &amp;lt;% issue.name %&amp;gt;, timemodified: &amp;lt;% issue.timemodified %&amp;gt;, filesize: &amp;lt;% issue.size %&amp;gt;}&amp;quot; component=&amp;quot;mod_certificate&amp;quot; componentId=&amp;quot;&amp;lt;% cm.id %&amp;gt;&amp;quot;&amp;gt;&amp;lt;/core-file&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-download-file====&lt;br /&gt;
&lt;br /&gt;
Directive to allow downloading and open a file. When the item with this directive is clicked, the file will be downloaded (if needed) and opened.&lt;br /&gt;
&lt;br /&gt;
It is usually recommended to use the core-file component since it also displays the state of the file.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;core-download-file&#039;&#039;&#039; (object): The file to download.&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): Optional. Component to link the file to.&lt;br /&gt;
* &#039;&#039;&#039;componentId&#039;&#039;&#039; (string|number): Optional. Component ID to use in conjunction with the component.&lt;br /&gt;
&lt;br /&gt;
Example usage: a button to download a file.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button [core-download-file]=&amp;quot;{fileurl: &amp;lt;% issue.url %&amp;gt;, timemodified: &amp;lt;% issue.timemodified %&amp;gt;, filesize: &amp;lt;% issue.size %&amp;gt;}&amp;quot; component=&amp;quot;mod_certificate&amp;quot; componentId=&amp;quot;&amp;lt;% cm.id %&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
     {{ &#039;plugin.mod_certificate.download | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-course-download-module-main-file====&lt;br /&gt;
&lt;br /&gt;
Directive to allow downloading and opening the main file of a module.&lt;br /&gt;
&lt;br /&gt;
When the item with this directive is clicked, the whole module will be downloaded (if needed) and its main file opened. This is meant for modules like mod_resource.&lt;br /&gt;
&lt;br /&gt;
This directive must receive either a module or a moduleId. If no files are provided, it will use module.contents.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;module&#039;&#039;&#039; (object): Optional. The module object. Required if module is not supplied.&lt;br /&gt;
* &#039;&#039;&#039;moduleId&#039;&#039;&#039; (number): Optional. The module ID. Required if module is not supplied.&lt;br /&gt;
* &#039;&#039;&#039;courseId&#039;&#039;&#039; (number): The course ID the module belongs to.&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): Optional. Component to link the file to.&lt;br /&gt;
* &#039;&#039;&#039;componentId&#039;&#039;&#039; (string|number): Optional. Component ID to use in conjunction with the component. If not defined, moduleId.&lt;br /&gt;
* &#039;&#039;&#039;files&#039;&#039;&#039; (object[]): Optional. List of files of the module. If not provided, use module.contents.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button block core-course-download-module-main-file moduleId=&amp;quot;&amp;lt;% cmid %&amp;gt;&amp;quot; courseId=&amp;quot;&amp;lt;% certificate.course %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; [files]=&amp;quot;[{fileurl: &#039;&amp;lt;% issue.fileurl %&amp;gt;&#039;, filename: &#039;&amp;lt;% issue.filename %&amp;gt;&#039;, timemodified: &#039;&amp;lt;% issue.timemodified %&amp;gt;&#039;, mimetype: &#039;&amp;lt;% issue.mimetype %&amp;gt;&#039;}]&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.getcertificate&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-navbar-buttons====&lt;br /&gt;
&lt;br /&gt;
Component to add buttons to the app&#039;s header without having to place them inside the header itself. Using this component in a site plugin will allow adding buttons to the header of the current page.&lt;br /&gt;
&lt;br /&gt;
If this component indicates a position (start/end), the buttons will only be added if the header has some buttons in that position. If no start/end is specified, then the buttons will be added to the first &amp;lt;ion-buttons&amp;gt; found in the header.&lt;br /&gt;
&lt;br /&gt;
You can use the [hidden] input to hide all the inner buttons if a certain condition is met.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;core-navbar-buttons end&amp;gt;&lt;br /&gt;
    &amp;lt;button ion-button icon-only (click)=&amp;quot;action()&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;ion-icon name=&amp;quot;funnel&amp;quot;&amp;gt;&amp;lt;/ion-icon&amp;gt;&lt;br /&gt;
    &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/core-navbar-buttons&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Specific component and directives for plugins===&lt;br /&gt;
&lt;br /&gt;
These are component and directives created specifically for supporting Moodle plugins.&lt;br /&gt;
&lt;br /&gt;
====core-site-plugins-new-content====&lt;br /&gt;
&lt;br /&gt;
Directive to display a new content when clicked. This new content can be displayed in a new page or in the current page (only if the current page is already displaying a site plugin content).&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): The component of the new content.&lt;br /&gt;
* &#039;&#039;&#039;method&#039;&#039;&#039; (string): The method to get the new content.&lt;br /&gt;
* &#039;&#039;&#039;args&#039;&#039;&#039; (object): The params to get the new content.&lt;br /&gt;
* &#039;&#039;&#039;title&#039;&#039;&#039; (string): The title to display with the new content. Only if samePage=false.&lt;br /&gt;
* &#039;&#039;&#039;samePage&#039;&#039;&#039; (boolean): Whether to display the content in same page or open a new one. Defaults to new page.&lt;br /&gt;
* &#039;&#039;&#039;useOtherData&#039;&#039;&#039; (any): Whether to include &#039;&#039;otherdata&#039;&#039; (from the &#039;&#039;get_content&#039;&#039; WS call) in the args for the new &#039;&#039;get_content&#039;&#039; call. The format is the same as in &#039;&#039;useOtherDataForWS&#039;&#039;. If not supplied, no other data will be added. If supplied but empty (null, false or empty string) all the &#039;&#039;otherdata&#039;&#039; will be added. If it’s an array, it will only copy the properties whose names are in the array.&lt;br /&gt;
* &#039;&#039;&#039;form&#039;&#039;&#039; (string): ID or name to identify a form in the template. The form will be obtained from &#039;&#039;document.forms&#039;&#039;. If supplied and form is found, the form data will be retrieved and sent to the new &#039;&#039;get_content&#039;&#039; WS call. If your form contains an ion-radio, ion-checkbox or ion-select, please see [[Mobile_support_for_plugins#Values_of_ion-radio.2C_ion-checkbox_or_ion-select_aren.27t_sent_to_my_WS|Values of ion-radio, ion-checkbox or ion-select aren&#039;t sent to my WS]].&lt;br /&gt;
&lt;br /&gt;
Example usages:&lt;br /&gt;
&lt;br /&gt;
A button to go to a new content page:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-new-content title=&amp;quot;&amp;lt;% certificate.name %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; method=&amp;quot;mobile_issues_view&amp;quot; [args]=&amp;quot;{cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;}&amp;quot;&amp;gt;&lt;br /&gt;
     {{ &#039;plugin.mod_certificate.viewissued&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A button to load new content in current page using userid from otherdata:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-new-content component=&amp;quot;mod_certificate&amp;quot; method=&amp;quot;mobile_issues_view&amp;quot; [args]=&amp;quot;{cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;}&amp;quot; samePage=&amp;quot;true&amp;quot; [useOtherData]=&amp;quot;[&#039;userid&#039;]&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.viewissued&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-site-plugins-call-ws====&lt;br /&gt;
&lt;br /&gt;
Directive to call a WS when the element is clicked. The action to do when the WS call is successful depends on the provided data: display a message, go back or refresh current view.&lt;br /&gt;
&lt;br /&gt;
If you want to load a new content when the WS call is done, please see core-site-plugins-call-ws-new-content.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; (string): The name of the WS to call.&lt;br /&gt;
* &#039;&#039;&#039;params&#039;&#039;&#039; (object): The params for the WS call.&lt;br /&gt;
* preSets (object): Extra options for the WS call: whether to use cache or not, etc.&lt;br /&gt;
* &#039;&#039;&#039;useOtherDataForWS&#039;&#039;&#039; (any): Whether to include &#039;&#039;otherdata&#039;&#039; (from the &#039;&#039;get_content&#039;&#039; WS call) in the params for the WS call. If not supplied, no other data will be added. If supplied but empty (null, false or empty string) all the &#039;&#039;otherdata&#039;&#039; will be added. If it’s an array, it will only copy the properties whose names are in the array.&lt;br /&gt;
* &#039;&#039;&#039;form&#039;&#039;&#039; (string): ID or name to identify a form in the template. The form will be obtained from &#039;&#039;document.forms&#039;&#039;. If supplied and form is found, the form data will be retrieved and sent to the WS. If your form contains an ion-radio, ion-checkbox or ion-select, please see [[Mobile_support_for_plugins#Values_of_ion-radio.2C_ion-checkbox_or_ion-select_aren.27t_sent_to_my_WS|Values of ion-radio, ion-checkbox or ion-select aren&#039;t sent to my WS]].&lt;br /&gt;
* &#039;&#039;&#039;confirmMessage&#039;&#039;&#039; (string): Message to confirm the action when the user clicks the element. If not supplied, no confirmation. If supplied but empty, default message (&amp;quot;Are you sure?&amp;quot;).&lt;br /&gt;
* &#039;&#039;&#039;successMessage&#039;&#039;&#039; (string): Message to show on success. If not supplied, no message. If supplied but empty, default message (“Success”).&lt;br /&gt;
* &#039;&#039;&#039;goBackOnSuccess&#039;&#039;&#039; (boolean): Whether to go back if the WS call is successful.&lt;br /&gt;
* &#039;&#039;&#039;refreshOnSuccess&#039;&#039;&#039; (boolean): Whether to refresh the current view if the WS call is successful.&lt;br /&gt;
&lt;br /&gt;
Example usages:&lt;br /&gt;
&lt;br /&gt;
A button to send some data to the server without using cache, displaying default messages and refreshing on success:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-call-ws name=&amp;quot;mod_certificate_view_certificate&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; [preSets]=&amp;quot;{getFromCache: 0, saveToCache: 0}&amp;quot; confirmMessage successMessage refreshOnSuccess=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.senddata&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A button to send some data to the server using cache without confirming, going back on success and using userid from otherdata:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-call-ws name=&amp;quot;mod_certificate_view_certificate&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; goBackOnSuccess=&amp;quot;true&amp;quot; [useOtherData]=&amp;quot;[&#039;userid&#039;]&amp;quot;&amp;gt;&lt;br /&gt;
     {{ &#039;plugin.mod_certificate.senddata&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-site-plugins-call-ws-new-content====&lt;br /&gt;
&lt;br /&gt;
Directive to call a WS when the element is clicked and load a new content passing the WS result as args. This new content can be displayed in a new page or in the same page (only if current page is already displaying a site plugin content).&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t need to load some new content when done, please see core-site-plugins-call-ws.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; (string): The name of the WS to call.&lt;br /&gt;
* &#039;&#039;&#039;params&#039;&#039;&#039; (object): The params for the WS call.&lt;br /&gt;
* &#039;&#039;&#039;preSets&#039;&#039;&#039; (object): Extra options for the WS call: whether to use cache or not, etc.&lt;br /&gt;
* &#039;&#039;&#039;useOtherDataForWS&#039;&#039;&#039; (any): Whether to include &#039;&#039;otherdata&#039;&#039; (from the &#039;&#039;get_content&#039;&#039; WS call) in the params for the WS call. If not supplied, no other data will be added. If supplied but empty (null, false or empty string) all the &#039;&#039;otherdata&#039;&#039; will be added. If it’s an array, it will only copy the properties whose names are in the array.&lt;br /&gt;
* &#039;&#039;&#039;form&#039;&#039;&#039; (string): ID or name to identify a form in the template. The form will be obtained from &#039;&#039;document.forms&#039;&#039;. If supplied and form is found, the form data will be retrieved and sent to the WS. If your form contains an ion-radio, ion-checkbox or ion-select, please see [[Mobile_support_for_plugins#Values_of_ion-radio.2C_ion-checkbox_or_ion-select_aren.27t_sent_to_my_WS|Values of ion-radio, ion-checkbox or ion-select aren&#039;t sent to my WS]].&lt;br /&gt;
* &#039;&#039;&#039;confirmMessage&#039;&#039;&#039; (string): Message to confirm the action when the user clicks the element. If not supplied, no confirmation. If supplied but empty, default message (&amp;quot;Are you sure?&amp;quot;).&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): The component of the new content.&lt;br /&gt;
* &#039;&#039;&#039;method&#039;&#039;&#039; (string): The method to get the new content.&lt;br /&gt;
* &#039;&#039;&#039;args&#039;&#039;&#039; (object): The params to get the new content.&lt;br /&gt;
* &#039;&#039;&#039;title&#039;&#039;&#039; (string): The title to display with the new content. Only if samePage=false.&lt;br /&gt;
* &#039;&#039;&#039;samePage&#039;&#039;&#039; (boolean): Whether to display the content in same page or open a new one. Defaults to new page.&lt;br /&gt;
* &#039;&#039;&#039;useOtherData&#039;&#039;&#039; (any): Whether to include &#039;&#039;otherdata&#039;&#039; (from the &#039;&#039;get_content&#039;&#039; WS call) in the args for the new &#039;&#039;get_content&#039;&#039; call. The format is the same as in &#039;&#039;useOtherDataForWS&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Example usages:&lt;br /&gt;
&lt;br /&gt;
A button to get some data from the server without using cache, showing default confirm and displaying a new page:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-call-ws-new-content name=&amp;quot;mod_certificate_get_issued_certificates&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; [preSets]=&amp;quot;{getFromCache: 0, saveToCache: 0}&amp;quot; confirmMessage title=&amp;quot;&amp;lt;% certificate.name %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; method=&amp;quot;mobile_issues_view&amp;quot; [args]=&amp;quot;{cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;}&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.getissued&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A button to get some data from the server using cache, without confirm, displaying new content in same page and using &#039;&#039;userid&#039;&#039; from &#039;&#039;otherdata&#039;&#039;:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-call-ws-new-content name=&amp;quot;mod_certificate_get_issued_certificates&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; component=&amp;quot;mod_certificate&amp;quot; method=&amp;quot;mobile_issues_view&amp;quot; [args]=&amp;quot;{cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;}&amp;quot; samePage=&amp;quot;true&amp;quot; [useOtherData]=&amp;quot;[&#039;userid&#039;]&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.getissued&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-site-plugins-call-ws-on-load====&lt;br /&gt;
&lt;br /&gt;
Directive to call a WS as soon as the template is loaded. This directive is meant for actions to do in the background, like calling logging Web Services.&lt;br /&gt;
&lt;br /&gt;
If you want to call a WS when the user clicks on a certain element, please see core-site-plugins-call-ws.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; (string): The name of the WS to call.&lt;br /&gt;
* &#039;&#039;&#039;params&#039;&#039;&#039; (object): The params for the WS call.&lt;br /&gt;
* &#039;&#039;&#039;preSets&#039;&#039;&#039; (object): Extra options for the WS call: whether to use cache or not, etc.&lt;br /&gt;
* &#039;&#039;&#039;useOtherDataForWS&#039;&#039;&#039; (any): Whether to include &#039;&#039;otherdata&#039;&#039; (from the &#039;&#039;get_content&#039;&#039; WS call) in the params for the WS call. If not supplied, no other data will be added. If supplied but empty (null, false or empty string) all the &#039;&#039;otherdata&#039;&#039; will be added. If it’s an array, it will only copy the properties whose names are in the array.&lt;br /&gt;
* &#039;&#039;&#039;form&#039;&#039;&#039; (string): ID or name to identify a form in the template. The form will be obtained from &#039;&#039;document.forms&#039;&#039;. If supplied and form is found, the form data will be retrieved and sent to the WS. If your form contains an ion-radio, ion-checkbox or ion-select, please see [[Mobile_support_for_plugins#Values_of_ion-radio.2C_ion-checkbox_or_ion-select_aren.27t_sent_to_my_WS|Values of ion-radio, ion-checkbox or ion-select aren&#039;t sent to my WS]].&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;span core-site-plugins-call-ws-on-load name=&amp;quot;mod_certificate_view_certificate&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; [preSets]=&amp;quot;{getFromCache: 0, saveToCache: 0}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Advanced features==&lt;br /&gt;
&lt;br /&gt;
===Display the plugin only if certain conditions are met===&lt;br /&gt;
&lt;br /&gt;
You might want to display your plugin in the mobile app only if certain dynamic conditions are met, so the plugin would be displayed only for some users. This can be achieved using the &amp;quot;init&amp;quot; method (for more info, please see the [[Mobile_support_for_plugins#Initialization|Initialization]] section ahead).&lt;br /&gt;
&lt;br /&gt;
All the init methods are called as soon as your plugin is retrieved. If you don&#039;t want your plugin to be displayed for the current user, then you should return an exception in this init method. It&#039;s recommended to include a message explaining why the plugin isn&#039;t available for the current user, this exception will be logged in the Javascript console.&lt;br /&gt;
&lt;br /&gt;
On the other hand, you might want to display a plugin only for certain courses (&#039;&#039;CoreCourseOptionsDelegate&#039;&#039;) or only if the user is viewing certain users&#039; profiles (&#039;&#039;CoreUserDelegate&#039;&#039;). This can be achieved with the init method too.&lt;br /&gt;
&lt;br /&gt;
In the init method you can return a &amp;quot;restrict&amp;quot; property with two fields in it: &#039;&#039;courses&#039;&#039; and &#039;&#039;users&#039;&#039;. If you return a list of courses IDs in this restrict property, then your plugin will only be displayed when the user views any of those courses. In the same way, if you return a list of user IDs then your plugin will only be displayed when the user views any of those users&#039; profiles.&lt;br /&gt;
&lt;br /&gt;
===Using “otherdata”===&lt;br /&gt;
&lt;br /&gt;
The values returned by the functions in otherdata are added to a variable so they can be used both in Javascript and in templates. The otherdata returned by a init call is added to a variable named INIT_OTHERDATA, while the otherdata returned by a &#039;&#039;get_content&#039;&#039; WS call is added to a variable named CONTENT_OTHERDATA.&lt;br /&gt;
&lt;br /&gt;
The otherdata returned by a init call will be passed to the JS and template of all the get_content calls in that handler. The otherdata returned by a get_content call will only be passed to the JS and template returned by that get_content call.&lt;br /&gt;
&lt;br /&gt;
This means that, in your Javascript, you can access and use these data like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
this.CONTENT_OTHERDATA.myVar&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
And in the template you could use it like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
{{ CONTENT_OTHERDATA.myVar }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;myVar&#039;&#039; is the name we put to one of our variables, it can be the name you want. In the example above, this is the otherdata returned by the PHP method:&lt;br /&gt;
&lt;br /&gt;
array(&#039;myVar&#039; =&amp;gt; &#039;Initial value&#039;)&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
In our plugin we want to display an input text with a certain initial value. When the user clicks a button, we want the value in the input to be sent to a certain WebService. This can be done using otherdata.&lt;br /&gt;
&lt;br /&gt;
We will return the initial value of the input in the otherdata of our PHP method:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&#039;otherdata&#039; =&amp;gt; array(&#039;myVar&#039; =&amp;gt; &#039;My initial value&#039;),&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Then in the template we will use it like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;ion-item text-wrap&amp;gt;&lt;br /&gt;
    &amp;lt;ion-label stacked&amp;gt;{{ &#039;plugin.mod_certificate.textlabel | translate }}&amp;lt;/ion-label&amp;gt;&lt;br /&gt;
    &amp;lt;ion-input type=&amp;quot;text&amp;quot; [(ngModel)]=&amp;quot;CONTENT_OTHERDATA.myVar&amp;quot;&amp;gt;&amp;lt;/ion-input&amp;gt;&lt;br /&gt;
&amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&amp;lt;ion-item&amp;gt;&lt;br /&gt;
    &amp;lt;button ion-button block color=&amp;quot;light&amp;quot; core-site-plugins-call-ws name=&amp;quot;mod_certificate_my_webservice&amp;quot; [useOtherDataForWS]=&amp;quot;[&#039;myVar&#039;]&amp;quot;&amp;gt;&lt;br /&gt;
        {{ &#039;plugin.mod_certificate.send | translate }}&lt;br /&gt;
    &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, we are creating an input text and we use &#039;&#039;[(ngModel)]&#039;&#039; to use the value in &#039;&#039;myVar&#039;&#039; as the initial value and to store the changes in the same &#039;&#039;myVar&#039;&#039; variable. This means that the initial value of the input will be “My initial value”, and if the user changes the value of the input these changes will be applied to the &#039;&#039;myVar&#039;&#039; variable. This is called 2-way data binding in Angular.&lt;br /&gt;
&lt;br /&gt;
Then we add a button to send this data to a WS, and for that we use the directive core-site-plugins-call-ws. We use the &#039;&#039;useOtherDataForWS&#039;&#039; attribute to specify which variable from &#039;&#039;otherdata&#039;&#039; we want to send to our WebService. So if the user enters “A new value” in the input and then clicks the button, it will call the WebService &#039;&#039;mod_certificate_my_webservice&#039;&#039; and will send as a param: myVar -&amp;gt; “A new value”.&lt;br /&gt;
&lt;br /&gt;
We can achieve the same result using the &#039;&#039;params&#039;&#039; attribute of the core-site-plugins-call-ws directive instead of using &#039;&#039;useOtherDataForWS&#039;&#039;:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button block color=&amp;quot;light&amp;quot; core-site-plugins-call-ws name=&amp;quot;mod_certificate_my_webservice&amp;quot; [params]=&amp;quot;{myVar: CONTENT_OTHERDATA.myVar}&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.send | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The WebService call will be exactly the same with both buttons.&lt;br /&gt;
&lt;br /&gt;
Please notice that this example could be done without using otherdata too, using the “&#039;&#039;form&#039;&#039;” input of the &#039;&#039;core-site-plugins-call-ws directive&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===JS functions visible in the templates===&lt;br /&gt;
&lt;br /&gt;
The app provides some Javascript functions that can be used from the templates to update, refresh or view content. These are the functions:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;openContent(title: string, args: any, component?: string, method?: string)&#039;&#039;&#039;: Open a new page to display some new content. You need to specify the &#039;&#039;title&#039;&#039; of the new page and the &#039;&#039;args&#039;&#039; to send to the method. If &#039;&#039;component&#039;&#039; and &#039;&#039;method&#039;&#039; aren&#039;t provided, it will use the same as in the current page.&lt;br /&gt;
* &#039;&#039;&#039;refreshContent(showSpinner = true)&#039;&#039;&#039;: Refresh the current content. By default it will display a spinner while refreshing, if you don&#039;t want it to be displayed you should pass false as a parameter.&lt;br /&gt;
* &#039;&#039;&#039;updateContent(args: any, component?: string, method?: string)&#039;&#039;&#039;: Refresh the current content using different params. You need to specify the &#039;&#039;args&#039;&#039; to send to the method. If &#039;&#039;component&#039;&#039; and &#039;&#039;method&#039;&#039; aren&#039;t provided, it will use the same as in the current page.&lt;br /&gt;
&lt;br /&gt;
====Examples====&lt;br /&gt;
&lt;br /&gt;
=====Group selector=====&lt;br /&gt;
&lt;br /&gt;
Imagine we have an activity that uses groups and we want to let the user select which group he wants to see. A possible solution would be to return all the groups in the same template (hidden), and then show the group user selects. However, we can make it more dynamic and return only the group the user is requesting.&lt;br /&gt;
&lt;br /&gt;
To do so, we&#039;ll use a drop down to select the group. When the user selects a group using this drop down we&#039;ll update the page content to display the new group.&lt;br /&gt;
&lt;br /&gt;
The main difficulty in this is to tell the view which group needs to be selected when the view is loaded. There are 2 ways to do it: using plain HTML or using Angular&#039;s &#039;&#039;ngModel&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
======Using plain HTML======&lt;br /&gt;
&lt;br /&gt;
We need to add a &amp;quot;&#039;&#039;selected&#039;&#039;&amp;quot; attribute to the option that needs to be selected. To do so, we need to pre-caclulate the selected option in the PHP code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
        $groupid = empty($args-&amp;gt;group) ? 0 : $args-&amp;gt;group; // By default, group 0.&lt;br /&gt;
        $groups = groups_get_activity_allowed_groups($cm, $user-&amp;gt;id);&lt;br /&gt;
        // Detect which group is selected.&lt;br /&gt;
        foreach ($groups as $gid=&amp;gt;$group) {&lt;br /&gt;
            $group-&amp;gt;selected = $gid === $groupid;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $data = array(&lt;br /&gt;
            &#039;cmid&#039; =&amp;gt; $cm-&amp;gt;id,&lt;br /&gt;
            &#039;courseid&#039; =&amp;gt; $args-&amp;gt;courseid,&lt;br /&gt;
            &#039;groups&#039; =&amp;gt; $groups&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;templates&#039; =&amp;gt; array(&lt;br /&gt;
                array(&lt;br /&gt;
                    &#039;id&#039; =&amp;gt; &#039;main&#039;,&lt;br /&gt;
                    &#039;html&#039; =&amp;gt; $OUTPUT-&amp;gt;render_from_template(&#039;mod_certificate/mobile_view_page&#039;, $data),&lt;br /&gt;
                ),&lt;br /&gt;
            ),&lt;br /&gt;
        );&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the code above, we&#039;re retrieving the groups the user can see and then we&#039;re adding a &amp;quot;selected&amp;quot; bool to each one to determine which one needs to be selected in the drop down. Finally, we pass the list of groups to the template.&lt;br /&gt;
&lt;br /&gt;
In the template, we display the drop down like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;ion-select (ionChange)=&amp;quot;updateContent({cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;, group: $event})&amp;quot; interface=&amp;quot;popover&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;%#groups%&amp;gt;&lt;br /&gt;
        &amp;lt;ion-option value=&amp;quot;&amp;lt;% id %&amp;gt;&amp;quot; &amp;lt;%#selected%&amp;gt;selected&amp;lt;%/selected%&amp;gt; &amp;gt;&amp;lt;% name %&amp;gt;&amp;lt;/ion-option&amp;gt;&lt;br /&gt;
    &amp;lt;%/groups%&amp;gt;&lt;br /&gt;
&amp;lt;/ion-select&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;ionChange&#039;&#039; function will be called everytime the user selects a different group with the drop down. We&#039;re using the function &#039;&#039;updateContent&#039;&#039; to update the current view using the new group. &#039;&#039;$event&#039;&#039; is an Angular variable that will have the selected value (in our case, the group ID that was just selected). This is enough to make the group selector work.&lt;br /&gt;
&lt;br /&gt;
======Using ngModel======&lt;br /&gt;
&lt;br /&gt;
ngModel is an Angular directive that allows storing the value of a certain input/select in a Javascript variable, and also the opposite way: tell the input/select which value to set. The main problem is that we cannot initialize a Javascript variable from the template (Angular doesn&#039;t have &#039;&#039;ng-init&#039;&#039; like in AngularJS), so we&#039;ll use &amp;quot;otherdata&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In the PHP function we&#039;ll return the group that needs to be selected in the &#039;&#039;otherdata&#039;&#039; array:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
        $groupid = empty($args-&amp;gt;group) ? 0 : $args-&amp;gt;group; // By default, group 0.&lt;br /&gt;
        $groups = groups_get_activity_allowed_groups($cm, $user-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
         ...&lt;br /&gt;
&lt;br /&gt;
         return array(&lt;br /&gt;
            &#039;templates&#039; =&amp;gt; array(&lt;br /&gt;
                array(&lt;br /&gt;
                    &#039;id&#039; =&amp;gt; &#039;main&#039;,&lt;br /&gt;
                    &#039;html&#039; =&amp;gt; $OUTPUT-&amp;gt;render_from_template(&#039;mod_certificate/mobile_view_page&#039;, $data),&lt;br /&gt;
                ),&lt;br /&gt;
            ),&lt;br /&gt;
            &#039;otherdata&#039; =&amp;gt; array(&lt;br /&gt;
                &#039;group&#039; =&amp;gt; $groupid&lt;br /&gt;
            ),&lt;br /&gt;
        );&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above we don&#039;t need to iterate over the groups array like in the plain HTML example. However, now we&#039;re returning the groupid in the &amp;quot;otherdata&amp;quot; array. As it&#039;s explained in the [[Mobile_support_for_plugins#Using_.E2.80.9Cotherdata.E2.80.9D|Using &amp;quot;otherdata&amp;quot;]] section, this &amp;quot;otherdata&amp;quot; is visible in the templates inside a variable named &#039;&#039;CONTENT_OTHERDATA&#039;&#039;. So in the template we&#039;ll use this variable like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;ion-select [(ngModel)]=&amp;quot;CONTENT_OTHERDATA.group&amp;quot; (ionChange)=&amp;quot;updateContent({cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;, group: CONTENT_OTHERDATA.group})&amp;quot; interface=&amp;quot;popover&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;%#groups%&amp;gt;&lt;br /&gt;
        &amp;lt;ion-option value=&amp;quot;&amp;lt;% id %&amp;gt;&amp;quot;&amp;gt;&amp;lt;% name %&amp;gt;&amp;lt;/ion-option&amp;gt;&lt;br /&gt;
    &amp;lt;%/groups%&amp;gt;&lt;br /&gt;
&amp;lt;/ion-select&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Initialization===&lt;br /&gt;
&lt;br /&gt;
All handlers can specify a “&#039;&#039;init&#039;&#039;” method in the mobile.php file. This method is meant to return some JavaScript code that needs to be executed as soon as the plugin is retrieved.&lt;br /&gt;
&lt;br /&gt;
When the app retrieves all the handlers, the first thing it will do is call the &#039;&#039;tool_mobile_get_content&#039;&#039; WebService with the init method. This WS call will only receive the default args.&lt;br /&gt;
&lt;br /&gt;
The app will immediately execute the JavaScript code returned by this WS call. This JavaScript can be used to manually register your handlers in the delegates you want, without having to rely on the default handlers built based on the mobile.php data.&lt;br /&gt;
&lt;br /&gt;
The templates returned by this init method will be added to a INIT_TEMPLATES variable that will be passed to all the Javascript code of that handler. This means that the Javascript returned by the init method or the “main” method can access any of the templates HTML like this:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
this.INIT_TEMPLATES[‘main’];&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
In this case, “main” is the ID of the template we want to use.&lt;br /&gt;
&lt;br /&gt;
The same happens with the &#039;&#039;otherdata&#039;&#039; returned by this init method, it is added to a INIT_OTHERDATA variable.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;restrict&#039;&#039; field returned by this init call will be used to determine if your handler is enabled or not. For example, if your handler is for the delegate &#039;&#039;CoreCourseOptionsDelegate&#039;&#039; and you return a list of courseids in restrict-&amp;gt;courses, then your handler will only be enabled in the courses you returned. This only applies to the “default” handlers, if you register your own handler using the Javascript code then you should check yourself if the handler is enabled.&lt;br /&gt;
&lt;br /&gt;
Finally, if you return an object in this init Javascript code, all the properties of that object will be passed to all the Javascript code of that handler so you can use them when the code is run. For example, if your init Javascript code does something like this:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var result = {&lt;br /&gt;
    MyAddonClass: new MyAddonClass()&lt;br /&gt;
};&lt;br /&gt;
result:&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Then, for the rest of Javascript code of your handler (e.g. for the “main” method) you can use this variable like this:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
this.MyAddonClass&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Examples====&lt;br /&gt;
&lt;br /&gt;
=====Module link handler=====&lt;br /&gt;
&lt;br /&gt;
A link handler allows you to decide what to do when a link with a certain URL is clicked. This is useful, for example, to open your module when a link to the module is clicked. In this example we’ll create a link handler to detect links to a certificate module using a init JavaScript:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var that = this;&lt;br /&gt;
&lt;br /&gt;
function AddonModCertificateModuleLinkHandler() {&lt;br /&gt;
    that.CoreContentLinksModuleIndexHandler.call(this, that.CoreCourseHelperProvider, &#039;mmaModCertificate&#039;, &#039;certificate&#039;);&lt;br /&gt;
&lt;br /&gt;
    this.name = &amp;quot;AddonModCertificateLinkHandler&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
AddonModCertificateModuleLinkHandler.prototype = Object.create(this.CoreContentLinksModuleIndexHandler.prototype);&lt;br /&gt;
AddonModCertificateModuleLinkHandler.prototype.constructor = AddonModCertificateModuleLinkHandler;&lt;br /&gt;
&lt;br /&gt;
this.CoreContentLinksDelegate.registerHandler(new AddonModCertificateModuleLinkHandler());&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Module prefetch handler=====&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;CoreCourseModuleDelegate&#039;&#039; handler allows you to define a list of &#039;&#039;offlinefunctions&#039;&#039; to prefetch a module. However, you might want to create your own prefetch handler to determine what needs to be downloaded. For example, you might need to chain WS calls (pass the result of a WS call to the next one), and this cannot be done using &#039;&#039;offlinefunctions&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Here’s an example on how to create a prefetch handler using init JS:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var that = this;&lt;br /&gt;
&lt;br /&gt;
function AddonModCertificateModulePrefetchHandler() {&lt;br /&gt;
    that.CoreCourseModulePrefetchHandlerBase.call(this, that.injector);&lt;br /&gt;
&lt;br /&gt;
    this.name = &amp;quot;certificate&amp;quot;;&lt;br /&gt;
    this.component = &amp;quot;mmaModCertificate&amp;quot;;&lt;br /&gt;
    this.updatesNames = /^configuration$|^.*files$/;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
AddonModCertificateModulePrefetchHandler.prototype = Object.create(this.CoreCourseModulePrefetchHandlerBase.prototype);&lt;br /&gt;
AddonModCertificateModulePrefetchHandler.prototype.constructor = AddonModCertificateModulePrefetchHandler;&lt;br /&gt;
&lt;br /&gt;
AddonModCertificateModulePrefetchHandler.prototype.downloadOrPrefetch = function(module, courseId, prefetch, dirPath) {&lt;br /&gt;
&lt;br /&gt;
    var promises = [];&lt;br /&gt;
&lt;br /&gt;
    promises.push(that.CoreCourseModulePrefetchHandlerBase.prototype.downloadOrPrefetch.call(this, module, courseId, prefetch, dirPath));&lt;br /&gt;
&lt;br /&gt;
    promises.push(that.sitesProvider.getCurrentSite().read(&amp;quot;mod_certificate_get_certificates_by_courses&amp;quot;, {courseids: [courseId]}));&lt;br /&gt;
&lt;br /&gt;
return Promise.all(promises);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
this.CoreCourseModulePrefetchDelegate.registerHandler(new AddonModCertificateModulePrefetchHandler());&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Single activity course format=====&lt;br /&gt;
&lt;br /&gt;
In the following example, the value of INIT_TEMPLATES[&amp;quot;main&amp;quot;] is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;core-dynamic-component [component]=&amp;quot;componentClass&amp;quot; [data]=&amp;quot;data&amp;quot;&amp;gt;&amp;lt;/core-dynamic-component&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This template is returned by the init method. And this is the JavaScript code returned by the init method:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var that = this;&lt;br /&gt;
&lt;br /&gt;
function getAddonSingleActivityFormatComponent() {&lt;br /&gt;
    function AddonSingleActivityFormatComponent() {&lt;br /&gt;
        this.data = {};&lt;br /&gt;
    };&lt;br /&gt;
    AddonSingleActivityFormatComponent.prototype.constructor = AddonSingleActivityFormatComponent;&lt;br /&gt;
    AddonSingleActivityFormatComponent.prototype.ngOnChanges = function(changes) {&lt;br /&gt;
        var self = this;&lt;br /&gt;
&lt;br /&gt;
        if (this.course &amp;amp;&amp;amp; this.sections &amp;amp;&amp;amp; this.sections.length) {&lt;br /&gt;
            var module = this.sections[0] &amp;amp;&amp;amp; this.sections[0].modules &amp;amp;&amp;amp; this.sections[0].modules[0];&lt;br /&gt;
            if (module &amp;amp;&amp;amp; !this.componentClass) {&lt;br /&gt;
                that.CoreCourseModuleDelegate.getMainComponent(that.Injector, this.course, module).then((component) =&amp;gt; {&lt;br /&gt;
                    self.componentClass = component || that.CoreCourseUnsupportedModuleComponent;&lt;br /&gt;
                });&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            this.data.courseId = this.course.id;&lt;br /&gt;
            this.data.module = module;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
    AddonSingleActivityFormatComponent.prototype.doRefresh = function(refresher, done) {&lt;br /&gt;
        return Promise.resolve(this.dynamicComponent.callComponentFunction(&amp;quot;doRefresh&amp;quot;, [refresher, done]));&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
return AddonSingleActivityFormatComponent;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function AddonSingleActivityFormatHandler() {&lt;br /&gt;
    this.name = &amp;quot;singleactivity&amp;quot;;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.constructor = AddonSingleActivityFormatHandler;&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.isEnabled = function() {&lt;br /&gt;
    return true;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.canViewAllSections = function(course) {&lt;br /&gt;
    return false;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.getCourseTitle = function(course, sections) {&lt;br /&gt;
    if (sections &amp;amp;&amp;amp; sections[0] &amp;amp;&amp;amp; sections[0].modules &amp;amp;&amp;amp; sections[0].modules[0]) {&lt;br /&gt;
        return sections[0].modules[0].name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return course.fullname || &amp;quot;&amp;quot;;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.displayEnableDownload = function(course) {&lt;br /&gt;
    return false;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.displaySectionSelector = function(course) {&lt;br /&gt;
    return false;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.getCourseFormatComponent = function(injector, course) {&lt;br /&gt;
    that.Injector = injector || that.Injector;&lt;br /&gt;
&lt;br /&gt;
    return that.CoreCompileProvider.instantiateDynamicComponent(that.INIT_TEMPLATES[&amp;quot;main&amp;quot;], getAddonSingleActivityFormatComponent(), injector);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
this.CoreCourseFormatDelegate.registerHandler(new AddonSingleActivityFormatHandler());&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Using the JavaScript API===&lt;br /&gt;
&lt;br /&gt;
The Javascript API is partly supported right now, only the &#039;&#039;CoreUserProfileFieldDelegate&#039;&#039; supports it now. This API allows you to override any of the functions of the default handler. &lt;br /&gt;
&lt;br /&gt;
The “method” specified in a handler registered in the &#039;&#039;CoreUserProfileFieldDelegate&#039;&#039; will be called immediately after the init method, and the Javascript returned by this method will be run. If this Javascript code returns an object with certain functions, these function will override the ones in the default handler.&lt;br /&gt;
&lt;br /&gt;
For example, if the Javascript returned by the method returns something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var result = {&lt;br /&gt;
    getData: function(field, signup, registerAuth, formValues) {&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
result;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The the &#039;&#039;getData&#039;&#039; function of the default handler will be overridden by the returned getData function.&lt;br /&gt;
&lt;br /&gt;
The default handler for &#039;&#039;CoreUserProfileFieldDelegate&#039;&#039; only has 2 functions: &#039;&#039;getComponent&#039;&#039; and &#039;&#039;getData&#039;&#039;. In addition, the JavaScript code can return an extra function named &#039;&#039;componentInit&#039;&#039; that will be executed when the component returned by &#039;&#039;getComponent&#039;&#039; is initialized.&lt;br /&gt;
&lt;br /&gt;
Here’s an example on how to support the text user profile field using this API:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var that = this;&lt;br /&gt;
&lt;br /&gt;
var result = {&lt;br /&gt;
    componentInit: function() {&lt;br /&gt;
        if (this.field &amp;amp;&amp;amp; this.edit &amp;amp;&amp;amp; this.form) {&lt;br /&gt;
            this.field.modelName = &amp;quot;profile_field_&amp;quot; + this.field.shortname;&lt;br /&gt;
&lt;br /&gt;
            if (this.field.param2) {&lt;br /&gt;
                this.field.maxlength = parseInt(this.field.param2, 10) || &amp;quot;&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            this.field.inputType = that.CoreUtilsProvider.isTrueOrOne(this.field.param3) ? &amp;quot;password&amp;quot; : &amp;quot;text&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
            var formData = {&lt;br /&gt;
                value: this.field.defaultdata,&lt;br /&gt;
                disabled: this.disabled&lt;br /&gt;
            };&lt;br /&gt;
&lt;br /&gt;
            this.form.addControl(this.field.modelName, that.FormBuilder.control(formData, this.field.required &amp;amp;&amp;amp; !this.field.locked ? that.Validators.required : null));&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    getData: function(field, signup, registerAuth, formValues) {&lt;br /&gt;
        var name = &amp;quot;profile_field_&amp;quot; + field.shortname;&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            type: &amp;quot;text&amp;quot;,&lt;br /&gt;
            name: name,&lt;br /&gt;
            value: that.CoreTextUtilsProvider.cleanTags(formValues[name])&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
result;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
&lt;br /&gt;
=== Invalid response received ===&lt;br /&gt;
&lt;br /&gt;
You might receive this error when using the &amp;quot;core-site-plugins-call-ws&amp;quot; directive or similar. By default, the app expects all WebService calls to return an object, if your WebService returns another type (string, bool, ...) then you need to specify it using the preSets attribute of the directive. For example, if your WS returns a boolean value, then you should specify it like this:&lt;br /&gt;
&lt;br /&gt;
[preSets]=&amp;quot;{typeExpected: &#039;boolean&#039;}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In a similar way, if your WebService returns null you need to tell the app not to expect any result using the preSets:&lt;br /&gt;
&lt;br /&gt;
[preSets]=&amp;quot;{responseExpected: false}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Values of ion-radio, ion-checkbox or ion-select aren&#039;t sent to my WS ===&lt;br /&gt;
&lt;br /&gt;
Some directives allow you to specify a form id or name to send the data from the form to a certain WS. These directives look for HTML inputs to retrieve the data to send. However, ion-radio, ion-checkbox and ion-select don&#039;t use HTML inputs, they simulate them, so the directive isn&#039;t going to find their data and so it won&#039;t be sent to the WebService.&lt;br /&gt;
&lt;br /&gt;
There are 2 workarounds to fix this problem. It seems that the next major release of Ionic framework does use HTML inputs, so these are temporary solutions.&lt;br /&gt;
&lt;br /&gt;
==== Sending the data manually ====&lt;br /&gt;
&lt;br /&gt;
The first solution is to send the missing params manually using the &amp;quot;&#039;&#039;params&#039;&#039;&amp;quot; property. We will use &#039;&#039;ngModel&#039;&#039; to store the input value in a variable, and this variable will be passed to the params. Please notice that &#039;&#039;ngModel&#039;&#039; &#039;&#039;&#039;requires&#039;&#039;&#039; the element to have a name, so if you add &#039;&#039;ngModel&#039;&#039; to a certain element you need to add a name too.&lt;br /&gt;
&lt;br /&gt;
For example, if you have a template like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&amp;lt;div radio-group name=&amp;quot;responses&amp;quot;&amp;gt; &lt;br /&gt;
    &amp;lt;ion-item&amp;gt;&lt;br /&gt;
        &amp;lt;ion-label&amp;gt;First value&amp;lt;/ion-label&amp;gt;&lt;br /&gt;
        &amp;lt;ion-radio value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/ion-radio&amp;gt;&lt;br /&gt;
    &amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;button ion-button block type=&amp;quot;submit&amp;quot; core-site-plugins-call-ws name=&amp;quot;myws&amp;quot; [params]=&amp;quot;{id: &amp;lt;% id %&amp;gt;}&amp;quot; form=&amp;quot;myform&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mycomponent.save&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you should modify it like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&amp;lt;div radio-group name=&amp;quot;responses&amp;quot; [(ngModel)]=&amp;quot;responses&amp;quot;&amp;gt; &lt;br /&gt;
    &amp;lt;ion-item&amp;gt;&lt;br /&gt;
        &amp;lt;ion-label&amp;gt;First value&amp;lt;/ion-label&amp;gt;&lt;br /&gt;
        &amp;lt;ion-radio value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/ion-radio&amp;gt;&lt;br /&gt;
    &amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;button ion-button block type=&amp;quot;submit&amp;quot; core-site-plugins-call-ws name=&amp;quot;myws&amp;quot; [params]=&amp;quot;{id: &amp;lt;% id %&amp;gt;, responses: responses}&amp;quot; form=&amp;quot;myform&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mycomponent.save&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Basically, you need to add &#039;&#039;ngModel&#039;&#039; to the affected element (in this case, the &#039;&#039;radio-group&#039;&#039;). You can put whatever name you want as the value, we used &amp;quot;responses&amp;quot;. With this, everytime the user selects a radio button the value will be stored in a variable named &amp;quot;responses&amp;quot;. Then, in the button we are passing this variable to the params of the WebService.&lt;br /&gt;
&lt;br /&gt;
Please notice that the &amp;quot;form&amp;quot; attribute has priority over &amp;quot;params&amp;quot;, so if you have an input with name=&amp;quot;responses&amp;quot; it will override what you&#039;re manually passing to params.&lt;br /&gt;
&lt;br /&gt;
==== Using a hidden input ====&lt;br /&gt;
&lt;br /&gt;
Since the directive is looking for HTML inputs, you need to add one with the value to send to the server. You can use &#039;&#039;ngModel&#039;&#039; to synchronize your ion-radio/ion-checkbox/ion-select with the new hidden input. Please notice that &#039;&#039;ngModel&#039;&#039; &#039;&#039;&#039;requires&#039;&#039;&#039; the element to have a name, so if you add &#039;&#039;ngModel&#039;&#039; to a certain element you need to add a name too.&lt;br /&gt;
&lt;br /&gt;
For example, if you have a radio button like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&amp;lt;div radio-group name=&amp;quot;responses&amp;quot;&amp;gt; &lt;br /&gt;
    &amp;lt;ion-item&amp;gt;&lt;br /&gt;
        &amp;lt;ion-label&amp;gt;First value&amp;lt;/ion-label&amp;gt;&lt;br /&gt;
        &amp;lt;ion-radio value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/ion-radio&amp;gt;&lt;br /&gt;
    &amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you should modify it like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&amp;lt;div radio-group name=&amp;quot;responses&amp;quot; [(ngModel)]=&amp;quot;responses&amp;quot;&amp;gt; &lt;br /&gt;
    &amp;lt;ion-item&amp;gt;&lt;br /&gt;
        &amp;lt;ion-label&amp;gt;First value&amp;lt;/ion-label&amp;gt;&lt;br /&gt;
        &amp;lt;ion-radio value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/ion-radio&amp;gt;&lt;br /&gt;
    &amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;ion-input type=&amp;quot;hidden&amp;quot; [ngModel]=&amp;quot;responses&amp;quot; name=&amp;quot;responses&amp;quot;&amp;gt;&amp;lt;/ion-input&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, we&#039;re using a variable named &amp;quot;responses&amp;quot; to synchronize the data between the &#039;&#039;radio-group&#039;&#039; and the hidden input. You can use whatever name you want.&lt;br /&gt;
&lt;br /&gt;
=== I can&#039;t return an object or array in otherdata ===&lt;br /&gt;
&lt;br /&gt;
If you try to return an object or an array in any field inside &#039;&#039;otherdata&#039;&#039;, the WebService call will fail with the following error:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Scalar type expected, array or object received&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Each field in &#039;&#039;otherdata&#039;&#039; must be a string, number or boolean, it cannot be an object or array. To make it work, you need to encode your object or array into a JSON string:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&#039;otherdata&#039; =&amp;gt; array(&#039;data&#039; =&amp;gt; json_encode($data))&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The app will automatically parse this JSON and convert it back into an array or object.&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
===Accepting dynamic names in a WebService===&lt;br /&gt;
&lt;br /&gt;
We want to display a form where the names of the fields are dynamic, like it happens in quiz. This data will be sent to a new WebService that we have created.&lt;br /&gt;
&lt;br /&gt;
The first issue we find is that the WebService needs to define the names of the parameters received, but in this case they&#039;re dynamic. The solution is to accept an array of objects with name and value. So in the &#039;&#039;_parameters()&#039;&#039; function of our new WebService, we will add this parameter:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&#039;data&#039; =&amp;gt; new external_multiple_structure(&lt;br /&gt;
     new external_single_structure(&lt;br /&gt;
        array(&lt;br /&gt;
            &#039;name&#039; =&amp;gt; new external_value(PARAM_RAW, &#039;data name&#039;),&lt;br /&gt;
            &#039;value&#039; =&amp;gt; new external_value(PARAM_RAW, &#039;data value&#039;),&lt;br /&gt;
        )&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;The data to be saved&#039;, VALUE_DEFAULT, array()&lt;br /&gt;
)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we need to adapt our form to send the data as the WebService requires it. In our template, we have a button with the directive &#039;&#039;core-site-plugins-call-ws&#039;&#039; that will send the form data to our WebService. To make this work we will have to pass the parameters manually, without using the &amp;quot;&#039;&#039;form&#039;&#039;&amp;quot; attribute, because we need to format the data before it is sent.&lt;br /&gt;
&lt;br /&gt;
Since we will send the params manually and we want it all to be sent in the same array, we will use &#039;&#039;ngModel&#039;&#039; to store the input data into a variable that we&#039;ll call &amp;quot;data&amp;quot;, but you can use the name you want. This &amp;quot;data&amp;quot; will be an object that will hold the input data with the format &amp;quot;name-&amp;gt;value&amp;quot;. For example, if I have an input with name &amp;quot;a1&amp;quot; and value &amp;quot;My answer&amp;quot;, the data object will be:&lt;br /&gt;
&lt;br /&gt;
{a1: &amp;quot;My answer&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
So we need to add &#039;&#039;ngModel&#039;&#039; to all the inputs whose values need to be sent to the &amp;quot;data&amp;quot; WS param. Please notice that &#039;&#039;ngModel&#039;&#039; &#039;&#039;&#039;requires&#039;&#039;&#039; the element to have a name, so if you add &#039;&#039;ngModel&#039;&#039; to a certain element you need to add a name too. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&amp;lt;ion-input name=&amp;quot;&amp;lt;% name %&amp;gt;&amp;quot; [(ngModel)]=&amp;quot;CONTENT_OTHERDATA.data[&#039;&amp;lt;% name %&amp;gt;&#039;]&amp;quot;&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, we&#039;re using &#039;&#039;CONTENT_OTHERDATA&#039;&#039; to store the data. We do it like this because we&#039;ll use &#039;&#039;otherdata&#039;&#039; to initialize the form, setting the values the user has already stored. If you don&#039;t need to initialize the form, then you can use the variable &amp;quot;dataObject&amp;quot;, an empty object that the Mobile app creates for you: [(ngModel)]=&amp;quot;dataObject[&#039;&amp;lt;% name %&amp;gt;&#039;]&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The Mobile app has a function that allows you to convert this data object into an array like the one the WS expects: &#039;&#039;objectToArrayOfObjects&#039;&#039;. So in our button we&#039;ll use this function to format the data before it&#039;s sent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button block type=&amp;quot;submit&amp;quot; core-site-plugins-call-ws name=&amp;quot;my_ws_name&amp;quot;&lt;br /&gt;
    [params]=&amp;quot;{id: &amp;lt;% id %&amp;gt;, data: CoreUtilsProvider.objectToArrayOfObjects(CONTENT_OTHERDATA.data, &#039;name&#039;, &#039;value&#039;)}&amp;quot;&lt;br /&gt;
    successMessage&lt;br /&gt;
    refreshOnSuccess=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see in the example above, we&#039;re specifying that the keys of the &amp;quot;data&amp;quot; object need to be stored in a property named &amp;quot;name&amp;quot;, and the values need to be stored in a property named &amp;quot;value&amp;quot;. If your WebService expects different names you need to change the parameters of the function &#039;&#039;objectToArrayOfObjects&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
If you open your plugin now in the Mobile app it will display an error in the Javascript console. The reason is that the variable &amp;quot;data&amp;quot; doesn&#039;t exist inside &#039;&#039;CONTENT_OTHERDATA&#039;&#039;. As it is explained in previous sections, &#039;&#039;CONTENT_OTHERDATA&#039;&#039; holds the data that you return in &#039;&#039;otherdata&#039;&#039; for your method. We&#039;ll use &#039;&#039;otherdata&#039;&#039; to initialize the values to be displayed in the form.&lt;br /&gt;
&lt;br /&gt;
If the user hasn&#039;t answered the form yet, we can initialize the &amp;quot;data&amp;quot; object as an empty object. Please remember that we cannot return arrays or objects in &#039;&#039;otherdata&#039;&#039;, so we&#039;ll return a JSON string.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&#039;otherdata&#039; =&amp;gt; array(&#039;data&#039; =&amp;gt; &#039;{}&#039;)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With the code above, the form will always be empty when the user opens it. But now we want to check if the user has already answered the form and fill the form with the previous values. We will do it like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$userdata = get_user_responses(); // It will held the data in a format name-&amp;gt;value. Example: array(&#039;a1&#039; =&amp;gt; &#039;My value&#039;).&lt;br /&gt;
...&lt;br /&gt;
&#039;otherdata&#039; =&amp;gt; array(&#039;data&#039; =&amp;gt; json_encode($userdata))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now the user will be able to see previous values when the form is opened, and clicking the button will send the data to our WebService in array format.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Mobile]]&lt;/div&gt;</summary>
		<author><name>Mayel</name></author>
	</entry>
</feed>